diff options
author | Hans Goudey <h.goudey@me.com> | 2020-06-05 18:34:10 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2020-06-05 18:34:10 +0300 |
commit | 76e9cdc90a43458ab0bb5d66883631f9dc5fe53b (patch) | |
tree | af531a8989c7bad0bc8d3020a5ef61ac0096c315 /source/blender | |
parent | 8a971c9d91fafaa77fcb320bfd1f25e7e905dce2 (diff) | |
parent | 9b099c86123fc828a194c59ce5b8bbf5a56f9cdb (diff) |
Merge branch 'master' into modifier-panels-ui
Diffstat (limited to 'source/blender')
541 files changed, 15496 insertions, 10203 deletions
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h index 8809fadd55c..5aeaf4405f5 100644 --- a/source/blender/blenkernel/BKE_anim_data.h +++ b/source/blender/blenkernel/BKE_anim_data.h @@ -32,6 +32,7 @@ extern "C" { struct AnimData; struct ID; +struct LibraryForeachIDData; struct Main; struct ReportList; struct bAction; @@ -58,6 +59,8 @@ 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); 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 5510f3c3d2e..9d948dfd57b 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -30,22 +30,26 @@ extern "C" { * * \note Use #STRINGIFY() rather than defining with quotes. */ + +/* Blender major and minor version. */ #define BLENDER_VERSION 290 -#define BLENDER_SUBVERSION 2 -/** 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 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 } diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index 458f1ab7a56..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. @@ -98,6 +99,9 @@ typedef enum BVHCacheType { BVHTREE_FROM_EM_VERTS, BVHTREE_FROM_EM_EDGES, BVHTREE_FROM_EM_LOOPTRI, + + /* Keep `BVHTREE_MAX_ITEM` as last item. */ + BVHTREE_MAX_ITEM, } BVHCacheType; /** @@ -122,7 +126,8 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache); + struct BVHCache **bvh_cache_p, + ThreadMutex *mesh_eval_mutex); BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data, const struct MVert *vert, @@ -134,7 +139,8 @@ BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache); + 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); @@ -147,7 +153,8 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache); + struct BVHCache **bvh_cache_p, + ThreadMutex *mesh_eval_mutex); BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data, const struct MVert *vert, @@ -161,7 +168,8 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache); + struct BVHCache **bvh_cache_p, + ThreadMutex *mesh_eval_mutex); BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data, const struct MVert *vert, @@ -175,7 +183,8 @@ BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache); + 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); @@ -188,7 +197,8 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache); + struct BVHCache **bvh_cache_p, + ThreadMutex *mesh_eval_mutex); BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data, const struct MVert *vert, @@ -204,7 +214,8 @@ BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache); + struct BVHCache **bvh_cache_p, + ThreadMutex *mesh_eval_mutex); BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, struct Mesh *mesh, @@ -215,7 +226,8 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data, struct BMEditMesh *em, const int tree_type, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache); + struct BVHCache **bvh_cache_p, + ThreadMutex *mesh_eval_mutex); /** * Frees data allocated by a call to bvhtree_from_mesh_*. @@ -244,10 +256,9 @@ float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray, /* Using local coordinates */ -bool bvhcache_find(const BVHCache *cache, BVHCacheType type, BVHTree **r_tree); -bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree); -void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, BVHCacheType 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_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_curve.h b/source/blender/blenkernel/BKE_curve.h index bf270f2c06f..40f73ccfe84 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -173,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); 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 21a9b7b8b04..c3a597e29b9 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -37,6 +37,7 @@ struct FModifier; struct AnimData; struct BezTriple; +struct LibraryForeachIDData; struct PathResolvedRNA; struct PointerRNA; struct PropertyRNA; @@ -178,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( @@ -196,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) @@ -228,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_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index faa331aa02d..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; @@ -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_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h index fac1852eafe..c5a25e8e7af 100644 --- a/source/blender/blenkernel/BKE_lib_query.h +++ b/source/blender/blenkernel/BKE_lib_query.h @@ -94,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. diff --git a/source/blender/blenkernel/BKE_light.h b/source/blender/blenkernel/BKE_light.h index 17f7a8596bf..ead27ec8002 100644 --- a/source/blender/blenkernel/BKE_light.h +++ b/source/blender/blenkernel/BKE_light.h @@ -31,6 +31,7 @@ extern "C" { #endif +struct Depsgraph; struct Light; struct Main; @@ -38,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 29ec65166a9..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 */ 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 672ee8f9cd5..e4cf7d44f05 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -102,6 +102,9 @@ typedef enum { /* For modifiers that use CD_PREVIEW_MCOL for preview. */ eModifierTypeFlag_UsesPreview = (1 << 9), eModifierTypeFlag_AcceptsVertexCosOnly = (1 << 10), + + /** Accepts #BMesh input (without conversion). */ + eModifierTypeFlag_AcceptsBMesh = (1 << 11), } ModifierTypeFlag; /* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */ @@ -212,10 +215,10 @@ typedef struct ModifierTypeInfo { /********************* Non-deform modifier functions *********************/ - /* For non-deform types: apply the modifier and return a mesh datablock. + /* For non-deform types: apply the modifier and return a mesh data-block. * * The mesh argument should always be non-NULL; the modifier should use the - * passed in mesh datablock rather than object->data, as it contains the mesh + * passed in mesh data-block rather than object->data, as it contains the mesh * with modifier applied up to this point. * * The modifier may modify and return the mesh argument, but must not free it @@ -365,9 +368,6 @@ const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type); /* For modifier UI panels. */ void BKE_modifier_type_panel_id(ModifierType type, char *r_idname); -/* For modifier UI panels. */ -void modifierType_panelId(ModifierType type, char *r_idname); - /* Modifier utility calls, do call through type pointer and return * default values if pointer is optional. */ @@ -403,7 +403,7 @@ void BKE_modifiers_foreach_ID_link(struct Object *ob, IDWalkFunc walk, void *use 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_findny_name(struct Object *ob, const char *name); +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, 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_paint.h b/source/blender/blenkernel/BKE_paint.h index a7ece2e3167..26ffd1bbfef 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -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 */ diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index ea81be05b03..00d010cd6d9 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -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 2bf16e38716..8fb6f140822 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -82,8 +82,8 @@ typedef struct PBVHFrustumPlanes { int num_planes; } PBVHFrustumPlanes; -void BKE_pbvh_set_frustum_planes(PBVH *bvh, PBVHFrustumPlanes *planes); -void BKE_pbvh_get_frustum_planes(PBVH *bvh, PBVHFrustumPlanes *planes); +void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes); +void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes); /* Callbacks */ @@ -98,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, @@ -109,47 +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(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, @@ -170,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, @@ -190,7 +190,7 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh, /* Drawing */ -void BKE_pbvh_draw_cb(PBVH *bvh, +void BKE_pbvh_draw_cb(PBVH *pbvh, bool update_only_visible, PBVHFrustumPlanes *update_frustum, PBVHFrustumPlanes *draw_frustum, @@ -198,7 +198,7 @@ void BKE_pbvh_draw_cb(PBVH *bvh, 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); @@ -209,26 +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 *bvh); +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 */ @@ -239,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], @@ -262,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); @@ -289,27 +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 *bvh, struct SubdivCCG *subdiv_ccg); -void BKE_pbvh_face_sets_set(PBVH *bvh, int *face_sets); +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); +void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default); -void BKE_pbvh_respect_hide_set(PBVH *bvh, bool respect_hide); +void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide); /* vertex deformer */ float (*BKE_pbvh_vert_coords_alloc(struct PBVH *pbvh))[3]; @@ -370,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) { \ @@ -446,30 +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 */ void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings, bool use_threading, int totnode); -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_screen.h b/source/blender/blenkernel/BKE_screen.h index 8794558b81f..fc7146b8cf4 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; @@ -48,7 +49,6 @@ struct WorkSpace; struct bContext; struct bContextDataResult; struct bScreen; -struct LibraryForeachIDData; struct uiLayout; struct uiList; struct wmGizmoMap; @@ -234,17 +234,17 @@ typedef struct PanelType { /** Reorder function, called when drag and drop finishes. */ void (*reorder)(struct bContext *C, struct Panel *pa, int new_index); /** - * Get the panel and subpanel's expansion state from the expansion flag in the corresponding data - * item. Called on draw updates. - * \note Subpanels are indexed in depth first order, the visualorder you would see if all panels - * were expanded. + * 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 bitfield from the closed / open state of this panel and its subpanels. + * 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 Subpanels are indexed in depth first order, the visual order you would see if all panels - * were expanded. + * \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); diff --git a/source/blender/blenkernel/BKE_simulation.h b/source/blender/blenkernel/BKE_simulation.h index d1cf782e9e5..ff6aaa5e30e 100644 --- a/source/blender/blenkernel/BKE_simulation.h +++ b/source/blender/blenkernel/BKE_simulation.h @@ -21,13 +21,15 @@ extern "C" { #endif +struct Depsgraph; struct Main; struct Simulation; -struct Depsgraph; void *BKE_simulation_add(struct Main *bmain, const char *name); -void BKE_simulation_data_update(struct Depsgraph *depsgraph, struct Scene *scene); +void BKE_simulation_data_update(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Simulation *simulation); #ifdef __cplusplus } 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 220bafa2187..817fe849eab 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -168,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 diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index b3893d8600f..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); /* -------------------------------------------------------------------- */ @@ -861,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, @@ -1391,11 +1403,16 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev 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. */ @@ -1501,7 +1518,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* Evaluate modifiers up to certain index to get the mesh cage. */ 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); } @@ -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 */ @@ -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 bd39ffc65e7..c776f0d077d 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -116,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); @@ -146,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); @@ -159,6 +159,10 @@ 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); } @@ -1306,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); diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 02b7763a9b4..9ab4e5c028d 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -32,6 +32,7 @@ #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" @@ -255,7 +256,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user) BKE_nla_tracks_free(&adt->nla_tracks, do_id_user); /* free drivers - stored as a list of F-Curves */ - free_fcurves(&adt->drivers); + BKE_fcurves_free(&adt->drivers); /* free driver array cache */ MEM_SAFE_FREE(adt->driver_array); @@ -289,6 +290,24 @@ bool BKE_animdata_id_is_animated(const struct ID *id) !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 -------------------------------------------- */ /** @@ -326,7 +345,7 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag) BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag); /* duplicate drivers (F-Curves) */ - copy_fcurves(&dadt->drivers, &adt->drivers); + BKE_fcurves_copy(&dadt->drivers, &adt->drivers); dadt->driver_array = NULL; /* don't copy overrides */ @@ -428,7 +447,7 @@ void BKE_animdata_merge_copy( if (src->drivers.first) { ListBase drivers = {NULL, NULL}; - copy_fcurves(&drivers, &src->drivers); + 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 @@ -1082,7 +1101,7 @@ static bool fcurves_path_remove_fix(const char *prefix, ListBase *curves) if (fcu->rna_path) { if (STRPREFIX(fcu->rna_path, prefix)) { BLI_remlink(curves, fcu); - free_fcurve(fcu); + BKE_fcurve_free(fcu); any_removed = true; } } diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index b3a4de02451..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 diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 13dcc7b06f6..ef474022f19 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -415,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/brush.c b/source/blender/blenkernel/intern/brush.c index 133917e441c..3241518cae5 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -520,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. */ @@ -744,6 +745,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. */ diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index cd90ebc2eed..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 * \{ */ @@ -518,29 +636,26 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache) + 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); } /** @@ -582,32 +698,26 @@ BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache) + 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; } } @@ -735,29 +845,26 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache) + 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); } /** @@ -802,32 +910,26 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache) + 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; } } @@ -937,32 +1039,26 @@ BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache) + 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; } } @@ -1113,29 +1209,28 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache) + 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); } /** @@ -1177,21 +1273,14 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data, int tree_type, int axis, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache) + 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; } } @@ -1315,11 +1405,10 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, 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; } @@ -1493,17 +1587,16 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data, struct BMEditMesh *em, const int tree_type, const BVHCacheType bvh_cache_type, - BVHCache **bvh_cache) + 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 { - BVHCacheType type; - BVHTree *tree; - -} BVHCacheItem; - -/** - * Queries a bvhcache for the cache bvhtree of the request type - */ -bool bvhcache_find(const BVHCache *cache, BVHCacheType 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, BVHCacheType 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/collection.c b/source/blender/blenkernel/intern/collection.c index c1d77fd5f9e..e8e3e61ced4 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -210,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). */ @@ -758,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) { diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index a96747f82c4..44ac59432e7 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -951,6 +951,10 @@ static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar /* 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; @@ -4691,7 +4695,7 @@ static void followtrack_evaluate_using_3d_position_object(FollowTrackContext *co MovieTrackingTrack *track = context->track; MovieTrackingObject *tracking_object = context->tracking_object; - /* Matrix of the object which is being solved prior to this contraint. */ + /* Matrix of the object which is being solved prior to this constraint. */ float obmat[4][4]; copy_m4_m4(obmat, cob->matrix); @@ -4716,7 +4720,7 @@ static void followtrack_evaluate_using_3d_position_camera(FollowTrackContext *co Object *camera_object = context->camera_object; MovieTrackingTrack *track = context->track; - /* Matrix of the object which is being solved prior to this contraint. */ + /* Matrix of the object which is being solved prior to this constraint. */ float obmat[4][4]; copy_m4_m4(obmat, cob->matrix); diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index f4acbdca772..6c8438e478e 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -293,7 +293,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra 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"); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 0798bc95797..e67cf8573f3 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -4485,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; @@ -4497,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++; } } @@ -4505,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; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index a022f3f5d14..b0007c2a598 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1339,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}, @@ -1654,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", @@ -1706,6 +1852,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { "CDHairCurve", "CDHairMapping", "CDPoint", + "CDPropCol", }; const CustomData_MeshMasks CD_MASK_BAREMESH = { diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index f3cc17f46f6..dae8a59fe43 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2704,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; } } diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 5aaae74e670..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" @@ -266,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/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 5d2207b5b80..d4754615c7f 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -31,6 +31,7 @@ #include "DNA_anim_types.h" #include "DNA_object_types.h" +#include "DNA_text_types.h" #include "BLI_blenlib.h" #include "BLI_easing.h" @@ -43,6 +44,8 @@ #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 "RNA_access.h" @@ -55,11 +58,15 @@ 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; @@ -81,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; @@ -96,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 */ @@ -106,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; @@ -139,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; @@ -153,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 */ @@ -195,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; } @@ -214,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; @@ -239,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; @@ -272,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; @@ -317,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; @@ -361,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; } @@ -397,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; @@ -406,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) { @@ -596,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; @@ -726,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; @@ -779,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) { @@ -847,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; } @@ -1447,8 +1483,8 @@ static float fcurve_eval_keyframes_extrapolate( return endpoint_bezt->vec[1][1] - (fac * dx); } - /* Use the gradient of the second handle (later) of neighbour to calculate the gradient and thus - * the value of the curve at evaltime */ + /* 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]; diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 4311e425abf..122cc656bc2 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -839,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 */ @@ -1855,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); @@ -1878,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. */ diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 780c3c2f14a..7bf9cb2d0a1 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1341,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) { @@ -1420,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; @@ -2396,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/layer.c b/source/blender/blenkernel/intern/layer.c index 0eaf7cf2f41..f03bf60817f 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -694,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 @@ -732,7 +732,6 @@ 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; LISTBASE_FOREACH (const CollectionChild *, child, lb_scene) { Collection *collection = child->collection; @@ -763,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).*/ @@ -846,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; } /** diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 9ef5c549235..19462c62496 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -128,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; @@ -146,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); } } @@ -310,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; } @@ -335,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); } /** @@ -393,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); @@ -1676,20 +1691,6 @@ static void library_make_local_copying_check(ID *id, /* 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) { -#ifndef NDEBUG - /* Some debug checks to ensure we explicitly are aware of all 'loop-back' cases, since those - * may not always be manageable in the same way... */ - switch (GS(par_id->name)) { - case ID_OB: - BLI_assert(((Object *)par_id)->proxy_from == (Object *)id); - break; - case ID_KE: - BLI_assert(((Key *)par_id)->from == id); - break; - default: - BLI_assert(0); - } -#endif continue; } diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 795390f1940..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); @@ -1027,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 @@ -1055,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 015fa235a06..00a42b12e07 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -24,41 +24,6 @@ #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_simulation_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" @@ -66,24 +31,12 @@ #include "BLI_utildefines.h" #include "BKE_anim_data.h" -#include "BKE_collection.h" -#include "BKE_constraint.h" -#include "BKE_fcurve_driver.h" -#include "BKE_gpencil_modifier.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_screen.h" -#include "BKE_sequencer.h" -#include "BKE_shader_fx.h" -#include "BKE_texture.h" -#include "BKE_workspace.h" /* status */ enum { @@ -122,6 +75,7 @@ bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int 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, @@ -182,39 +136,6 @@ void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, IDWALK_CB_USER); } -static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip) -{ - BKE_LIB_FOREACHID_PROCESS(data, strip->act, IDWALK_CB_USER); - - LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) { - library_foreach_nla_strip(data, substrip); - } -} - -static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt) -{ - LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { - ChannelDriver *driver = fcu->driver; - - 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; - } - } - - 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) { - library_foreach_nla_strip(data, nla_strip); - } - } -} - bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) { /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */ @@ -341,7 +262,7 @@ static void library_foreach_ID_link(Main *bmain, AnimData *adt = BKE_animdata_from_id(id); if (adt) { - library_foreach_animationData(&data, adt); + BKE_animdata_foreach_id(adt, &data); } const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c index 9dc338ce580..aa1005c663f 100644 --- a/source/blender/blenkernel/intern/light.c +++ b/source/blender/blenkernel/intern/light.c @@ -48,6 +48,8 @@ #include "BLT_translation.h" +#include "DEG_depsgraph.h" + static void light_init_data(ID *id) { Light *la = (Light *)id; @@ -178,3 +180,8 @@ Light *BKE_light_localize(Light *la) return lan; } + +void BKE_light_eval(struct Depsgraph *depsgraph, Light *la) +{ + DEG_debug_print_eval(depsgraph, __func__, la->id.name, la); +} diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index aeef287bb87..0d20d25f84c 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -866,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, @@ -895,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; } @@ -916,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; } diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 655c70bcf61..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, diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index f0d19f01aab..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); 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_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_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 138ffbaaf71..324a9d3ccb0 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -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" @@ -247,7 +248,7 @@ ModifierData *BKE_modifiers_findby_type(Object *ob, ModifierType type) return md; } -ModifierData *BKE_modifiers_findny_name(Object *ob, const char *name) +ModifierData *BKE_modifiers_findby_name(Object *ob, const char *name) { return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name)); } @@ -947,6 +948,30 @@ void BKE_modifier_path_init(char *path, int path_maxlen, const char *name) BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name); } +/** + * 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; + } +} + /* wrapper around ModifierTypeInfo.modifyMesh that ensures valid normals */ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md, @@ -956,8 +981,14 @@ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md, 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->modifyMesh(md, ctx, me); } @@ -972,7 +1003,7 @@ void BKE_modifier_deform_verts(ModifierData *md, 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); } @@ -1043,5 +1074,5 @@ struct ModifierData *BKE_modifier_get_evaluated(Depsgraph *depsgraph, if (object_eval == object) { return md; } - return BKE_modifiers_findny_name(object_eval, md->name); + return BKE_modifiers_findby_name(object_eval, md->name); } diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c index 7312ac2bf5e..3564ae80d24 100644 --- a/source/blender/blenkernel/intern/multires_reshape_smooth.c +++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c @@ -55,7 +55,7 @@ /* 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 - * travesing the final limit surface. */ + * traversing the final limit surface. */ typedef struct SurfacePoint { float P[3]; 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/object.c b/source/blender/blenkernel/intern/object.c index d17575195e3..e7a8d04e0b8 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -81,6 +81,7 @@ #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" @@ -2086,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; @@ -3089,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); } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 015c67806c6..eb485e1522f 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -4783,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_system.c b/source/blender/blenkernel/intern/particle_system.c index df74b7a75da..31d51a74e7f 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2163,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); @@ -4046,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; } } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index e31d2a8e005..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,19 +295,19 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) node->face_vert_indices = (const int(*)[3])face_vert_indices; - if (bvh->respect_hide == false) { + 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 (has_visible == false) { - if (!paint_is_face_hidden(lt, bvh->verts, bvh->mloop)) { + if (!paint_is_face_hidden(lt, pbvh->verts, pbvh->mloop)) { has_visible = true; } } @@ -347,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; } @@ -389,77 +389,78 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden, return totquad; } -void BKE_pbvh_sync_face_sets_to_grids(PBVH *bvh) +void BKE_pbvh_sync_face_sets_to_grids(PBVH *pbvh) { - const int gridsize = bvh->gridkey.grid_size; - for (int i = 0; i < bvh->totgrid; i++) { - BLI_bitmap *gh = bvh->grid_hidden[i]; - const int face_index = BKE_subdiv_ccg_grid_to_face_index(bvh->subdiv_ccg, i); - if (!gh && bvh->face_sets[face_index] < 0) { - gh = bvh->grid_hidden[i] = BLI_BITMAP_NEW(bvh->gridkey.grid_area, "partialvis_update_grids"); + 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, bvh->face_sets[face_index] < 0); + BLI_BITMAP_SET(gh, y * gridsize + x, pbvh->face_sets[face_index] < 0); } } } } } -static void build_grid_leaf_node(PBVH *bvh, PBVHNode *node) +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; } } @@ -479,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 */ @@ -506,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, @@ -521,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); } /** @@ -561,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, @@ -576,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); @@ -605,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); @@ -614,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, @@ -632,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); @@ -663,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); @@ -671,15 +676,15 @@ void BKE_pbvh_build_grids(PBVH *bvh, PBVH *BKE_pbvh_new(void) { - PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); - bvh->respect_hide = true; - 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) { @@ -703,42 +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); + 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; } @@ -804,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); } } @@ -834,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); } } @@ -843,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) { @@ -875,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, @@ -884,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) { @@ -958,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, @@ -968,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) { @@ -1009,7 +1014,7 @@ static bool update_search_cb(PBVHNode *node, void *data_v) } typedef struct PBVHUpdateData { - PBVH *bvh; + PBVH *pbvh; PBVHNode **nodes; int totnode; @@ -1024,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; @@ -1036,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 @@ -1073,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; @@ -1083,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. */ @@ -1098,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 @@ -1115,7 +1120,7 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode) */ PBVHUpdateData data = { - .bvh = bvh, + .pbvh = pbvh, .nodes = nodes, .vnors = vnors, }; @@ -1135,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) { @@ -1144,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; @@ -1166,10 +1171,10 @@ 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, }; @@ -1185,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); @@ -1204,10 +1209,10 @@ 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, }; @@ -1222,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)) { @@ -1241,11 +1246,11 @@ 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, }; @@ -1255,7 +1260,7 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); } -static int pbvh_get_buffers_update_flags(PBVH *UNUSED(bvh)) +static int pbvh_get_buffers_update_flags(PBVH *UNUSED(pbvh)) { int update_flags = GPU_PBVH_BUFFERS_SHOW_VCOL | GPU_PBVH_BUFFERS_SHOW_MASK | GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS; @@ -1270,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( - 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); - 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->subdiv_ccg, - bvh->grids, - bvh->grid_flag_mats, + pbvh->subdiv_ccg, + pbvh->grids, + pbvh->grid_flag_mats, node->prim_indices, node->totprim, - bvh->face_sets, - bvh->face_sets_color_seed, - bvh->face_sets_color_default, - &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, - 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, + 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, @@ -1334,9 +1339,9 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, } } -static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, 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]; @@ -1345,11 +1350,11 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, i 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); } } @@ -1358,7 +1363,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, i /* Parallel creation and update of draw buffers. */ PBVHUpdateData data = { - .bvh = bvh, + .pbvh = pbvh, .nodes = nodes, }; @@ -1367,7 +1372,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, i 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; @@ -1386,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; @@ -1400,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) { @@ -1446,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]]; @@ -1465,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; @@ -1530,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); @@ -1548,10 +1553,10 @@ 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, }; @@ -1560,9 +1565,9 @@ static void pbvh_update_visibility(PBVH *bvh, PBVHNode **nodes, int totnode) 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; } @@ -1570,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; @@ -1586,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) { @@ -1600,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); } @@ -1647,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); } @@ -1675,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(bvh->type == PBVH_GRIDS); - return bvh->grid_hidden; + BLI_assert(pbvh->type == PBVH_GRIDS); + return pbvh->grid_hidden; } -const CCGKey *BKE_pbvh_get_grid_key(const PBVH *bvh) +const CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh) { - BLI_assert(bvh->type == PBVH_GRIDS); - return &bvh->gridkey; + BLI_assert(pbvh->type == PBVH_GRIDS); + return &pbvh->gridkey; } -struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh) +struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh) { - BLI_assert(bvh->type == PBVH_GRIDS); - return bvh->grids; + BLI_assert(pbvh->type == PBVH_GRIDS); + return pbvh->grids; } -int BKE_pbvh_get_grid_num_vertices(const PBVH *bvh) +BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh) { - BLI_assert(bvh->type == PBVH_GRIDS); - return bvh->totgrid * bvh->gridkey.grid_area; + BLI_assert(pbvh->type == PBVH_GRIDS); + return pbvh->grid_hidden; } -BMesh *BKE_pbvh_get_bmesh(PBVH *bvh) +int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh) { - BLI_assert(bvh->type == PBVH_BMESH); - return bvh->bm; + BLI_assert(pbvh->type == PBVH_GRIDS); + return pbvh->totgrid * pbvh->gridkey.grid_area; +} + +BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh) +{ + BLI_assert(pbvh->type == PBVH_BMESH); + return pbvh->bm; } /***************************** Node Access ***********************************/ @@ -1785,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) @@ -1795,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; } @@ -1833,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, @@ -1841,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; @@ -1850,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: @@ -1927,15 +1938,15 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node, * 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; @@ -1971,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], @@ -1983,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], @@ -2101,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], @@ -2112,18 +2123,18 @@ static bool pbvh_faces_node_raycast(PBVH *bvh, 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 (bvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) { + if (pbvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) { continue; } @@ -2169,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], @@ -2181,21 +2192,21 @@ static bool pbvh_grids_node_raycast(PBVH *bvh, 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++) { @@ -2263,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, @@ -2281,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, @@ -2295,7 +2306,7 @@ bool BKE_pbvh_node_raycast(PBVH *bvh, face_normal); break; case PBVH_GRIDS: - hit |= pbvh_grids_node_raycast(bvh, + hit |= pbvh_grids_node_raycast(pbvh, node, origco, ray_start, @@ -2307,7 +2318,7 @@ bool BKE_pbvh_node_raycast(PBVH *bvh, 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, @@ -2323,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; @@ -2334,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 @@ -2399,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], @@ -2411,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], @@ -2422,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 (bvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) { + if (pbvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) { continue; } @@ -2461,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], @@ -2470,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++) { @@ -2505,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); } @@ -2523,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, @@ -2538,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( @@ -2619,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); @@ -2649,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; } /** @@ -2675,7 +2686,7 @@ static bool pbvh_draw_search_cb(PBVHNode *node, void *data_v) return true; } -void BKE_pbvh_draw_cb(PBVH *bvh, +void BKE_pbvh_draw_cb(PBVH *pbvh, bool update_only_visible, PBVHFrustumPlanes *update_frustum, PBVHFrustumPlanes *draw_frustum, @@ -2689,10 +2700,11 @@ 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, update_flag); + pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag); } MEM_SAFE_FREE(nodes); @@ -2700,11 +2712,11 @@ void BKE_pbvh_draw_cb(PBVH *bvh, /* Gather visible nodes. */ PBVHDrawSearchData data = {.frustum = update_frustum, .accum_update_flag = 0}; - BKE_pbvh_search_gather(bvh, pbvh_draw_search_cb, &data, &nodes, &totnode); + 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, data.accum_update_flag); + pbvh_update_draw_buffers(pbvh, nodes, totnode, data.accum_update_flag); } /* Draw. */ @@ -2722,7 +2734,7 @@ void BKE_pbvh_draw_cb(PBVH *bvh, MEM_SAFE_FREE(nodes); PBVHDrawSearchData draw_data = {.frustum = draw_frustum, .accum_update_flag = 0}; - BKE_pbvh_search_gather(bvh, pbvh_draw_search_cb, &draw_data, &nodes, &totnode); + BKE_pbvh_search_gather(pbvh, pbvh_draw_search_cb, &draw_data, &nodes, &totnode); for (int a = 0; a < totnode; a++) { PBVHNode *node = nodes[a]; @@ -2735,29 +2747,29 @@ 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]); } } } @@ -2830,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; @@ -2845,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; @@ -2893,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; @@ -2906,16 +2918,16 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo vi->fno = NULL; vi->mvert = NULL; - vi->respect_hide = bvh->respect_hide; - if (bvh->respect_hide == false) { + 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(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; + 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; @@ -2931,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 (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_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; } @@ -2977,29 +2989,29 @@ 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) { - bvh->show_mask = show_mask; + pbvh->show_mask = show_mask; } -void pbvh_show_face_sets_set(PBVH *bvh, bool show_face_sets) +void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets) { - bvh->show_face_sets = show_face_sets; + pbvh->show_face_sets = show_face_sets; } -void BKE_pbvh_set_frustum_planes(PBVH *bvh, PBVHFrustumPlanes *planes) +void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes) { - bvh->num_planes = planes->num_planes; - for (int i = 0; i < bvh->num_planes; i++) { - copy_v4_v4(bvh->planes[i], planes->planes[i]); + 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 BKE_pbvh_get_frustum_planes(PBVH *bvh, PBVHFrustumPlanes *planes) +void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes) { - planes->num_planes = bvh->num_planes; + planes->num_planes = pbvh->num_planes; for (int i = 0; i < planes->num_planes; i++) { - copy_v4_v4(planes->planes[i], bvh->planes[i]); + copy_v4_v4(planes->planes[i], pbvh->planes[i]); } } @@ -3011,23 +3023,23 @@ void BKE_pbvh_parallel_range_settings(TaskParallelSettings *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(bvh->type == PBVH_FACES); - return bvh->verts; + BLI_assert(pbvh->type == PBVH_FACES); + return pbvh->verts; } -void BKE_pbvh_subdiv_cgg_set(PBVH *bvh, SubdivCCG *subdiv_ccg) +void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, SubdivCCG *subdiv_ccg) { - bvh->subdiv_ccg = subdiv_ccg; + pbvh->subdiv_ccg = subdiv_ccg; } -void BKE_pbvh_face_sets_set(PBVH *bvh, int *face_sets) +void BKE_pbvh_face_sets_set(PBVH *pbvh, int *face_sets) { - bvh->face_sets = face_sets; + pbvh->face_sets = face_sets; } -void BKE_pbvh_respect_hide_set(PBVH *bvh, bool respect_hide) +void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide) { - bvh->respect_hide = respect_hide; + 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/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 4d37c2ea931..c9911d2cf85 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -2116,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 34249e0a8f7..aa2a1b14841 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -158,7 +158,7 @@ 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. */ + /* Anti-Aliasing threshold. */ scene->grease_pencil_settings.smaa_threshold = 1.0f; { @@ -621,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); } } } @@ -668,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; @@ -1249,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) { diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index a08bbf182fa..5c2d5b0087f 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -1217,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) { @@ -1314,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) { @@ -1322,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/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c index f00d517940a..30a371b5b28 100644 --- a/source/blender/blenkernel/intern/seqprefetch.c +++ b/source/blender/blenkernel/intern/seqprefetch.c @@ -179,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) @@ -198,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) @@ -347,7 +351,7 @@ static bool seq_prefetch_do_skip_frame(Scene *scene) { Editing *ed = scene->ed; PrefetchJob *pfjob = seq_prefetch_job_get(scene); - float cfra = pfjob->cfra + pfjob->num_frames_prefetched; + 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; @@ -403,20 +407,36 @@ static bool seq_prefetch_do_skip_frame(Scene *scene) 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; 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, - pfjob->cfra + pfjob->num_frames_prefetched, - ADT_RECALC_ALL, - false); + 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. @@ -431,26 +451,17 @@ static void *seq_prefetch_frames(void *job) continue; } - ImBuf *ibuf = BKE_sequencer_give_ibuf( - &pfjob->context_cpy, pfjob->cfra + pfjob->num_frames_prefetched, 0); + 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; } @@ -463,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; @@ -520,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 954dca0f679..90edebfaa97 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -5119,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); } } @@ -5152,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; } diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 50770125a18..d5ba345928b 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -18,6 +18,8 @@ * \ingroup bke */ +#include <iostream> + #include "MEM_guardedalloc.h" #include "DNA_ID.h" @@ -46,6 +48,7 @@ #include "BLT_translation.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" static void simulation_init_data(ID *id) { @@ -122,6 +125,8 @@ void *BKE_simulation_add(Main *bmain, const char *name) return simulation; } -void BKE_simulation_data_update(Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene)) +void BKE_simulation_data_update(Depsgraph *UNUSED(depsgraph), + Scene *UNUSED(scene), + Simulation *UNUSED(simulation)) { } diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index aef274f7d91..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, true); - GPU_texture_unbind(tex); } 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, true); - GPU_texture_unbind(tex); } sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE; } 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/workspace.c b/source/blender/blenkernel/intern/workspace.c index 3a69b95c114..4625fd76293 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -69,17 +69,9 @@ static void workspace_free_data(ID *id) static void workspace_foreach_id(ID *id, LibraryForeachIDData *data) { WorkSpace *workspace = (WorkSpace *)id; - ListBase *layouts = BKE_workspace_layouts_get(workspace); - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { - 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. */ - BKE_LIB_FOREACHID_PROCESS(data, screen, IDWALK_CB_USER); - /* allow callback to set a different screen */ - BKE_workspace_layout_screen_set(layout, screen); + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { + BKE_LIB_FOREACHID_PROCESS(data, layout->screen, IDWALK_CB_USER); } } @@ -228,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; @@ -433,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( @@ -443,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) @@ -462,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) @@ -485,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/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 { diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h index b9cb32a310e..603be115b35 100644 --- a/source/blender/blenlib/BLI_assert.h +++ b/source/blender/blenlib/BLI_assert.h @@ -69,7 +69,13 @@ extern "C" { # endif /* _BLI_ASSERT_ABORT */ # ifdef WITH_ASSERT_ABORT -# define _BLI_ASSERT_ABORT abort +# ifdef __GNUC__ +/* Cast to remove 'noreturn' attribute since this suppresses missing return statements, + * allowing changes to debug builds to accidentally to break release builds. */ +# define _BLI_ASSERT_ABORT ((void (*)(void))(*(((void **)abort)))) +# else +# define _BLI_ASSERT_ABORT abort +# endif # else # define _BLI_ASSERT_ABORT() (void)0 # endif diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index af28e826e84..d46c02a961c 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -436,6 +436,7 @@ MINLINE void normal_short_to_float_v3(float r[3], const short n[3]); MINLINE void normal_float_to_short_v3(short r[3], const float n[3]); MINLINE void normal_float_to_short_v4(short r[4], const float n[4]); +void minmax_v4v4_v4(float min[4], float max[4], const float vec[4]); void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]); void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]); diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index 64dfdc2ad25..eee304a9b72 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -237,6 +237,82 @@ BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *setti * Only here for code to be removed. */ int BLI_task_parallel_thread_id(const TaskParallelTLS *tls); +/* Task Graph Scheduling */ +/* Task Graphs can be used to create a forest of directional trees and schedule work to any tree. + * The nodes in the graph can be run in separate threads. + * + * +---- [root] ----+ + * | | + * v v + * [node_1] +---- [node_2] ----+ + * | | + * v v + * [node_3] [node_4] + * + * TaskGraph *task_graph = BLI_task_graph_create(); + * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL); + * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); + * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); + * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); + * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); + * + * BLI_task_graph_edge_create(root, node_1); + * BLI_task_graph_edge_create(root, node_2); + * BLI_task_graph_edge_create(node_2, node_3); + * BLI_task_graph_edge_create(node_2, node_4); + * + * Any node can be triggered to start a chain of tasks. Normally you would trigger a root node but + * it is supported to start the chain of tasks anywhere in the forest or tree. When a node + * completes, the execution flow is forwarded via the created edges. + * When a child node has multiple parents the child node will be triggered once for each parent. + * + * BLI_task_graph_node_push_work(root); + * + * In this example After `root` is finished, `node_1` and `node_2` will be started. + * Only after `node_2` is finished `node_3` and `node_4` will be started. + * + * After scheduling work we need to wait until all the tasks have been finished. + * + * BLI_task_graph_work_and_wait(); + * + * When finished you can clean up all the resources by freeing the task_graph. Nodes are owned by + * the graph and are freed task_data will only be freed if a free_func was given. + * + * BLI_task_graph_free(task_graph); + * + * Work can enter a tree on any node. Normally this would be the root_node. + * A `task_graph` can be reused, but the caller needs to make sure the task_data is reset. + * + * ** Task-Data ** + * + * Typically you want give a task data to work on. + * Task data can be shared with other nodes, but be careful not to free the data multiple times. + * Task data is freed when calling `BLI_task_graph_free`. + * + * MyData *task_data = MEM_callocN(sizeof(MyData), __func__); + * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN); + * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); + * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); + * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); + * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); + * + */ +struct TaskGraph; +struct TaskNode; + +typedef void (*TaskGraphNodeRunFunction)(void *__restrict task_data); +typedef void (*TaskGraphNodeFreeFunction)(void *task_data); + +struct TaskGraph *BLI_task_graph_create(void); +void BLI_task_graph_work_and_wait(struct TaskGraph *task_graph); +void BLI_task_graph_free(struct TaskGraph *task_graph); +struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph, + TaskGraphNodeRunFunction run, + void *task_data, + TaskGraphNodeFreeFunction free_func); +bool BLI_task_graph_node_push_work(struct TaskNode *task_node); +void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 18d58cdcaf3..7757b838afe 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -119,6 +119,7 @@ set(SRC intern/string_utf8.c intern/string_utils.c intern/system.c + intern/task_graph.cc intern/task_iterator.c intern/task_pool.cc intern/task_range.cc @@ -138,7 +139,6 @@ set(SRC intern/list_sort_impl.h - BLI_asan.h BLI_alloca.h BLI_allocator.hh BLI_args.h @@ -148,6 +148,7 @@ set(SRC BLI_array_store.h BLI_array_store_utils.h BLI_array_utils.h + BLI_asan.h BLI_assert.h BLI_astar.h BLI_bitmap.h diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 3a07cef7cac..da67baf0ead 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -719,10 +719,10 @@ static void non_recursive_bvh_div_nodes_task_cb(void *__restrict userdata, refit_kdop_hull(data->tree, parent, parent_leafs_begin, parent_leafs_end); split_axis = get_largest_axis(parent->bv); - /* Save split axis (this can be used on raytracing to speedup the query time) */ + /* Save split axis (this can be used on ray-tracing to speedup the query time) */ parent->main_axis = split_axis / 2; - /* Split the childs along the split_axis, note: its not needed to sort the whole leafs array + /* Split the children along the split_axis, note: its not needed to sort the whole leafs array * Only to assure that the elements are partitioned on a way that each child takes the elements * it would take in case the whole array was sorted. * Split_leafs takes care of that "sort" problem. */ diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 2ad9b53ba3d..1b388dcf11f 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -360,7 +360,7 @@ MINLINE int divide_floor_i(int a, int b) } /** - * Integer division that ceils the result, instead of flooring like normal C division. + * Integer division that returns the ceiling, instead of flooring like normal C division. */ MINLINE uint divide_ceil_u(uint a, uint b) { diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c index cc29ebe4f20..c1f7b0c2907 100644 --- a/source/blender/blenlib/intern/math_color.c +++ b/source/blender/blenlib/intern/math_color.c @@ -91,6 +91,7 @@ void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv, int break; case BLI_YUV_ITU_BT709: default: + BLI_assert(colorspace == BLI_YUV_ITU_BT709); y = 0.2126f * r + 0.7152f * g + 0.0722f * b; u = -0.09991f * r - 0.33609f * g + 0.436f * b; v = 0.615f * r - 0.55861f * g - 0.05639f * b; @@ -113,6 +114,8 @@ void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb, int b = y + 2.032f * u; break; case BLI_YUV_ITU_BT709: + default: + BLI_assert(colorspace == BLI_YUV_ITU_BT709); r = y + 1.28033f * v; g = y - 0.21482f * u - 0.38059f * v; b = y + 2.12798f * u; diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index a26824bd2b5..e7c1fc8c2d9 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -4220,7 +4220,19 @@ static float mean_value_half_tan_v2(const struct Float2_Len *d_curr, void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[3]) { - const float eps = 1e-5f; /* take care, low values cause [#36105] */ + /* Before starting to calculate the weight, we need to figure out the floating point precision we + * can expect from the supplied data. */ + float max_value = 0; + + for (int i = 0; i < n; i++) { + max_value = max_ff(max_value, fabsf(v[i][0] - co[0])); + max_value = max_ff(max_value, fabsf(v[i][1] - co[1])); + max_value = max_ff(max_value, fabsf(v[i][2] - co[2])); + } + + /* These to values we derived by empirically testing different values that works for the test + * files in D7772. */ + const float eps = 16.0f * FLT_EPSILON * max_value; const float eps_sq = eps * eps; const float *v_curr, *v_next; float ht_prev, ht; /* half tangents */ @@ -4293,8 +4305,20 @@ void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[2]) { - const float eps = 1e-5f; /* take care, low values cause [#36105] */ + /* Before starting to calculate the weight, we need to figure out the floating point precision we + * can expect from the supplied data. */ + float max_value = 0; + + for (int i = 0; i < n; i++) { + max_value = max_ff(max_value, fabsf(v[i][0] - co[0])); + max_value = max_ff(max_value, fabsf(v[i][1] - co[1])); + } + + /* These to values we derived by empirically testing different values that works for the test + * files in D7772. */ + const float eps = 16.0f * FLT_EPSILON * max_value; const float eps_sq = eps * eps; + const float *v_curr, *v_next; float ht_prev, ht; /* half tangents */ float totweight = 0.0f; diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 9009f73a62f..6ec7c960d6b 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -949,6 +949,35 @@ void print_vn(const char *str, const float v[], const int n) printf("\n"); } +void minmax_v4v4_v4(float min[4], float max[4], const float vec[4]) +{ + if (min[0] > vec[0]) { + min[0] = vec[0]; + } + if (min[1] > vec[1]) { + min[1] = vec[1]; + } + if (min[2] > vec[2]) { + min[2] = vec[2]; + } + if (min[3] > vec[3]) { + min[3] = vec[3]; + } + + if (max[0] < vec[0]) { + max[0] = vec[0]; + } + if (max[1] < vec[1]) { + max[1] = vec[1]; + } + if (max[2] < vec[2]) { + max[2] = vec[2]; + } + if (max[3] < vec[3]) { + max[3] = vec[3]; + } +} + void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]) { if (min[0] > vec[0]) { diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 87536ea8116..fbfb258693b 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -55,6 +55,7 @@ # include "utfconv.h" # include <direct.h> # include <io.h> +# include <shobjidl_core.h> # include <stdbool.h> #else # include <pwd.h> @@ -226,12 +227,18 @@ size_t BLI_file_size(const char *path) return stats.st_size; } +/* Return file attributes. Apple version of this function is defined in storage_apple.mm */ #ifndef __APPLE__ eFileAttributes BLI_file_attributes(const char *path) { int ret = 0; # ifdef WIN32 + + if (BLI_path_extension_check(path, ".lnk")) { + return FILE_ATTR_ALIAS; + } + WCHAR wline[FILE_MAXDIR]; if (conv_utf_8_to_16(path, wline, ARRAY_SIZE(wline)) != 0) { return ret; @@ -284,15 +291,52 @@ eFileAttributes BLI_file_attributes(const char *path) } #endif -/** - * Returns the target path of a file-based redirection, like Mac Alias or Win32 Shortcut file. - */ +/* Return alias/shortcut file target. Apple version is defined in storage_apple.mm */ #ifndef __APPLE__ -bool BLI_file_alias_target(char UNUSED(target[FILE_MAXDIR]), const char *UNUSED(filepath)) +bool BLI_file_alias_target(char target[FILE_MAXDIR], const char *filepath) { - /* TODO: Find target in Win32 Shortcut - Shell Link (.lnk) file. - * Format: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/ */ +# ifdef WIN32 + if (!BLI_path_extension_check(filepath, ".lnk")) { + return false; + } + + IShellLinkW *Shortcut = NULL; + bool success = false; + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + HRESULT hr = CoCreateInstance( + &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID *)&Shortcut); + if (SUCCEEDED(hr)) { + IPersistFile *PersistFile; + hr = Shortcut->lpVtbl->QueryInterface(Shortcut, &IID_IPersistFile, (LPVOID *)&PersistFile); + if (SUCCEEDED(hr)) { + WCHAR path_utf16[FILE_MAXDIR] = {0}; + if (conv_utf_8_to_16(filepath, path_utf16, ARRAY_SIZE(path_utf16)) == 0) { + hr = PersistFile->lpVtbl->Load(PersistFile, path_utf16, STGM_READ); + if (SUCCEEDED(hr)) { + hr = Shortcut->lpVtbl->Resolve(Shortcut, 0, SLR_NO_UI | SLR_UPDATE); + if (SUCCEEDED(hr)) { + wchar_t target_utf16[FILE_MAXDIR] = {0}; + hr = Shortcut->lpVtbl->GetPath(Shortcut, target_utf16, FILE_MAXDIR, NULL, 0); + if (SUCCEEDED(hr)) { + success = (conv_utf_16_to_8(target_utf16, target, FILE_MAXDIR) == 0); + } + } + PersistFile->lpVtbl->Release(PersistFile); + } + } + } + Shortcut->lpVtbl->Release(Shortcut); + } + + return (success && target[0]); +# endif + +# ifdef __linux__ + UNUSED_VARS(target, filepath); + /* File-based redirection not supported. */ return false; +# endif } #endif diff --git a/source/blender/blenlib/intern/task_graph.cc b/source/blender/blenlib/intern/task_graph.cc new file mode 100644 index 00000000000..4f112c5b2c8 --- /dev/null +++ b/source/blender/blenlib/intern/task_graph.cc @@ -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 bli + * + * Task graph. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_task.h" + +#include <memory> +#include <vector> + +#ifdef WITH_TBB +/* Quiet top level deprecation message, unrelated to API usage here. */ +# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1 +# include <tbb/flow_graph.h> +# include <tbb/tbb.h> +#endif + +/* Task Graph */ +struct TaskGraph { +#ifdef WITH_TBB + tbb::flow::graph tbb_graph; +#endif + std::vector<std::unique_ptr<TaskNode>> nodes; + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("task_graph:TaskGraph") +#endif +}; + +/* TaskNode - a node in the task graph. */ +struct TaskNode { + /* TBB Node. */ +#ifdef WITH_TBB + tbb::flow::continue_node<tbb::flow::continue_msg> tbb_node; +#endif + /* Successors to execute after this task, for serial execution fallback. */ + std::vector<TaskNode *> successors; + + /* User function to be executed with given task data. */ + TaskGraphNodeRunFunction run_func; + void *task_data; + /* Optional callback to free task data along with the graph. If task data + * is shared between nodes, only a single task node should free the data. */ + TaskGraphNodeFreeFunction free_func; + + TaskNode(TaskGraph *task_graph, + TaskGraphNodeRunFunction run_func, + void *task_data, + TaskGraphNodeFreeFunction free_func) + : +#ifdef WITH_TBB + tbb_node(task_graph->tbb_graph, + tbb::flow::unlimited, + std::bind(&TaskNode::run, this, std::placeholders::_1)), +#endif + run_func(run_func), + task_data(task_data), + free_func(free_func) + { +#ifndef WITH_TBB + UNUSED_VARS(task_graph); +#endif + } + + TaskNode(const TaskNode &other) = delete; + TaskNode &operator=(const TaskNode &other) = delete; + + ~TaskNode() + { + if (task_data && free_func) { + free_func(task_data); + } + } + +#ifdef WITH_TBB + tbb::flow::continue_msg run(const tbb::flow::continue_msg UNUSED(input)) + { + tbb::this_task_arena::isolate([this] { run_func(task_data); }); + return tbb::flow::continue_msg(); + } +#endif + + void run_serial() + { + run_func(task_data); + for (TaskNode *successor : successors) { + successor->run_serial(); + } + } + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("task_graph:TaskNode") +#endif +}; + +TaskGraph *BLI_task_graph_create(void) +{ + return new TaskGraph(); +} + +void BLI_task_graph_free(TaskGraph *task_graph) +{ + delete task_graph; +} + +void BLI_task_graph_work_and_wait(TaskGraph *task_graph) +{ +#ifdef WITH_TBB + task_graph->tbb_graph.wait_for_all(); +#else + UNUSED_VARS(task_graph); +#endif +} + +struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph, + TaskGraphNodeRunFunction run, + void *user_data, + TaskGraphNodeFreeFunction free_func) +{ + TaskNode *task_node = new TaskNode(task_graph, run, user_data, free_func); + task_graph->nodes.push_back(std::unique_ptr<TaskNode>(task_node)); + return task_node; +} + +bool BLI_task_graph_node_push_work(struct TaskNode *task_node) +{ +#ifdef WITH_TBB + if (BLI_task_scheduler_num_threads() > 1) { + return task_node->tbb_node.try_put(tbb::flow::continue_msg()); + } +#endif + + task_node->run_serial(); + return true; +} + +void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node) +{ +#ifdef WITH_TBB + if (BLI_task_scheduler_num_threads() > 1) { + tbb::flow::make_edge(from_node->tbb_node, to_node->tbb_node); + return; + } +#endif + + from_node->successors.push_back(to_node); +} diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h new file mode 100644 index 00000000000..1b86b5668cc --- /dev/null +++ b/source/blender/blenloader/BLO_read_write.h @@ -0,0 +1,210 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup blenloader + * + * This file contains an API that allows different parts of Blender to define what data is stored + * in .blend files. + * + * Four callbacks have to be provided to fully implement .blend I/O for a piece of data. One of + * those is related to file writing and three for file reading. Reading requires multiple + * callbacks, due to the way linking between files works. + * + * Brief description of the individual callbacks: + * - Blend Write: Define which structs and memory buffers are saved. + * - Blend Read Data: Loads structs and memory buffers from file and updates pointers them. + * - Blend Read Lib: Updates pointers to ID data blocks. + * - Blend Expand: Defines which other data blocks should be loaded (possibly from other files). + * + * Each of these callbacks uses a different API functions. + * + * Some parts of Blender, e.g. modifiers, don't require you to implement all four callbacks. + * Instead only the first two are necessary. The other two are handled by general ID management. In + * the future, we might want to get rid of those two callbacks entirely, but for now they are + * necessary. + */ + +#ifndef __BLO_READ_WRITE_H__ +#define __BLO_READ_WRITE_H__ + +/* for SDNA_TYPE_FROM_STRUCT() macro */ +#include "dna_type_offsets.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BlendWriter BlendWriter; +typedef struct BlendDataReader BlendDataReader; +typedef struct BlendLibReader BlendLibReader; +typedef struct BlendExpander BlendExpander; + +/* Blend Write API + * =============== + * + * Most functions fall into one of two categories. Either they write a DNA struct or a raw memory + * buffer to the .blend file. + * + * It is safe to pass NULL as data_ptr. In this case nothing will be stored. + * + * DNA Struct Writing + * ------------------ + * + * Functions dealing with DNA structs begin with BLO_write_struct_*. + * + * DNA struct types can be identified in different ways: + * - Run-time Name: The name is provided as const char *. + * - Compile-time Name: The name is provided at compile time. This is more efficient. + * - Struct ID: Every DNA struct type has an integer ID that can be queried with + * BLO_get_struct_id_by_name. Providing this ID can be a useful optimization when many structs + * of the same type are stored AND if those structs are not in a continuous array. + * + * Often only a single instance of a struct is written at once. However, sometimes it is necessary + * to write arrays or linked lists. Separate functions for that are provided as well. + * + * There is a special macro for writing id structs: BLO_write_id_struct. Those are handled + * differently from other structs. + * + * Raw Data Writing + * ---------------- + * + * At the core there is BLO_write_raw, which can write arbitrary memory buffers to the file. The + * code that reads this data might have to correct its byte-order. For the common cases there are + * convenience functions that write and read arrays of simple types such as int32. Those will + * correct endianness automatically. + */ + +/* Mapping between names and ids. */ +int BLO_get_struct_id_by_name(BlendWriter *writer, const char *struct_name); +#define BLO_get_struct_id(writer, struct_name) SDNA_TYPE_FROM_STRUCT(struct_name) + +/* Write single struct. */ +void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr); +void BLO_write_struct_by_id(BlendWriter *writer, int struct_id, const void *data_ptr); +#define BLO_write_struct(writer, struct_name, data_ptr) \ + BLO_write_struct_by_id(writer, BLO_get_struct_id(writer, struct_name), data_ptr) + +/* Write struct array. */ +void BLO_write_struct_array_by_name(BlendWriter *writer, + const char *struct_name, + int array_size, + const void *data_ptr); +void BLO_write_struct_array_by_id(BlendWriter *writer, + int struct_id, + int array_size, + const void *data_ptr); +#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr) \ + BLO_write_struct_array_by_id( \ + writer, BLO_get_struct_id(writer, struct_name), array_size, data_ptr) + +/* Write struct list. */ +void BLO_write_struct_list_by_name(BlendWriter *writer, + const char *struct_name, + struct ListBase *list); +void BLO_write_struct_list_by_id(BlendWriter *writer, int struct_id, struct ListBase *list); +#define BLO_write_struct_list(writer, struct_name, list_ptr) \ + BLO_write_struct_list_by_id(writer, BLO_get_struct_id(writer, struct_name), list_ptr) + +/* Write id struct. */ +void blo_write_id_struct(BlendWriter *writer, + int struct_id, + const void *id_address, + const struct ID *id); +#define BLO_write_id_struct(writer, struct_name, id_address, id) \ + blo_write_id_struct(writer, BLO_get_struct_id(writer, struct_name), id_address, id) + +/* Write raw data. */ +void BLO_write_raw(BlendWriter *writer, int size_in_bytes, const void *data_ptr); +void BLO_write_int32_array(BlendWriter *writer, int size, const int32_t *data_ptr); +void BLO_write_uint32_array(BlendWriter *writer, int size, const uint32_t *data_ptr); +void BLO_write_float_array(BlendWriter *writer, int size, const float *data_ptr); +void BLO_write_float3_array(BlendWriter *writer, int size, const float *data_ptr); +void BLO_write_pointer_array(BlendWriter *writer, int size, const void *data_ptr); +void BLO_write_string(BlendWriter *writer, const char *data_ptr); + +/* Misc. */ +bool BLO_write_is_undo(BlendWriter *writer); + +/* Blend Read Data API + * =================== + * + * Generally, for every BLO_write_* call there should be a corresponding BLO_read_* call. + * + * Most BLO_read_* functions get a pointer to a pointer as argument. That allows the function to + * update the pointer to its new value. + * + * When the given pointer points to a memory buffer that was not stored in the file, the pointer is + * updated to be NULL. When it was pointing to NULL before, it will stay that way. + * + * Examples of matching calls: + * BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms); + * BLO_read_data_address(reader, &clmd->sim_parms); + * + * BLO_write_struct_list(writer, TimeMarker, &action->markers); + * BLO_read_list(reader, &action->markers, NULL); + * + * BLO_write_int32_array(writer, hmd->totindex, hmd->indexar); + * BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar); + */ + +void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address); + +#define BLO_read_data_address(reader, ptr_p) \ + *(ptr_p) = BLO_read_get_new_data_address((reader), *(ptr_p)) + +typedef void (*BlendReadListFn)(BlendDataReader *reader, void *data); +void BLO_read_list(BlendDataReader *reader, struct ListBase *list, BlendReadListFn callback); + +/* Update data pointers and correct byte-order if necessary. */ +void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p); +void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p); +void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p); +void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p); +void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p); +void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); + +/* Misc. */ +bool BLO_read_requires_endian_switch(BlendDataReader *reader); + +/* Blend Read Lib API + * =================== + * + * This API does almost the same as the Blend Read Data API. However, now only pointers to ID data + * blocks are updated. + */ + +ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, struct ID *id); + +#define BLO_read_id_address(reader, lib, id_ptr_p) \ + *(id_ptr_p) = (void *)BLO_read_get_new_id_address((reader), (lib), (ID *)*(id_ptr_p)) + +/* Blend Expand API + * =================== + * + * BLO_expand has to be called for every data block that should be loaded. If the data block is in + * a separate .blend file, it will be pulled from there. + */ + +void BLO_expand_id(BlendExpander *expander, struct ID *id); + +#define BLO_expand(expander, id) BLO_expand_id(expander, (struct ID *)id) + +#ifdef __cplusplus +} +#endif + +#endif /* __BLO_READ_WRITE_H__ */ diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h index f280b8f3b9c..f9300f8a521 100644 --- a/source/blender/blenloader/BLO_undofile.h +++ b/source/blender/blenloader/BLO_undofile.h @@ -26,6 +26,7 @@ */ struct Scene; +struct GHash; typedef struct { void *next, *prev; @@ -38,6 +39,9 @@ typedef struct { * detect unchanged IDs). * Defined when writing the next step (i.e. last undo step has those always false). */ bool is_identical_future; + /** Session UUID of the ID being currently written (MAIN_ID_SESSION_UUID_UNSET when not writing + * ID-related data). Used to find matching chunks in previous memundo step. */ + uint id_session_uuid; } MemFileChunk; typedef struct MemFile { @@ -45,6 +49,17 @@ typedef struct MemFile { size_t size; } MemFile; +typedef struct MemFileWriteData { + MemFile *written_memfile; + MemFile *reference_memfile; + + uint current_id_session_uuid; + MemFileChunk *reference_current_chunk; + + /** Maps an ID session uuid to its first reference MemFileChunk, if existing. */ + struct GHash *id_session_uuid_mapping; +} MemFileWriteData; + typedef struct MemFileUndoData { char filename[1024]; /* FILE_MAX */ MemFile memfile; @@ -52,10 +67,13 @@ typedef struct MemFileUndoData { } MemFileUndoData; /* actually only used writefile.c */ -extern void memfile_chunk_add(MemFile *memfile, - const char *buf, - unsigned int size, - MemFileChunk **compchunk_step); + +void BLO_memfile_write_init(MemFileWriteData *mem_data, + MemFile *written_memfile, + MemFile *reference_memfile); +void BLO_memfile_write_finalize(MemFileWriteData *mem_data); + +void BLO_memfile_chunk_add(MemFileWriteData *mem_data, const char *buf, unsigned int size); /* exports */ extern void BLO_memfile_free(MemFile *memfile); diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 1555b9231ed..09e2f4bf417 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -64,6 +64,7 @@ set(SRC BLO_blend_defs.h BLO_blend_validate.h BLO_readfile.h + BLO_read_write.h BLO_undofile.h BLO_writefile.h intern/readfile.h diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index adf7db0267e..1309b3e3c33 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -428,41 +428,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, * but oldmain itself shall *never* be 'transferred' to new mainlist! */ BLI_assert(old_mainlist.first == oldmain); - if (bfd && old_mainlist.first != old_mainlist.last) { - /* Even though directly used libs have been already moved to new main, - * indirect ones have not. - * This is a bit annoying, but we have no choice but to keep them all for now - - * means some now unused data may remain in memory, but think we'll have to live with it. */ - Main *libmain, *libmain_next; - Main *newmain = bfd->main; - ListBase new_mainlist = {newmain, newmain}; - - for (libmain = oldmain->next; libmain; libmain = libmain_next) { - libmain_next = libmain->next; - /* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL - * parent to detect indirect-linked ones. */ - if (libmain->curlib && (libmain->curlib->parent != NULL)) { - BLI_remlink(&old_mainlist, libmain); - BLI_addtail(&new_mainlist, libmain); - } - else { -#ifdef PRINT_DEBUG - printf("Dropped Main for lib: %s\n", libmain->curlib->id.name); -#endif - } - } - /* In any case, we need to move all lib data-blocks themselves - those are - * 'first level data', getting rid of them would imply updating spaces & co - * to prevent invalid pointers access. */ - BLI_movelisttolist(&newmain->libraries, &oldmain->libraries); - - blo_join_main(&new_mainlist); - } - -#if 0 - printf("Remaining mains/libs in oldmain: %d\n", BLI_listbase_count(&fd->old_mainlist) - 1); -#endif - /* That way, libs (aka mains) we did not reuse in new undone/redone state * will be cleared together with oldmain... */ blo_join_main(&old_mainlist); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index b661a1e7696..53502a8138a 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -160,6 +160,7 @@ #include "BLO_blend_defs.h" #include "BLO_blend_validate.h" +#include "BLO_read_write.h" #include "BLO_readfile.h" #include "BLO_undofile.h" @@ -691,7 +692,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab /* Important, consistency with main ID reading code from read_libblock(). */ lib->id.us = ID_FAKE_USERS(lib); - /* Matches lib_link_library(). */ + /* Matches direct_link_library(). */ id_us_ensure_real(&lib->id); BLI_strncpy(lib->name, filepath, sizeof(lib->name)); @@ -713,6 +714,20 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab /** \name File Parsing * \{ */ +typedef struct BlendDataReader { + FileData *fd; +} BlendDataReader; + +typedef struct BlendLibReader { + FileData *fd; + Main *main; +} BlendLibReader; + +typedef struct BlendExpander { + FileData *fd; + Main *main; +} BlendExpander; + static void switch_endian_bh4(BHead4 *bhead) { /* the ID_.. codes */ @@ -2890,8 +2905,8 @@ static void direct_link_id_common( id->tag = tag; if (tag & LIB_TAG_ID_LINK_PLACEHOLDER) { - /* For placeholder we only need to set the tag and properly init generic ID fieds above, no - * further data to read. */ + /* For placeholder we only need to set the tag and properly initialize generic ID fields above, + * no further data to read. */ return; } @@ -3415,11 +3430,6 @@ static void lib_link_nladata_strips(FileData *fd, ID *id, ListBase *list) /* reassign the counted-reference to action */ strip->act = newlibadr(fd, id->lib, strip->act); - - /* fix action id-root (i.e. if it comes from a pre 2.57 .blend file) */ - if ((strip->act) && (strip->act->idroot == 0)) { - strip->act->idroot = GS(id->name); - } } } @@ -3514,14 +3524,6 @@ static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt) adt->action = newlibadr(fd, id->lib, adt->action); adt->tmpact = newlibadr(fd, id->lib, adt->tmpact); - /* fix action id-roots (i.e. if they come from a pre 2.57 .blend file) */ - if ((adt->action) && (adt->action->idroot == 0)) { - adt->action->idroot = GS(id->name); - } - if ((adt->tmpact) && (adt->tmpact->idroot == 0)) { - adt->tmpact->idroot = GS(id->name); - } - /* link drivers */ lib_link_fcurves(fd, id, &adt->drivers); @@ -3592,15 +3594,11 @@ static void direct_link_cachefile(FileData *fd, CacheFile *cache_file) static void lib_link_workspaces(FileData *fd, Main *bmain, WorkSpace *workspace) { - ListBase *layouts = BKE_workspace_layouts_get(workspace); ID *id = (ID *)workspace; - id_us_ensure_real(id); - - for (WorkSpaceLayout *layout = layouts->first, *layout_next; layout; layout = layout_next) { + LISTBASE_FOREACH_MUTABLE (WorkSpaceLayout *, layout, &workspace->layouts) { layout->screen = newlibadr(fd, id->lib, layout->screen); - layout_next = layout->next; if (layout->screen) { if (ID_IS_LINKED(id)) { layout->screen->winid = 0; @@ -3620,16 +3618,14 @@ static void lib_link_workspaces(FileData *fd, Main *bmain, WorkSpace *workspace) static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main *main) { - link_list(fd, BKE_workspace_layouts_get(workspace)); + link_list(fd, &workspace->layouts); link_list(fd, &workspace->hook_layout_relations); link_list(fd, &workspace->owner_ids); link_list(fd, &workspace->tools); LISTBASE_FOREACH (WorkSpaceDataRelation *, relation, &workspace->hook_layout_relations) { - /* data from window - need to access through global oldnew-map */ relation->parent = newglobadr(fd, relation->parent); - relation->value = newdataadr(fd, relation->value); } @@ -3637,11 +3633,7 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main * when reading windows, so have to update windows after/when reading workspaces. */ for (wmWindowManager *wm = main->wm.first; wm; wm = wm->id.next) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - WorkSpaceLayout *act_layout = newdataadr( - fd, BKE_workspace_active_layout_get(win->workspace_hook)); - if (act_layout) { - BKE_workspace_active_layout_set(win->workspace_hook, act_layout); - } + win->workspace_hook->act_layout = newdataadr(fd, win->workspace_hook->act_layout); } } @@ -3652,6 +3644,8 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main } workspace->status_text = NULL; + + id_us_ensure_real(&workspace->id); } static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook *hook, ID *id) @@ -3897,23 +3891,23 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree) } #if 0 - if (ntree->previews) { - bNodeInstanceHash* new_previews = BKE_node_instance_hash_new("node previews"); - bNodeInstanceHashIterator iter; - - NODE_INSTANCE_HASH_ITER(iter, ntree->previews) { - bNodePreview* preview = BKE_node_instance_hash_iterator_get_value(&iter); - if (preview) { - bNodePreview* new_preview = newimaadr(fd, preview); - if (new_preview) { - bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); - BKE_node_instance_hash_insert(new_previews, key, new_preview); - } - } - } - BKE_node_instance_hash_free(ntree->previews, NULL); - ntree->previews = new_previews; - } + if (ntree->previews) { + bNodeInstanceHash* new_previews = BKE_node_instance_hash_new("node previews"); + bNodeInstanceHashIterator iter; + + NODE_INSTANCE_HASH_ITER(iter, ntree->previews) { + bNodePreview* preview = BKE_node_instance_hash_iterator_get_value(&iter); + if (preview) { + bNodePreview* new_preview = newimaadr(fd, preview); + if (new_preview) { + bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); + BKE_node_instance_hash_insert(new_previews, key, new_preview); + } + } + } + BKE_node_instance_hash_free(ntree->previews, NULL); + ntree->previews = new_previews; + } #else /* XXX TODO */ ntree->previews = NULL; @@ -4363,10 +4357,10 @@ static void direct_link_text(FileData *fd, Text *text) text->compiled = NULL; #if 0 - if (text->flags & TXT_ISEXT) { - BKE_text_reload(text); - } - /* else { */ + if (text->flags & TXT_ISEXT) { + BKE_text_reload(text); + } + /* else { */ #endif link_list(fd, &text->lines); @@ -5354,7 +5348,7 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob) * some leaked memory rather then crashing immediately * while bad this _is_ an exceptional case - campbell */ #if 0 - BKE_pose_free(ob->pose); + BKE_pose_free(ob->pose); #else MEM_freeN(ob->pose); #endif @@ -5831,15 +5825,15 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob) else if (md->type == eModifierType_Collision) { CollisionModifierData *collmd = (CollisionModifierData *)md; #if 0 - // TODO: CollisionModifier should use pointcache - // + have proper reset events before enabling this - collmd->x = newdataadr(fd, collmd->x); - collmd->xnew = newdataadr(fd, collmd->xnew); - collmd->mfaces = newdataadr(fd, collmd->mfaces); - - collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x"); - collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew"); - collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v"); + // TODO: CollisionModifier should use pointcache + // + have proper reset events before enabling this + collmd->x = newdataadr(fd, collmd->x); + collmd->xnew = newdataadr(fd, collmd->xnew); + collmd->mfaces = newdataadr(fd, collmd->mfaces); + + collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x"); + collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew"); + collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v"); #endif collmd->x = NULL; @@ -6962,7 +6956,6 @@ static void direct_link_scene(FileData *fd, Scene *sce) direct_link_paint(fd, sce, &sce->toolsettings->imapaint.paint); - sce->toolsettings->imapaint.paintcursor = NULL; sce->toolsettings->particle.paintcursor = NULL; sce->toolsettings->particle.scene = NULL; sce->toolsettings->particle.object = NULL; @@ -7545,10 +7538,10 @@ static void direct_link_area(FileData *fd, ScrArea *area) * so sacrifice a few old files for now to avoid crashes with new files! * committed: r28002 */ #if 0 - sima->gpd = newdataadr(fd, sima->gpd); - if (sima->gpd) { - direct_link_gpencil(fd, sima->gpd); - } + sima->gpd = newdataadr(fd, sima->gpd); + if (sima->gpd) { + direct_link_gpencil(fd, sima->gpd); + } #endif } else if (sl->spacetype == SPACE_NODE) { @@ -7579,10 +7572,10 @@ static void direct_link_area(FileData *fd, ScrArea *area) * simple return NULL here (sergey) */ #if 0 - if (sseq->gpd) { - sseq->gpd = newdataadr(fd, sseq->gpd); - direct_link_gpencil(fd, sseq->gpd); - } + if (sseq->gpd) { + sseq->gpd = newdataadr(fd, sseq->gpd); + direct_link_gpencil(fd, sseq->gpd); + } #endif sseq->scopes.reference_ibuf = NULL; sseq->scopes.zebra_ibuf = NULL; @@ -8269,11 +8262,11 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, sima->iuser.scene = NULL; #if 0 - /* Those are allocated and freed by space code, no need to handle them here. */ - MEM_SAFE_FREE(sima->scopes.waveform_1); - MEM_SAFE_FREE(sima->scopes.waveform_2); - MEM_SAFE_FREE(sima->scopes.waveform_3); - MEM_SAFE_FREE(sima->scopes.vecscope); + /* Those are allocated and freed by space code, no need to handle them here. */ + MEM_SAFE_FREE(sima->scopes.waveform_1); + MEM_SAFE_FREE(sima->scopes.waveform_2); + MEM_SAFE_FREE(sima->scopes.waveform_3); + MEM_SAFE_FREE(sima->scopes.vecscope); #endif sima->scopes.ok = 0; @@ -8424,9 +8417,7 @@ void blo_lib_link_restore(Main *oldmain, for (WorkSpace *workspace = newmain->workspaces.first; workspace; workspace = workspace->id.next) { - ListBase *layouts = BKE_workspace_layouts_get(workspace); - - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { lib_link_workspace_layout_restore(id_map, newmain, layout); } } @@ -8574,11 +8565,12 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) newmain->curlib = lib; lib->parent = NULL; + + id_us_ensure_real(&lib->id); } -static void lib_link_library(FileData *UNUSED(fd), Main *UNUSED(bmain), Library *lib) +static void lib_link_library(FileData *UNUSED(fd), Main *UNUSED(bmain), Library *UNUSED(lib)) { - id_us_ensure_real(&lib->id); } /* Always call this once you have loaded new library data to set the relative paths correctly @@ -8646,8 +8638,8 @@ static void direct_link_speaker(FileData *fd, Speaker *spk) direct_link_animdata(fd, spk->adt); #if 0 - spk->sound = newdataadr(fd, spk->sound); - direct_link_sound(fd, spk->sound); + spk->sound = newdataadr(fd, spk->sound); + direct_link_sound(fd, spk->sound); #endif } @@ -9521,12 +9513,12 @@ static BHead *read_data_into_datamap(FileData *fd, BHead *bhead, const char *all while (bhead && bhead->code == DATA) { void *data; #if 0 - /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */ - short* sp = fd->filesdna->structs[bhead->SDNAnr]; - char* tmp = malloc(100); - allocname = fd->filesdna->types[sp[0]]; - strcpy(tmp, allocname); - data = read_struct(fd, bhead, tmp); + /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */ + short* sp = fd->filesdna->structs[bhead->SDNAnr]; + char* tmp = malloc(100); + allocname = fd->filesdna->types[sp[0]]; + strcpy(tmp, allocname); + data = read_struct(fd, bhead, tmp); #else data = read_struct(fd, bhead, allocname); #endif @@ -9732,7 +9724,7 @@ static bool read_libblock_undo_restore( } /* Restore local datablocks. */ - DEBUG_PRINTF("UNDO: read %s (uuid %d) -> ", id->name, id->session_uuid); + DEBUG_PRINTF("UNDO: read %s (uuid %u) -> ", id->name, id->session_uuid); ID *id_old = NULL; const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; @@ -10053,6 +10045,7 @@ static void do_versions_after_linking(Main *main, ReportList *reports) do_versions_after_linking_260(main); do_versions_after_linking_270(main); do_versions_after_linking_280(main, reports); + do_versions_after_linking_290(main, reports); do_versions_after_linking_cycles(main); main->is_locked_for_linking = false; @@ -10600,7 +10593,7 @@ static BHead *find_previous_lib(FileData *fd, BHead *bhead) static BHead *find_bhead(FileData *fd, void *old) { #if 0 - BHead* bhead; + BHead* bhead; #endif struct BHeadSort *bhs, bhs_s; @@ -10620,11 +10613,11 @@ static BHead *find_bhead(FileData *fd, void *old) } #if 0 - for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { - if (bhead->old == old) { - return bhead; - } - } + for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { + if (bhead->old == old) { + return bhead; + } + } #endif return NULL; @@ -10755,9 +10748,9 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) /* Commented because this can print way too much. */ #if 0 - if (G.debug & G_DEBUG) { - printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name); - } + if (G.debug & G_DEBUG) { + printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name); + } #endif } @@ -11637,9 +11630,7 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd) static void expand_workspace(FileData *fd, Main *mainvar, WorkSpace *workspace) { - ListBase *layouts = BKE_workspace_layouts_get(workspace); - - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { expand_doit(fd, mainvar, BKE_workspace_layout_screen_get(layout)); } } @@ -12623,9 +12614,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) /* Does this library have any more linked data-blocks we need to read? */ if (has_linked_ids_to_read(mainptr)) { #if 0 - printf("Reading linked data-blocks from %s (%s)\n", - mainptr->curlib->id.name, - mainptr->curlib->name); + printf("Reading linked data-blocks from %s (%s)\n", + mainptr->curlib->id.name, + mainptr->curlib->name); #endif /* Open file if it has not been done yet. */ @@ -12689,4 +12680,164 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) BKE_main_free(main_newid); } +void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address) +{ + return newdataadr(reader->fd, old_address); +} + +ID *BLO_read_get_new_id_address(BlendLibReader *reader, Library *lib, ID *id) +{ + return newlibadr(reader->fd, lib, id); +} + +bool BLO_read_requires_endian_switch(BlendDataReader *reader) +{ + return (reader->fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0; +} + +/** + * Updates all ->prev and ->next pointers of the list elements. + * Updates the list->first and list->last pointers. + * When not NULL, calls the callback on every element. + */ +void BLO_read_list(BlendDataReader *reader, ListBase *list, BlendReadListFn callback) +{ + if (BLI_listbase_is_empty(list)) { + return; + } + + BLO_read_data_address(reader, &list->first); + if (callback != NULL) { + callback(reader, list->first); + } + Link *ln = list->first; + Link *prev = NULL; + while (ln) { + BLO_read_data_address(reader, &ln->next); + if (ln->next != NULL && callback != NULL) { + callback(reader, ln->next); + } + ln->prev = prev; + prev = ln; + ln = ln->next; + } + list->last = prev; +} + +void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p) +{ + BLO_read_data_address(reader, ptr_p); + if (BLO_read_requires_endian_switch(reader)) { + BLI_endian_switch_int32_array(*ptr_p, array_size); + } +} + +void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p) +{ + BLO_read_data_address(reader, ptr_p); + if (BLO_read_requires_endian_switch(reader)) { + BLI_endian_switch_uint32_array(*ptr_p, array_size); + } +} + +void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p) +{ + BLO_read_data_address(reader, ptr_p); + if (BLO_read_requires_endian_switch(reader)) { + BLI_endian_switch_float_array(*ptr_p, array_size); + } +} + +void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p) +{ + BLO_read_float_array(reader, array_size * 3, ptr_p); +} + +void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p) +{ + BLO_read_data_address(reader, ptr_p); + if (BLO_read_requires_endian_switch(reader)) { + BLI_endian_switch_double_array(*ptr_p, array_size); + } +} + +static void convert_pointer_array_64_to_32(BlendDataReader *reader, + uint array_size, + const uint64_t *src, + uint32_t *dst) +{ + /* Match pointer conversion rules from bh4_from_bh8 and cast_pointer. */ + if (BLO_read_requires_endian_switch(reader)) { + for (int i = 0; i < array_size; i++) { + uint64_t ptr = src[i]; + BLI_endian_switch_uint64(&ptr); + dst[i] = (uint32_t)(ptr >> 3); + } + } + else { + for (int i = 0; i < array_size; i++) { + dst[i] = (uint32_t)(src[i] >> 3); + } + } +} + +static void convert_pointer_array_32_to_64(BlendDataReader *UNUSED(reader), + uint array_size, + const uint32_t *src, + uint64_t *dst) +{ + /* Match pointer conversion rules from bh8_from_bh4 and cast_pointer. */ + for (int i = 0; i < array_size; i++) { + dst[i] = src[i]; + } +} + +void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) +{ + FileData *fd = reader->fd; + + void *orig_array = newdataadr(fd, *ptr_p); + if (orig_array == NULL) { + *ptr_p = NULL; + return; + } + + int file_pointer_size = fd->filesdna->pointer_size; + int current_pointer_size = fd->memsdna->pointer_size; + + /* Overallocation is fine, but might be better to pass the length as parameter. */ + int array_size = MEM_allocN_len(orig_array) / file_pointer_size; + + void *final_array = NULL; + + if (file_pointer_size == current_pointer_size) { + /* No pointer conversion necessary. */ + final_array = orig_array; + } + else if (file_pointer_size == 8 && current_pointer_size == 4) { + /* Convert pointers from 64 to 32 bit. */ + final_array = MEM_malloc_arrayN(array_size, 4, "new pointer array"); + convert_pointer_array_64_to_32( + reader, array_size, (uint64_t *)orig_array, (uint32_t *)final_array); + MEM_freeN(orig_array); + } + else if (file_pointer_size == 4 && current_pointer_size == 8) { + /* Convert pointers from 32 to 64 bit. */ + final_array = MEM_malloc_arrayN(array_size, 8, "new pointer array"); + convert_pointer_array_32_to_64( + reader, array_size, (uint32_t *)orig_array, (uint64_t *)final_array); + MEM_freeN(orig_array); + } + else { + BLI_assert(false); + } + + *ptr_p = final_array; +} + +void BLO_expand_id(BlendExpander *expander, ID *id) +{ + expand_doit(expander->fd, expander->main, id); +} + /** \} */ diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 55abbe703de..f698d642e33 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -205,7 +205,8 @@ void blo_do_versions_cycles(struct FileData *fd, struct Library *lib, struct Mai void do_versions_after_linking_250(struct Main *bmain); void do_versions_after_linking_260(struct Main *bmain); void do_versions_after_linking_270(struct Main *bmain); -void do_versions_after_linking_280(struct Main *bmain, ReportList *reports); +void do_versions_after_linking_280(struct Main *bmain, struct ReportList *reports); +void do_versions_after_linking_290(struct Main *bmain, struct ReportList *reports); void do_versions_after_linking_cycles(struct Main *bmain); #endif diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c index c7057883f88..62ffbcc874b 100644 --- a/source/blender/blenloader/intern/undofile.c +++ b/source/blender/blenloader/intern/undofile.c @@ -41,10 +41,12 @@ #include "DNA_listBase.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" #include "BLO_readfile.h" #include "BLO_undofile.h" +#include "BKE_lib_id.h" #include "BKE_main.h" /* keep last */ @@ -70,25 +72,36 @@ void BLO_memfile_free(MemFile *memfile) /* result is that 'first' is being freed */ void BLO_memfile_merge(MemFile *first, MemFile *second) { - MemFileChunk *fc, *sc; + /* We use this mapping to store the memory buffers from second memfile chunks which are not owned + * by it (i.e. shared with some previous memory steps). */ + GHash *buffer_to_second_memchunk = BLI_ghash_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - fc = first->chunks.first; - sc = second->chunks.first; - while (fc || sc) { - if (fc && sc) { - if (sc->is_identical) { + /* First, detect all memchunks in second memfile that are not owned by it. */ + for (MemFileChunk *sc = second->chunks.first; sc != NULL; sc = sc->next) { + if (sc->is_identical) { + BLI_ghash_insert(buffer_to_second_memchunk, (void *)sc->buf, sc); + } + } + + /* Now, check all chunks from first memfile (the one we are removing), and if a memchunk owned by + * it is also used by the second memfile, transfer the ownership. */ + for (MemFileChunk *fc = first->chunks.first; fc != NULL; fc = fc->next) { + if (!fc->is_identical) { + MemFileChunk *sc = BLI_ghash_lookup(buffer_to_second_memchunk, fc->buf); + if (sc != NULL) { + BLI_assert(sc->is_identical); sc->is_identical = false; fc->is_identical = true; } - } - if (fc) { - fc = fc->next; - } - if (sc) { - sc = sc->next; + /* Note that if the second memfile does not use that chunk, we assume that the first one + * fully owns it without sharing it with any other memfile, and hence it should be freed with + * it. */ } } + BLI_ghash_free(buffer_to_second_memchunk, NULL, NULL); + BLO_memfile_free(first); } @@ -100,8 +113,52 @@ void BLO_memfile_clear_future(MemFile *memfile) } } -void memfile_chunk_add(MemFile *memfile, const char *buf, uint size, MemFileChunk **compchunk_step) +void BLO_memfile_write_init(MemFileWriteData *mem_data, + MemFile *written_memfile, + MemFile *reference_memfile) { + mem_data->written_memfile = written_memfile; + mem_data->reference_memfile = reference_memfile; + mem_data->reference_current_chunk = reference_memfile ? reference_memfile->chunks.first : NULL; + + /* If we have a reference memfile, we generate a mapping between the session_uuid's of the + * IDs stored in that previous undo step, and its first matching memchunk. This will allow + * us to easily find the existing undo memory storage of IDs even when some re-ordering in + * current Main data-base broke the order matching with the memchunks from previous step. + */ + if (reference_memfile != NULL) { + mem_data->id_session_uuid_mapping = BLI_ghash_new( + BLI_ghashutil_inthash_p_simple, BLI_ghashutil_intcmp, __func__); + uint current_session_uuid = MAIN_ID_SESSION_UUID_UNSET; + LISTBASE_FOREACH (MemFileChunk *, mem_chunk, &reference_memfile->chunks) { + if (!ELEM(mem_chunk->id_session_uuid, MAIN_ID_SESSION_UUID_UNSET, current_session_uuid)) { + current_session_uuid = mem_chunk->id_session_uuid; + void **entry; + if (!BLI_ghash_ensure_p(mem_data->id_session_uuid_mapping, + POINTER_FROM_UINT(current_session_uuid), + &entry)) { + *entry = mem_chunk; + } + else { + BLI_assert(0); + } + } + } + } +} + +void BLO_memfile_write_finalize(MemFileWriteData *mem_data) +{ + if (mem_data->id_session_uuid_mapping != NULL) { + BLI_ghash_free(mem_data->id_session_uuid_mapping, NULL, NULL); + } +} + +void BLO_memfile_chunk_add(MemFileWriteData *mem_data, const char *buf, uint size) +{ + MemFile *memfile = mem_data->written_memfile; + MemFileChunk **compchunk_step = &mem_data->reference_current_chunk; + MemFileChunk *curchunk = MEM_mallocN(sizeof(MemFileChunk), "MemFileChunk"); curchunk->size = size; curchunk->buf = NULL; @@ -110,6 +167,7 @@ void memfile_chunk_add(MemFile *memfile, const char *buf, uint size, MemFileChun * perform an undo push may make changes after the last undo push that * will then not be undo. Though it's not entirely clear that is wrong behavior. */ curchunk->is_identical_future = true; + curchunk->id_session_uuid = mem_data->current_id_session_uuid; BLI_addtail(&memfile->chunks, curchunk); /* we compare compchunk with buf */ diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 62cda5d8feb..eaeef0d52c1 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -61,6 +61,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BKE_anim_data.h" #include "BKE_anim_visualization.h" #include "BKE_armature.h" #include "BKE_colortools.h" @@ -2352,4 +2353,32 @@ void do_versions_after_linking_250(Main *bmain) } FOREACH_NODETREE_END; } + + if (!MAIN_VERSION_ATLEAST(bmain, 258, 0)) { + /* Some very old (original comments claim pre-2.57) versioning that was wrongly done in + * lib-linking code... Putting it here just to be sure (this is also checked at runtime anyway + * by `action_idcode_patch_check`). */ + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + AnimData *adt = BKE_animdata_from_id(id); + if (adt != NULL) { + /* Fix actions' id-roots (i.e. if they come from a pre 2.57 .blend file). */ + if ((adt->action) && (adt->action->idroot == 0)) { + adt->action->idroot = GS(id->name); + } + if ((adt->tmpact) && (adt->tmpact->idroot == 0)) { + adt->tmpact->idroot = GS(id->name); + } + + LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) { + LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) { + if ((nla_strip->act) && (nla_strip->act->idroot == 0)) { + nla_strip->act->idroot = GS(id->name); + } + } + } + } + } + FOREACH_MAIN_ID_END; + } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index e32a40e1ad5..6211c58d7d4 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -257,7 +257,7 @@ static void do_version_workspaces_after_lib_link(Main *bmain) win->workspace_hook = BKE_workspace_instance_hook_create(bmain); BKE_workspace_active_set(win->workspace_hook, workspace); - BKE_workspace_active_layout_set(win->workspace_hook, layout); + BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout); /* Move scene and view layer to window. */ Scene *scene = screen->scene; @@ -759,7 +759,7 @@ static void do_version_bbone_scale_fcurve_fix(ListBase *curves, FCurve *fcu) /* Update F-Curve's path. */ if (replace_bbone_scale_rnapath(&fcu->rna_path)) { /* If matched, duplicate the curve and tweak name. */ - FCurve *second = copy_fcurve(fcu); + FCurve *second = BKE_fcurve_copy(fcu); second->rna_path[strlen(second->rna_path) - 1] = 'y'; @@ -1737,144 +1737,6 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports)) } } - if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) { - /* Patch old grease pencil modifiers material filter. */ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { - switch (md->type) { - case eGpencilModifierType_Array: { - ArrayGpencilModifierData *gpmd = (ArrayGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Color: { - ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Hook: { - HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Lattice: { - LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Mirror: { - MirrorGpencilModifierData *gpmd = (MirrorGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Multiply: { - MultiplyGpencilModifierData *gpmd = (MultiplyGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Noise: { - NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Offset: { - OffsetGpencilModifierData *gpmd = (OffsetGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Opacity: { - OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Simplify: { - SimplifyGpencilModifierData *gpmd = (SimplifyGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Smooth: { - SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Subdiv: { - SubdivGpencilModifierData *gpmd = (SubdivGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Texture: { - TextureGpencilModifierData *gpmd = (TextureGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Thick: { - ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - default: - break; - } - } - } - } - /** * Versioning code until next subversion bump goes here. * @@ -3040,8 +2902,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) v3d->overlay.edit_flag |= V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS | V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE | V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES | - V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS | - V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS; + V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS; } } } diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 207cee5ac50..c4d7e871ea0 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -28,6 +28,7 @@ #include "DNA_genfile.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_modifier_types.h" +#include "DNA_object_types.h" #include "DNA_screen_types.h" #include "BKE_collection.h" @@ -41,6 +42,161 @@ /* Make preferences read-only, use versioning_userdef.c. */ #define U (*((const UserDef *)&U)) +void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) +{ + if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) { + /* Patch old grease pencil modifiers material filter. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { + switch (md->type) { + case eGpencilModifierType_Array: { + ArrayGpencilModifierData *gpmd = (ArrayGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Color: { + ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Hook: { + HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Lattice: { + LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Mirror: { + MirrorGpencilModifierData *gpmd = (MirrorGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Multiply: { + MultiplyGpencilModifierData *gpmd = (MultiplyGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Noise: { + NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Offset: { + OffsetGpencilModifierData *gpmd = (OffsetGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Opacity: { + OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Simplify: { + SimplifyGpencilModifierData *gpmd = (SimplifyGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Smooth: { + SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Subdiv: { + SubdivGpencilModifierData *gpmd = (SubdivGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Texture: { + TextureGpencilModifierData *gpmd = (TextureGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Thick: { + ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + default: + break; + } + } + } + } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - #blo_do_versions_290 in this file. + * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ + } +} + void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) { UNUSED_VARS(fd); @@ -88,6 +244,18 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 290, 4)) { + /* Clear old deprecated bit-flag from edit weights modifiers, we now use it for something else. + */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_WeightVGEdit) { + ((WeightVGEditModifierData *)md)->edit_flags &= ~MOD_WVG_EDIT_WEIGHTS_NORMALIZE; + } + } + } + } + /** * Versioning code until next subversion bump goes here. * @@ -100,29 +268,29 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) { /* Keep this block, even when empty. */ - /* Transition to saving expansion for all of a constraint's subpanels. */ - if (!DNA_struct_elem_find(fd->filesdna, "bSizeLikeConstraint", "short", "ui_expand_flag")) { + /* Transition to saving expansion for all of a modifier's subpanels. */ + if (!DNA_struct_elem_find(fd->filesdna, "ModifierData", "short", "ui_expand_flag")) { for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { - LISTBASE_FOREACH (bConstraint *, con, &object->constraints) { - if (con->flag & CONSTRAINT_EXPAND_DEPRECATED) { - con->ui_expand_flag = 1; + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + if (md->mode & eModifierMode_Expanded_DEPRECATED) { + md->ui_expand_flag = 1; } else { - con->ui_expand_flag = 0; + md->ui_expand_flag = 0; } } } } - /* Transition to saving expansion for all of a modifier's subpanels. */ - if (!DNA_struct_elem_find(fd->filesdna, "SolidifyModifierData", "short", "ui_expand_flag")) { + /* Transition to saving expansion for all of a constraint's subpanels. */ + if (!DNA_struct_elem_find(fd->filesdna, "bSizeLikeConstraint", "short", "ui_expand_flag")) { for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { - LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { - if (md->mode & eModifierMode_Expanded_DEPRECATED) { - md->ui_expand_flag = 1; + LISTBASE_FOREACH (bConstraint *, con, &object->constraints) { + if (con->flag & CONSTRAINT_EXPAND_DEPRECATED) { + con->ui_expand_flag = 1; } else { - md->ui_expand_flag = 0; + con->ui_expand_flag = 0; } } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 665771cce1e..91d89254c90 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -251,8 +251,7 @@ static void blo_update_defaults_screen(bScreen *screen, void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_template) { - ListBase *layouts = BKE_workspace_layouts_get(workspace); - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { if (layout->screen) { blo_update_defaults_screen(layout->screen, app_template, workspace->id.name + 2); } @@ -271,7 +270,7 @@ void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_templat /* For Sculpting template. */ if (STREQ(workspace->id.name + 2, "Sculpting")) { - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { bScreen *screen = layout->screen; if (screen) { LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { @@ -466,6 +465,9 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) /* Reset all grease pencil brushes. */ Scene *scene = bmain->scenes.first; BKE_brush_gpencil_paint_presets(bmain, scene->toolsettings, true); + BKE_brush_gpencil_sculpt_presets(bmain, scene->toolsettings, true); + BKE_brush_gpencil_vertex_presets(bmain, scene->toolsettings, true); + BKE_brush_gpencil_weight_presets(bmain, scene->toolsettings, true); /* Ensure new Paint modes. */ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_VERTEX_GPENCIL); @@ -489,8 +491,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) { - WorkSpaceLayout *layout = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, - workspace); + WorkSpaceLayout *layout = BKE_workspace_active_layout_for_workspace_get( + win->workspace_hook, workspace); /* Name all screens by their workspaces (avoids 'Default.###' names). */ /* Default only has one window. */ if (layout->screen) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index a54085b3036..5e78f0c1052 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -162,6 +162,7 @@ #include "BKE_gpencil_modifier.h" #include "BKE_idtype.h" #include "BKE_layer.h" +#include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_main.h" #include "BKE_modifier.h" @@ -176,15 +177,13 @@ #include "BLO_blend_defs.h" #include "BLO_blend_validate.h" +#include "BLO_read_write.h" #include "BLO_readfile.h" #include "BLO_undofile.h" #include "BLO_writefile.h" #include "readfile.h" -/* for SDNA_TYPE_FROM_STRUCT() macro */ -#include "dna_type_offsets.h" - #include <errno.h> /* Make preferences read-only. */ @@ -326,12 +325,7 @@ typedef struct { bool error; /** #MemFile writing (used for undo). */ - struct { - MemFile *current; - MemFile *compare; - /** Use to de-duplicate chunks when writing. */ - MemFileChunk *compare_chunk; - } mem; + MemFileWriteData mem; /** When true, write to #WriteData.current, could also call 'is_undo'. */ bool use_memfile; @@ -343,6 +337,10 @@ typedef struct { WriteWrap *ww; } WriteData; +typedef struct BlendWriter { + WriteData *wd; +} BlendWriter; + static WriteData *writedata_new(WriteWrap *ww) { WriteData *wd = MEM_callocN(sizeof(*wd), "writedata"); @@ -370,7 +368,7 @@ static void writedata_do_write(WriteData *wd, const void *mem, int memlen) /* memory based save */ if (wd->use_memfile) { - memfile_chunk_add(wd->mem.current, mem, memlen, &wd->mem.compare_chunk); + BLO_memfile_chunk_add(&wd->mem, mem, memlen); } else { if (wd->ww->write(wd->ww, mem, memlen) != memlen) { @@ -471,9 +469,7 @@ static WriteData *mywrite_begin(WriteWrap *ww, MemFile *compare, MemFile *curren WriteData *wd = writedata_new(ww); if (current != NULL) { - wd->mem.current = current; - wd->mem.compare = compare; - wd->mem.compare_chunk = compare ? compare->chunks.first : NULL; + BLO_memfile_write_init(&wd->mem, current, compare); wd->use_memfile = true; } @@ -493,12 +489,58 @@ static bool mywrite_end(WriteData *wd) wd->buf_used_len = 0; } + if (wd->use_memfile) { + BLO_memfile_write_finalize(&wd->mem); + } + const bool err = wd->error; writedata_free(wd); return err; } +/** + * Start writing of data related to a single ID. + * + * Only does something when storing an undo step. + */ +static void mywrite_id_begin(WriteData *wd, ID *id) +{ + if (wd->use_memfile) { + wd->mem.current_id_session_uuid = id->session_uuid; + + /* If current next memchunk does not match the ID we are about to write, try to find the + * correct memchunk in the mapping using ID's session_uuid. */ + if (wd->mem.id_session_uuid_mapping != NULL && + (wd->mem.reference_current_chunk == NULL || + wd->mem.reference_current_chunk->id_session_uuid != id->session_uuid)) { + void *ref = BLI_ghash_lookup(wd->mem.id_session_uuid_mapping, + POINTER_FROM_UINT(id->session_uuid)); + if (ref != NULL) { + wd->mem.reference_current_chunk = ref; + } + /* Else, no existing memchunk found, i.e. this is supposed to be a new ID. */ + } + /* Otherwise, we try with the current memchunk in any case, whether it is matching current + * ID's session_uuid or not. */ + } +} + +/** + * Start writing of data related to a single ID. + * + * Only does something when storing an undo step. + */ +static void mywrite_id_end(WriteData *wd, ID *UNUSED(id)) +{ + if (wd->use_memfile) { + /* Very important to do it after every ID write now, otherwise we cannot know whether a + * specific ID changed or not. */ + mywrite_flush(wd); + wd->mem.current_id_session_uuid = MAIN_ID_SESSION_UUID_UNSET; + } +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -634,103 +676,109 @@ static void writelist_id(WriteData *wd, int filecode, const char *structname, co * These functions are used by blender's .blend system for file saving/loading. * \{ */ -void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd); -void IDP_WriteProperty(const IDProperty *prop, void *wd); +void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer); +void IDP_WriteProperty(const IDProperty *prop, WriteData *wd); +void IDP_WriteProperty_new_api(const IDProperty *prop, BlendWriter *writer); -static void IDP_WriteArray(const IDProperty *prop, void *wd) +static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer) { /*REMEMBER to set totalen to len in the linking code!!*/ if (prop->data.pointer) { - writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer); + BLO_write_raw(writer, MEM_allocN_len(prop->data.pointer), prop->data.pointer); if (prop->subtype == IDP_GROUP) { IDProperty **array = prop->data.pointer; int a; for (a = 0; a < prop->len; a++) { - IDP_WriteProperty(array[a], wd); + IDP_WriteProperty_new_api(array[a], writer); } } } } -static void IDP_WriteIDPArray(const IDProperty *prop, void *wd) +static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer) { /*REMEMBER to set totalen to len in the linking code!!*/ if (prop->data.pointer) { const IDProperty *array = prop->data.pointer; int a; - writestruct(wd, DATA, IDProperty, prop->len, array); + BLO_write_struct_array(writer, IDProperty, prop->len, array); for (a = 0; a < prop->len; a++) { - IDP_WriteProperty_OnlyData(&array[a], wd); + IDP_WriteProperty_OnlyData(&array[a], writer); } } } -static void IDP_WriteString(const IDProperty *prop, void *wd) +static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer) { /*REMEMBER to set totalen to len in the linking code!!*/ - writedata(wd, DATA, prop->len, prop->data.pointer); + BLO_write_raw(writer, prop->len, prop->data.pointer); } -static void IDP_WriteGroup(const IDProperty *prop, void *wd) +static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer) { IDProperty *loop; for (loop = prop->data.group.first; loop; loop = loop->next) { - IDP_WriteProperty(loop, wd); + IDP_WriteProperty_new_api(loop, writer); } } /* Functions to read/write ID Properties */ -void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd) +void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer) { switch (prop->type) { case IDP_GROUP: - IDP_WriteGroup(prop, wd); + IDP_WriteGroup(prop, writer); break; case IDP_STRING: - IDP_WriteString(prop, wd); + IDP_WriteString(prop, writer); break; case IDP_ARRAY: - IDP_WriteArray(prop, wd); + IDP_WriteArray(prop, writer); break; case IDP_IDPARRAY: - IDP_WriteIDPArray(prop, wd); + IDP_WriteIDPArray(prop, writer); break; } } -void IDP_WriteProperty(const IDProperty *prop, void *wd) +void IDP_WriteProperty_new_api(const IDProperty *prop, BlendWriter *writer) { - writestruct(wd, DATA, IDProperty, 1, prop); - IDP_WriteProperty_OnlyData(prop, wd); + BLO_write_struct(writer, IDProperty, prop); + IDP_WriteProperty_OnlyData(prop, writer); } -static void write_iddata(WriteData *wd, ID *id) +void IDP_WriteProperty(const IDProperty *prop, WriteData *wd) +{ + BlendWriter writer = {wd}; + IDP_WriteProperty_new_api(prop, &writer); +} + +static void write_iddata(BlendWriter *writer, ID *id) { /* ID_WM's id->properties are considered runtime only, and never written in .blend file. */ if (id->properties && !ELEM(GS(id->name), ID_WM)) { - IDP_WriteProperty(id->properties, wd); + IDP_WriteProperty_new_api(id->properties, writer); } if (id->override_library) { - writestruct(wd, DATA, IDOverrideLibrary, 1, id->override_library); + BLO_write_struct(writer, IDOverrideLibrary, id->override_library); - writelist(wd, DATA, IDOverrideLibraryProperty, &id->override_library->properties); + BLO_write_struct_list(writer, IDOverrideLibraryProperty, &id->override_library->properties); LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) { - writedata(wd, DATA, strlen(op->rna_path) + 1, op->rna_path); + BLO_write_string(writer, op->rna_path); - writelist(wd, DATA, IDOverrideLibraryPropertyOperation, &op->operations); + BLO_write_struct_list(writer, IDOverrideLibraryPropertyOperation, &op->operations); LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) { if (opop->subitem_reference_name) { - writedata( - wd, DATA, strlen(opop->subitem_reference_name) + 1, opop->subitem_reference_name); + BLO_write_string(writer, opop->subitem_reference_name); } if (opop->subitem_local_name) { - writedata(wd, DATA, strlen(opop->subitem_local_name) + 1, opop->subitem_local_name); + BLO_write_string(writer, opop->subitem_local_name); } } } @@ -761,12 +809,12 @@ static void write_previews(WriteData *wd, const PreviewImage *prv_orig) } } -static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) +static void write_fmodifiers(BlendWriter *writer, ListBase *fmodifiers) { FModifier *fcm; /* Write all modifiers first (for faster reloading) */ - writelist(wd, DATA, FModifier, fmodifiers); + BLO_write_struct_list(writer, FModifier, fmodifiers); /* Modifiers */ for (fcm = fmodifiers->first; fcm; fcm = fcm->next) { @@ -775,7 +823,7 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) /* Write the specific data */ if (fmi && fcm->data) { /* firstly, just write the plain fmi->data struct */ - writestruct_id(wd, DATA, fmi->structName, 1, fcm->data); + BLO_write_struct_by_name(writer, fmi->structName, fcm->data); /* do any modifier specific stuff */ switch (fcm->type) { @@ -784,7 +832,7 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) /* write coefficients array */ if (data->coefficients) { - writedata(wd, DATA, sizeof(float) * (data->arraysize), data->coefficients); + BLO_write_float_array(writer, data->arraysize, data->coefficients); } break; @@ -794,7 +842,7 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) /* write envelope data */ if (data->data) { - writestruct(wd, DATA, FCM_EnvelopeData, data->totvert, data->data); + BLO_write_struct_array(writer, FCM_EnvelopeData, data->totvert, data->data); } break; @@ -804,7 +852,7 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) /* Write ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - IDP_WriteProperty(data->prop, wd); + IDP_WriteProperty_new_api(data->prop, writer); break; } @@ -813,22 +861,22 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) } } -static void write_fcurves(WriteData *wd, ListBase *fcurves) +static void write_fcurves(BlendWriter *writer, ListBase *fcurves) { FCurve *fcu; - writelist(wd, DATA, FCurve, fcurves); + BLO_write_struct_list(writer, FCurve, fcurves); for (fcu = fcurves->first; fcu; fcu = fcu->next) { /* curve data */ if (fcu->bezt) { - writestruct(wd, DATA, BezTriple, fcu->totvert, fcu->bezt); + BLO_write_struct_array(writer, BezTriple, fcu->totvert, fcu->bezt); } if (fcu->fpt) { - writestruct(wd, DATA, FPoint, fcu->totvert, fcu->fpt); + BLO_write_struct_array(writer, FPoint, fcu->totvert, fcu->fpt); } if (fcu->rna_path) { - writedata(wd, DATA, strlen(fcu->rna_path) + 1, fcu->rna_path); + BLO_write_string(writer, fcu->rna_path); } /* driver data */ @@ -836,14 +884,14 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves) ChannelDriver *driver = fcu->driver; DriverVar *dvar; - writestruct(wd, DATA, ChannelDriver, 1, driver); + BLO_write_struct(writer, ChannelDriver, driver); /* variables */ - writelist(wd, DATA, DriverVar, &driver->variables); + BLO_write_struct_list(writer, DriverVar, &driver->variables); for (dvar = driver->variables.first; dvar; dvar = dvar->next) { DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { if (dtar->rna_path) { - writedata(wd, DATA, strlen(dtar->rna_path) + 1, dtar->rna_path); + BLO_write_string(writer, dtar->rna_path); } } DRIVER_TARGETS_LOOPER_END; @@ -851,24 +899,24 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves) } /* write F-Modifiers */ - write_fmodifiers(wd, &fcu->modifiers); + write_fmodifiers(writer, &fcu->modifiers); } } -static void write_action(WriteData *wd, bAction *act, const void *id_address) +static void write_action(BlendWriter *writer, bAction *act, const void *id_address) { - if (act->id.us > 0 || wd->use_memfile) { - writestruct_at_address(wd, ID_AC, bAction, 1, id_address, act); - write_iddata(wd, &act->id); + if (act->id.us > 0 || BLO_write_is_undo(writer)) { + BLO_write_id_struct(writer, bAction, id_address, &act->id); + write_iddata(writer, &act->id); - write_fcurves(wd, &act->curves); + write_fcurves(writer, &act->curves); LISTBASE_FOREACH (bActionGroup *, grp, &act->groups) { - writestruct(wd, DATA, bActionGroup, 1, grp); + BLO_write_struct(writer, bActionGroup, grp); } LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { - writestruct(wd, DATA, TimeMarker, 1, marker); + BLO_write_struct(writer, TimeMarker, marker); } } } @@ -894,57 +942,57 @@ static void write_keyingsets(WriteData *wd, ListBase *list) } } -static void write_nlastrips(WriteData *wd, ListBase *strips) +static void write_nlastrips(BlendWriter *writer, ListBase *strips) { NlaStrip *strip; - writelist(wd, DATA, NlaStrip, strips); + BLO_write_struct_list(writer, NlaStrip, strips); for (strip = strips->first; strip; strip = strip->next) { /* write the strip's F-Curves and modifiers */ - write_fcurves(wd, &strip->fcurves); - write_fmodifiers(wd, &strip->modifiers); + write_fcurves(writer, &strip->fcurves); + write_fmodifiers(writer, &strip->modifiers); /* write the strip's children */ - write_nlastrips(wd, &strip->strips); + write_nlastrips(writer, &strip->strips); } } -static void write_nladata(WriteData *wd, ListBase *nlabase) +static void write_nladata(BlendWriter *writer, ListBase *nlabase) { NlaTrack *nlt; /* write all the tracks */ for (nlt = nlabase->first; nlt; nlt = nlt->next) { /* write the track first */ - writestruct(wd, DATA, NlaTrack, 1, nlt); + BLO_write_struct(writer, NlaTrack, nlt); /* write the track's strips */ - write_nlastrips(wd, &nlt->strips); + write_nlastrips(writer, &nlt->strips); } } -static void write_animdata(WriteData *wd, AnimData *adt) +static void write_animdata(BlendWriter *writer, AnimData *adt) { AnimOverride *aor; /* firstly, just write the AnimData block */ - writestruct(wd, DATA, AnimData, 1, adt); + BLO_write_struct(writer, AnimData, adt); /* write drivers */ - write_fcurves(wd, &adt->drivers); + write_fcurves(writer, &adt->drivers); /* write overrides */ // FIXME: are these needed? for (aor = adt->overrides.first; aor; aor = aor->next) { /* overrides consist of base data + rna_path */ - writestruct(wd, DATA, AnimOverride, 1, aor); - writedata(wd, DATA, strlen(aor->rna_path) + 1, aor->rna_path); + BLO_write_struct(writer, AnimOverride, aor); + BLO_write_string(writer, aor->rna_path); } // TODO write the remaps (if they are needed) /* write NLA data */ - write_nladata(wd, &adt->nla_tracks); + write_nladata(writer, &adt->nla_tracks); } static void write_curvemapping_curves(WriteData *wd, CurveMapping *cumap) @@ -967,7 +1015,7 @@ static void write_CurveProfile(WriteData *wd, CurveProfile *profile) writestruct(wd, DATA, CurveProfilePoint, profile->path_len, profile->path); } -static void write_node_socket_default_value(WriteData *wd, bNodeSocket *sock) +static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *sock) { if (sock->default_value == NULL) { return; @@ -975,28 +1023,28 @@ static void write_node_socket_default_value(WriteData *wd, bNodeSocket *sock) switch ((eNodeSocketDatatype)sock->type) { case SOCK_FLOAT: - writestruct(wd, DATA, bNodeSocketValueFloat, 1, sock->default_value); + BLO_write_struct(writer, bNodeSocketValueFloat, sock->default_value); break; case SOCK_VECTOR: - writestruct(wd, DATA, bNodeSocketValueVector, 1, sock->default_value); + BLO_write_struct(writer, bNodeSocketValueVector, sock->default_value); break; case SOCK_RGBA: - writestruct(wd, DATA, bNodeSocketValueRGBA, 1, sock->default_value); + BLO_write_struct(writer, bNodeSocketValueRGBA, sock->default_value); break; case SOCK_BOOLEAN: - writestruct(wd, DATA, bNodeSocketValueBoolean, 1, sock->default_value); + BLO_write_struct(writer, bNodeSocketValueBoolean, sock->default_value); break; case SOCK_INT: - writestruct(wd, DATA, bNodeSocketValueInt, 1, sock->default_value); + BLO_write_struct(writer, bNodeSocketValueInt, sock->default_value); break; case SOCK_STRING: - writestruct(wd, DATA, bNodeSocketValueString, 1, sock->default_value); + BLO_write_struct(writer, bNodeSocketValueString, sock->default_value); break; case SOCK_OBJECT: - writestruct(wd, DATA, bNodeSocketValueObject, 1, sock->default_value); + BLO_write_struct(writer, bNodeSocketValueObject, sock->default_value); break; case SOCK_IMAGE: - writestruct(wd, DATA, bNodeSocketValueImage, 1, sock->default_value); + BLO_write_struct(writer, bNodeSocketValueImage, sock->default_value); break; case __SOCK_MESH: case SOCK_CUSTOM: @@ -1010,30 +1058,30 @@ static void write_node_socket_default_value(WriteData *wd, bNodeSocket *sock) } } -static void write_node_socket(WriteData *wd, bNodeSocket *sock) +static void write_node_socket(BlendWriter *writer, bNodeSocket *sock) { /* actual socket writing */ - writestruct(wd, DATA, bNodeSocket, 1, sock); + BLO_write_struct(writer, bNodeSocket, sock); if (sock->prop) { - IDP_WriteProperty(sock->prop, wd); + IDP_WriteProperty_new_api(sock->prop, writer); } - write_node_socket_default_value(wd, sock); + write_node_socket_default_value(writer, sock); } -static void write_node_socket_interface(WriteData *wd, bNodeSocket *sock) +static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock) { /* actual socket writing */ - writestruct(wd, DATA, bNodeSocket, 1, sock); + BLO_write_struct(writer, bNodeSocket, sock); if (sock->prop) { - IDP_WriteProperty(sock->prop, wd); + IDP_WriteProperty_new_api(sock->prop, writer); } - write_node_socket_default_value(wd, sock); + write_node_socket_default_value(writer, sock); } /* this is only direct data, tree itself should have been written */ -static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree) +static void write_nodetree_nolib(BlendWriter *writer, bNodeTree *ntree) { bNode *node; bNodeSocket *sock; @@ -1042,50 +1090,50 @@ static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree) /* for link_list() speed, we write per list */ if (ntree->adt) { - write_animdata(wd, ntree->adt); + write_animdata(writer, ntree->adt); } for (node = ntree->nodes.first; node; node = node->next) { - writestruct(wd, DATA, bNode, 1, node); + BLO_write_struct(writer, bNode, node); if (node->prop) { - IDP_WriteProperty(node->prop, wd); + IDP_WriteProperty_new_api(node->prop, writer); } for (sock = node->inputs.first; sock; sock = sock->next) { - write_node_socket(wd, sock); + write_node_socket(writer, sock); } for (sock = node->outputs.first; sock; sock = sock->next) { - write_node_socket(wd, sock); + write_node_socket(writer, sock); } for (link = node->internal_links.first; link; link = link->next) { - writestruct(wd, DATA, bNodeLink, 1, link); + BLO_write_struct(writer, bNodeLink, link); } if (node->storage) { /* could be handlerized at some point, now only 1 exception still */ if ((ntree->type == NTREE_SHADER) && ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) { - write_curvemapping(wd, node->storage); + write_curvemapping(writer->wd, node->storage); } else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) { NodeShaderScript *nss = (NodeShaderScript *)node->storage; if (nss->bytecode) { - writedata(wd, DATA, strlen(nss->bytecode) + 1, nss->bytecode); + BLO_write_string(writer, nss->bytecode); } - writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage); + BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); } else if ((ntree->type == NTREE_COMPOSIT) && ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) { - write_curvemapping(wd, node->storage); + write_curvemapping(writer->wd, node->storage); } else if ((ntree->type == NTREE_TEXTURE) && (node->type == TEX_NODE_CURVE_RGB || node->type == TEX_NODE_CURVE_TIME)) { - write_curvemapping(wd, node->storage); + write_curvemapping(writer->wd, node->storage); } else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_MOVIEDISTORTION)) { /* pass */ @@ -1095,7 +1143,7 @@ static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree) * Not ideal (there is no ideal solution here), but should do for now. */ NodeGlare *ndg = node->storage; /* Not in undo case. */ - if (wd->use_memfile == false) { + if (!BLO_write_is_undo(writer)) { switch (ndg->type) { case 2: /* Grrrr! magic numbers :( */ ndg->angle = ndg->streaks; @@ -1107,43 +1155,43 @@ static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree) break; } } - writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage); + BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); } else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) { NodeCryptomatte *nc = (NodeCryptomatte *)node->storage; if (nc->matte_id) { - writedata(wd, DATA, strlen(nc->matte_id) + 1, nc->matte_id); + BLO_write_string(writer, nc->matte_id); } - writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage); + BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); } else { - writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage); + BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); } } if (node->type == CMP_NODE_OUTPUT_FILE) { /* inputs have own storage data */ for (sock = node->inputs.first; sock; sock = sock->next) { - writestruct(wd, DATA, NodeImageMultiFileSocket, 1, sock->storage); + BLO_write_struct(writer, NodeImageMultiFileSocket, sock->storage); } } if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) { /* write extra socket info */ for (sock = node->outputs.first; sock; sock = sock->next) { - writestruct(wd, DATA, NodeImageLayer, 1, sock->storage); + BLO_write_struct(writer, NodeImageLayer, sock->storage); } } } for (link = ntree->links.first; link; link = link->next) { - writestruct(wd, DATA, bNodeLink, 1, link); + BLO_write_struct(writer, bNodeLink, link); } for (sock = ntree->inputs.first; sock; sock = sock->next) { - write_node_socket_interface(wd, sock); + write_node_socket_interface(writer, sock); } for (sock = ntree->outputs.first; sock; sock = sock->next) { - write_node_socket_interface(wd, sock); + write_node_socket_interface(writer, sock); } } @@ -1396,28 +1444,30 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches) } } -static void write_particlesettings(WriteData *wd, ParticleSettings *part, const void *id_address) +static void write_particlesettings(BlendWriter *writer, + ParticleSettings *part, + const void *id_address) { - if (part->id.us > 0 || wd->use_memfile) { + if (part->id.us > 0 || BLO_write_is_undo(writer)) { /* write LibData */ - writestruct_at_address(wd, ID_PA, ParticleSettings, 1, id_address, part); - write_iddata(wd, &part->id); + BLO_write_id_struct(writer, ParticleSettings, id_address, &part->id); + write_iddata(writer, &part->id); if (part->adt) { - write_animdata(wd, part->adt); + write_animdata(writer, part->adt); } - writestruct(wd, DATA, PartDeflect, 1, part->pd); - writestruct(wd, DATA, PartDeflect, 1, part->pd2); - writestruct(wd, DATA, EffectorWeights, 1, part->effector_weights); + BLO_write_struct(writer, PartDeflect, part->pd); + BLO_write_struct(writer, PartDeflect, part->pd2); + BLO_write_struct(writer, EffectorWeights, part->effector_weights); if (part->clumpcurve) { - write_curvemapping(wd, part->clumpcurve); + write_curvemapping(writer->wd, part->clumpcurve); } if (part->roughcurve) { - write_curvemapping(wd, part->roughcurve); + write_curvemapping(writer->wd, part->roughcurve); } if (part->twistcurve) { - write_curvemapping(wd, part->twistcurve); + write_curvemapping(writer->wd, part->twistcurve); } LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) { @@ -1434,23 +1484,23 @@ static void write_particlesettings(WriteData *wd, ParticleSettings *part, const FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } } - writestruct(wd, DATA, ParticleDupliWeight, 1, dw); + BLO_write_struct(writer, ParticleDupliWeight, dw); } if (part->boids && part->phystype == PART_PHYS_BOIDS) { - writestruct(wd, DATA, BoidSettings, 1, part->boids); + BLO_write_struct(writer, BoidSettings, part->boids); LISTBASE_FOREACH (BoidState *, state, &part->boids->states) { - write_boid_state(wd, state); + write_boid_state(writer->wd, state); } } if (part->fluid && part->phystype == PART_PHYS_FLUID) { - writestruct(wd, DATA, SPHFluidSettings, 1, part->fluid); + BLO_write_struct(writer, SPHFluidSettings, part->fluid); } for (int a = 0; a < MAX_MTEX; a++) { if (part->mtex[a]) { - writestruct(wd, DATA, MTex, 1, part->mtex[a]); + BLO_write_struct(writer, MTex, part->mtex[a]); } } } @@ -1637,7 +1687,7 @@ static void write_fmaps(WriteData *wd, ListBase *fbase) } } -static void write_modifiers(WriteData *wd, ListBase *modbase) +static void write_modifiers(BlendWriter *writer, ListBase *modbase) { ModifierData *md; @@ -1651,86 +1701,86 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) return; } - writestruct_id(wd, DATA, mti->structName, 1, md); + BLO_write_struct_by_name(writer, mti->structName, md); if (md->type == eModifierType_Hook) { HookModifierData *hmd = (HookModifierData *)md; if (hmd->curfalloff) { - write_curvemapping(wd, hmd->curfalloff); + write_curvemapping(writer->wd, hmd->curfalloff); } - writedata(wd, DATA, sizeof(int) * hmd->totindex, hmd->indexar); + BLO_write_int32_array(writer, hmd->totindex, hmd->indexar); } else if (md->type == eModifierType_Cloth) { ClothModifierData *clmd = (ClothModifierData *)md; - writestruct(wd, DATA, ClothSimSettings, 1, clmd->sim_parms); - writestruct(wd, DATA, ClothCollSettings, 1, clmd->coll_parms); - writestruct(wd, DATA, EffectorWeights, 1, clmd->sim_parms->effector_weights); - write_pointcaches(wd, &clmd->ptcaches); + BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms); + BLO_write_struct(writer, ClothCollSettings, clmd->coll_parms); + BLO_write_struct(writer, EffectorWeights, clmd->sim_parms->effector_weights); + write_pointcaches(writer->wd, &clmd->ptcaches); } else if (md->type == eModifierType_Fluid) { FluidModifierData *mmd = (FluidModifierData *)md; if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { - writestruct(wd, DATA, FluidDomainSettings, 1, mmd->domain); + BLO_write_struct(writer, FluidDomainSettings, mmd->domain); if (mmd->domain) { - write_pointcaches(wd, &(mmd->domain->ptcaches[0])); + write_pointcaches(writer->wd, &(mmd->domain->ptcaches[0])); /* create fake pointcache so that old blender versions can read it */ mmd->domain->point_cache[1] = BKE_ptcache_add(&mmd->domain->ptcaches[1]); mmd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE; mmd->domain->point_cache[1]->step = 1; - write_pointcaches(wd, &(mmd->domain->ptcaches[1])); + write_pointcaches(writer->wd, &(mmd->domain->ptcaches[1])); if (mmd->domain->coba) { - writestruct(wd, DATA, ColorBand, 1, mmd->domain->coba); + BLO_write_struct(writer, ColorBand, mmd->domain->coba); } /* cleanup the fake pointcache */ BKE_ptcache_free_list(&mmd->domain->ptcaches[1]); mmd->domain->point_cache[1] = NULL; - writestruct(wd, DATA, EffectorWeights, 1, mmd->domain->effector_weights); + BLO_write_struct(writer, EffectorWeights, mmd->domain->effector_weights); } } else if (mmd->type & MOD_FLUID_TYPE_FLOW) { - writestruct(wd, DATA, FluidFlowSettings, 1, mmd->flow); + BLO_write_struct(writer, FluidFlowSettings, mmd->flow); } else if (mmd->type & MOD_FLUID_TYPE_EFFEC) { - writestruct(wd, DATA, FluidEffectorSettings, 1, mmd->effector); + BLO_write_struct(writer, FluidEffectorSettings, mmd->effector); } } else if (md->type == eModifierType_Fluidsim) { FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; - writestruct(wd, DATA, FluidsimSettings, 1, fluidmd->fss); + BLO_write_struct(writer, FluidsimSettings, fluidmd->fss); } else if (md->type == eModifierType_DynamicPaint) { DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; if (pmd->canvas) { DynamicPaintSurface *surface; - writestruct(wd, DATA, DynamicPaintCanvasSettings, 1, pmd->canvas); + BLO_write_struct(writer, DynamicPaintCanvasSettings, pmd->canvas); /* write surfaces */ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { - writestruct(wd, DATA, DynamicPaintSurface, 1, surface); + BLO_write_struct(writer, DynamicPaintSurface, surface); } /* write caches and effector weights */ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { - write_pointcaches(wd, &(surface->ptcaches)); + write_pointcaches(writer->wd, &(surface->ptcaches)); - writestruct(wd, DATA, EffectorWeights, 1, surface->effector_weights); + BLO_write_struct(writer, EffectorWeights, surface->effector_weights); } } if (pmd->brush) { - writestruct(wd, DATA, DynamicPaintBrushSettings, 1, pmd->brush); - writestruct(wd, DATA, ColorBand, 1, pmd->brush->paint_ramp); - writestruct(wd, DATA, ColorBand, 1, pmd->brush->vel_ramp); + BLO_write_struct(writer, DynamicPaintBrushSettings, pmd->brush); + BLO_write_struct(writer, ColorBand, pmd->brush->paint_ramp); + BLO_write_struct(writer, ColorBand, pmd->brush->vel_ramp); } } else if (md->type == eModifierType_Collision) { @@ -1748,63 +1798,59 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; int size = mmd->dyngridsize; - writestruct(wd, DATA, MDefInfluence, mmd->totinfluence, mmd->bindinfluences); - writedata(wd, DATA, sizeof(int) * (mmd->totvert + 1), mmd->bindoffsets); - writedata(wd, DATA, sizeof(float) * 3 * mmd->totcagevert, mmd->bindcagecos); - writestruct(wd, DATA, MDefCell, size * size * size, mmd->dyngrid); - writestruct(wd, DATA, MDefInfluence, mmd->totinfluence, mmd->dyninfluences); - writedata(wd, DATA, sizeof(int) * mmd->totvert, mmd->dynverts); + BLO_write_struct_array(writer, MDefInfluence, mmd->totinfluence, mmd->bindinfluences); + BLO_write_int32_array(writer, mmd->totvert + 1, mmd->bindoffsets); + BLO_write_float3_array(writer, mmd->totcagevert, mmd->bindcagecos); + BLO_write_struct_array(writer, MDefCell, size * size * size, mmd->dyngrid); + BLO_write_struct_array(writer, MDefInfluence, mmd->totinfluence, mmd->dyninfluences); + BLO_write_int32_array(writer, mmd->totvert, mmd->dynverts); } else if (md->type == eModifierType_Warp) { WarpModifierData *tmd = (WarpModifierData *)md; if (tmd->curfalloff) { - write_curvemapping(wd, tmd->curfalloff); + write_curvemapping(writer->wd, tmd->curfalloff); } } else if (md->type == eModifierType_WeightVGEdit) { WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; if (wmd->cmap_curve) { - write_curvemapping(wd, wmd->cmap_curve); + write_curvemapping(writer->wd, wmd->cmap_curve); } } else if (md->type == eModifierType_LaplacianDeform) { LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; - writedata(wd, DATA, sizeof(float) * lmd->total_verts * 3, lmd->vertexco); + BLO_write_float3_array(writer, lmd->total_verts, lmd->vertexco); } else if (md->type == eModifierType_CorrectiveSmooth) { CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; if (csmd->bind_coords) { - writedata(wd, DATA, sizeof(float[3]) * csmd->bind_coords_num, csmd->bind_coords); + BLO_write_float3_array(writer, csmd->bind_coords_num, (float *)csmd->bind_coords); } } else if (md->type == eModifierType_SurfaceDeform) { SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; - writestruct(wd, DATA, SDefVert, smd->numverts, smd->verts); + BLO_write_struct_array(writer, SDefVert, smd->numverts, smd->verts); if (smd->verts) { for (int i = 0; i < smd->numverts; i++) { - writestruct(wd, DATA, SDefBind, smd->verts[i].numbinds, smd->verts[i].binds); + BLO_write_struct_array(writer, SDefBind, smd->verts[i].numbinds, smd->verts[i].binds); if (smd->verts[i].binds) { for (int j = 0; j < smd->verts[i].numbinds; j++) { - writedata(wd, - DATA, - sizeof(int) * smd->verts[i].binds[j].numverts, - smd->verts[i].binds[j].vert_inds); + BLO_write_uint32_array( + writer, smd->verts[i].binds[j].numverts, smd->verts[i].binds[j].vert_inds); if (smd->verts[i].binds[j].mode == MOD_SDEF_MODE_CENTROID || smd->verts[i].binds[j].mode == MOD_SDEF_MODE_LOOPTRI) { - writedata(wd, DATA, sizeof(float) * 3, smd->verts[i].binds[j].vert_weights); + BLO_write_float3_array(writer, 1, smd->verts[i].binds[j].vert_weights); } else { - writedata(wd, - DATA, - sizeof(float) * smd->verts[i].binds[j].numverts, - smd->verts[i].binds[j].vert_weights); + BLO_write_float_array( + writer, smd->verts[i].binds[j].numverts, smd->verts[i].binds[j].vert_weights); } } } @@ -1814,13 +1860,13 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) else if (md->type == eModifierType_Bevel) { BevelModifierData *bmd = (BevelModifierData *)md; if (bmd->custom_profile) { - write_CurveProfile(wd, bmd->custom_profile); + write_CurveProfile(writer->wd, bmd->custom_profile); } } } } -static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase) +static void write_gpencil_modifiers(BlendWriter *writer, ListBase *modbase) { GpencilModifierData *md; @@ -1834,54 +1880,54 @@ static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase) return; } - writestruct_id(wd, DATA, mti->struct_name, 1, md); + BLO_write_struct_by_name(writer, mti->struct_name, md); if (md->type == eGpencilModifierType_Thick) { ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; if (gpmd->curve_thickness) { - write_curvemapping(wd, gpmd->curve_thickness); + write_curvemapping(writer->wd, gpmd->curve_thickness); } } else if (md->type == eGpencilModifierType_Noise) { NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md; if (gpmd->curve_intensity) { - write_curvemapping(wd, gpmd->curve_intensity); + write_curvemapping(writer->wd, gpmd->curve_intensity); } } else if (md->type == eGpencilModifierType_Hook) { HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md; if (gpmd->curfalloff) { - write_curvemapping(wd, gpmd->curfalloff); + write_curvemapping(writer->wd, gpmd->curfalloff); } } else if (md->type == eGpencilModifierType_Tint) { TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; if (gpmd->colorband) { - writestruct(wd, DATA, ColorBand, 1, gpmd->colorband); + BLO_write_struct(writer, ColorBand, gpmd->colorband); } if (gpmd->curve_intensity) { - write_curvemapping(wd, gpmd->curve_intensity); + write_curvemapping(writer->wd, gpmd->curve_intensity); } } else if (md->type == eGpencilModifierType_Smooth) { SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md; if (gpmd->curve_intensity) { - write_curvemapping(wd, gpmd->curve_intensity); + write_curvemapping(writer->wd, gpmd->curve_intensity); } } else if (md->type == eGpencilModifierType_Color) { ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md; if (gpmd->curve_intensity) { - write_curvemapping(wd, gpmd->curve_intensity); + write_curvemapping(writer->wd, gpmd->curve_intensity); } } else if (md->type == eGpencilModifierType_Opacity) { OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; if (gpmd->curve_intensity) { - write_curvemapping(wd, gpmd->curve_intensity); + write_curvemapping(writer->wd, gpmd->curve_intensity); } } } @@ -1905,24 +1951,23 @@ static void write_shaderfxs(WriteData *wd, ListBase *fxbase) } } -static void write_object(WriteData *wd, Object *ob, const void *id_address) +static void write_object(BlendWriter *writer, Object *ob, const void *id_address) { - if (ob->id.us > 0 || wd->use_memfile) { + if (ob->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ BKE_object_runtime_reset(ob); /* write LibData */ - writestruct_at_address(wd, ID_OB, Object, 1, id_address, ob); - write_iddata(wd, &ob->id); + BLO_write_id_struct(writer, Object, id_address, &ob->id); + write_iddata(writer, &ob->id); if (ob->adt) { - write_animdata(wd, ob->adt); + write_animdata(writer, ob->adt); } /* direct data */ - writedata(wd, DATA, sizeof(void *) * ob->totcol, ob->mat); - writedata(wd, DATA, sizeof(char) * ob->totcol, ob->matbits); - /* write_effects(wd, &ob->effect); */ /* not used anymore */ + BLO_write_pointer_array(writer, ob->totcol, ob->mat); + BLO_write_raw(writer, sizeof(char) * ob->totcol, ob->matbits); if (ob->type == OB_ARMATURE) { bArmature *arm = ob->data; @@ -1932,108 +1977,108 @@ static void write_object(WriteData *wd, Object *ob, const void *id_address) } } - write_pose(wd, ob->pose); - write_defgroups(wd, &ob->defbase); - write_fmaps(wd, &ob->fmaps); - write_constraints(wd, &ob->constraints); - write_motionpath(wd, ob->mpath); + write_pose(writer->wd, ob->pose); + write_defgroups(writer->wd, &ob->defbase); + write_fmaps(writer->wd, &ob->fmaps); + write_constraints(writer->wd, &ob->constraints); + write_motionpath(writer->wd, ob->mpath); - writestruct(wd, DATA, PartDeflect, 1, ob->pd); + BLO_write_struct(writer, PartDeflect, ob->pd); if (ob->soft) { /* Set deprecated pointers to prevent crashes of older Blenders */ ob->soft->pointcache = ob->soft->shared->pointcache; ob->soft->ptcaches = ob->soft->shared->ptcaches; - writestruct(wd, DATA, SoftBody, 1, ob->soft); - writestruct(wd, DATA, SoftBody_Shared, 1, ob->soft->shared); - write_pointcaches(wd, &(ob->soft->shared->ptcaches)); - writestruct(wd, DATA, EffectorWeights, 1, ob->soft->effector_weights); + BLO_write_struct(writer, SoftBody, ob->soft); + BLO_write_struct(writer, SoftBody_Shared, ob->soft->shared); + write_pointcaches(writer->wd, &(ob->soft->shared->ptcaches)); + BLO_write_struct(writer, EffectorWeights, ob->soft->effector_weights); } if (ob->rigidbody_object) { /* TODO: if any extra data is added to handle duplis, will need separate function then */ - writestruct(wd, DATA, RigidBodyOb, 1, ob->rigidbody_object); + BLO_write_struct(writer, RigidBodyOb, ob->rigidbody_object); } if (ob->rigidbody_constraint) { - writestruct(wd, DATA, RigidBodyCon, 1, ob->rigidbody_constraint); + BLO_write_struct(writer, RigidBodyCon, ob->rigidbody_constraint); } if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) { - writestruct(wd, DATA, ImageUser, 1, ob->iuser); + BLO_write_struct(writer, ImageUser, ob->iuser); } - write_particlesystems(wd, &ob->particlesystem); - write_modifiers(wd, &ob->modifiers); - write_gpencil_modifiers(wd, &ob->greasepencil_modifiers); - write_shaderfxs(wd, &ob->shader_fx); + write_particlesystems(writer->wd, &ob->particlesystem); + write_modifiers(writer, &ob->modifiers); + write_gpencil_modifiers(writer, &ob->greasepencil_modifiers); + write_shaderfxs(writer->wd, &ob->shader_fx); - writelist(wd, DATA, LinkData, &ob->pc_ids); - writelist(wd, DATA, LodLevel, &ob->lodlevels); + BLO_write_struct_list(writer, LinkData, &ob->pc_ids); + BLO_write_struct_list(writer, LodLevel, &ob->lodlevels); - write_previews(wd, ob->preview); + write_previews(writer->wd, ob->preview); } } -static void write_vfont(WriteData *wd, VFont *vf, const void *id_address) +static void write_vfont(BlendWriter *writer, VFont *vf, const void *id_address) { - if (vf->id.us > 0 || wd->use_memfile) { + if (vf->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ vf->data = NULL; vf->temp_pf = NULL; /* write LibData */ - writestruct_at_address(wd, ID_VF, VFont, 1, id_address, vf); - write_iddata(wd, &vf->id); + BLO_write_id_struct(writer, VFont, id_address, &vf->id); + write_iddata(writer, &vf->id); /* direct data */ if (vf->packedfile) { PackedFile *pf = vf->packedfile; - writestruct(wd, DATA, PackedFile, 1, pf); - writedata(wd, DATA, pf->size, pf->data); + BLO_write_struct(writer, PackedFile, pf); + BLO_write_raw(writer, pf->size, pf->data); } } } -static void write_key(WriteData *wd, Key *key, const void *id_address) +static void write_key(BlendWriter *writer, Key *key, const void *id_address) { - if (key->id.us > 0 || wd->use_memfile) { + if (key->id.us > 0 || BLO_write_is_undo(writer)) { /* write LibData */ - writestruct_at_address(wd, ID_KE, Key, 1, id_address, key); - write_iddata(wd, &key->id); + BLO_write_id_struct(writer, Key, id_address, &key->id); + write_iddata(writer, &key->id); if (key->adt) { - write_animdata(wd, key->adt); + write_animdata(writer, key->adt); } /* direct data */ LISTBASE_FOREACH (KeyBlock *, kb, &key->block) { - writestruct(wd, DATA, KeyBlock, 1, kb); + BLO_write_struct(writer, KeyBlock, kb); if (kb->data) { - writedata(wd, DATA, kb->totelem * key->elemsize, kb->data); + BLO_write_raw(writer, kb->totelem * key->elemsize, kb->data); } } } } -static void write_camera(WriteData *wd, Camera *cam, const void *id_address) +static void write_camera(BlendWriter *writer, Camera *cam, const void *id_address) { - if (cam->id.us > 0 || wd->use_memfile) { + if (cam->id.us > 0 || BLO_write_is_undo(writer)) { /* write LibData */ - writestruct_at_address(wd, ID_CA, Camera, 1, id_address, cam); - write_iddata(wd, &cam->id); + BLO_write_id_struct(writer, Camera, id_address, &cam->id); + write_iddata(writer, &cam->id); if (cam->adt) { - write_animdata(wd, cam->adt); + write_animdata(writer, cam->adt); } LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) { - writestruct(wd, DATA, CameraBGImage, 1, bgpic); + BLO_write_struct(writer, CameraBGImage, bgpic); } } } -static void write_mball(WriteData *wd, MetaBall *mb, const void *id_address) +static void write_mball(BlendWriter *writer, MetaBall *mb, const void *id_address) { - if (mb->id.us > 0 || wd->use_memfile) { + if (mb->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ BLI_listbase_clear(&mb->disp); mb->editelems = NULL; @@ -2043,60 +2088,61 @@ static void write_mball(WriteData *wd, MetaBall *mb, const void *id_address) mb->batch_cache = NULL; /* write LibData */ - writestruct_at_address(wd, ID_MB, MetaBall, 1, id_address, mb); - write_iddata(wd, &mb->id); + BLO_write_id_struct(writer, MetaBall, id_address, &mb->id); + write_iddata(writer, &mb->id); /* direct data */ - writedata(wd, DATA, sizeof(void *) * mb->totcol, mb->mat); + BLO_write_pointer_array(writer, mb->totcol, mb->mat); if (mb->adt) { - write_animdata(wd, mb->adt); + write_animdata(writer, mb->adt); } LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) { - writestruct(wd, DATA, MetaElem, 1, ml); + BLO_write_struct(writer, MetaElem, ml); } } } -static void write_curve(WriteData *wd, Curve *cu, const void *id_address) +static void write_curve(BlendWriter *writer, Curve *cu, const void *id_address) { - if (cu->id.us > 0 || wd->use_memfile) { + if (cu->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ cu->editnurb = NULL; cu->editfont = NULL; cu->batch_cache = NULL; /* write LibData */ - writestruct_at_address(wd, ID_CU, Curve, 1, id_address, cu); - write_iddata(wd, &cu->id); + BLO_write_id_struct(writer, Curve, id_address, &cu->id); + write_iddata(writer, &cu->id); /* direct data */ - writedata(wd, DATA, sizeof(void *) * cu->totcol, cu->mat); + BLO_write_pointer_array(writer, cu->totcol, cu->mat); if (cu->adt) { - write_animdata(wd, cu->adt); + write_animdata(writer, cu->adt); } if (cu->vfont) { - writedata(wd, DATA, cu->len + 1, cu->str); - writestruct(wd, DATA, CharInfo, cu->len_wchar + 1, cu->strinfo); - writestruct(wd, DATA, TextBox, cu->totbox, cu->tb); + BLO_write_raw(writer, cu->len + 1, cu->str); + BLO_write_struct_array(writer, CharInfo, cu->len_wchar + 1, cu->strinfo); + BLO_write_struct_array(writer, TextBox, cu->totbox, cu->tb); } else { /* is also the order of reading */ LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { - writestruct(wd, DATA, Nurb, 1, nu); + BLO_write_struct(writer, Nurb, nu); } LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { if (nu->type == CU_BEZIER) { - writestruct(wd, DATA, BezTriple, nu->pntsu, nu->bezt); + BLO_write_struct_array(writer, BezTriple, nu->pntsu, nu->bezt); } else { - writestruct(wd, DATA, BPoint, nu->pntsu * nu->pntsv, nu->bp); + + BLO_write_struct_array(writer, BPoint, nu->pntsu * nu->pntsv, nu->bp); if (nu->knotsu) { - writedata(wd, DATA, KNOTSU(nu) * sizeof(float), nu->knotsu); + BLO_write_float_array(writer, KNOTSU(nu), nu->knotsu); } if (nu->knotsv) { - writedata(wd, DATA, KNOTSV(nu) * sizeof(float), nu->knotsv); + BLO_write_float_array(writer, KNOTSV(nu), nu->knotsv); } } } @@ -2104,60 +2150,60 @@ static void write_curve(WriteData *wd, Curve *cu, const void *id_address) } } -static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist) +static void write_dverts(BlendWriter *writer, int count, MDeformVert *dvlist) { if (dvlist) { /* Write the dvert list */ - writestruct(wd, DATA, MDeformVert, count, dvlist); + BLO_write_struct_array(writer, MDeformVert, count, dvlist); /* Write deformation data for each dvert */ for (int i = 0; i < count; i++) { if (dvlist[i].dw) { - writestruct(wd, DATA, MDeformWeight, dvlist[i].totweight, dvlist[i].dw); + BLO_write_struct_array(writer, MDeformWeight, dvlist[i].totweight, dvlist[i].dw); } } } } -static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external) +static void write_mdisps(BlendWriter *writer, int count, MDisps *mdlist, int external) { if (mdlist) { int i; - writestruct(wd, DATA, MDisps, count, mdlist); + BLO_write_struct_array(writer, MDisps, count, mdlist); for (i = 0; i < count; i++) { MDisps *md = &mdlist[i]; if (md->disps) { if (!external) { - writedata(wd, DATA, sizeof(float) * 3 * md->totdisp, md->disps); + BLO_write_float3_array(writer, md->totdisp, &md->disps[0][0]); } } if (md->hidden) { - writedata(wd, DATA, BLI_BITMAP_SIZE(md->totdisp), md->hidden); + BLO_write_raw(writer, BLI_BITMAP_SIZE(md->totdisp), md->hidden); } } } } -static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_paint_mask) +static void write_grid_paint_mask(BlendWriter *writer, int count, GridPaintMask *grid_paint_mask) { if (grid_paint_mask) { int i; - writestruct(wd, DATA, GridPaintMask, count, grid_paint_mask); + BLO_write_struct_array(writer, GridPaintMask, count, grid_paint_mask); for (i = 0; i < count; i++) { GridPaintMask *gpm = &grid_paint_mask[i]; if (gpm->data) { const int gridsize = BKE_ccg_gridsize(gpm->level); - writedata(wd, DATA, sizeof(*gpm->data) * gridsize * gridsize, gpm->data); + BLO_write_raw(writer, sizeof(*gpm->data) * gridsize * gridsize, gpm->data); } } } } -static void write_customdata(WriteData *wd, +static void write_customdata(BlendWriter *writer, ID *id, int count, CustomData *data, @@ -2167,11 +2213,11 @@ static void write_customdata(WriteData *wd, int i; /* write external customdata (not for undo) */ - if (data->external && (wd->use_memfile == false)) { + if (data->external && !BLO_write_is_undo(writer)) { CustomData_external_write(data, id, cddata_mask, count, 0); } - writestruct_at_address(wd, DATA, CustomDataLayer, data->totlayer, data->layers, layers); + writestruct_at_address(writer->wd, DATA, CustomDataLayer, data->totlayer, data->layers, layers); for (i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &layers[i]; @@ -2180,33 +2226,33 @@ static void write_customdata(WriteData *wd, if (layer->type == CD_MDEFORMVERT) { /* layer types that allocate own memory need special handling */ - write_dverts(wd, count, layer->data); + write_dverts(writer, count, layer->data); } else if (layer->type == CD_MDISPS) { - write_mdisps(wd, count, layer->data, layer->flag & CD_FLAG_EXTERNAL); + write_mdisps(writer, count, layer->data, layer->flag & CD_FLAG_EXTERNAL); } else if (layer->type == CD_PAINT_MASK) { const float *layer_data = layer->data; - writedata(wd, DATA, sizeof(*layer_data) * count, layer_data); + BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); } else if (layer->type == CD_SCULPT_FACE_SETS) { const float *layer_data = layer->data; - writedata(wd, DATA, sizeof(*layer_data) * count, layer_data); + BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); } else if (layer->type == CD_GRID_PAINT_MASK) { - write_grid_paint_mask(wd, count, layer->data); + write_grid_paint_mask(writer, count, layer->data); } else if (layer->type == CD_FACEMAP) { const int *layer_data = layer->data; - writedata(wd, DATA, sizeof(*layer_data) * count, layer_data); + BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); } else { CustomData_file_write_info(layer->type, &structname, &structnum); if (structnum) { datasize = structnum * count; - writestruct_id(wd, DATA, structname, datasize, layer->data); + BLO_write_struct_array_by_name(writer, structname, datasize, layer->data); } - else if (!wd->use_memfile) { /* Do not warn on undo. */ + else if (!BLO_write_is_undo(writer)) { /* Do not warn on undo. */ printf("%s error: layer '%s':%d - can't be written to file\n", __func__, structname, @@ -2216,13 +2262,13 @@ static void write_customdata(WriteData *wd, } if (data->external) { - writestruct(wd, DATA, CustomDataExternal, 1, data->external); + BLO_write_struct(writer, CustomDataExternal, data->external); } } -static void write_mesh(WriteData *wd, Mesh *mesh, const void *id_address) +static void write_mesh(BlendWriter *writer, Mesh *mesh, const void *id_address) { - if (mesh->id.us > 0 || wd->use_memfile) { + if (mesh->id.us > 0 || BLO_write_is_undo(writer)) { /* cache only - don't write */ mesh->mface = NULL; mesh->totface = 0; @@ -2244,23 +2290,23 @@ static void write_mesh(WriteData *wd, Mesh *mesh, const void *id_address) CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); - writestruct_at_address(wd, ID_ME, Mesh, 1, id_address, mesh); - write_iddata(wd, &mesh->id); + BLO_write_id_struct(writer, Mesh, id_address, &mesh->id); + write_iddata(writer, &mesh->id); /* direct data */ if (mesh->adt) { - write_animdata(wd, mesh->adt); + write_animdata(writer, mesh->adt); } - writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat); - writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); + BLO_write_pointer_array(writer, mesh->totcol, mesh->mat); + BLO_write_raw(writer, sizeof(MSelect) * mesh->totselect, mesh->mselect); - write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, CD_MASK_MESH.vmask); - write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, CD_MASK_MESH.emask); + write_customdata(writer, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, CD_MASK_MESH.vmask); + write_customdata(writer, &mesh->id, mesh->totedge, &mesh->edata, elayers, CD_MASK_MESH.emask); /* fdata is really a dummy - written so slots align */ - write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, CD_MASK_MESH.fmask); - write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, CD_MASK_MESH.lmask); - write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, CD_MASK_MESH.pmask); + write_customdata(writer, &mesh->id, mesh->totface, &mesh->fdata, flayers, CD_MASK_MESH.fmask); + write_customdata(writer, &mesh->id, mesh->totloop, &mesh->ldata, llayers, CD_MASK_MESH.lmask); + write_customdata(writer, &mesh->id, mesh->totpoly, &mesh->pdata, players, CD_MASK_MESH.pmask); /* free temporary data */ if (vlayers && vlayers != vlayers_buff) { @@ -2281,32 +2327,32 @@ static void write_mesh(WriteData *wd, Mesh *mesh, const void *id_address) } } -static void write_lattice(WriteData *wd, Lattice *lt, const void *id_address) +static void write_lattice(BlendWriter *writer, Lattice *lt, const void *id_address) { - if (lt->id.us > 0 || wd->use_memfile) { + if (lt->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ lt->editlatt = NULL; lt->batch_cache = NULL; /* write LibData */ - writestruct_at_address(wd, ID_LT, Lattice, 1, id_address, lt); - write_iddata(wd, <->id); + BLO_write_id_struct(writer, Lattice, id_address, <->id); + write_iddata(writer, <->id); /* write animdata */ if (lt->adt) { - write_animdata(wd, lt->adt); + write_animdata(writer, lt->adt); } /* direct data */ - writestruct(wd, DATA, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def); + BLO_write_struct_array(writer, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def); - write_dverts(wd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert); + write_dverts(writer, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert); } } -static void write_image(WriteData *wd, Image *ima, const void *id_address) +static void write_image(BlendWriter *writer, Image *ima, const void *id_address) { - if (ima->id.us > 0 || wd->use_memfile) { + if (ima->id.us > 0 || BLO_write_is_undo(writer)) { ImagePackedFile *imapf; /* Some trickery to keep forward compatibility of packed images. */ @@ -2317,135 +2363,135 @@ static void write_image(WriteData *wd, Image *ima, const void *id_address) } /* write LibData */ - writestruct_at_address(wd, ID_IM, Image, 1, id_address, ima); - write_iddata(wd, &ima->id); + BLO_write_id_struct(writer, Image, id_address, &ima->id); + write_iddata(writer, &ima->id); for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { - writestruct(wd, DATA, ImagePackedFile, 1, imapf); + BLO_write_struct(writer, ImagePackedFile, imapf); if (imapf->packedfile) { PackedFile *pf = imapf->packedfile; - writestruct(wd, DATA, PackedFile, 1, pf); - writedata(wd, DATA, pf->size, pf->data); + BLO_write_struct(writer, PackedFile, pf); + BLO_write_raw(writer, pf->size, pf->data); } } - write_previews(wd, ima->preview); + write_previews(writer->wd, ima->preview); LISTBASE_FOREACH (ImageView *, iv, &ima->views) { - writestruct(wd, DATA, ImageView, 1, iv); + BLO_write_struct(writer, ImageView, iv); } - writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format); + BLO_write_struct(writer, Stereo3dFormat, ima->stereo3d_format); - writelist(wd, DATA, ImageTile, &ima->tiles); + BLO_write_struct_list(writer, ImageTile, &ima->tiles); ima->packedfile = NULL; - writelist(wd, DATA, RenderSlot, &ima->renderslots); + BLO_write_struct_list(writer, RenderSlot, &ima->renderslots); } } -static void write_texture(WriteData *wd, Tex *tex, const void *id_address) +static void write_texture(BlendWriter *writer, Tex *tex, const void *id_address) { - if (tex->id.us > 0 || wd->use_memfile) { + if (tex->id.us > 0 || BLO_write_is_undo(writer)) { /* write LibData */ - writestruct_at_address(wd, ID_TE, Tex, 1, id_address, tex); - write_iddata(wd, &tex->id); + BLO_write_id_struct(writer, Tex, id_address, &tex->id); + write_iddata(writer, &tex->id); if (tex->adt) { - write_animdata(wd, tex->adt); + write_animdata(writer, tex->adt); } /* direct data */ if (tex->coba) { - writestruct(wd, DATA, ColorBand, 1, tex->coba); + BLO_write_struct(writer, ColorBand, tex->coba); } /* nodetree is integral part of texture, no libdata */ if (tex->nodetree) { - writestruct(wd, DATA, bNodeTree, 1, tex->nodetree); - write_nodetree_nolib(wd, tex->nodetree); + BLO_write_struct(writer, bNodeTree, tex->nodetree); + write_nodetree_nolib(writer, tex->nodetree); } - write_previews(wd, tex->preview); + write_previews(writer->wd, tex->preview); } } -static void write_material(WriteData *wd, Material *ma, const void *id_address) +static void write_material(BlendWriter *writer, Material *ma, const void *id_address) { - if (ma->id.us > 0 || wd->use_memfile) { + if (ma->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ ma->texpaintslot = NULL; BLI_listbase_clear(&ma->gpumaterial); /* write LibData */ - writestruct_at_address(wd, ID_MA, Material, 1, id_address, ma); - write_iddata(wd, &ma->id); + BLO_write_id_struct(writer, Material, id_address, &ma->id); + write_iddata(writer, &ma->id); if (ma->adt) { - write_animdata(wd, ma->adt); + write_animdata(writer, ma->adt); } /* nodetree is integral part of material, no libdata */ if (ma->nodetree) { - writestruct(wd, DATA, bNodeTree, 1, ma->nodetree); - write_nodetree_nolib(wd, ma->nodetree); + BLO_write_struct(writer, bNodeTree, ma->nodetree); + write_nodetree_nolib(writer, ma->nodetree); } - write_previews(wd, ma->preview); + write_previews(writer->wd, ma->preview); /* grease pencil settings */ if (ma->gp_style) { - writestruct(wd, DATA, MaterialGPencilStyle, 1, ma->gp_style); + BLO_write_struct(writer, MaterialGPencilStyle, ma->gp_style); } } } -static void write_world(WriteData *wd, World *wrld, const void *id_address) +static void write_world(BlendWriter *writer, World *wrld, const void *id_address) { - if (wrld->id.us > 0 || wd->use_memfile) { + if (wrld->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ BLI_listbase_clear(&wrld->gpumaterial); /* write LibData */ - writestruct_at_address(wd, ID_WO, World, 1, id_address, wrld); - write_iddata(wd, &wrld->id); + BLO_write_id_struct(writer, World, id_address, &wrld->id); + write_iddata(writer, &wrld->id); if (wrld->adt) { - write_animdata(wd, wrld->adt); + write_animdata(writer, wrld->adt); } /* nodetree is integral part of world, no libdata */ if (wrld->nodetree) { - writestruct(wd, DATA, bNodeTree, 1, wrld->nodetree); - write_nodetree_nolib(wd, wrld->nodetree); + BLO_write_struct(writer, bNodeTree, wrld->nodetree); + write_nodetree_nolib(writer, wrld->nodetree); } - write_previews(wd, wrld->preview); + write_previews(writer->wd, wrld->preview); } } -static void write_light(WriteData *wd, Light *la, const void *id_address) +static void write_light(BlendWriter *writer, Light *la, const void *id_address) { - if (la->id.us > 0 || wd->use_memfile) { + if (la->id.us > 0 || BLO_write_is_undo(writer)) { /* write LibData */ - writestruct_at_address(wd, ID_LA, Light, 1, id_address, la); - write_iddata(wd, &la->id); + BLO_write_id_struct(writer, Light, id_address, &la->id); + write_iddata(writer, &la->id); if (la->adt) { - write_animdata(wd, la->adt); + write_animdata(writer, la->adt); } if (la->curfalloff) { - write_curvemapping(wd, la->curfalloff); + write_curvemapping(writer->wd, la->curfalloff); } /* Node-tree is integral part of lights, no libdata. */ if (la->nodetree) { - writestruct(wd, DATA, bNodeTree, 1, la->nodetree); - write_nodetree_nolib(wd, la->nodetree); + BLO_write_struct(writer, bNodeTree, la->nodetree); + write_nodetree_nolib(writer, la->nodetree); } - write_previews(wd, la->preview); + write_previews(writer->wd, la->preview); } } @@ -2463,9 +2509,9 @@ static void write_collection_nolib(WriteData *wd, Collection *collection) } } -static void write_collection(WriteData *wd, Collection *collection, const void *id_address) +static void write_collection(BlendWriter *writer, Collection *collection, const void *id_address) { - if (collection->id.us > 0 || wd->use_memfile) { + if (collection->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE; collection->tag = 0; @@ -2473,10 +2519,10 @@ static void write_collection(WriteData *wd, Collection *collection, const void * BLI_listbase_clear(&collection->parents); /* write LibData */ - writestruct_at_address(wd, ID_GR, Collection, 1, id_address, collection); - write_iddata(wd, &collection->id); + BLO_write_id_struct(writer, Collection, id_address, &collection->id); + write_iddata(writer, &collection->id); - write_collection_nolib(wd, collection); + write_collection_nolib(writer->wd, collection); } } @@ -2587,82 +2633,82 @@ static void write_lightcache(WriteData *wd, LightCache *cache) writestruct(wd, DATA, LightProbeCache, cache->cube_len, cache->cube_data); } -static void write_scene(WriteData *wd, Scene *sce, const void *id_address) +static void write_scene(BlendWriter *writer, Scene *sce, const void *id_address) { - if (wd->use_memfile) { + if (BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ /* XXX This UI data should not be stored in Scene at all... */ memset(&sce->cursor, 0, sizeof(sce->cursor)); } /* write LibData */ - writestruct_at_address(wd, ID_SCE, Scene, 1, id_address, sce); - write_iddata(wd, &sce->id); + BLO_write_id_struct(writer, Scene, id_address, &sce->id); + write_iddata(writer, &sce->id); if (sce->adt) { - write_animdata(wd, sce->adt); + write_animdata(writer, sce->adt); } - write_keyingsets(wd, &sce->keyingsets); + write_keyingsets(writer->wd, &sce->keyingsets); /* direct data */ ToolSettings *tos = sce->toolsettings; - writestruct(wd, DATA, ToolSettings, 1, tos); + BLO_write_struct(writer, ToolSettings, tos); if (tos->vpaint) { - writestruct(wd, DATA, VPaint, 1, tos->vpaint); - write_paint(wd, &tos->vpaint->paint); + BLO_write_struct(writer, VPaint, tos->vpaint); + write_paint(writer->wd, &tos->vpaint->paint); } if (tos->wpaint) { - writestruct(wd, DATA, VPaint, 1, tos->wpaint); - write_paint(wd, &tos->wpaint->paint); + BLO_write_struct(writer, VPaint, tos->wpaint); + write_paint(writer->wd, &tos->wpaint->paint); } if (tos->sculpt) { - writestruct(wd, DATA, Sculpt, 1, tos->sculpt); - write_paint(wd, &tos->sculpt->paint); + BLO_write_struct(writer, Sculpt, tos->sculpt); + write_paint(writer->wd, &tos->sculpt->paint); } if (tos->uvsculpt) { - writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt); - write_paint(wd, &tos->uvsculpt->paint); + BLO_write_struct(writer, UvSculpt, tos->uvsculpt); + write_paint(writer->wd, &tos->uvsculpt->paint); } if (tos->gp_paint) { - writestruct(wd, DATA, GpPaint, 1, tos->gp_paint); - write_paint(wd, &tos->gp_paint->paint); + BLO_write_struct(writer, GpPaint, tos->gp_paint); + write_paint(writer->wd, &tos->gp_paint->paint); } if (tos->gp_vertexpaint) { - writestruct(wd, DATA, GpVertexPaint, 1, tos->gp_vertexpaint); - write_paint(wd, &tos->gp_vertexpaint->paint); + BLO_write_struct(writer, GpVertexPaint, tos->gp_vertexpaint); + write_paint(writer->wd, &tos->gp_vertexpaint->paint); } if (tos->gp_sculptpaint) { - writestruct(wd, DATA, GpSculptPaint, 1, tos->gp_sculptpaint); - write_paint(wd, &tos->gp_sculptpaint->paint); + BLO_write_struct(writer, GpSculptPaint, tos->gp_sculptpaint); + write_paint(writer->wd, &tos->gp_sculptpaint->paint); } if (tos->gp_weightpaint) { - writestruct(wd, DATA, GpWeightPaint, 1, tos->gp_weightpaint); - write_paint(wd, &tos->gp_weightpaint->paint); + BLO_write_struct(writer, GpWeightPaint, tos->gp_weightpaint); + write_paint(writer->wd, &tos->gp_weightpaint->paint); } /* write grease-pencil custom ipo curve to file */ if (tos->gp_interpolate.custom_ipo) { - write_curvemapping(wd, tos->gp_interpolate.custom_ipo); + write_curvemapping(writer->wd, tos->gp_interpolate.custom_ipo); } /* write grease-pencil multiframe falloff curve to file */ if (tos->gp_sculpt.cur_falloff) { - write_curvemapping(wd, tos->gp_sculpt.cur_falloff); + write_curvemapping(writer->wd, tos->gp_sculpt.cur_falloff); } /* write grease-pencil primitive curve to file */ if (tos->gp_sculpt.cur_primitive) { - write_curvemapping(wd, tos->gp_sculpt.cur_primitive); + write_curvemapping(writer->wd, tos->gp_sculpt.cur_primitive); } /* Write the curve profile to the file. */ if (tos->custom_bevel_profile_preset) { - write_CurveProfile(wd, tos->custom_bevel_profile_preset); + write_CurveProfile(writer->wd, tos->custom_bevel_profile_preset); } - write_paint(wd, &tos->imapaint.paint); + write_paint(writer->wd, &tos->imapaint.paint); Editing *ed = sce->ed; if (ed) { Sequence *seq; - writestruct(wd, DATA, Editing, 1, ed); + BLO_write_struct(writer, Editing, ed); /* reset write flags too */ @@ -2670,7 +2716,7 @@ static void write_scene(WriteData *wd, Scene *sce, const void *id_address) if (seq->strip) { seq->strip->done = false; } - writestruct(wd, DATA, Sequence, 1, seq); + BLO_write_struct(writer, Sequence, seq); } SEQ_END; @@ -2681,147 +2727,146 @@ static void write_scene(WriteData *wd, Scene *sce, const void *id_address) if (seq->effectdata) { switch (seq->type) { case SEQ_TYPE_COLOR: - writestruct(wd, DATA, SolidColorVars, 1, seq->effectdata); + BLO_write_struct(writer, SolidColorVars, seq->effectdata); break; case SEQ_TYPE_SPEED: - writestruct(wd, DATA, SpeedControlVars, 1, seq->effectdata); + BLO_write_struct(writer, SpeedControlVars, seq->effectdata); break; case SEQ_TYPE_WIPE: - writestruct(wd, DATA, WipeVars, 1, seq->effectdata); + BLO_write_struct(writer, WipeVars, seq->effectdata); break; case SEQ_TYPE_GLOW: - writestruct(wd, DATA, GlowVars, 1, seq->effectdata); + BLO_write_struct(writer, GlowVars, seq->effectdata); break; case SEQ_TYPE_TRANSFORM: - writestruct(wd, DATA, TransformVars, 1, seq->effectdata); + BLO_write_struct(writer, TransformVars, seq->effectdata); break; case SEQ_TYPE_GAUSSIAN_BLUR: - writestruct(wd, DATA, GaussianBlurVars, 1, seq->effectdata); + BLO_write_struct(writer, GaussianBlurVars, seq->effectdata); break; case SEQ_TYPE_TEXT: - writestruct(wd, DATA, TextVars, 1, seq->effectdata); + BLO_write_struct(writer, TextVars, seq->effectdata); break; case SEQ_TYPE_COLORMIX: - writestruct(wd, DATA, ColorMixVars, 1, seq->effectdata); + BLO_write_struct(writer, ColorMixVars, seq->effectdata); break; } } - writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format); + BLO_write_struct(writer, Stereo3dFormat, seq->stereo3d_format); Strip *strip = seq->strip; - writestruct(wd, DATA, Strip, 1, strip); + BLO_write_struct(writer, Strip, strip); if (strip->crop) { - writestruct(wd, DATA, StripCrop, 1, strip->crop); + BLO_write_struct(writer, StripCrop, strip->crop); } if (strip->transform) { - writestruct(wd, DATA, StripTransform, 1, strip->transform); + BLO_write_struct(writer, StripTransform, strip->transform); } if (strip->proxy) { - writestruct(wd, DATA, StripProxy, 1, strip->proxy); + BLO_write_struct(writer, StripProxy, strip->proxy); } if (seq->type == SEQ_TYPE_IMAGE) { - writestruct(wd, - DATA, - StripElem, - MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem), - strip->stripdata); + BLO_write_struct_array(writer, + StripElem, + MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem), + strip->stripdata); } else if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { - writestruct(wd, DATA, StripElem, 1, strip->stripdata); + BLO_write_struct(writer, StripElem, strip->stripdata); } strip->done = true; } if (seq->prop) { - IDP_WriteProperty(seq->prop, wd); + IDP_WriteProperty_new_api(seq->prop, writer); } - write_sequence_modifiers(wd, &seq->modifiers); + write_sequence_modifiers(writer->wd, &seq->modifiers); } SEQ_END; /* new; meta stack too, even when its nasty restore code */ LISTBASE_FOREACH (MetaStack *, ms, &ed->metastack) { - writestruct(wd, DATA, MetaStack, 1, ms); + BLO_write_struct(writer, MetaStack, ms); } } if (sce->r.avicodecdata) { - writestruct(wd, DATA, AviCodecData, 1, sce->r.avicodecdata); + BLO_write_struct(writer, AviCodecData, sce->r.avicodecdata); if (sce->r.avicodecdata->lpFormat) { - writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat); + BLO_write_raw(writer, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat); } if (sce->r.avicodecdata->lpParms) { - writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms); + BLO_write_raw(writer, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms); } } if (sce->r.ffcodecdata.properties) { - IDP_WriteProperty(sce->r.ffcodecdata.properties, wd); + IDP_WriteProperty_new_api(sce->r.ffcodecdata.properties, writer); } /* writing dynamic list of TimeMarkers to the blend file */ LISTBASE_FOREACH (TimeMarker *, marker, &sce->markers) { - writestruct(wd, DATA, TimeMarker, 1, marker); + BLO_write_struct(writer, TimeMarker, marker); } /* writing dynamic list of TransformOrientations to the blend file */ LISTBASE_FOREACH (TransformOrientation *, ts, &sce->transform_spaces) { - writestruct(wd, DATA, TransformOrientation, 1, ts); + BLO_write_struct(writer, TransformOrientation, ts); } /* writing MultiView to the blend file */ LISTBASE_FOREACH (SceneRenderView *, srv, &sce->r.views) { - writestruct(wd, DATA, SceneRenderView, 1, srv); + BLO_write_struct(writer, SceneRenderView, srv); } if (sce->nodetree) { - writestruct(wd, DATA, bNodeTree, 1, sce->nodetree); - write_nodetree_nolib(wd, sce->nodetree); + BLO_write_struct(writer, bNodeTree, sce->nodetree); + write_nodetree_nolib(writer, sce->nodetree); } - write_view_settings(wd, &sce->view_settings); + write_view_settings(writer->wd, &sce->view_settings); /* writing RigidBodyWorld data to the blend file */ if (sce->rigidbody_world) { /* Set deprecated pointers to prevent crashes of older Blenders */ sce->rigidbody_world->pointcache = sce->rigidbody_world->shared->pointcache; sce->rigidbody_world->ptcaches = sce->rigidbody_world->shared->ptcaches; - writestruct(wd, DATA, RigidBodyWorld, 1, sce->rigidbody_world); + BLO_write_struct(writer, RigidBodyWorld, sce->rigidbody_world); - writestruct(wd, DATA, RigidBodyWorld_Shared, 1, sce->rigidbody_world->shared); - writestruct(wd, DATA, EffectorWeights, 1, sce->rigidbody_world->effector_weights); - write_pointcaches(wd, &(sce->rigidbody_world->shared->ptcaches)); + BLO_write_struct(writer, RigidBodyWorld_Shared, sce->rigidbody_world->shared); + BLO_write_struct(writer, EffectorWeights, sce->rigidbody_world->effector_weights); + write_pointcaches(writer->wd, &(sce->rigidbody_world->shared->ptcaches)); } - write_previews(wd, sce->preview); - write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve); + write_previews(writer->wd, sce->preview); + write_curvemapping_curves(writer->wd, &sce->r.mblur_shutter_curve); LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) { - write_view_layer(wd, view_layer); + write_view_layer(writer->wd, view_layer); } if (sce->master_collection) { - writestruct(wd, DATA, Collection, 1, sce->master_collection); - write_collection_nolib(wd, sce->master_collection); + BLO_write_struct(writer, Collection, sce->master_collection); + write_collection_nolib(writer->wd, sce->master_collection); } /* Eevee Lightcache */ - if (sce->eevee.light_cache_data && !wd->use_memfile) { - writestruct(wd, DATA, LightCache, 1, sce->eevee.light_cache_data); - write_lightcache(wd, sce->eevee.light_cache_data); + if (sce->eevee.light_cache_data && !BLO_write_is_undo(writer)) { + BLO_write_struct(writer, LightCache, sce->eevee.light_cache_data); + write_lightcache(writer->wd, sce->eevee.light_cache_data); } - write_view3dshading(wd, &sce->display.shading); + write_view3dshading(writer->wd, &sce->display.shading); /* Freed on doversion. */ BLI_assert(sce->layer_properties == NULL); } -static void write_gpencil(WriteData *wd, bGPdata *gpd, const void *id_address) +static void write_gpencil(BlendWriter *writer, bGPdata *gpd, const void *id_address) { - if (gpd->id.us > 0 || wd->use_memfile) { + if (gpd->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed data-blocks. */ /* XXX not sure why the whole run-time data is not cleared in reading code, * for now mimicking it here. */ @@ -2831,29 +2876,29 @@ static void write_gpencil(WriteData *wd, bGPdata *gpd, const void *id_address) gpd->runtime.tot_cp_points = 0; /* write gpd data block to file */ - writestruct_at_address(wd, ID_GD, bGPdata, 1, id_address, gpd); - write_iddata(wd, &gpd->id); + BLO_write_id_struct(writer, bGPdata, id_address, &gpd->id); + write_iddata(writer, &gpd->id); if (gpd->adt) { - write_animdata(wd, gpd->adt); + write_animdata(writer, gpd->adt); } - writedata(wd, DATA, sizeof(void *) * gpd->totcol, gpd->mat); + BLO_write_pointer_array(writer, gpd->totcol, gpd->mat); /* write grease-pencil layers to file */ - writelist(wd, DATA, bGPDlayer, &gpd->layers); + BLO_write_struct_list(writer, bGPDlayer, &gpd->layers); LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* Write mask list. */ - writelist(wd, DATA, bGPDlayer_Mask, &gpl->mask_layers); + BLO_write_struct_list(writer, bGPDlayer_Mask, &gpl->mask_layers); /* write this layer's frames to file */ - writelist(wd, DATA, bGPDframe, &gpl->frames); + BLO_write_struct_list(writer, bGPDframe, &gpl->frames); LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* write strokes */ - writelist(wd, DATA, bGPDstroke, &gpf->strokes); + BLO_write_struct_list(writer, bGPDstroke, &gpf->strokes); LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { - writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points); - writestruct(wd, DATA, bGPDtriangle, gps->tot_triangles, gps->triangles); - write_dverts(wd, gps->totpoints, gps->dvert); + BLO_write_struct_array(writer, bGPDspoint, gps->totpoints, gps->points); + BLO_write_struct_array(writer, bGPDtriangle, gps->tot_triangles, gps->triangles); + write_dverts(writer, gps->totpoints, gps->dvert); } } } @@ -3105,11 +3150,11 @@ static void write_area_map(WriteData *wd, ScrAreaMap *area_map) } } -static void write_windowmanager(WriteData *wd, wmWindowManager *wm, const void *id_address) +static void write_windowmanager(BlendWriter *writer, wmWindowManager *wm, const void *id_address) { - writestruct_at_address(wd, ID_WM, wmWindowManager, 1, id_address, wm); - write_iddata(wd, &wm->id); - write_wm_xr_data(wd, &wm->xr); + BLO_write_id_struct(writer, wmWindowManager, id_address, &wm->id); + write_iddata(writer, &wm->id); + write_wm_xr_data(writer->wd, &wm->xr); LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { #ifndef WITH_GLOBAL_AREA_WRITING @@ -3121,12 +3166,12 @@ static void write_windowmanager(WriteData *wd, wmWindowManager *wm, const void * /* update deprecated screen member (for so loading in 2.7x uses the correct screen) */ win->screen = BKE_workspace_active_screen_get(win->workspace_hook); - writestruct(wd, DATA, wmWindow, 1, win); - writestruct(wd, DATA, WorkSpaceInstanceHook, 1, win->workspace_hook); - writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format); + BLO_write_struct(writer, wmWindow, win); + BLO_write_struct(writer, WorkSpaceInstanceHook, win->workspace_hook); + BLO_write_struct(writer, Stereo3dFormat, win->stereo3d_format); #ifdef WITH_GLOBAL_AREA_WRITING - write_area_map(wd, &win->global_areas); + write_area_map(writer->wd, &win->global_areas); #else win->global_areas = global_areas; #endif @@ -3136,19 +3181,19 @@ static void write_windowmanager(WriteData *wd, wmWindowManager *wm, const void * } } -static void write_screen(WriteData *wd, bScreen *screen, const void *id_address) +static void write_screen(BlendWriter *writer, bScreen *screen, const void *id_address) { /* Screens are reference counted, only saved if used by a workspace. */ - if (screen->id.us > 0 || wd->use_memfile) { + if (screen->id.us > 0 || BLO_write_is_undo(writer)) { /* write LibData */ /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */ - writestruct_at_address(wd, ID_SCRN, bScreen, 1, id_address, screen); - write_iddata(wd, &screen->id); + writestruct_at_address(writer->wd, ID_SCRN, bScreen, 1, id_address, screen); + write_iddata(writer, &screen->id); - write_previews(wd, screen->preview); + write_previews(writer->wd, screen->preview); /* direct data */ - write_area_map(wd, AREAMAP_FROM_SCREEN(screen)); + write_area_map(writer->wd, AREAMAP_FROM_SCREEN(screen)); } } @@ -3172,9 +3217,9 @@ static void write_bone(WriteData *wd, Bone *bone) } } -static void write_armature(WriteData *wd, bArmature *arm, const void *id_address) +static void write_armature(BlendWriter *writer, bArmature *arm, const void *id_address) { - if (arm->id.us > 0 || wd->use_memfile) { + if (arm->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ arm->bonehash = NULL; arm->edbo = NULL; @@ -3182,21 +3227,21 @@ static void write_armature(WriteData *wd, bArmature *arm, const void *id_address arm->needs_flush_to_id = 0; arm->act_edbone = NULL; - writestruct_at_address(wd, ID_AR, bArmature, 1, id_address, arm); - write_iddata(wd, &arm->id); + BLO_write_id_struct(writer, bArmature, id_address, &arm->id); + write_iddata(writer, &arm->id); if (arm->adt) { - write_animdata(wd, arm->adt); + write_animdata(writer, arm->adt); } /* Direct data */ LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) { - write_bone(wd, bone); + write_bone(writer->wd, bone); } } } -static void write_text(WriteData *wd, Text *text, const void *id_address) +static void write_text(BlendWriter *writer, Text *text, const void *id_address) { /* Note: we are clearing local temp data here, *not* the flag in the actual 'real' ID. */ if ((text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) { @@ -3207,41 +3252,41 @@ static void write_text(WriteData *wd, Text *text, const void *id_address) text->compiled = NULL; /* write LibData */ - writestruct_at_address(wd, ID_TXT, Text, 1, id_address, text); - write_iddata(wd, &text->id); + BLO_write_id_struct(writer, Text, id_address, &text->id); + write_iddata(writer, &text->id); if (text->name) { - writedata(wd, DATA, strlen(text->name) + 1, text->name); + BLO_write_string(writer, text->name); } if (!(text->flags & TXT_ISEXT)) { /* now write the text data, in two steps for optimization in the readfunction */ LISTBASE_FOREACH (TextLine *, tmp, &text->lines) { - writestruct(wd, DATA, TextLine, 1, tmp); + BLO_write_struct(writer, TextLine, tmp); } LISTBASE_FOREACH (TextLine *, tmp, &text->lines) { - writedata(wd, DATA, tmp->len + 1, tmp->line); + BLO_write_raw(writer, tmp->len + 1, tmp->line); } } } -static void write_speaker(WriteData *wd, Speaker *spk, const void *id_address) +static void write_speaker(BlendWriter *writer, Speaker *spk, const void *id_address) { - if (spk->id.us > 0 || wd->use_memfile) { + if (spk->id.us > 0 || BLO_write_is_undo(writer)) { /* write LibData */ - writestruct_at_address(wd, ID_SPK, Speaker, 1, id_address, spk); - write_iddata(wd, &spk->id); + BLO_write_id_struct(writer, Speaker, id_address, &spk->id); + write_iddata(writer, &spk->id); if (spk->adt) { - write_animdata(wd, spk->adt); + write_animdata(writer, spk->adt); } } } -static void write_sound(WriteData *wd, bSound *sound, const void *id_address) +static void write_sound(BlendWriter *writer, bSound *sound, const void *id_address) { - if (sound->id.us > 0 || wd->use_memfile) { + if (sound->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ sound->tags = 0; sound->handle = NULL; @@ -3249,33 +3294,33 @@ static void write_sound(WriteData *wd, bSound *sound, const void *id_address) sound->spinlock = NULL; /* write LibData */ - writestruct_at_address(wd, ID_SO, bSound, 1, id_address, sound); - write_iddata(wd, &sound->id); + BLO_write_id_struct(writer, bSound, id_address, &sound->id); + write_iddata(writer, &sound->id); if (sound->packedfile) { PackedFile *pf = sound->packedfile; - writestruct(wd, DATA, PackedFile, 1, pf); - writedata(wd, DATA, pf->size, pf->data); + BLO_write_struct(writer, PackedFile, pf); + BLO_write_raw(writer, pf->size, pf->data); } } } -static void write_probe(WriteData *wd, LightProbe *prb, const void *id_address) +static void write_probe(BlendWriter *writer, LightProbe *prb, const void *id_address) { - if (prb->id.us > 0 || wd->use_memfile) { + if (prb->id.us > 0 || BLO_write_is_undo(writer)) { /* write LibData */ - writestruct_at_address(wd, ID_LP, LightProbe, 1, id_address, prb); - write_iddata(wd, &prb->id); + BLO_write_id_struct(writer, LightProbe, id_address, &prb->id); + write_iddata(writer, &prb->id); if (prb->adt) { - write_animdata(wd, prb->adt); + write_animdata(writer, prb->adt); } } } -static void write_nodetree(WriteData *wd, bNodeTree *ntree, const void *id_address) +static void write_nodetree(BlendWriter *writer, bNodeTree *ntree, const void *id_address) { - if (ntree->id.us > 0 || wd->use_memfile) { + if (ntree->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ ntree->init = 0; /* to set callbacks and force setting types */ ntree->is_updating = false; @@ -3284,82 +3329,82 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree, const void *id_addre ntree->progress = NULL; ntree->execdata = NULL; - writestruct_at_address(wd, ID_NT, bNodeTree, 1, id_address, ntree); + BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id); /* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot * be linked, etc., so we write actual id data here only, for 'real' ID trees. */ - write_iddata(wd, &ntree->id); + write_iddata(writer, &ntree->id); - write_nodetree_nolib(wd, ntree); + write_nodetree_nolib(writer, ntree); } } -static void write_brush(WriteData *wd, Brush *brush, const void *id_address) +static void write_brush(BlendWriter *writer, Brush *brush, const void *id_address) { - if (brush->id.us > 0 || wd->use_memfile) { - writestruct_at_address(wd, ID_BR, Brush, 1, id_address, brush); - write_iddata(wd, &brush->id); + if (brush->id.us > 0 || BLO_write_is_undo(writer)) { + BLO_write_id_struct(writer, Brush, id_address, &brush->id); + write_iddata(writer, &brush->id); if (brush->curve) { - write_curvemapping(wd, brush->curve); + write_curvemapping(writer->wd, brush->curve); } if (brush->gpencil_settings) { - writestruct(wd, DATA, BrushGpencilSettings, 1, brush->gpencil_settings); + BLO_write_struct(writer, BrushGpencilSettings, brush->gpencil_settings); if (brush->gpencil_settings->curve_sensitivity) { - write_curvemapping(wd, brush->gpencil_settings->curve_sensitivity); + write_curvemapping(writer->wd, brush->gpencil_settings->curve_sensitivity); } if (brush->gpencil_settings->curve_strength) { - write_curvemapping(wd, brush->gpencil_settings->curve_strength); + write_curvemapping(writer->wd, brush->gpencil_settings->curve_strength); } if (brush->gpencil_settings->curve_jitter) { - write_curvemapping(wd, brush->gpencil_settings->curve_jitter); + write_curvemapping(writer->wd, brush->gpencil_settings->curve_jitter); } if (brush->gpencil_settings->curve_rand_pressure) { - write_curvemapping(wd, brush->gpencil_settings->curve_rand_pressure); + write_curvemapping(writer->wd, brush->gpencil_settings->curve_rand_pressure); } if (brush->gpencil_settings->curve_rand_strength) { - write_curvemapping(wd, brush->gpencil_settings->curve_rand_strength); + write_curvemapping(writer->wd, brush->gpencil_settings->curve_rand_strength); } if (brush->gpencil_settings->curve_rand_uv) { - write_curvemapping(wd, brush->gpencil_settings->curve_rand_uv); + write_curvemapping(writer->wd, brush->gpencil_settings->curve_rand_uv); } if (brush->gpencil_settings->curve_rand_hue) { - write_curvemapping(wd, brush->gpencil_settings->curve_rand_hue); + write_curvemapping(writer->wd, brush->gpencil_settings->curve_rand_hue); } if (brush->gpencil_settings->curve_rand_saturation) { - write_curvemapping(wd, brush->gpencil_settings->curve_rand_saturation); + write_curvemapping(writer->wd, brush->gpencil_settings->curve_rand_saturation); } if (brush->gpencil_settings->curve_rand_value) { - write_curvemapping(wd, brush->gpencil_settings->curve_rand_value); + write_curvemapping(writer->wd, brush->gpencil_settings->curve_rand_value); } } if (brush->gradient) { - writestruct(wd, DATA, ColorBand, 1, brush->gradient); + BLO_write_struct(writer, ColorBand, brush->gradient); } } } -static void write_palette(WriteData *wd, Palette *palette, const void *id_address) +static void write_palette(BlendWriter *writer, Palette *palette, const void *id_address) { - if (palette->id.us > 0 || wd->use_memfile) { + if (palette->id.us > 0 || BLO_write_is_undo(writer)) { PaletteColor *color; - writestruct_at_address(wd, ID_PAL, Palette, 1, id_address, palette); - write_iddata(wd, &palette->id); + BLO_write_id_struct(writer, Palette, id_address, &palette->id); + write_iddata(writer, &palette->id); for (color = palette->colors.first; color; color = color->next) { - writestruct(wd, DATA, PaletteColor, 1, color); + BLO_write_struct(writer, PaletteColor, color); } } } -static void write_paintcurve(WriteData *wd, PaintCurve *pc, const void *id_address) +static void write_paintcurve(BlendWriter *writer, PaintCurve *pc, const void *id_address) { - if (pc->id.us > 0 || wd->use_memfile) { - writestruct_at_address(wd, ID_PC, PaintCurve, 1, id_address, pc); - write_iddata(wd, &pc->id); + if (pc->id.us > 0 || BLO_write_is_undo(writer)) { + BLO_write_id_struct(writer, PaintCurve, id_address, &pc->id); + write_iddata(writer, &pc->id); - writestruct(wd, DATA, PaintCurvePoint, pc->tot_points, pc->points); + BLO_write_struct_array(writer, PaintCurvePoint, pc->tot_points, pc->points); } } @@ -3402,9 +3447,9 @@ static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction } } -static void write_movieclip(WriteData *wd, MovieClip *clip, const void *id_address) +static void write_movieclip(BlendWriter *writer, MovieClip *clip, const void *id_address) { - if (clip->id.us > 0 || wd->use_memfile) { + if (clip->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ clip->anim = NULL; clip->tracking_context = NULL; @@ -3413,47 +3458,47 @@ static void write_movieclip(WriteData *wd, MovieClip *clip, const void *id_addre MovieTracking *tracking = &clip->tracking; MovieTrackingObject *object; - writestruct_at_address(wd, ID_MC, MovieClip, 1, id_address, clip); - write_iddata(wd, &clip->id); + BLO_write_id_struct(writer, MovieClip, id_address, &clip->id); + write_iddata(writer, &clip->id); if (clip->adt) { - write_animdata(wd, clip->adt); + write_animdata(writer, clip->adt); } - write_movieTracks(wd, &tracking->tracks); - write_moviePlaneTracks(wd, &tracking->plane_tracks); - write_movieReconstruction(wd, &tracking->reconstruction); + write_movieTracks(writer->wd, &tracking->tracks); + write_moviePlaneTracks(writer->wd, &tracking->plane_tracks); + write_movieReconstruction(writer->wd, &tracking->reconstruction); object = tracking->objects.first; while (object) { - writestruct(wd, DATA, MovieTrackingObject, 1, object); + BLO_write_struct(writer, MovieTrackingObject, object); - write_movieTracks(wd, &object->tracks); - write_moviePlaneTracks(wd, &object->plane_tracks); - write_movieReconstruction(wd, &object->reconstruction); + write_movieTracks(writer->wd, &object->tracks); + write_moviePlaneTracks(writer->wd, &object->plane_tracks); + write_movieReconstruction(writer->wd, &object->reconstruction); object = object->next; } } } -static void write_mask(WriteData *wd, Mask *mask, const void *id_address) +static void write_mask(BlendWriter *writer, Mask *mask, const void *id_address) { - if (mask->id.us > 0 || wd->use_memfile) { + if (mask->id.us > 0 || BLO_write_is_undo(writer)) { MaskLayer *masklay; - writestruct_at_address(wd, ID_MSK, Mask, 1, id_address, mask); - write_iddata(wd, &mask->id); + BLO_write_id_struct(writer, Mask, id_address, &mask->id); + write_iddata(writer, &mask->id); if (mask->adt) { - write_animdata(wd, mask->adt); + write_animdata(writer, mask->adt); } for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; MaskLayerShape *masklay_shape; - writestruct(wd, DATA, MaskLayer, 1, masklay); + BLO_write_struct(writer, MaskLayer, masklay); for (spline = masklay->splines.first; spline; spline = spline->next) { int i; @@ -3461,8 +3506,8 @@ static void write_mask(WriteData *wd, Mask *mask, const void *id_address) void *points_deform = spline->points_deform; spline->points_deform = NULL; - writestruct(wd, DATA, MaskSpline, 1, spline); - writestruct(wd, DATA, MaskSplinePoint, spline->tot_point, spline->points); + BLO_write_struct(writer, MaskSpline, spline); + BLO_write_struct_array(writer, MaskSplinePoint, spline->tot_point, spline->points); spline->points_deform = points_deform; @@ -3470,18 +3515,16 @@ static void write_mask(WriteData *wd, Mask *mask, const void *id_address) MaskSplinePoint *point = &spline->points[i]; if (point->tot_uw) { - writestruct(wd, DATA, MaskSplinePointUW, point->tot_uw, point->uw); + BLO_write_struct_array(writer, MaskSplinePointUW, point->tot_uw, point->uw); } } } for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) { - writestruct(wd, DATA, MaskLayerShape, 1, masklay_shape); - writedata(wd, - DATA, - masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, - masklay_shape->data); + BLO_write_struct(writer, MaskLayerShape, masklay_shape); + BLO_write_float_array( + writer, masklay_shape->tot_vert * MASK_OBJECT_SHAPE_ELEM_SIZE, masklay_shape->data); } } } @@ -3744,84 +3787,84 @@ static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifier } } -static void write_linestyle(WriteData *wd, FreestyleLineStyle *linestyle, const void *id_address) +static void write_linestyle(BlendWriter *writer, + FreestyleLineStyle *linestyle, + const void *id_address) { - if (linestyle->id.us > 0 || wd->use_memfile) { - writestruct_at_address(wd, ID_LS, FreestyleLineStyle, 1, id_address, linestyle); - write_iddata(wd, &linestyle->id); + if (linestyle->id.us > 0 || BLO_write_is_undo(writer)) { + BLO_write_id_struct(writer, FreestyleLineStyle, id_address, &linestyle->id); + write_iddata(writer, &linestyle->id); if (linestyle->adt) { - write_animdata(wd, linestyle->adt); + write_animdata(writer, linestyle->adt); } - write_linestyle_color_modifiers(wd, &linestyle->color_modifiers); - write_linestyle_alpha_modifiers(wd, &linestyle->alpha_modifiers); - write_linestyle_thickness_modifiers(wd, &linestyle->thickness_modifiers); - write_linestyle_geometry_modifiers(wd, &linestyle->geometry_modifiers); + write_linestyle_color_modifiers(writer->wd, &linestyle->color_modifiers); + write_linestyle_alpha_modifiers(writer->wd, &linestyle->alpha_modifiers); + write_linestyle_thickness_modifiers(writer->wd, &linestyle->thickness_modifiers); + write_linestyle_geometry_modifiers(writer->wd, &linestyle->geometry_modifiers); for (int a = 0; a < MAX_MTEX; a++) { if (linestyle->mtex[a]) { - writestruct(wd, DATA, MTex, 1, linestyle->mtex[a]); + BLO_write_struct(writer, MTex, linestyle->mtex[a]); } } if (linestyle->nodetree) { - writestruct(wd, DATA, bNodeTree, 1, linestyle->nodetree); - write_nodetree_nolib(wd, linestyle->nodetree); + BLO_write_struct(writer, bNodeTree, linestyle->nodetree); + write_nodetree_nolib(writer, linestyle->nodetree); } } } -static void write_cachefile(WriteData *wd, CacheFile *cache_file, const void *id_address) +static void write_cachefile(BlendWriter *writer, CacheFile *cache_file, const void *id_address) { - if (cache_file->id.us > 0 || wd->use_memfile) { + if (cache_file->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ BLI_listbase_clear(&cache_file->object_paths); cache_file->handle = NULL; memset(cache_file->handle_filepath, 0, sizeof(cache_file->handle_filepath)); cache_file->handle_readers = NULL; - writestruct_at_address(wd, ID_CF, CacheFile, 1, id_address, cache_file); + BLO_write_id_struct(writer, CacheFile, id_address, &cache_file->id); if (cache_file->adt) { - write_animdata(wd, cache_file->adt); + write_animdata(writer, cache_file->adt); } } } -static void write_workspace(WriteData *wd, WorkSpace *workspace, const void *id_address) +static void write_workspace(BlendWriter *writer, WorkSpace *workspace, const void *id_address) { - ListBase *layouts = BKE_workspace_layouts_get(workspace); - - writestruct_at_address(wd, ID_WS, WorkSpace, 1, id_address, workspace); - write_iddata(wd, &workspace->id); - writelist(wd, DATA, WorkSpaceLayout, layouts); - writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations); - writelist(wd, DATA, wmOwnerID, &workspace->owner_ids); - writelist(wd, DATA, bToolRef, &workspace->tools); + BLO_write_id_struct(writer, WorkSpace, id_address, &workspace->id); + write_iddata(writer, &workspace->id); + BLO_write_struct_list(writer, WorkSpaceLayout, &workspace->layouts); + BLO_write_struct_list(writer, WorkSpaceDataRelation, &workspace->hook_layout_relations); + BLO_write_struct_list(writer, wmOwnerID, &workspace->owner_ids); + BLO_write_struct_list(writer, bToolRef, &workspace->tools); LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) { if (tref->properties) { - IDP_WriteProperty(tref->properties, wd); + IDP_WriteProperty_new_api(tref->properties, writer); } } } -static void write_hair(WriteData *wd, Hair *hair, const void *id_address) +static void write_hair(BlendWriter *writer, Hair *hair, const void *id_address) { - if (hair->id.us > 0 || wd->use_memfile) { + if (hair->id.us > 0 || BLO_write_is_undo(writer)) { CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *clayers = NULL, clayers_buff[CD_TEMP_CHUNK_SIZE]; CustomData_file_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); CustomData_file_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff)); /* Write LibData */ - writestruct_at_address(wd, ID_HA, Hair, 1, id_address, hair); - write_iddata(wd, &hair->id); + BLO_write_id_struct(writer, Hair, id_address, &hair->id); + write_iddata(writer, &hair->id); /* Direct data */ - write_customdata(wd, &hair->id, hair->totpoint, &hair->pdata, players, CD_MASK_ALL); - write_customdata(wd, &hair->id, hair->totcurve, &hair->cdata, clayers, CD_MASK_ALL); - writedata(wd, DATA, sizeof(void *) * hair->totcol, hair->mat); + write_customdata(writer, &hair->id, hair->totpoint, &hair->pdata, players, CD_MASK_ALL); + write_customdata(writer, &hair->id, hair->totcurve, &hair->cdata, clayers, CD_MASK_ALL); + BLO_write_pointer_array(writer, hair->totcol, hair->mat); if (hair->adt) { - write_animdata(wd, hair->adt); + write_animdata(writer, hair->adt); } /* Remove temporary data. */ @@ -3834,23 +3877,23 @@ static void write_hair(WriteData *wd, Hair *hair, const void *id_address) } } -static void write_pointcloud(WriteData *wd, PointCloud *pointcloud, const void *id_address) +static void write_pointcloud(BlendWriter *writer, PointCloud *pointcloud, const void *id_address) { - if (pointcloud->id.us > 0 || wd->use_memfile) { + if (pointcloud->id.us > 0 || BLO_write_is_undo(writer)) { CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; CustomData_file_write_prepare( &pointcloud->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); /* Write LibData */ - writestruct_at_address(wd, ID_PT, PointCloud, 1, id_address, pointcloud); - write_iddata(wd, &pointcloud->id); + BLO_write_id_struct(writer, PointCloud, id_address, &pointcloud->id); + write_iddata(writer, &pointcloud->id); /* Direct data */ write_customdata( - wd, &pointcloud->id, pointcloud->totpoint, &pointcloud->pdata, players, CD_MASK_ALL); - writedata(wd, DATA, sizeof(void *) * pointcloud->totcol, pointcloud->mat); + writer, &pointcloud->id, pointcloud->totpoint, &pointcloud->pdata, players, CD_MASK_ALL); + BLO_write_pointer_array(writer, pointcloud->totcol, pointcloud->mat); if (pointcloud->adt) { - write_animdata(wd, pointcloud->adt); + write_animdata(writer, pointcloud->adt); } /* Remove temporary data. */ @@ -3860,44 +3903,44 @@ static void write_pointcloud(WriteData *wd, PointCloud *pointcloud, const void * } } -static void write_volume(WriteData *wd, Volume *volume, const void *id_address) +static void write_volume(BlendWriter *writer, Volume *volume, const void *id_address) { - if (volume->id.us > 0 || wd->use_memfile) { + if (volume->id.us > 0 || BLO_write_is_undo(writer)) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ volume->runtime.grids = 0; /* write LibData */ - writestruct_at_address(wd, ID_VO, Volume, 1, id_address, volume); - write_iddata(wd, &volume->id); + BLO_write_id_struct(writer, Volume, id_address, &volume->id); + write_iddata(writer, &volume->id); /* direct data */ - writedata(wd, DATA, sizeof(void *) * volume->totcol, volume->mat); + BLO_write_pointer_array(writer, volume->totcol, volume->mat); if (volume->adt) { - write_animdata(wd, volume->adt); + write_animdata(writer, volume->adt); } if (volume->packedfile) { PackedFile *pf = volume->packedfile; - writestruct(wd, DATA, PackedFile, 1, pf); - writedata(wd, DATA, pf->size, pf->data); + BLO_write_struct(writer, PackedFile, pf); + BLO_write_raw(writer, pf->size, pf->data); } } } -static void write_simulation(WriteData *wd, Simulation *simulation) +static void write_simulation(BlendWriter *writer, Simulation *simulation, const void *id_address) { - if (simulation->id.us > 0 || wd->use_memfile) { - writestruct(wd, ID_SIM, Simulation, 1, simulation); - write_iddata(wd, &simulation->id); + if (simulation->id.us > 0 || BLO_write_is_undo(writer)) { + BLO_write_id_struct(writer, Simulation, id_address, &simulation->id); + write_iddata(writer, &simulation->id); if (simulation->adt) { - write_animdata(wd, simulation->adt); + write_animdata(writer, simulation->adt); } /* nodetree is integral part of simulation, no libdata */ if (simulation->nodetree) { - writestruct(wd, DATA, bNodeTree, 1, simulation->nodetree); - write_nodetree_nolib(wd, simulation->nodetree); + BLO_write_struct(writer, bNodeTree, simulation->nodetree); + write_nodetree_nolib(writer, simulation->nodetree); } } } @@ -3917,6 +3960,11 @@ static void write_libraries(WriteData *wd, Main *main) if (main->curlib && main->curlib->packedfile) { found_one = true; } + else if (wd->use_memfile) { + /* When writing undo step we always write all existing libraries, makes reading undo step + * much easier when dealing with purely indirectly used libraries. */ + found_one = true; + } else { found_one = false; while (!found_one && tot--) { @@ -3938,8 +3986,9 @@ static void write_libraries(WriteData *wd, Main *main) if (found_one) { /* Not overridable. */ + BlendWriter writer = {wd}; writestruct(wd, ID_LI, Library, 1, main->curlib); - write_iddata(wd, &main->curlib->id); + write_iddata(&writer, &main->curlib->id); if (main->curlib->packedfile) { PackedFile *pf = main->curlib->packedfile; @@ -4004,12 +4053,12 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) fg.globalf = G.f; BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename)); - sprintf(subvstr, "%4d", BLENDER_SUBVERSION); + sprintf(subvstr, "%4d", BLENDER_FILE_SUBVERSION); memcpy(fg.subvstr, subvstr, 4); - fg.subversion = BLENDER_SUBVERSION; - fg.minversion = BLENDER_MINVERSION; - fg.minsubversion = BLENDER_MINSUBVERSION; + fg.subversion = BLENDER_FILE_SUBVERSION; + fg.minversion = BLENDER_FILE_MIN_VERSION; + fg.minsubversion = BLENDER_FILE_MIN_SUBVERSION; #ifdef WITH_BUILDINFO { extern unsigned long build_commit_timestamp; @@ -4063,7 +4112,7 @@ static bool write_file_handle(Main *mainvar, "BLENDER%c%c%.3d", (sizeof(void *) == 8) ? '-' : '_', (ENDIAN_ORDER == B_ENDIAN) ? 'V' : 'v', - BLENDER_VERSION); + BLENDER_FILE_VERSION); mywrite(wd, buf, 12); @@ -4135,124 +4184,133 @@ static bool write_file_handle(Main *mainvar, } } + mywrite_id_begin(wd, id); + memcpy(id_buffer, id, idtype_struct_size); ((ID *)id_buffer)->tag = 0; + /* Those listbase data change every time we add/remove an ID, and also often when renaming + * one (due to re-sorting). This avoids generating a lot of false 'is changed' detections + * between undo steps. */ + ((ID *)id_buffer)->prev = NULL; + ((ID *)id_buffer)->next = NULL; + + BlendWriter writer = {wd}; switch ((ID_Type)GS(id->name)) { case ID_WM: - write_windowmanager(wd, (wmWindowManager *)id_buffer, id); + write_windowmanager(&writer, (wmWindowManager *)id_buffer, id); break; case ID_WS: - write_workspace(wd, (WorkSpace *)id_buffer, id); + write_workspace(&writer, (WorkSpace *)id_buffer, id); break; case ID_SCR: - write_screen(wd, (bScreen *)id_buffer, id); + write_screen(&writer, (bScreen *)id_buffer, id); break; case ID_MC: - write_movieclip(wd, (MovieClip *)id_buffer, id); + write_movieclip(&writer, (MovieClip *)id_buffer, id); break; case ID_MSK: - write_mask(wd, (Mask *)id_buffer, id); + write_mask(&writer, (Mask *)id_buffer, id); break; case ID_SCE: - write_scene(wd, (Scene *)id_buffer, id); + write_scene(&writer, (Scene *)id_buffer, id); break; case ID_CU: - write_curve(wd, (Curve *)id_buffer, id); + write_curve(&writer, (Curve *)id_buffer, id); break; case ID_MB: - write_mball(wd, (MetaBall *)id_buffer, id); + write_mball(&writer, (MetaBall *)id_buffer, id); break; case ID_IM: - write_image(wd, (Image *)id_buffer, id); + write_image(&writer, (Image *)id_buffer, id); break; case ID_CA: - write_camera(wd, (Camera *)id_buffer, id); + write_camera(&writer, (Camera *)id_buffer, id); break; case ID_LA: - write_light(wd, (Light *)id_buffer, id); + write_light(&writer, (Light *)id_buffer, id); break; case ID_LT: - write_lattice(wd, (Lattice *)id_buffer, id); + write_lattice(&writer, (Lattice *)id_buffer, id); break; case ID_VF: - write_vfont(wd, (VFont *)id_buffer, id); + write_vfont(&writer, (VFont *)id_buffer, id); break; case ID_KE: - write_key(wd, (Key *)id_buffer, id); + write_key(&writer, (Key *)id_buffer, id); break; case ID_WO: - write_world(wd, (World *)id_buffer, id); + write_world(&writer, (World *)id_buffer, id); break; case ID_TXT: - write_text(wd, (Text *)id_buffer, id); + write_text(&writer, (Text *)id_buffer, id); break; case ID_SPK: - write_speaker(wd, (Speaker *)id_buffer, id); + write_speaker(&writer, (Speaker *)id_buffer, id); break; case ID_LP: - write_probe(wd, (LightProbe *)id_buffer, id); + write_probe(&writer, (LightProbe *)id_buffer, id); break; case ID_SO: - write_sound(wd, (bSound *)id_buffer, id); + write_sound(&writer, (bSound *)id_buffer, id); break; case ID_GR: - write_collection(wd, (Collection *)id_buffer, id); + write_collection(&writer, (Collection *)id_buffer, id); break; case ID_AR: - write_armature(wd, (bArmature *)id_buffer, id); + write_armature(&writer, (bArmature *)id_buffer, id); break; case ID_AC: - write_action(wd, (bAction *)id_buffer, id); + write_action(&writer, (bAction *)id_buffer, id); break; case ID_OB: - write_object(wd, (Object *)id_buffer, id); + write_object(&writer, (Object *)id_buffer, id); break; case ID_MA: - write_material(wd, (Material *)id_buffer, id); + write_material(&writer, (Material *)id_buffer, id); break; case ID_TE: - write_texture(wd, (Tex *)id_buffer, id); + write_texture(&writer, (Tex *)id_buffer, id); break; case ID_ME: - write_mesh(wd, (Mesh *)id_buffer, id); + write_mesh(&writer, (Mesh *)id_buffer, id); break; case ID_PA: - write_particlesettings(wd, (ParticleSettings *)id_buffer, id); + write_particlesettings(&writer, (ParticleSettings *)id_buffer, id); break; case ID_NT: - write_nodetree(wd, (bNodeTree *)id_buffer, id); + write_nodetree(&writer, (bNodeTree *)id_buffer, id); break; case ID_BR: - write_brush(wd, (Brush *)id_buffer, id); + write_brush(&writer, (Brush *)id_buffer, id); break; case ID_PAL: - write_palette(wd, (Palette *)id_buffer, id); + write_palette(&writer, (Palette *)id_buffer, id); break; case ID_PC: - write_paintcurve(wd, (PaintCurve *)id_buffer, id); + write_paintcurve(&writer, (PaintCurve *)id_buffer, id); break; case ID_GD: - write_gpencil(wd, (bGPdata *)id_buffer, id); + write_gpencil(&writer, (bGPdata *)id_buffer, id); break; case ID_LS: - write_linestyle(wd, (FreestyleLineStyle *)id_buffer, id); + write_linestyle(&writer, (FreestyleLineStyle *)id_buffer, id); break; case ID_CF: - write_cachefile(wd, (CacheFile *)id_buffer, id); + write_cachefile(&writer, (CacheFile *)id_buffer, id); break; case ID_HA: - write_hair(wd, (Hair *)id_buffer, id); + write_hair(&writer, (Hair *)id_buffer, id); break; case ID_PT: - write_pointcloud(wd, (PointCloud *)id_buffer, id); + write_pointcloud(&writer, (PointCloud *)id_buffer, id); break; case ID_VO: - write_volume(wd, (Volume *)id_buffer, id); + write_volume(&writer, (Volume *)id_buffer, id); break; case ID_SIM: - write_simulation(wd, (Simulation *)id); + write_simulation(&writer, (Simulation *)id_buffer, id); break; case ID_LI: /* Do nothing, handled below - and should never be reached. */ @@ -4271,11 +4329,7 @@ static bool write_file_handle(Main *mainvar, BKE_lib_override_library_operations_store_end(override_storage, id); } - if (wd->use_memfile) { - /* Very important to do it after every ID write now, otherwise we cannot know whether a - * specific ID changed or not. */ - mywrite_flush(wd); - } + mywrite_id_end(wd, id); } if (id_buffer != id_buffer_static) { @@ -4490,4 +4544,103 @@ bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int w return (err == 0); } +void BLO_write_raw(BlendWriter *writer, int size_in_bytes, const void *data_ptr) +{ + writedata(writer->wd, DATA, size_in_bytes, data_ptr); +} + +void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr) +{ + int struct_id = BLO_get_struct_id_by_name(writer, struct_name); + BLO_write_struct_by_id(writer, struct_id, data_ptr); +} + +void BLO_write_struct_array_by_name(BlendWriter *writer, + const char *struct_name, + int array_size, + const void *data_ptr) +{ + int struct_id = BLO_get_struct_id_by_name(writer, struct_name); + BLO_write_struct_array_by_id(writer, struct_id, array_size, data_ptr); +} + +void BLO_write_struct_by_id(BlendWriter *writer, int struct_id, const void *data_ptr) +{ + writestruct_nr(writer->wd, DATA, struct_id, 1, data_ptr); +} + +void BLO_write_struct_array_by_id(BlendWriter *writer, + int struct_id, + int array_size, + const void *data_ptr) +{ + writestruct_nr(writer->wd, DATA, struct_id, array_size, data_ptr); +} + +void BLO_write_struct_list_by_id(BlendWriter *writer, int struct_id, ListBase *list) +{ + writelist_nr(writer->wd, DATA, struct_id, list); +} + +void BLO_write_struct_list_by_name(BlendWriter *writer, const char *struct_name, ListBase *list) +{ + BLO_write_struct_list_by_id(writer, BLO_get_struct_id_by_name(writer, struct_name), list); +} + +void blo_write_id_struct(BlendWriter *writer, int struct_id, const void *id_address, const ID *id) +{ + writestruct_at_address_nr(writer->wd, GS(id->name), struct_id, 1, id_address, id); +} + +int BLO_get_struct_id_by_name(BlendWriter *writer, const char *struct_name) +{ + int struct_id = DNA_struct_find_nr(writer->wd->sdna, struct_name); + BLI_assert(struct_id >= 0); + return struct_id; +} + +void BLO_write_int32_array(BlendWriter *writer, int size, const int32_t *data_ptr) +{ + BLO_write_raw(writer, sizeof(int32_t) * size, data_ptr); +} + +void BLO_write_uint32_array(BlendWriter *writer, int size, const uint32_t *data_ptr) +{ + BLO_write_raw(writer, sizeof(uint32_t) * size, data_ptr); +} + +void BLO_write_float_array(BlendWriter *writer, int size, const float *data_ptr) +{ + BLO_write_raw(writer, sizeof(float) * size, data_ptr); +} + +void BLO_write_pointer_array(BlendWriter *writer, int size, const void *data_ptr) +{ + BLO_write_raw(writer, sizeof(void *) * size, data_ptr); +} + +void BLO_write_float3_array(BlendWriter *writer, int size, const float *data_ptr) +{ + BLO_write_raw(writer, sizeof(float) * 3 * size, data_ptr); +} + +/** + * Write a null terminated string. + */ +void BLO_write_string(BlendWriter *writer, const char *str) +{ + if (str != NULL) { + BLO_write_raw(writer, strlen(str) + 1, str); + } +} + +/** + * Sometimes different data is written depending on whether the file is saved to disk or used for + * undo. This function returns true when the current file-writing is done for undo. + */ +bool BLO_write_is_undo(BlendWriter *writer) +{ + return writer->wd->use_memfile; +} + /** \} */ diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 35c33837d64..7a389c63abd 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -56,7 +56,7 @@ set(SRC operators/bmo_hull.c operators/bmo_inset.c operators/bmo_join_triangles.c - operators/bmo_mesh_conv.c + operators/bmo_mesh_convert.c operators/bmo_mirror.c operators/bmo_normals.c operators/bmo_offset_edgeloops.c @@ -97,8 +97,8 @@ set(SRC intern/bmesh_marking.h intern/bmesh_mesh.c intern/bmesh_mesh.h - intern/bmesh_mesh_conv.c - intern/bmesh_mesh_conv.h + intern/bmesh_mesh_convert.c + intern/bmesh_mesh_convert.h intern/bmesh_mesh_duplicate.c intern/bmesh_mesh_duplicate.h intern/bmesh_mesh_validate.c diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index 9b5072e8e16..c0791e6fdbc 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -215,7 +215,7 @@ extern "C" { #include "intern/bmesh_log.h" #include "intern/bmesh_marking.h" #include "intern/bmesh_mesh.h" -#include "intern/bmesh_mesh_conv.h" +#include "intern/bmesh_mesh_convert.h" #include "intern/bmesh_mesh_duplicate.h" #include "intern/bmesh_mesh_validate.h" #include "intern/bmesh_mods.h" diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index 1bf419f4461..177599656b6 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -1021,7 +1021,7 @@ void BM_select_history_validate(BMesh *bm) bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese) { BMEditSelection *ese_last = bm->selected.last; - BMFace *efa = BM_mesh_active_face_get(bm, false, false); + BMFace *efa = BM_mesh_active_face_get(bm, false, true); ese->next = ese->prev = NULL; diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c index de32d7881b0..b8508f7e12c 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.c +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c @@ -893,6 +893,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh j = bm_to_mesh_shape_layer_index_from_kb(bm, currkey); cd_shape_offset = CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, j); + if (cd_shape_offset < 0) { + /* The target Mesh has more shapekeys than the BMesh. */ + continue; + } fp = newkey = MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data"); oldkey = currkey->data; diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h index 1ad43558c60..1ad43558c60 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.h +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c index 64950411fed..e000b253000 100644 --- a/source/blender/bmesh/intern/bmesh_query.c +++ b/source/blender/bmesh/intern/bmesh_query.c @@ -1568,6 +1568,41 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, } /** + * A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates. + */ +float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l, + const float normal_fallback[3], + float const (*vertexCos)[3], + const float epsilon_sq, + float r_normal[3]) +{ + const int i_prev = BM_elem_index_get(l->prev->v); + const int i_next = BM_elem_index_get(l->next->v); + const int i = BM_elem_index_get(l->v); + + float v1[3], v2[3], v_tmp[3]; + sub_v3_v3v3(v1, vertexCos[i_prev], vertexCos[i]); + sub_v3_v3v3(v2, vertexCos[i_next], vertexCos[i]); + + const float fac = ((v2[0] == 0.0f) ? + ((v2[1] == 0.0f) ? ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) : + v1[1] / v2[1]) : + v1[0] / v2[0]); + + mul_v3_v3fl(v_tmp, v2, fac); + sub_v3_v3(v_tmp, v1); + if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) { + /* Not co-linear, we can compute cross-product and normalize it into normal. */ + cross_v3_v3v3(r_normal, v1, v2); + return normalize_v3(r_normal); + } + else { + copy_v3_v3(r_normal, normal_fallback); + return 0.0f; + } +} + +/** * #BM_loop_calc_face_normal_safe_ex with pre-defined sane epsilon. * * Since this doesn't scale based on triangle size, fixed value works well. @@ -1577,6 +1612,15 @@ float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal); } +float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l, + const float normal_fallback[3], + float const (*vertexCos)[3], + float r_normal[3]) + +{ + return BM_loop_calc_face_normal_safe_vcos_ex(l, normal_fallback, vertexCos, 1e-5f, r_normal); +} + /** * \brief BM_loop_calc_face_normal * diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h index aaf8191c5db..7e07059d4d8 100644 --- a/source/blender/bmesh/intern/bmesh_query.h +++ b/source/blender/bmesh/intern/bmesh_query.h @@ -142,6 +142,16 @@ float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL( float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(); float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3]) ATTR_NONNULL(); +float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l, + const float normal_fallback[3], + float const (*vertexCos)[3], + const float epsilon_sq, + float r_normal[3]) ATTR_NONNULL(); +float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l, + const float normal_fallback[3], + float const (*vertexCos)[3], + float r_normal[3]) ATTR_NONNULL(); + void BM_loop_calc_face_direction(const BMLoop *l, float r_normal[3]); void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]); diff --git a/source/blender/bmesh/operators/bmo_mesh_conv.c b/source/blender/bmesh/operators/bmo_mesh_convert.c index e480db64f9d..e480db64f9d 100644 --- a/source/blender/bmesh/operators/bmo_mesh_conv.c +++ b/source/blender/bmesh/operators/bmo_mesh_convert.c diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index 64687ac154c..d661859c8e3 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -1393,16 +1393,15 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2; BMFace *f; float vec[3], mat[4][4], phi, phid; - float dia1 = BMO_slot_float_get(op->slots_in, "diameter1"); - float dia2 = BMO_slot_float_get(op->slots_in, "diameter2"); - float depth = BMO_slot_float_get(op->slots_in, "depth"); + const float dia1 = BMO_slot_float_get(op->slots_in, "diameter1"); + const float dia2 = BMO_slot_float_get(op->slots_in, "diameter2"); + const float depth_half = 0.5f * BMO_slot_float_get(op->slots_in, "depth"); int segs = BMO_slot_int_get(op->slots_in, "segments"); const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); - int a; if (!segs) { return; @@ -1413,16 +1412,15 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) phid = 2.0f * (float)M_PI / segs; phi = 0; - depth *= 0.5f; if (cap_ends) { vec[0] = vec[1] = 0.0f; - vec[2] = -depth; + vec[2] = -depth_half; mul_m4_v3(mat, vec); cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); vec[0] = vec[1] = 0.0f; - vec[2] = depth; + vec[2] = depth_half; mul_m4_v3(mat, vec); cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); @@ -1431,23 +1429,26 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) BMO_vert_flag_enable(bm, cent2, VERT_MARK); } - for (a = 0; a < segs; a++, phi += phid) { + const int side_faces_len = segs - 1; + BMFace **side_faces = MEM_mallocN(sizeof(*side_faces) * side_faces_len, __func__); + + for (int i = 0; i < segs; i++, phi += phid) { vec[0] = dia1 * sinf(phi); vec[1] = dia1 * cosf(phi); - vec[2] = -depth; + vec[2] = -depth_half; mul_m4_v3(mat, vec); v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); vec[0] = dia2 * sinf(phi); vec[1] = dia2 * cosf(phi); - vec[2] = depth; + vec[2] = depth_half; mul_m4_v3(mat, vec); v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); BMO_vert_flag_enable(bm, v1, VERT_MARK); BMO_vert_flag_enable(bm, v2, VERT_MARK); - if (a) { + if (i) { if (cap_ends) { f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { @@ -1466,6 +1467,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) if (calc_uvs) { BMO_face_flag_enable(bm, f, FACE_MARK); } + side_faces[i - 1] = f; } else { firstv1 = v1; @@ -1476,10 +1478,6 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) lastv2 = v2; } - if (!a) { - return; - } - if (cap_ends) { f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { @@ -1503,11 +1501,38 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK, cd_loop_uv_offset); } + /* Collapse vertices at the first end. */ + if (dia1 == 0.0f) { + if (cap_ends) { + BM_vert_kill(bm, cent1); + } + for (int i = 0; i < side_faces_len; i++) { + f = side_faces[i]; + BMLoop *l = BM_FACE_FIRST_LOOP(f); + BM_edge_collapse(bm, l->prev->e, l->prev->v, true, true); + } + } + + /* Collapse vertices at the second end. */ + if (dia2 == 0.0f) { + if (cap_ends) { + BM_vert_kill(bm, cent2); + } + for (int i = 0; i < side_faces_len; i++) { + f = side_faces[i]; + BMLoop *l = BM_FACE_FIRST_LOOP(f); + BM_edge_collapse(bm, l->next->e, l->next->v, true, true); + } + } + if (!cap_tris) { BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); } - BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.0000005 * depth); + if (side_faces != NULL) { + MEM_freeN(side_faces); + } + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c index 0331ca476dd..713a68969e5 100644 --- a/source/blender/bmesh/tools/bmesh_path.c +++ b/source/blender/bmesh/tools/bmesh_path.c @@ -225,7 +225,7 @@ static void edgetag_add_adjacent(HeapSimple *heap, /* unlike vert/face, stepping faces disables scanning connected edges * and only steps over faces (selecting a ring of edges instead of a loop) */ - if (params->use_step_face == false) { + if (params->use_step_face == false || e_a->l == NULL) { BMIter viter; BMVert *v; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index eddc58a8d98..9230fa19c32 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -83,6 +83,7 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_layer.h" +#include "BKE_light.h" #include "BKE_mask.h" #include "BKE_material.h" #include "BKE_mball.h" @@ -1441,6 +1442,12 @@ void DepsgraphNodeBuilder::build_light(Light *lamp) build_parameters(&lamp->id); /* light's nodetree */ build_nodetree(lamp->nodetree); + + Light *lamp_cow = get_cow_datablock(lamp); + add_operation_node(&lamp->id, + NodeType::SHADING, + OperationCode::LIGHT_UPDATE, + function_bind(BKE_light_eval, _1, lamp_cow)); } void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) @@ -1574,6 +1581,7 @@ void DepsgraphNodeBuilder::build_texture(Tex *texture) return; } /* Texture itself. */ + add_id_node(&texture->id); build_idproperties(texture->id.properties); build_animdata(&texture->id); build_parameters(&texture->id); @@ -1759,10 +1767,13 @@ void DepsgraphNodeBuilder::build_simulation(Simulation *simulation) build_animdata(&simulation->id); build_parameters(&simulation->id); + Simulation *simulation_cow = get_cow_datablock(simulation); + Scene *scene_cow = get_cow_datablock(scene_); + add_operation_node(&simulation->id, NodeType::SIMULATION, OperationCode::SIMULATION_EVAL, - function_bind(BKE_simulation_data_update, _1, get_cow_datablock(scene_))); + function_bind(BKE_simulation_data_update, _1, scene_cow, simulation_cow)); } void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h index c3c90e5aae4..df8b295f5bb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h @@ -28,7 +28,7 @@ namespace DEG { struct RootPChanMap { - /* ctor and dtor - Create and free the internal map respectively. */ + /* Constructor and destructor - Create and free the internal map respectively. */ RootPChanMap(); ~RootPChanMap(); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index ae90ad8a281..f5a131a1731 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1500,7 +1500,10 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) } } if (property_entry_key.prop != nullptr && RNA_property_is_idprop(property_entry_key.prop)) { - RNAPathKey property_exit_key(id, rna_path, RNAPointerSource::EXIT); + RNAPathKey property_exit_key(property_entry_key.id, + property_entry_key.ptr, + property_entry_key.prop, + RNAPointerSource::EXIT); OperationKey parameters_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); add_relation(property_exit_key, parameters_key, "Driven Property -> Properties"); } @@ -2245,14 +2248,20 @@ void DepsgraphRelationBuilder::build_light(Light *lamp) build_idproperties(lamp->id.properties); build_animdata(&lamp->id); build_parameters(&lamp->id); + + ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); + /* light's nodetree */ if (lamp->nodetree != nullptr) { build_nodetree(lamp->nodetree); - ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING); add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters"); build_nested_nodetree(&lamp->id, lamp->nodetree); } + + /* For allowing drivers on lamp properties. */ + ComponentKey shading_key(&lamp->id, NodeType::SHADING); + add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters"); } void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) @@ -2422,6 +2431,11 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture) ComponentKey animation_key(&texture->id, NodeType::ANIMATION); add_relation(animation_key, texture_key, "Datablock Animation"); } + + if (BKE_image_user_id_has_animation(&texture->id)) { + ComponentKey image_animation_key(&texture->id, NodeType::IMAGE_ANIMATION); + add_relation(image_animation_key, texture_key, "Datablock Image Animation"); + } } void DepsgraphRelationBuilder::build_image(Image *image) @@ -2878,6 +2892,9 @@ void DepsgraphRelationBuilder::build_driver_relations(IDNode *id_node) DriverGroupMap driver_groups; LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { + if (fcu->rna_path == nullptr) { + continue; + } // Get the RNA path except the part after the last dot. char *last_dot = strrchr(fcu->rna_path, '.'); string rna_prefix; @@ -2928,7 +2945,7 @@ void DepsgraphRelationBuilder::build_driver_relations(IDNode *id_node) } } } -} +} // namespace DEG /* **** ID traversal callbacks functions **** */ diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index 2381076161f..91bd0117f6c 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -172,6 +172,8 @@ const char *operationCodeAsString(OperationCode opcode) return "SHADING"; case OperationCode::MATERIAL_UPDATE: return "MATERIAL_UPDATE"; + case OperationCode::LIGHT_UPDATE: + return "LIGHT_UPDATE"; case OperationCode::WORLD_UPDATE: return "WORLD_UPDATE"; /* Movie clip. */ diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h index 865a25d2124..6b14e6af02f 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.h +++ b/source/blender/depsgraph/intern/node/deg_node_operation.h @@ -170,6 +170,7 @@ enum class OperationCode { /* Shading. ------------------------------------------------------------- */ SHADING, MATERIAL_UPDATE, + LIGHT_UPDATE, WORLD_UPDATE, /* Batch caches. -------------------------------------------------------- */ diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 0214a8e1887..a26c150cb51 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -34,6 +34,7 @@ set(INC ../imbuf ../makesdna ../makesrna + ../nodes ../render/extern/include ../render/intern/include ../windowmanager @@ -303,8 +304,8 @@ data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC) data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC) data_to_c_simple(engines/basic/shaders/conservative_depth_geom.glsl SRC) -data_to_c_simple(engines/basic/shaders/conservative_depth_vert.glsl SRC) -data_to_c_simple(engines/basic/shaders/conservative_depth_frag.glsl SRC) +data_to_c_simple(engines/basic/shaders/depth_vert.glsl SRC) +data_to_c_simple(engines/basic/shaders/depth_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/antialiasing_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/antialiasing_vert.glsl SRC) diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index 6658fea7825..bbc3c407f14 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -37,8 +37,8 @@ #define BASIC_ENGINE "BLENDER_BASIC" -extern char datatoc_conservative_depth_frag_glsl[]; -extern char datatoc_conservative_depth_vert_glsl[]; +extern char datatoc_depth_frag_glsl[]; +extern char datatoc_depth_vert_glsl[]; extern char datatoc_conservative_depth_geom_glsl[]; extern char datatoc_common_view_lib_glsl[]; @@ -91,22 +91,28 @@ static void basic_engine_init(void *UNUSED(vedata)) /* Depth prepass */ if (!sh_data->depth) { - sh_data->depth = DRW_shader_create_3d_depth_only(draw_ctx->sh_cfg); - const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + + sh_data->depth = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, NULL}, + }); + sh_data->depth_conservative = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg->lib, datatoc_common_view_lib_glsl, - datatoc_conservative_depth_vert_glsl, + datatoc_depth_vert_glsl, NULL}, .geom = (const char *[]){sh_cfg->lib, datatoc_common_view_lib_glsl, datatoc_conservative_depth_geom_glsl, NULL}, - .frag = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_conservative_depth_frag_glsl, - NULL}, - .defs = (const char *[]){sh_cfg->def, NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, "#define CONSERVATIVE_RASTER\n", NULL}, }); } } @@ -233,6 +239,7 @@ static void basic_engine_free(void) { for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) { BASIC_Shaders *sh_data = &e_data.sh_data[i]; + DRW_SHADER_FREE_SAFE(sh_data->depth); DRW_SHADER_FREE_SAFE(sh_data->depth_conservative); } } diff --git a/source/blender/draw/engines/basic/shaders/conservative_depth_frag.glsl b/source/blender/draw/engines/basic/shaders/depth_frag.glsl index ff4a015c335..ff4a015c335 100644 --- a/source/blender/draw/engines/basic/shaders/conservative_depth_frag.glsl +++ b/source/blender/draw/engines/basic/shaders/depth_frag.glsl diff --git a/source/blender/draw/engines/basic/shaders/conservative_depth_vert.glsl b/source/blender/draw/engines/basic/shaders/depth_vert.glsl index c55a3211ff2..318d0acef6f 100644 --- a/source/blender/draw/engines/basic/shaders/conservative_depth_vert.glsl +++ b/source/blender/draw/engines/basic/shaders/depth_vert.glsl @@ -1,12 +1,16 @@ +#ifdef CONSERVATIVE_RASTER RESOURCE_ID_VARYING +#endif in vec3 pos; void main() { GPU_INTEL_VERTEX_SHADER_WORKAROUND +#ifdef CONSERVATIVE_RASTER PASS_RESOURCE_ID +#endif vec3 world_pos = point_object_to_world(pos); gl_Position = point_world_to_ndc(world_pos); diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index 6874947de55..a19af77124f 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -24,6 +24,8 @@ #include "DRW_render.h" +#include "BLI_memblock.h" + #include "eevee_lightcache.h" #include "eevee_private.h" @@ -54,8 +56,17 @@ void EEVEE_view_layer_data_free(void *storage) DRW_UBO_FREE_SAFE(sldata->grid_ubo); DRW_UBO_FREE_SAFE(sldata->planar_ubo); DRW_UBO_FREE_SAFE(sldata->common_ubo); - for (int i = 0; i < MAX_MATERIAL_RENDER_PASSES_UBO; i++) { - DRW_UBO_FREE_SAFE(sldata->renderpass_ubo[i]); + + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.combined); + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.diff_color); + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.diff_light); + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.spec_color); + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.spec_light); + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.emit); + + if (sldata->material_cache) { + BLI_memblock_destroy(sldata->material_cache, NULL); + sldata->material_cache = NULL; } } diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c index ec6770e4549..4a3cc36ddef 100644 --- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -31,6 +31,8 @@ #include "BKE_camera.h" +#include "BLI_string_utils.h" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -48,24 +50,28 @@ static struct { extern char datatoc_effect_dof_vert_glsl[]; extern char datatoc_effect_dof_frag_glsl[]; +extern char datatoc_common_view_lib_glsl[]; + static void eevee_create_shader_depth_of_field(const bool use_alpha) { + char *frag = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_effect_dof_frag_glsl); e_data.dof_downsample_sh[use_alpha] = DRW_shader_create_fullscreen( - datatoc_effect_dof_frag_glsl, + frag, use_alpha ? "#define USE_ALPHA_DOF\n" "#define STEP_DOWNSAMPLE\n" : "#define STEP_DOWNSAMPLE\n"); e_data.dof_scatter_sh[use_alpha] = DRW_shader_create(datatoc_effect_dof_vert_glsl, NULL, - datatoc_effect_dof_frag_glsl, + frag, use_alpha ? "#define USE_ALPHA_DOF\n" "#define STEP_SCATTER\n" : "#define STEP_SCATTER\n"); - e_data.dof_resolve_sh[use_alpha] = DRW_shader_create_fullscreen(datatoc_effect_dof_frag_glsl, + e_data.dof_resolve_sh[use_alpha] = DRW_shader_create_fullscreen(frag, use_alpha ? "#define USE_ALPHA_DOF\n" "#define STEP_RESOLVE\n" : "#define STEP_RESOLVE\n"); + MEM_freeN(frag); } int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 05b18da4374..ab846fe0f11 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -333,8 +333,7 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) grp = DRW_shgroup_create(EEVEE_shaders_velocity_resolve_sh_get(), psl->velocity_resolve); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_mat4(grp, "currPersinv", effects->velocity_curr_persinv); DRW_shgroup_uniform_mat4(grp, "pastPersmat", effects->velocity_past_persmat); DRW_shgroup_call(grp, quad, NULL); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index a1112eb92df..b698574f9d7 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -88,7 +88,7 @@ static void eevee_engine_init(void *ved) * `EEVEE_effects_init` needs to go second for TAA. */ EEVEE_renderpasses_init(vedata); EEVEE_effects_init(sldata, vedata, camera, false); - EEVEE_materials_init(sldata, stl, fbl); + EEVEE_materials_init(sldata, vedata, stl, fbl); EEVEE_shadows_init(sldata); EEVEE_lightprobes_init(sldata, vedata); } @@ -230,7 +230,7 @@ static void eevee_draw_scene(void *vedata) BLI_halton_3d(primes, offset, samp, r); EEVEE_update_noise(psl, fbl, r); EEVEE_volumes_set_jitter(sldata, samp - 1); - EEVEE_materials_init(sldata, stl, fbl); + EEVEE_materials_init(sldata, vedata, stl, fbl); } /* Copy previous persmat to UBO data */ copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat); @@ -274,8 +274,7 @@ static void eevee_draw_scene(void *vedata) /* Depth prepass */ DRW_stats_group_start("Prepass"); - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); + DRW_draw_pass(psl->depth_ps); DRW_stats_group_end(); /* Create minmax texture */ @@ -289,9 +288,9 @@ static void eevee_draw_scene(void *vedata) /* Shading pass */ DRW_stats_group_start("Shading"); if (DRW_state_draw_background()) { - DRW_draw_pass(psl->background_pass); + DRW_draw_pass(psl->background_ps); } - EEVEE_materials_draw_opaque(sldata, psl); + DRW_draw_pass(psl->material_ps); EEVEE_subsurface_data_render(sldata, vedata); DRW_stats_group_end(); @@ -306,9 +305,8 @@ static void eevee_draw_scene(void *vedata) /* Opaque refraction */ DRW_stats_group_start("Opaque Refraction"); - DRW_draw_pass(psl->refract_depth_pass); - DRW_draw_pass(psl->refract_depth_pass_cull); - DRW_draw_pass(psl->refract_pass); + DRW_draw_pass(psl->depth_refract_ps); + DRW_draw_pass(psl->material_refract_ps); DRW_stats_group_end(); /* Volumetrics Resolve Opaque */ diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 614c749b9aa..4cdd166f09c 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -379,9 +379,7 @@ static bool eevee_lightcache_static_load(LightCache *lcache) 0, false, NULL); - GPU_texture_bind(lcache->grid_tx.tex, 0); GPU_texture_filter_mode(lcache->grid_tx.tex, true); - GPU_texture_unbind(lcache->grid_tx.tex); } if (lcache->cube_tx.tex == NULL) { @@ -406,13 +404,11 @@ static bool eevee_lightcache_static_load(LightCache *lcache) NULL); } - GPU_texture_bind(lcache->cube_tx.tex, 0); - GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true); for (int mip = 0; mip < lcache->mips_len; mip++) { GPU_texture_add_mipmap( lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1, lcache->cube_mips[mip].data); } - GPU_texture_unbind(lcache->cube_tx.tex); + GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true); } return true; } @@ -822,7 +818,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb DRW_render_viewport_size_set(viewport_size); EEVEE_effects_init(sldata, vedata, NULL, true); - EEVEE_materials_init(sldata, stl, fbl); + EEVEE_materials_init(sldata, vedata, stl, fbl); EEVEE_shadows_init(sldata); EEVEE_lightprobes_init(sldata, vedata); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 9816632c0c3..83b2a9bb6d4 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -248,8 +248,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, // DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call_instances(grp, NULL, geom, 6); @@ -271,8 +270,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call(grp, geom, NULL); @@ -293,8 +291,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); DRW_shgroup_uniform_texture(grp, "probeDepth", rt_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call(grp, geom, NULL); @@ -337,51 +334,29 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat Scene *scene = draw_ctx->scene; World *wo = scene->world; - const float *col = G_draw.block.colorBackground; - /* LookDev */ EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->probe_background, wo, pinfo); - /* END */ + if (!grp && wo) { - col = &wo->horr; - - if (wo->use_nodes && wo->nodetree) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float queue_col[3] = {0.5f, 0.5f, 0.5f}; - struct GPUMaterial *gpumat = EEVEE_material_world_lightprobe_get(scene, wo); - - eGPUMaterialStatus status = GPU_material_status(gpumat); - - switch (status) { - case GPU_MAT_SUCCESS: - grp = DRW_shgroup_material_create(gpumat, psl->probe_background); - DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f); - /* TODO (fclem): remove those (need to clean the GLSL files). */ - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_call(grp, geom, NULL); - break; - case GPU_MAT_QUEUED: - stl->g_data->queued_shaders_count++; - col = queue_col; - break; - default: - col = error_col; - break; - } - } + struct GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, NULL, wo, VAR_WORLD_PROBE); + + grp = DRW_shgroup_material_create(gpumat, psl->probe_background); + DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f); + /* TODO (fclem): remove those (need to clean the GLSL files). */ + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_call(grp, geom, NULL); } /* Fallback if shader fails or if not using nodetree. */ if (grp == NULL) { grp = DRW_shgroup_create(EEVEE_shaders_probe_default_sh_get(), psl->probe_background); - DRW_shgroup_uniform_vec3(grp, "color", col, 1); + DRW_shgroup_uniform_vec3(grp, "color", G_draw.block.colorBackground, 1); DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f); DRW_shgroup_call(grp, geom, NULL); } @@ -402,14 +377,13 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); + DRW_shgroup_uniform_vec3(grp, "screen_vecs", DRW_viewport_screenvecs_get(), 2); DRW_shgroup_uniform_float_copy( grp, "sphere_size", scene_eval->eevee.gi_cubemap_draw_size * 0.5f); /* TODO (fclem) get rid of those UBO. */ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles(grp, NULL, cube_len * 2); } @@ -427,7 +401,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_vec3(shgrp, "increment_x", egrid->increment_x, 1); DRW_shgroup_uniform_vec3(shgrp, "increment_y", egrid->increment_y, 1); DRW_shgroup_uniform_vec3(shgrp, "increment_z", egrid->increment_z, 1); - DRW_shgroup_uniform_vec3(shgrp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); + DRW_shgroup_uniform_vec3(shgrp, "screen_vecs", DRW_viewport_screenvecs_get(), 2); DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex); DRW_shgroup_uniform_float_copy( shgrp, "sphere_size", scene_eval->eevee.gi_irradiance_draw_size * 0.5f); @@ -436,8 +410,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(shgrp, "renderpass_block", sldata->renderpass_ubo.combined); int tri_count = egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2] * 2; DRW_shgroup_call_procedural_triangles(shgrp, NULL, tri_count); } @@ -455,8 +428,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_planar_display_sh_get(), psl->probe_display); DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &txl->planar_pool); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); stl->g_data->planar_display_shgrp = DRW_shgroup_call_buffer_instance( grp, e_data.format_probe_display_planar, DRW_cache_quad_get()); @@ -923,12 +895,10 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat GPU_framebuffer_bind(face_fb[face]); GPU_framebuffer_clear_depth(face_fb[face], 1.0f); - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); + DRW_draw_pass(psl->depth_ps); DRW_draw_pass(psl->probe_background); - EEVEE_materials_draw_opaque(sldata, psl); - DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ - DRW_draw_pass(psl->sss_pass_cull); + DRW_draw_pass(psl->material_ps); + DRW_draw_pass(psl->material_sss_ps); /* Only output standard pass */ DRW_draw_pass(psl->transparent_pass); } @@ -987,10 +957,8 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us /* Slight modification: we handle refraction as normal * shading and don't do SSRefraction. */ - DRW_draw_pass(psl->depth_pass_clip); - DRW_draw_pass(psl->depth_pass_clip_cull); - DRW_draw_pass(psl->refract_depth_pass_clip); - DRW_draw_pass(psl->refract_depth_pass_clip_cull); + DRW_draw_pass(psl->depth_ps); + DRW_draw_pass(psl->depth_refract_ps); DRW_draw_pass(psl->probe_background); EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer); @@ -999,10 +967,9 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us GPU_framebuffer_bind(fbl->planarref_fb); /* Shading pass */ - EEVEE_materials_draw_opaque(sldata, psl); - DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ - DRW_draw_pass(psl->sss_pass_cull); - DRW_draw_pass(psl->refract_pass); + DRW_draw_pass(psl->material_ps); + DRW_draw_pass(psl->material_sss_ps); /* Only output standard pass */ + DRW_draw_pass(psl->material_refract_ps); /* Transparent */ if (DRW_state_is_image_render()) { diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index b33be750d80..18365d69514 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -34,6 +34,8 @@ #include "ED_screen.h" +#include "GPU_material.h" + #include "UI_resources.h" #include "eevee_lightcache.h" @@ -56,6 +58,43 @@ static void eevee_lookdev_lightcache_delete(EEVEE_Data *vedata) g_data->studiolight_rot_z = 0.0f; } +static void eevee_lookdev_hdri_preview_init(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata) +{ + EEVEE_PassList *psl = vedata->psl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + DRWShadingGroup *grp; + + struct GPUBatch *sphere = DRW_cache_sphere_get(); + int mat_options = VAR_MAT_MESH | VAR_MAT_LOOKDEV; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | + DRW_STATE_CULL_BACK; + + { + Material *ma = EEVEE_material_default_diffuse_get(); + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); + struct GPUShader *sh = GPU_material_get_shader(gpumat); + + DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state); + grp = DRW_shgroup_create(sh, psl->lookdev_diffuse_pass); + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false); + DRW_shgroup_add_material_resources(grp, gpumat); + DRW_shgroup_call(grp, sphere, NULL); + } + { + Material *ma = EEVEE_material_default_glossy_get(); + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); + struct GPUShader *sh = GPU_material_get_shader(gpumat); + + DRW_PASS_CREATE(psl->lookdev_glossy_pass, state); + grp = DRW_shgroup_create(sh, psl->lookdev_glossy_pass); + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false); + DRW_shgroup_add_material_resources(grp, gpumat); + DRW_shgroup_call(grp, sphere, NULL); + } +} + void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, DRWShadingGroup **r_grp, @@ -106,6 +145,8 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, effects->anchor[1] = rect->ymin; EEVEE_temporal_sampling_reset(vedata); } + + eevee_lookdev_hdri_preview_init(vedata, sldata); } if (LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d)) { @@ -176,8 +217,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); } DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); diff --git a/source/blender/draw/engines/eevee/eevee_lut_gen.c b/source/blender/draw/engines/eevee/eevee_lut_gen.c new file mode 100644 index 00000000000..5f20d6fbfb8 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_lut_gen.c @@ -0,0 +1,198 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * EEVEE LUT generation: + * + * Routine to generate the LUT used by eevee stored in eevee_lut.h + * Theses functions are not to be used in the final executable. + */ + +#include "DRW_render.h" + +#include "BLI_alloca.h" +#include "BLI_rand.h" +#include "BLI_string_utils.h" + +extern char datatoc_bsdf_lut_frag_glsl[]; +extern char datatoc_btdf_lut_frag_glsl[]; +extern char datatoc_bsdf_common_lib_glsl[]; +extern char datatoc_bsdf_sampling_lib_glsl[]; +extern char datatoc_lightprobe_geom_glsl[]; +extern char datatoc_lightprobe_vert_glsl[]; + +static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h)) +{ + struct GPUTexture *tex; + struct GPUFrameBuffer *fb = NULL; + static float samples_len = 8192.0f; + static float inv_samples_len = 1.0f / 8192.0f; + + char *lib_str = BLI_string_joinN(datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl); + + struct GPUShader *sh = DRW_shader_create_with_lib(datatoc_lightprobe_vert_glsl, + datatoc_lightprobe_geom_glsl, + datatoc_bsdf_lut_frag_glsl, + lib_str, + "#define HAMMERSLEY_SIZE 8192\n" + "#define BRDF_LUT_SIZE 64\n" + "#define NOISE_SIZE 64\n"); + + DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1); + DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); + DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); + + struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); + DRW_shgroup_call(grp, geom, NULL); + + float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); + + tex = DRW_texture_create_2d(w, h, GPU_RG16F, DRW_TEX_FILTER, (float *)texels); + + DRWFboTexture tex_filter = {&tex, GPU_RG16F, DRW_TEX_FILTER}; + GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); + + GPU_framebuffer_bind(fb); + DRW_draw_pass(pass); + + float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glReadPixels(0, 0, w, h, GL_RGB, GL_FLOAT, data); + + printf("{"); + for (int i = 0; i < w * h * 3; i += 3) { + printf("%ff, %ff, ", data[i], data[i + 1]); + i += 3; + printf("%ff, %ff, ", data[i], data[i + 1]); + i += 3; + printf("%ff, %ff, ", data[i], data[i + 1]); + i += 3; + printf("%ff, %ff, \n", data[i], data[i + 1]); + } + printf("}"); + + MEM_freeN(texels); + MEM_freeN(data); + + return tex; +} + +static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h) +{ + struct GPUTexture *tex; + struct GPUTexture *hammersley = create_hammersley_sample_texture(8192); + struct GPUFrameBuffer *fb = NULL; + static float samples_len = 8192.0f; + static float a2 = 0.0f; + static float inv_samples_len = 1.0f / 8192.0f; + + char *frag_str = BLI_string_joinN( + datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_btdf_lut_frag_glsl); + + struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str, + "#define HAMMERSLEY_SIZE 8192\n" + "#define BRDF_LUT_SIZE 64\n" + "#define NOISE_SIZE 64\n" + "#define LUT_SIZE 64\n"); + + MEM_freeN(frag_str); + + DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_float(grp, "a2", &a2, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1); + DRW_shgroup_uniform_texture(grp, "texHammersley", hammersley); + DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex); + + struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); + DRW_shgroup_call(grp, geom, NULL); + + float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); + + tex = DRW_texture_create_2d(w, h, GPU_R16F, DRW_TEX_FILTER, (float *)texels); + + DRWFboTexture tex_filter = {&tex, GPU_R16F, DRW_TEX_FILTER}; + GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); + + GPU_framebuffer_bind(fb); + + float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); + + float inc = 1.0f / 31.0f; + float roughness = 1e-8f - inc; + FILE *f = BLI_fopen("btdf_split_sum_ggx.h", "w"); + fprintf(f, "static float btdf_split_sum_ggx[32][64 * 64] = {\n"); + do { + roughness += inc; + CLAMP(roughness, 1e-4f, 1.0f); + a2 = powf(roughness, 4.0f); + DRW_draw_pass(pass); + + GPU_framebuffer_read_data(0, 0, w, h, 3, 0, data); + +#if 1 + fprintf(f, "\t{\n\t\t"); + for (int i = 0; i < w * h * 3; i += 3) { + fprintf(f, "%ff,", data[i]); + if (((i / 3) + 1) % 12 == 0) { + fprintf(f, "\n\t\t"); + } + else { + fprintf(f, " "); + } + } + fprintf(f, "\n\t},\n"); +#else + for (int i = 0; i < w * h * 3; i += 3) { + if (data[i] < 0.01) { + printf(" "); + } + else if (data[i] < 0.3) { + printf("."); + } + else if (data[i] < 0.6) { + printf("+"); + } + else if (data[i] < 0.9) { + printf("%%"); + } + else { + printf("#"); + } + if ((i / 3 + 1) % 64 == 0) { + printf("\n"); + } + } +#endif + + } while (roughness < 1.0f); + fprintf(f, "\n};\n"); + + fclose(f); + + MEM_freeN(texels); + MEM_freeN(data); + + return tex; +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 03cdb02a48a..cfc70baaf01 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -23,10 +23,10 @@ #include "DRW_render.h" #include "BLI_alloca.h" -#include "BLI_dynstr.h" #include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_math_bits.h" +#include "BLI_memblock.h" #include "BLI_rand.h" #include "BLI_string_utils.h" @@ -48,29 +48,11 @@ /* *********** STATIC *********** */ static struct { - char *frag_shader_lib; - char *vert_shader_str; - char *vert_shadow_shader_str; - char *vert_background_shader_str; - char *vert_volume_shader_str; - char *geom_volume_shader_str; - char *volume_shader_lib; - - struct GPUShader *default_prepass_sh; - struct GPUShader *default_prepass_clip_sh; - struct GPUShader *default_hair_prepass_sh; - struct GPUShader *default_hair_prepass_clip_sh; - struct GPUShader *default_lit[VAR_MAT_MAX]; - struct GPUShader *default_background; - struct GPUShader *update_noise_sh; - /* 64*64 array texture containing all LUTs and other utilitarian arrays. * Packing enables us to same precious textures slots. */ struct GPUTexture *util_tex; struct GPUTexture *noise_tex; - uint sss_count; - float noise_offsets[3]; } e_data = {NULL}; /* Engine data */ @@ -82,8 +64,6 @@ extern char datatoc_prepass_vert_glsl[]; extern char datatoc_default_frag_glsl[]; extern char datatoc_default_world_frag_glsl[]; extern char datatoc_ltc_lib_glsl[]; -extern char datatoc_bsdf_lut_frag_glsl[]; -extern char datatoc_btdf_lut_frag_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; @@ -107,320 +87,45 @@ extern char datatoc_volumetric_frag_glsl[]; extern char datatoc_volumetric_lib_glsl[]; extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; -#define DEFAULT_RENDER_PASS_FLAG 0xefffffff - -/* Iterator for render passes. This iteration will only do the material based render passes. it - * will ignore `EEVEE_RENDER_PASS_ENVIRONMENT`. - * - * parameters: - * - `render_passes_` is a bitflag for render_passes that needs to be iterated over. - * - `render_pass_index_` is a parameter name where the index of the render_pass will be available - * during iteration. This index can be used to select the right pass in the `psl`. - * - `render_pass_` is the bitflag of the render_pass of the current iteration. - * - * The `render_pass_index_` parameter needs to be the same for the `RENDER_PASS_ITER_BEGIN` and - * `RENDER_PASS_ITER_END`. - */ -#define RENDER_PASS_ITER_BEGIN(render_passes_, render_pass_index_, render_pass_) \ - const eViewLayerEEVEEPassType __filtered_##render_pass_index_ = render_passes_ & \ - EEVEE_RENDERPASSES_MATERIAL & \ - ~EEVEE_RENDER_PASS_ENVIRONMENT; \ - if (__filtered_##render_pass_index_ != 0) { \ - int render_pass_index_ = 1; \ - for (int bit_##render_pass_ = 0; bit_##render_pass_ < EEVEE_RENDER_PASS_MAX_BIT; \ - bit_##render_pass_++) { \ - eViewLayerEEVEEPassType render_pass_ = (1 << bit_##render_pass_); \ - if ((__filtered_##render_pass_index_ & render_pass_) != 0) { -#define RENDER_PASS_ITER_END(render_pass_index_) \ - render_pass_index_ += 1; \ - } \ - } \ - } \ - ((void)0) +typedef struct EeveeMaterialCache { + struct DRWShadingGroup *depth_grp; + struct DRWShadingGroup *shading_grp; + struct DRWShadingGroup *shadow_grp; + struct GPUMaterial *shading_gpumat; + /* Meh, Used by hair to ensure draw order when calling DRW_shgroup_create_sub. + * Pointers to ghash values. */ + struct DRWShadingGroup **depth_grp_p; + struct DRWShadingGroup **shading_grp_p; + struct DRWShadingGroup **shadow_grp_p; +} EeveeMaterialCache; /* *********** FUNCTIONS *********** */ -#if 0 /* Used only to generate the LUT values */ -static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h)) -{ - struct GPUTexture *tex; - struct GPUFrameBuffer *fb = NULL; - static float samples_len = 8192.0f; - static float inv_samples_len = 1.0f / 8192.0f; - - char *lib_str = BLI_string_joinN(datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl); - - struct GPUShader *sh = DRW_shader_create_with_lib(datatoc_lightprobe_vert_glsl, - datatoc_lightprobe_geom_glsl, - datatoc_bsdf_lut_frag_glsl, - lib_str, - "#define HAMMERSLEY_SIZE 8192\n" - "#define BRDF_LUT_SIZE 64\n" - "#define NOISE_SIZE 64\n"); - - DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1); - DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); - DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); - - struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call(grp, geom, NULL); - - float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); - - tex = DRW_texture_create_2d(w, h, GPU_RG16F, DRW_TEX_FILTER, (float *)texels); - - DRWFboTexture tex_filter = {&tex, GPU_RG16F, DRW_TEX_FILTER}; - GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); - - GPU_framebuffer_bind(fb); - DRW_draw_pass(pass); - - float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glReadPixels(0, 0, w, h, GL_RGB, GL_FLOAT, data); - - printf("{"); - for (int i = 0; i < w * h * 3; i += 3) { - printf("%ff, %ff, ", data[i], data[i + 1]); - i += 3; - printf("%ff, %ff, ", data[i], data[i + 1]); - i += 3; - printf("%ff, %ff, ", data[i], data[i + 1]); - i += 3; - printf("%ff, %ff, \n", data[i], data[i + 1]); - } - printf("}"); - - MEM_freeN(texels); - MEM_freeN(data); - - return tex; -} - -static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h) -{ - struct GPUTexture *tex; - struct GPUTexture *hammersley = create_hammersley_sample_texture(8192); - struct GPUFrameBuffer *fb = NULL; - static float samples_len = 8192.0f; - static float a2 = 0.0f; - static float inv_samples_len = 1.0f / 8192.0f; - - char *frag_str = BLI_string_joinN( - datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_btdf_lut_frag_glsl); - - struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str, - "#define HAMMERSLEY_SIZE 8192\n" - "#define BRDF_LUT_SIZE 64\n" - "#define NOISE_SIZE 64\n" - "#define LUT_SIZE 64\n"); - - MEM_freeN(frag_str); - - DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_float(grp, "a2", &a2, 1); - DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1); - DRW_shgroup_uniform_texture(grp, "texHammersley", hammersley); - DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex); - - struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call(grp, geom, NULL); - - float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); - - tex = DRW_texture_create_2d(w, h, GPU_R16F, DRW_TEX_FILTER, (float *)texels); - - DRWFboTexture tex_filter = {&tex, GPU_R16F, DRW_TEX_FILTER}; - GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); - - GPU_framebuffer_bind(fb); - - float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); - - float inc = 1.0f / 31.0f; - float roughness = 1e-8f - inc; - FILE *f = BLI_fopen("btdf_split_sum_ggx.h", "w"); - fprintf(f, "static float btdf_split_sum_ggx[32][64 * 64] = {\n"); - do { - roughness += inc; - CLAMP(roughness, 1e-4f, 1.0f); - a2 = powf(roughness, 4.0f); - DRW_draw_pass(pass); - - GPU_framebuffer_read_data(0, 0, w, h, 3, 0, data); - -# if 1 - fprintf(f, "\t{\n\t\t"); - for (int i = 0; i < w * h * 3; i += 3) { - fprintf(f, "%ff,", data[i]); - if (((i / 3) + 1) % 12 == 0) { - fprintf(f, "\n\t\t"); - } - else { - fprintf(f, " "); - } - } - fprintf(f, "\n\t},\n"); -# else - for (int i = 0; i < w * h * 3; i += 3) { - if (data[i] < 0.01) { - printf(" "); - } - else if (data[i] < 0.3) { - printf("."); - } - else if (data[i] < 0.6) { - printf("+"); - } - else if (data[i] < 0.9) { - printf("%%"); - } - else { - printf("#"); - } - if ((i / 3 + 1) % 64 == 0) { - printf("\n"); - } - } -# endif - - } while (roughness < 1.0f); - fprintf(f, "\n};\n"); - - fclose(f); - - MEM_freeN(texels); - MEM_freeN(data); - - return tex; -} -#endif /* XXX TODO define all shared resources in a shared place without duplication */ struct GPUTexture *EEVEE_materials_get_util_tex(void) { return e_data.util_tex; } -static char *eevee_get_defines(int options) -{ - char *str = NULL; - - DynStr *ds = BLI_dynstr_new(); - BLI_dynstr_append(ds, SHADER_DEFINES); - - if ((options & VAR_MAT_MESH) != 0) { - BLI_dynstr_append(ds, "#define MESH_SHADER\n"); - } - if ((options & VAR_MAT_HAIR) != 0) { - BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); - } - if ((options & VAR_MAT_PROBE) != 0) { - BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n"); - } - if ((options & VAR_MAT_CLIP) != 0) { - BLI_dynstr_append(ds, "#define USE_ALPHA_CLIP\n"); - } - if ((options & VAR_MAT_SHADOW) != 0) { - BLI_dynstr_append(ds, "#define SHADOW_SHADER\n"); - } - if ((options & VAR_MAT_HASH) != 0) { - BLI_dynstr_append(ds, "#define USE_ALPHA_HASH\n"); - } - if ((options & VAR_MAT_BLEND) != 0) { - BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND\n"); - } - if ((options & VAR_MAT_MULT) != 0) { - BLI_dynstr_append(ds, "#define USE_MULTIPLY\n"); - } - if ((options & VAR_MAT_REFRACT) != 0) { - BLI_dynstr_append(ds, "#define USE_REFRACTION\n"); - } - if ((options & VAR_MAT_LOOKDEV) != 0) { - BLI_dynstr_append(ds, "#define LOOKDEV\n"); - } - if ((options & VAR_MAT_HOLDOUT) != 0) { - BLI_dynstr_append(ds, "#define HOLDOUT\n"); - } - - str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - return str; -} - -static char *eevee_get_volume_defines(int options) -{ - char *str = NULL; - - DynStr *ds = BLI_dynstr_new(); - BLI_dynstr_append(ds, SHADER_DEFINES); - BLI_dynstr_append(ds, "#define VOLUMETRICS\n"); - - if ((options & VAR_MAT_VOLUME) != 0) { - BLI_dynstr_append(ds, "#define MESH_SHADER\n"); - } - - str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - return str; -} - -/* Get the default render pass ubo. This is a ubo that enables all bsdf render passes. */ -struct GPUUniformBuffer *EEVEE_material_default_render_pass_ubo_get(EEVEE_ViewLayerData *sldata) -{ - return sldata->renderpass_ubo[0]; -} - -/* Get the render pass ubo for rendering the given render_pass. */ -static struct GPUUniformBuffer *get_render_pass_ubo(EEVEE_ViewLayerData *sldata, - eViewLayerEEVEEPassType render_pass) -{ - int index; - switch (render_pass) { - case EEVEE_RENDER_PASS_DIFFUSE_COLOR: - index = 1; - break; - case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: - index = 2; - break; - case EEVEE_RENDER_PASS_SPECULAR_COLOR: - index = 3; - break; - case EEVEE_RENDER_PASS_SPECULAR_LIGHT: - index = 4; - break; - case EEVEE_RENDER_PASS_EMIT: - index = 5; - break; - default: - index = 0; - break; - } - return sldata->renderpass_ubo[index]; -} /** * ssr_id can be null to disable ssr contribution. */ -static void add_standard_uniforms(DRWShadingGroup *shgrp, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - int *ssr_id, - float *refract_depth, - bool use_diffuse, - bool use_glossy, - bool use_refract, - bool use_ssrefraction, - bool use_alpha_blend, - eViewLayerEEVEEPassType render_pass) +void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, + GPUMaterial *gpumat, + EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + int *ssr_id, + float *refract_depth, + bool use_ssrefraction, + bool use_alpha_blend) { + bool use_diffuse = GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE); + bool use_glossy = GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY); + bool use_refract = GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT); + LightCache *lcache = vedata->stl->g_data->light_cache; EEVEE_EffectsInfo *effects = vedata->stl->effects; + EEVEE_PrivateData *pd = vedata->stl->g_data; DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); @@ -428,11 +133,11 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(shgrp, "renderpass_block", get_render_pass_ubo(sldata, render_pass)); + DRW_shgroup_uniform_block_ref(shgrp, "renderpass_block", &pd->renderpass_ubo); DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1); + DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); if (use_diffuse || use_glossy || use_refract) { - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool); DRW_shgroup_uniform_texture_ref(shgrp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); DRW_shgroup_uniform_texture_ref(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); @@ -463,36 +168,6 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, } } -/* Add the uniforms for the background shader to `shgrp`. */ -static void add_background_uniforms(DRWShadingGroup *shgrp, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata) -{ - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - DRW_shgroup_uniform_float(shgrp, "backgroundAlpha", &stl->g_data->background_alpha, 1); - /* TODO (fclem): remove those (need to clean the GLSL files). */ - DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); -} - -static void create_default_shader(int options) -{ - char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_default_frag_glsl); - - char *defines = eevee_get_defines(options); - - e_data.default_lit[options] = DRW_shader_create(e_data.vert_shader_str, NULL, frag_str, defines); - - MEM_freeN(defines); - MEM_freeN(frag_str); -} - static void eevee_init_noise_texture(void) { e_data.noise_tex = DRW_texture_create_2d(64, 64, GPU_RGBA16F, 0, (float *)blue_noise); @@ -559,8 +234,6 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const d e_data.noise_offsets[1] = offsets[1]; e_data.noise_offsets[2] = offsets[2]; - /* Attach & detach because we don't currently support multiple FB per texture, - * and this would be the case for multiple viewport. */ GPU_framebuffer_bind(fbl->update_noise_fb); DRW_draw_pass(psl->update_noise_pass); } @@ -606,94 +279,15 @@ void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_vi } void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) { const DRWContextState *draw_ctx = DRW_context_state_get(); EEVEE_PrivateData *g_data = stl->g_data; - if (!e_data.frag_shader_lib) { - /* Shaders */ - e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_common_uniforms_lib_glsl, - datatoc_bsdf_common_lib_glsl, - datatoc_bsdf_sampling_lib_glsl, - datatoc_ambient_occlusion_lib_glsl, - datatoc_raytrace_lib_glsl, - datatoc_ssr_lib_glsl, - datatoc_octahedron_lib_glsl, - datatoc_cubemap_lib_glsl, - datatoc_irradiance_lib_glsl, - datatoc_lightprobe_lib_glsl, - datatoc_ltc_lib_glsl, - datatoc_lights_lib_glsl, - /* Add one for each Closure */ - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_volumetric_lib_glsl); - - e_data.volume_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_common_uniforms_lib_glsl, - datatoc_bsdf_common_lib_glsl, - datatoc_ambient_occlusion_lib_glsl, - datatoc_octahedron_lib_glsl, - datatoc_cubemap_lib_glsl, - datatoc_irradiance_lib_glsl, - datatoc_lightprobe_lib_glsl, - datatoc_ltc_lib_glsl, - datatoc_lights_lib_glsl, - datatoc_volumetric_lib_glsl, - datatoc_volumetric_frag_glsl); - - e_data.vert_shader_str = BLI_string_joinN( - datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl); - - e_data.vert_shadow_shader_str = BLI_string_joinN( - datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl); - - e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_background_vert_glsl); - - e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_volumetric_vert_glsl); - - e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_volumetric_geom_glsl); - - e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl, - NULL, - datatoc_default_world_frag_glsl, - datatoc_common_view_lib_glsl, - NULL); - - char *vert_str = BLI_string_joinN( - datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_prepass_vert_glsl); - - e_data.default_prepass_sh = DRW_shader_create(vert_str, NULL, datatoc_prepass_frag_glsl, NULL); - - e_data.default_prepass_clip_sh = DRW_shader_create( - vert_str, NULL, datatoc_prepass_frag_glsl, "#define CLIP_PLANES\n"); - - e_data.default_hair_prepass_sh = DRW_shader_create( - vert_str, NULL, datatoc_prepass_frag_glsl, "#define HAIR_SHADER\n"); - - e_data.default_hair_prepass_clip_sh = DRW_shader_create(vert_str, - NULL, - datatoc_prepass_frag_glsl, - "#define HAIR_SHADER\n" - "#define CLIP_PLANES\n"); - MEM_freeN(vert_str); - - e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL); + if (!e_data.util_tex) { + EEVEE_shaders_material_shaders_init(); eevee_init_util_texture(); eevee_init_noise_texture(); @@ -728,33 +322,36 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, { /* Create RenderPass UBO */ - if (sldata->renderpass_ubo[0] == NULL) { - /* EEVEE_RENDER_PASS_COMBINED */ - sldata->renderpass_data[0] = (const EEVEE_RenderPassData){ - true, true, true, true, true, false}; - /* EEVEE_RENDER_PASS_DIFFUSE_COLOR */ - sldata->renderpass_data[1] = (const EEVEE_RenderPassData){ - true, false, false, false, false, true}; - /* EEVEE_RENDER_PASS_DIFFUSE_LIGHT */ - sldata->renderpass_data[2] = (const EEVEE_RenderPassData){ - true, true, false, false, false, false}; - /* EEVEE_RENDER_PASS_SPECULAR_COLOR */ - sldata->renderpass_data[3] = (const EEVEE_RenderPassData){ - false, false, true, false, false, false}; - /* EEVEE_RENDER_PASS_SPECULAR_LIGHT */ - sldata->renderpass_data[4] = (const EEVEE_RenderPassData){ - false, false, true, true, false, false}; - /* EEVEE_RENDER_PASS_EMIT */ - sldata->renderpass_data[5] = (const EEVEE_RenderPassData){ - false, false, false, false, true, false}; - - for (int i = 0; i < MAX_MATERIAL_RENDER_PASSES_UBO; i++) { - sldata->renderpass_ubo[i] = DRW_uniformbuffer_create(sizeof(EEVEE_RenderPassData), - &sldata->renderpass_data[i]); - } + if (sldata->renderpass_ubo.combined == NULL) { + sldata->renderpass_ubo.combined = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){true, true, true, true, true, false}); + + sldata->renderpass_ubo.diff_color = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){true, false, false, false, false, true}); + + sldata->renderpass_ubo.diff_light = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){true, true, false, false, false, false}); + + sldata->renderpass_ubo.spec_color = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){false, false, true, false, false, false}); + + sldata->renderpass_ubo.spec_light = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){false, false, true, true, false, false}); + + sldata->renderpass_ubo.emit = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){false, false, false, false, true, false}); } - /* HACK: EEVEE_material_world_background_get can create a new context. This can only be + /* Used combined pass by default. */ + g_data->renderpass_ubo = sldata->renderpass_ubo.combined; + + /* HACK: EEVEE_material_get can create a new context. This can only be * done when there is no active framebuffer. We do this here otherwise * `EEVEE_renderpasses_output_init` will fail. It cannot be done in * `EEVEE_renderpasses_init` as the `e_data.vertcode` can be uninitialized. @@ -763,414 +360,12 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, struct Scene *scene = draw_ctx->scene; struct World *wo = scene->world; if (wo && wo->use_nodes) { - EEVEE_material_world_background_get(scene, wo); + EEVEE_material_get(vedata, scene, NULL, wo, VAR_WORLD_BACKGROUND); } } } } -struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, World *wo) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - const int options = VAR_WORLD_PROBE; - - GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, false); - if (mat != NULL) { - return mat; - } - return DRW_shader_create_from_world(scene, - wo, - engine, - options, - false, - e_data.vert_background_shader_str, - NULL, - e_data.frag_shader_lib, - SHADER_DEFINES "#define PROBE_CAPTURE\n", - false); -} - -struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, World *wo) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_WORLD_BACKGROUND; - - GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true); - if (mat != NULL) { - return mat; - } - return DRW_shader_create_from_world(scene, - wo, - engine, - options, - false, - e_data.vert_background_shader_str, - NULL, - e_data.frag_shader_lib, - SHADER_DEFINES "#define WORLD_BACKGROUND\n", - true); -} - -struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *wo) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_WORLD_VOLUME; - - GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true); - if (mat != NULL) { - return mat; - } - - char *defines = eevee_get_volume_defines(options); - - mat = DRW_shader_create_from_world(scene, - wo, - engine, - options, - true, - e_data.vert_volume_shader_str, - e_data.geom_volume_shader_str, - e_data.volume_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, - Material *ma, - EEVEE_Data *UNUSED(vedata), - bool use_blend, - bool use_refract) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND); - SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT); - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - e_data.vert_shader_str, - NULL, - e_data.frag_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_VOLUME; - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat != NULL) { - return mat; - } - - char *defines = eevee_get_volume_defines(options); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - true, - e_data.vert_volume_shader_str, - e_data.geom_volume_shader_str, - e_data.volume_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, - Material *ma, - bool use_hashed_alpha, - bool is_shadow) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, use_hashed_alpha, VAR_MAT_HASH); - SET_FLAG_FROM_TEST(options, !use_hashed_alpha, VAR_MAT_CLIP); - SET_FLAG_FROM_TEST(options, is_shadow, VAR_MAT_SHADOW); - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - (is_shadow) ? e_data.vert_shadow_shader_str : - e_data.vert_shader_str, - NULL, - frag_str, - defines, - true); - - MEM_freeN(frag_str); - MEM_freeN(defines); - - return mat; -} - -static struct GPUMaterial *EEVEE_material_hair_depth_get(struct Scene *scene, - Material *ma, - bool use_hashed_alpha, - bool is_shadow) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH | VAR_MAT_HAIR; - - SET_FLAG_FROM_TEST(options, use_hashed_alpha, VAR_MAT_HASH); - SET_FLAG_FROM_TEST(options, !use_hashed_alpha, VAR_MAT_CLIP); - SET_FLAG_FROM_TEST(options, is_shadow, VAR_MAT_SHADOW); - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - (is_shadow) ? e_data.vert_shadow_shader_str : - e_data.vert_shader_str, - NULL, - frag_str, - defines, - false); - - MEM_freeN(frag_str); - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH | VAR_MAT_HAIR; - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - e_data.vert_shader_str, - NULL, - e_data.frag_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -/** - * Create a default shading group inside the given pass. - */ -static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - DRWPass *pass, - bool is_hair, - bool use_blend, - bool use_ssr) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR); - SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - true, - true, - false, - false, - use_blend, - DEFAULT_RENDER_PASS_FLAG); - - return shgrp; -} - -/** - * Create a default shading group inside the default pass without standard uniforms. - */ -static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - Object *ob, - ParticleSystem *psys, - ModifierData *md, - bool is_hair, - bool holdout, - bool use_ssr) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH; - - EEVEE_PassList *psl = vedata->psl; - - BLI_assert(!is_hair || (ob && ((psys && md) || ob->type == OB_HAIR))); - - SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR); - SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - if (psl->default_pass[options] == NULL) { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->default_pass[options], state); - - /* XXX / WATCH: This creates non persistent binds for the ubos and textures. - * But it's currently OK because the following shgroups does not add any bind. - * EDIT: THIS IS NOT THE CASE FOR HAIRS !!! DUMMY!!! */ - if (!is_hair) { - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], - psl->default_pass[options]); - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - } - } - - if (is_hair) { - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( - ob, psys, md, vedata->psl->default_pass[options], e_data.default_lit[options]); - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - return shgrp; - } - else { - return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); - } -} - -static struct DRWShadingGroup *EEVEE_default_render_pass_shading_group_get( - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - bool holdout, - bool use_ssr, - DRWPass *pass, - eViewLayerEEVEEPassType render_pass_flag) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); - add_standard_uniforms( - shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false, render_pass_flag); - return shgrp; -} - -static struct DRWShadingGroup *EEVEE_default_hair_render_pass_shading_group_get( - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - Object *ob, - ParticleSystem *psys, - ModifierData *md, - bool holdout, - bool use_ssr, - DRWPass *pass, - eViewLayerEEVEEPassType render_pass_flag) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH | VAR_MAT_HAIR; - - BLI_assert((ob && psys && md)); - - SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( - ob, psys, md, pass, e_data.default_lit[options]); - add_standard_uniforms( - shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false, render_pass_flag); - return shgrp; -} - void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; @@ -1180,10 +375,17 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* Create Material Ghash */ { stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash"); + + if (sldata->material_cache == NULL) { + sldata->material_cache = BLI_memblock_create(sizeof(EeveeMaterialCache)); + } + else { + BLI_memblock_clear(sldata->material_cache, NULL); + } } { - DRW_PASS_CREATE(psl->background_pass, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + DRW_PASS_CREATE(psl->background_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = NULL; @@ -1191,485 +393,297 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) Scene *scene = draw_ctx->scene; World *wo = scene->world; - const float *col = G_draw.block.colorBackground; - - EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->background_pass, wo, NULL); + EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->background_ps, wo, NULL); if (!grp && wo) { - col = &wo->horr; - - if (wo->use_nodes && wo->nodetree) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo); - - switch (GPU_material_status(gpumat)) { - case GPU_MAT_SUCCESS: - grp = DRW_shgroup_material_create(gpumat, psl->background_pass); - add_background_uniforms(grp, sldata, vedata); - DRW_shgroup_call(grp, geom, NULL); - break; - case GPU_MAT_QUEUED: - /* TODO Bypass probe compilation. */ - stl->g_data->queued_shaders_count++; - col = compile_col; - break; - case GPU_MAT_FAILED: - default: - col = error_col; - break; - } - } + struct GPUMaterial *gpumat = EEVEE_material_get( + vedata, scene, NULL, wo, VAR_WORLD_BACKGROUND); + + grp = DRW_shgroup_material_create(gpumat, psl->background_ps); + DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); + /* TODO (fclem): remove those (need to clean the GLSL files). */ + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_call(grp, geom, NULL); } /* Fallback if shader fails or if not using nodetree. */ if (grp == NULL) { - grp = DRW_shgroup_create(e_data.default_background, psl->background_pass); - DRW_shgroup_uniform_vec3(grp, "color", col, 1); + GPUShader *sh = EEVEE_shaders_default_background_sh_get(); + grp = DRW_shgroup_create(sh, psl->background_ps); + DRW_shgroup_uniform_vec3(grp, "color", G_draw.block.colorBackground, 1); DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); DRW_shgroup_call(grp, geom, NULL); } } - { - DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRW_PASS_CREATE(psl->depth_pass, state); - stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, psl->depth_pass); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->depth_pass_cull, state); - stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh, - psl->depth_pass_cull); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->depth_pass_clip, state); - stl->g_data->depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, - psl->depth_pass_clip); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->depth_pass_clip_cull, state); - stl->g_data->depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_clip_sh, - psl->depth_pass_clip_cull); - } +#define EEVEE_PASS_CREATE(pass, state) \ + do { \ + DRW_PASS_CREATE(psl->pass##_ps, state); \ + DRW_PASS_CREATE(psl->pass##_cull_ps, state | DRW_STATE_CULL_BACK); \ + DRW_pass_link(psl->pass##_ps, psl->pass##_cull_ps); \ + } while (0) - { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->material_pass, state); - DRW_PASS_CREATE(psl->material_pass_cull, state | DRW_STATE_CULL_BACK); - } +#define EEVEE_CLIP_PASS_CREATE(pass, state) \ + do { \ + DRWState st = state | DRW_STATE_CLIP_PLANES; \ + DRW_PASS_INSTANCE_CREATE(psl->pass##_clip_ps, psl->pass##_ps, st); \ + DRW_PASS_INSTANCE_CREATE( \ + psl->pass##_clip_cull_ps, psl->pass##_cull_ps, st | DRW_STATE_CULL_BACK); \ + DRW_pass_link(psl->pass##_clip_ps, psl->pass##_clip_cull_ps); \ + } while (0) { - DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRW_PASS_CREATE(psl->refract_depth_pass, state); - stl->g_data->refract_depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, - psl->refract_depth_pass); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->refract_depth_pass_cull, state); - stl->g_data->refract_depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh, - psl->refract_depth_pass_cull); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->refract_depth_pass_clip, state); - stl->g_data->refract_depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, - psl->refract_depth_pass_clip); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->refract_depth_pass_clip_cull, state); - stl->g_data->refract_depth_shgrp_clip_cull = DRW_shgroup_create( - e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip_cull); - } + DRWState state_depth = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + DRWState state_shading = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; + DRWState state_sss = DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; - { - DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES); - DRW_PASS_CREATE(psl->refract_pass, state); - } + EEVEE_PASS_CREATE(depth, state_depth); + EEVEE_CLIP_PASS_CREATE(depth, state_depth); - { - DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS); - DRW_PASS_CREATE(psl->sss_pass, state); - DRW_PASS_CREATE(psl->sss_pass_cull, state | DRW_STATE_CULL_BACK); - e_data.sss_count = 0; + EEVEE_PASS_CREATE(depth_refract, state_depth); + EEVEE_CLIP_PASS_CREATE(depth_refract, state_depth); + + EEVEE_PASS_CREATE(material, state_shading); + EEVEE_PASS_CREATE(material_refract, state_shading); + EEVEE_PASS_CREATE(material_sss, state_shading | state_sss); } + { + /* Renderpass accumulation. */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ADD_FULL; + /* Create an instance of each of theses passes and link them together. */ + DRWPass *passes[] = { + psl->material_ps, + psl->material_cull_ps, + psl->material_sss_ps, + psl->material_sss_cull_ps, + }; + DRWPass *first = NULL, *last = NULL; + for (int i = 0; i < ARRAY_SIZE(passes); i++) { + DRWPass *pass = DRW_pass_create_instance("Renderpass Accumulation", passes[i], state); + if (first == NULL) { + first = last = pass; + } + else { + DRW_pass_link(last, pass); + last = pass; + } + } + psl->material_accum_ps = first; + /* Same for background */ + DRW_PASS_INSTANCE_CREATE(psl->background_accum_ps, psl->background_ps, state); + } { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; DRW_PASS_CREATE(psl->transparent_pass, state); } - { DRW_PASS_CREATE(psl->update_noise_pass, DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.update_noise_sh, psl->update_noise_pass); + GPUShader *sh = EEVEE_shaders_update_noise_sh_get(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->update_noise_pass); DRW_shgroup_uniform_texture(grp, "blueNoise", e_data.noise_tex); DRW_shgroup_uniform_vec3(grp, "offsets", e_data.noise_offsets, 1); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } +} - if (eevee_hdri_preview_overlay_enabled(draw_ctx->v3d)) { - DRWShadingGroup *shgrp; - - struct GPUBatch *sphere = DRW_cache_sphere_get(); - static float color_chrome[3] = {1.0f, 1.0f, 1.0f}; - static float color_diffuse[3] = {0.8f, 0.8f, 0.8f}; - int options = VAR_MAT_MESH | VAR_MAT_LOOKDEV; +BLI_INLINE void material_shadow(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Material *ma, + bool is_hair, + EeveeMaterialCache *emc) +{ + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_PassList *psl = vedata->psl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); + if (ma->blend_shadow != MA_BS_NONE) { + /* Shadow Pass */ + const bool use_shadow_shader = ma->use_nodes && ma->nodetree && + ELEM(ma->blend_shadow, MA_BS_CLIP, MA_BS_HASHED); + int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH; + SET_FLAG_FROM_TEST(mat_options, use_shadow_shader, VAR_MAT_HASH); + SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR); + GPUMaterial *gpumat = (use_shadow_shader) ? + EEVEE_material_get(vedata, scene, ma, NULL, mat_options) : + EEVEE_material_default_get(scene, ma, mat_options); + + /* Avoid possible confusion with depth pre-pass options. */ + int option = KEY_SHADOW; + SET_FLAG_FROM_TEST(option, is_hair, KEY_HAIR); + + /* Search for the same shaders usage in the pass. */ + struct GPUShader *sh = GPU_material_get_shader(gpumat); + void *cache_key = (char *)sh + option; + DRWShadingGroup *grp, **grp_p; + + if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) { + /* This GPUShader has already been used by another material. + * Add new shading group just after to avoid shader switching cost. */ + grp = DRW_shgroup_create_sub(*grp_p); + } + else { + *grp_p = grp = DRW_shgroup_create(sh, psl->shadow_pass); + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false); } - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | - DRW_STATE_CULL_BACK; - - DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state); - shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_diffuse_pass); - add_standard_uniforms(shgrp, - sldata, - vedata, - NULL, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_diffuse, 1); - DRW_shgroup_uniform_float_copy(shgrp, "metallic", 0.0f); - DRW_shgroup_uniform_float_copy(shgrp, "specular", 0.5f); - DRW_shgroup_uniform_float_copy(shgrp, "roughness", 1.0f); - DRW_shgroup_call(shgrp, sphere, NULL); - - DRW_PASS_CREATE(psl->lookdev_glossy_pass, state); - shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_glossy_pass); - add_standard_uniforms(shgrp, - sldata, - vedata, - NULL, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_chrome, 1); - DRW_shgroup_uniform_float_copy(shgrp, "metallic", 1.0f); - DRW_shgroup_uniform_float_copy(shgrp, "roughness", 0.0f); - DRW_shgroup_call(shgrp, sphere, NULL); - } + DRW_shgroup_add_material_resources(grp, gpumat); - { - memset(psl->material_accum_pass, 0, sizeof(psl->material_accum_pass)); - for (int pass_index = 0; pass_index < stl->g_data->render_passes_material_count; - pass_index++) { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ADD_FULL; - DRW_PASS_CREATE(psl->material_accum_pass[pass_index], state); - } + emc->shadow_grp = grp; + emc->shadow_grp_p = grp_p; + } + else { + emc->shadow_grp = NULL; + emc->shadow_grp_p = NULL; } } -#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ - do { \ - if (oedata) { \ - DRW_shgroup_call_with_callback(shgrp, geom, ob, oedata); \ - } \ - else { \ - DRW_shgroup_call(shgrp, geom, ob); \ - } \ - } while (0) - -#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom, oedata) \ - do { \ - if (shgrp) { \ - ADD_SHGROUP_CALL(shgrp, ob, geom, oedata); \ - } \ - } while (0) - -typedef struct EeveeMaterialShadingGroups { - struct DRWShadingGroup *shading_grp; - struct DRWShadingGroup *depth_grp; - struct DRWShadingGroup *depth_clip_grp; - struct DRWShadingGroup *material_accum_grp[MAX_MATERIAL_RENDER_PASSES]; -} EeveeMaterialShadingGroups; - -static void material_opaque(Material *ma, - GHash *material_hash, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - struct GPUMaterial **gpumat, - struct GPUMaterial **gpumat_depth, - struct EeveeMaterialShadingGroups *shgrps, - bool holdout) +static EeveeMaterialCache material_opaque(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Material *ma, + const bool is_hair) { EEVEE_EffectsInfo *effects = vedata->stl->effects; + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_PassList *psl = vedata->psl; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - bool use_diffuse, use_glossy, use_refract; - bool store_material = true; - float *color_p = &ma->r; - float *metal_p = &ma->metallic; - float *spec_p = &ma->spec; - float *rough_p = &ma->roughness; - const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; - const bool use_gpumat = (ma->use_nodes && ma->nodetree && !holdout); + const bool do_cull = !is_hair && (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; + const bool use_gpumat = (ma->use_nodes && ma->nodetree); const bool use_ssrefract = use_gpumat && ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && ((effects->enabled_effects & EFFECT_REFRACT) != 0); - const bool use_translucency = ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0); + const bool use_depth_shader = use_gpumat && ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED); - EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma); - - if (emsg) { - memcpy(shgrps, emsg, sizeof(EeveeMaterialShadingGroups)); - - /* This will have been created already, just perform a lookup. */ - *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract) : - NULL; - *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get( - scene, ma, (ma->blend_method == MA_BM_HASHED), false) : - NULL; - return; + /* HACK: Assume the struct will never be smaller than our variations. + * This allow us to only keep one ghash and avoid bigger keys comparisons/hashing. */ + void *key = (char *)ma + is_hair; + /* Search for other material instances (sharing the same Material data-block). */ + EeveeMaterialCache **emc_p, *emc; + if (BLI_ghash_ensure_p(pd->material_hash, key, (void ***)&emc_p)) { + return **emc_p; + } + else { + *emc_p = emc = BLI_memblock_alloc(sldata->material_cache); } - emsg = MEM_callocN(sizeof(EeveeMaterialShadingGroups), "EeveeMaterialShadingGroups"); - if (use_gpumat) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - static float half = 0.5f; - - /* Shading */ - *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract); - - eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat); - - /* Alpha CLipped : Discard pixel from depth pass, then - * fail the depth test for shading. */ - if (ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED)) { - *gpumat_depth = EEVEE_material_mesh_depth_get( - scene, ma, (ma->blend_method == MA_BM_HASHED), false); + material_shadow(vedata, sldata, ma, is_hair, emc); - eGPUMaterialStatus status_mat_depth = GPU_material_status(*gpumat_depth); - if (status_mat_depth != GPU_MAT_SUCCESS) { - /* Mixing both flags. If depth shader fails, show it to the user by not using - * the surface shader. */ - status_mat_surface = status_mat_depth; - } - else if (use_ssrefract) { - emsg->depth_grp = DRW_shgroup_material_create( - *gpumat_depth, (do_cull) ? psl->refract_depth_pass_cull : psl->refract_depth_pass); - emsg->depth_clip_grp = DRW_shgroup_material_create( - *gpumat_depth, - (do_cull) ? psl->refract_depth_pass_clip_cull : psl->refract_depth_pass_clip); - } - else { - emsg->depth_grp = DRW_shgroup_material_create( - *gpumat_depth, (do_cull) ? psl->depth_pass_cull : psl->depth_pass); - emsg->depth_clip_grp = DRW_shgroup_material_create( - *gpumat_depth, (do_cull) ? psl->depth_pass_clip_cull : psl->depth_pass_clip); - } - - if (emsg->depth_grp != NULL) { - use_diffuse = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_DIFFUSE); - use_glossy = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_GLOSSY); - use_refract = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_REFRACT); - - add_standard_uniforms(emsg->depth_grp, - sldata, - vedata, - NULL, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - add_standard_uniforms(emsg->depth_clip_grp, - sldata, - vedata, - NULL, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - - if (ma->blend_method == MA_BM_CLIP) { - DRW_shgroup_uniform_float(emsg->depth_grp, "alphaThreshold", &ma->alpha_threshold, 1); - DRW_shgroup_uniform_float( - emsg->depth_clip_grp, "alphaThreshold", &ma->alpha_threshold, 1); - } - } + { + /* Depth Pass */ + int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH; + SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT); + SET_FLAG_FROM_TEST(mat_options, use_depth_shader, VAR_MAT_HASH); + SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR); + GPUMaterial *gpumat = (use_depth_shader) ? + EEVEE_material_get(vedata, scene, ma, NULL, mat_options) : + EEVEE_material_default_get(scene, ma, mat_options); + + int option = 0; + SET_FLAG_FROM_TEST(option, do_cull, KEY_CULL); + SET_FLAG_FROM_TEST(option, use_ssrefract, KEY_REFRACT); + DRWPass *depth_ps = (DRWPass *[]){ + psl->depth_ps, + psl->depth_cull_ps, + psl->depth_refract_ps, + psl->depth_refract_cull_ps, + }[option]; + /* Hair are rendered inside the non-cull pass but needs to have a separate cache key. */ + SET_FLAG_FROM_TEST(option, is_hair, KEY_HAIR); + + /* Search for the same shaders usage in the pass. */ + struct GPUShader *sh = GPU_material_get_shader(gpumat); + void *cache_key = (char *)sh + option; + DRWShadingGroup *grp, **grp_p; + + if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) { + /* This GPUShader has already been used by another material. + * Add new shading group just after to avoid shader switching cost. */ + grp = DRW_shgroup_create_sub(*grp_p); } - - switch (status_mat_surface) { - case GPU_MAT_SUCCESS: { - static int no_ssr = 0; - static int first_ssr = 1; - int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ? - &first_ssr : - &no_ssr; - const bool use_sss = GPU_material_flag_get(*gpumat, GPU_MATFLAG_SSS); - use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE); - use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY); - use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT); - - emsg->shading_grp = DRW_shgroup_material_create( - *gpumat, - (use_ssrefract) ? - psl->refract_pass : - (use_sss) ? ((do_cull) ? psl->sss_pass_cull : psl->sss_pass) : - ((do_cull) ? psl->material_pass_cull : psl->material_pass)); - - add_standard_uniforms(emsg->shading_grp, - sldata, - vedata, - ssr_id, - &ma->refract_depth, - use_diffuse, - use_glossy, - use_refract, - use_ssrefract, - false, - DEFAULT_RENDER_PASS_FLAG); - - if (use_sss) { - struct GPUTexture *sss_tex_profile = NULL; - struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get( - *gpumat, stl->effects->sss_sample_count, &sss_tex_profile); - - if (sss_profile) { - /* Limit of 8 bit stencil buffer. ID 255 is refraction. */ - if (e_data.sss_count < 254) { - int sss_id = e_data.sss_count + 1; - DRW_shgroup_stencil_mask(emsg->shading_grp, sss_id); - EEVEE_subsurface_add_pass(sldata, vedata, sss_id, sss_profile); - if (use_translucency) { - EEVEE_subsurface_translucency_add_pass( - sldata, vedata, sss_id, sss_profile, sss_tex_profile); - } - e_data.sss_count++; - } - else { - /* TODO : display message. */ - printf("Error: Too many different Subsurface shader in the scene.\n"); - } - } - } - - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - emsg->material_accum_grp[render_pass_index] = DRW_shgroup_material_create( - *gpumat, psl->material_accum_pass[render_pass_index]); - add_standard_uniforms(emsg->material_accum_grp[render_pass_index], - sldata, - vedata, - ssr_id, - &ma->refract_depth, - use_diffuse, - use_glossy, - use_refract, - use_ssrefract, - false, - render_pass_flag); - } - RENDER_PASS_ITER_END(render_pass_index); - - break; - } - case GPU_MAT_QUEUED: { - stl->g_data->queued_shaders_count++; - color_p = compile_col; - metal_p = spec_p = rough_p = ½ - store_material = false; - break; - } - case GPU_MAT_FAILED: - default: - color_p = error_col; - metal_p = spec_p = rough_p = ½ - break; + else { + *grp_p = grp = DRW_shgroup_create(sh, depth_ps); + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false); } - } - /* Fallback to default shader */ - if (emsg->shading_grp == NULL) { - bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0); - emsg->shading_grp = EEVEE_default_shading_group_get( - sldata, vedata, NULL, NULL, NULL, false, holdout, use_ssr); - DRW_shgroup_uniform_vec3(emsg->shading_grp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(emsg->shading_grp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(emsg->shading_grp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(emsg->shading_grp, "roughness", rough_p, 1); - - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - DRWShadingGroup *shgrp = EEVEE_default_render_pass_shading_group_get( - sldata, - vedata, - holdout, - use_ssr, - psl->material_accum_pass[render_pass_index], - render_pass_flag); - - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - emsg->material_accum_grp[render_pass_index] = shgrp; - } - RENDER_PASS_ITER_END(render_pass_index); - } + DRW_shgroup_add_material_resources(grp, gpumat); - /* Fallback default depth prepass */ - if (emsg->depth_grp == NULL) { - if (use_ssrefract) { - emsg->depth_grp = (do_cull) ? stl->g_data->refract_depth_shgrp_cull : - stl->g_data->refract_depth_shgrp; - emsg->depth_clip_grp = (do_cull) ? stl->g_data->refract_depth_shgrp_clip_cull : - stl->g_data->refract_depth_shgrp_clip; + emc->depth_grp = grp; + emc->depth_grp_p = grp_p; + } + { + /* Shading Pass */ + int mat_options = VAR_MAT_MESH; + SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT); + SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR); + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); + const bool use_sss = GPU_material_flag_get(gpumat, GPU_MATFLAG_SSS); + + int ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ? 1 : 0; + int option = (use_ssrefract ? 0 : (use_sss ? 1 : 2)) * 2 + do_cull; + DRWPass *shading_pass = (DRWPass *[]){ + psl->material_refract_ps, + psl->material_refract_cull_ps, + psl->material_sss_ps, + psl->material_sss_cull_ps, + psl->material_ps, + psl->material_cull_ps, + }[option]; + /* Hair are rendered inside the non-cull pass but needs to have a separate cache key */ + option = option * 2 + is_hair; + + /* Search for the same shaders usage in the pass. */ + /* HACK: Assume the struct will never be smaller than our variations. + * This allow us to only keep one ghash and avoid bigger keys comparisons/hashing. */ + BLI_assert(option <= 16); + struct GPUShader *sh = GPU_material_get_shader(gpumat); + void *cache_key = (char *)sh + option; + DRWShadingGroup *grp, **grp_p; + + if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) { + /* This GPUShader has already been used by another material. + * Add new shading group just after to avoid shader switching cost. */ + grp = DRW_shgroup_create_sub(*grp_p); } else { - emsg->depth_grp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp; - emsg->depth_clip_grp = (do_cull) ? stl->g_data->depth_shgrp_clip_cull : - stl->g_data->depth_shgrp_clip; + *grp_p = grp = DRW_shgroup_create(sh, shading_pass); + EEVEE_material_bind_resources( + grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, false); } - } + DRW_shgroup_add_material_resources(grp, gpumat); - memcpy(shgrps, emsg, sizeof(EeveeMaterialShadingGroups)); - if (store_material) { - BLI_ghash_insert(material_hash, ma, emsg); - } - else { - MEM_freeN(emsg); + if (use_sss) { + EEVEE_subsurface_add_pass(sldata, vedata, ma, grp, gpumat); + } + + emc->shading_grp = grp; + emc->shading_grp_p = grp_p; + emc->shading_gpumat = gpumat; } + return *emc; } -static void material_transparent(Material *ma, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - struct GPUMaterial **gpumat, - struct EeveeMaterialShadingGroups *shgrps) +static EeveeMaterialCache material_transparent(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Material *ma) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; + EeveeMaterialCache emc = {0}; const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; const bool use_gpumat = ma->use_nodes && ma->nodetree; const bool use_ssrefract = use_gpumat && ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && - ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0); - const float *color_p = &ma->r; - const float *metal_p = &ma->metallic; - const float *spec_p = &ma->spec; - const float *rough_p = &ma->roughness; - + ((effects->enabled_effects & EFFECT_REFRACT) != 0); const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0); DRWState cur_state; @@ -1677,81 +691,53 @@ static void material_transparent(Material *ma, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_CUSTOM); - /* Depth prepass */ + material_shadow(vedata, sldata, ma, false, &emc); + if (use_prepass) { - shgrps->depth_grp = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass); + /* Depth prepass */ + int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH; + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); + struct GPUShader *sh = GPU_material_get_shader(gpumat); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->transparent_pass); + + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, true); + DRW_shgroup_add_material_resources(grp, gpumat); cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; - DRW_shgroup_state_disable(shgrps->depth_grp, all_state); - DRW_shgroup_state_enable(shgrps->depth_grp, cur_state); + DRW_shgroup_state_disable(grp, all_state); + DRW_shgroup_state_enable(grp, cur_state); + + emc.depth_grp = grp; } + { + /* Shading */ + int ssr_id = -1; /* TODO transparent SSR */ + int mat_options = VAR_MAT_MESH | VAR_MAT_BLEND; + SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT); + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); - if (use_gpumat) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - static float half = 0.5f; + DRWShadingGroup *grp = DRW_shgroup_create(GPU_material_get_shader(gpumat), + psl->transparent_pass); - /* Shading */ - *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, use_ssrefract); - - switch (GPU_material_status(*gpumat)) { - case GPU_MAT_SUCCESS: { - static int ssr_id = -1; /* TODO transparent SSR */ - - shgrps->shading_grp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); - - bool use_blend = true; - bool use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE); - bool use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY); - bool use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT); - - add_standard_uniforms(shgrps->shading_grp, - sldata, - vedata, - &ssr_id, - &ma->refract_depth, - use_diffuse, - use_glossy, - use_refract, - use_ssrefract, - use_blend, - DEFAULT_RENDER_PASS_FLAG); - break; - } - case GPU_MAT_QUEUED: { - /* TODO Bypass probe compilation. */ - stl->g_data->queued_shaders_count++; - color_p = compile_col; - metal_p = spec_p = rough_p = ½ - break; - } - case GPU_MAT_FAILED: - default: - color_p = error_col; - metal_p = spec_p = rough_p = ½ - break; - } - } + EEVEE_material_bind_resources( + grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, true); + DRW_shgroup_add_material_resources(grp, gpumat); - /* Fallback to default shader */ - if (shgrps->shading_grp == NULL) { - shgrps->shading_grp = EEVEE_default_shading_group_create( - sldata, vedata, psl->transparent_pass, false, true, false); - DRW_shgroup_uniform_vec3(shgrps->shading_grp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrps->shading_grp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrps->shading_grp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrps->shading_grp, "roughness", rough_p, 1); - } + cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; + cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL; + cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; - cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; - cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL; - cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; + /* Disable other blend modes and use the one we want. */ + DRW_shgroup_state_disable(grp, all_state); + DRW_shgroup_state_enable(grp, cur_state); - /* Disable other blend modes and use the one we want. */ - DRW_shgroup_state_disable(shgrps->shading_grp, all_state); - DRW_shgroup_state_enable(shgrps->shading_grp, cur_state); + emc.shading_grp = grp; + emc.shading_gpumat = gpumat; + } + return emc; } /* Return correct material or empty default material if slot is empty. */ @@ -1766,12 +752,35 @@ BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot, bool holdou ma = BKE_material_default_volume(); } else { - ma = BKE_material_default_empty(); + ma = BKE_material_default_surface(); } } return ma; } +BLI_INLINE EeveeMaterialCache eevee_material_cache_get( + EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, int slot, bool is_hair) +{ + const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0; + EeveeMaterialCache matcache; + Material *ma = eevee_object_material_get(ob, slot, holdout); + switch (ma->blend_method) { + case MA_BM_BLEND: + if (!is_hair) { + matcache = material_transparent(vedata, sldata, ma); + break; + } + ATTR_FALLTHROUGH; + case MA_BM_SOLID: + case MA_BM_CLIP: + case MA_BM_HASHED: + default: + matcache = material_opaque(vedata, sldata, ma, is_hair); + break; + } + return matcache; +} + static void eevee_hair_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, @@ -1780,240 +789,49 @@ static void eevee_hair_cache_populate(EEVEE_Data *vedata, int matnr, bool *cast_shadow) { - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0; - - DRWShadingGroup *shgrp = NULL; - Material *ma = eevee_object_material_get(ob, matnr - 1, holdout); - const bool use_gpumat = ma->use_nodes && ma->nodetree && !holdout; - const bool use_alpha_hash = (ma->blend_method == MA_BM_HASHED); - const bool use_alpha_clip = (ma->blend_method == MA_BM_CLIP); - const bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0); + EeveeMaterialCache matcache = eevee_material_cache_get(vedata, sldata, ob, matnr - 1, true); - GPUMaterial *gpumat = use_gpumat ? EEVEE_material_hair_get(scene, ma) : NULL; - eGPUMaterialStatus status_mat_surface = gpumat ? GPU_material_status(gpumat) : GPU_MAT_SUCCESS; - - float *color_p = &ma->r; - float *metal_p = &ma->metallic; - float *spec_p = &ma->spec; - float *rough_p = &ma->roughness; - - /* Depth prepass. */ - if (use_gpumat && (use_alpha_clip || use_alpha_hash)) { - GPUMaterial *gpumat_depth = EEVEE_material_hair_depth_get(scene, ma, use_alpha_hash, false); - - eGPUMaterialStatus status_mat_depth = GPU_material_status(gpumat_depth); - - if (status_mat_depth != GPU_MAT_SUCCESS) { - /* Mixing both flags. If depth shader fails, show it to the user by not using - * the surface shader. */ - status_mat_surface = status_mat_depth; - } - else { - const bool use_diffuse = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_DIFFUSE); - const bool use_glossy = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_GLOSSY); - const bool use_refract = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_REFRACT); - - for (int i = 0; i < 2; i++) { - DRWPass *pass = (i == 0) ? psl->depth_pass : psl->depth_pass_clip; - - shgrp = DRW_shgroup_material_hair_create(ob, psys, md, pass, gpumat_depth); - - add_standard_uniforms(shgrp, - sldata, - vedata, - NULL, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - - /* Unfortunately needed for correctness but not 99% of the time not needed. - * TODO detect when needed? */ - DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - - if (use_alpha_clip) { - DRW_shgroup_uniform_float(shgrp, "alphaThreshold", &ma->alpha_threshold, 1); - } - } - } + if (matcache.depth_grp) { + *matcache.depth_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.depth_grp); } - - /* Fallback to default shader */ - if (shgrp == NULL) { - for (int i = 0; i < 2; i++) { - DRWPass *depth_pass = (i == 0) ? psl->depth_pass : psl->depth_pass_clip; - struct GPUShader *depth_sh = (i == 0) ? e_data.default_hair_prepass_sh : - e_data.default_hair_prepass_clip_sh; - DRW_shgroup_hair_create(ob, psys, md, depth_pass, depth_sh); - } + if (matcache.shading_grp) { + *matcache.shading_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shading_grp); } - - shgrp = NULL; - - if (gpumat) { - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - static float half = 0.5f; - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - - switch (status_mat_surface) { - case GPU_MAT_SUCCESS: { - bool use_diffuse = GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE); - bool use_glossy = GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY); - bool use_refract = GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT); - - shgrp = DRW_shgroup_material_hair_create(ob, psys, md, psl->material_pass, gpumat); - - if (!use_diffuse && !use_glossy && !use_refract) { - /* HACK: Small hack to avoid issue when utilTex is needed for - * world_normals_get and none of the bsdfs are present. - * This binds utilTex even if not needed. */ - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - } - - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - - /* Add the hair to all the render_passes that are enabled */ - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - shgrp = DRW_shgroup_material_hair_create( - ob, psys, md, psl->material_accum_pass[render_pass_index], gpumat); - if (!use_diffuse && !use_glossy && !use_refract) { - /* Small hack to avoid issue when utilTex is needed for - * world_normals_get and none of the bsdfs that need it are present. - * This binds `utilTex` even if not needed. */ - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - } - - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - render_pass_flag); - } - RENDER_PASS_ITER_END(render_pass_index); - - break; - } - case GPU_MAT_QUEUED: { - stl->g_data->queued_shaders_count++; - color_p = compile_col; - metal_p = spec_p = rough_p = ½ - break; - } - case GPU_MAT_FAILED: - default: - color_p = error_col; - metal_p = spec_p = rough_p = ½ - break; - } + if (matcache.shadow_grp) { + *matcache.shadow_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shadow_grp); + *cast_shadow = true; } +} - /* Fallback to default shader */ - if (shgrp == NULL) { - shgrp = EEVEE_default_shading_group_get(sldata, vedata, ob, psys, md, true, holdout, use_ssr); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - shgrp = EEVEE_default_hair_render_pass_shading_group_get( - sldata, - vedata, - ob, - psys, - md, - holdout, - use_ssr, - psl->material_accum_pass[render_pass_index], - render_pass_flag); - - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - } - RENDER_PASS_ITER_END(render_pass_index); - } +#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ + do { \ + if (oedata) { \ + DRW_shgroup_call_with_callback(shgrp, geom, ob, oedata); \ + } \ + else { \ + DRW_shgroup_call(shgrp, geom, ob); \ + } \ + } while (0) - /* Shadows */ - char blend_shadow = use_gpumat ? ma->blend_shadow : MA_BS_SOLID; - const bool shadow_alpha_hash = (blend_shadow == MA_BS_HASHED); - switch (blend_shadow) { - case MA_BS_SOLID: - DRW_shgroup_hair_create(ob, psys, md, psl->shadow_pass, e_data.default_hair_prepass_sh); - *cast_shadow = true; - break; - case MA_BS_CLIP: - case MA_BS_HASHED: - gpumat = EEVEE_material_hair_depth_get(scene, ma, shadow_alpha_hash, true); - shgrp = DRW_shgroup_material_hair_create(ob, psys, md, psl->shadow_pass, gpumat); - /* Unfortunately needed for correctness but not 99% of the time not needed. - * TODO detect when needed? */ - DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - - if (!shadow_alpha_hash) { - DRW_shgroup_uniform_float(shgrp, "alphaThreshold", &ma->alpha_threshold, 1); - } - *cast_shadow = true; - break; - case MA_BS_NONE: - default: - break; +#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom, oedata) \ + do { \ + if (shgrp) { \ + ADD_SHGROUP_CALL(shgrp, ob, geom, oedata); \ + } \ + } while (0) + +#define MATCACHE_AS_ARRAY(matcache, member, materials_len, output_array) \ + for (int i = 0; i < materials_len; i++) { \ + output_array[i] = matcache[i].member; \ } -} void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, bool *cast_shadow) { - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - GHash *material_hash = stl->g_data->material_hash; - const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0; bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && !DRW_state_is_image_render(); @@ -2022,139 +840,64 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { const int materials_len = DRW_cache_object_material_count_get(ob); - struct EeveeMaterialShadingGroups *shgrps_array = BLI_array_alloca(shgrps_array, - materials_len); - - struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - struct GPUMaterial **gpumat_depth_array = BLI_array_alloca(gpumat_array, materials_len); - struct Material **ma_array = BLI_array_alloca(ma_array, materials_len); - + EeveeMaterialCache *matcache = BLI_array_alloca(matcache, materials_len); for (int i = 0; i < materials_len; i++) { - ma_array[i] = eevee_object_material_get(ob, i, holdout); - memset(&shgrps_array[i], 0, sizeof(EeveeMaterialShadingGroups)); - gpumat_array[i] = NULL; - gpumat_depth_array[i] = NULL; - - switch (ma_array[i]->blend_method) { - case MA_BM_SOLID: - case MA_BM_CLIP: - case MA_BM_HASHED: - material_opaque(ma_array[i], - material_hash, - sldata, - vedata, - &gpumat_array[i], - &gpumat_depth_array[i], - &shgrps_array[i], - holdout); - break; - case MA_BM_BLEND: - material_transparent(ma_array[i], sldata, vedata, &gpumat_array[i], &shgrps_array[i]); - break; - default: - BLI_assert(0); - break; - } + matcache[i] = eevee_material_cache_get(vedata, sldata, ob, i, false); } /* Only support single volume material for now. */ /* XXX We rely on the previously compiled surface shader * to know if the material has a "volume nodetree". */ - bool use_volume_material = (gpumat_array[0] && - GPU_material_has_volume_output(gpumat_array[0])); + bool use_volume_material = (matcache[0].shading_gpumat && + GPU_material_has_volume_output(matcache[0].shading_gpumat)); if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) { - /* Get per-material split surface */ - struct GPUBatch **mat_geom = NULL; - - if (!use_sculpt_pbvh) { - mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); - } - if (use_sculpt_pbvh) { - struct DRWShadingGroup **sculpt_shgrps_array = BLI_array_alloca(sculpt_shgrps_array, - materials_len); - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].shading_grp; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); + struct DRWShadingGroup **shgrps_array = BLI_array_alloca(shgrps_array, materials_len); - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].depth_grp; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].depth_clip_grp; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); + MATCACHE_AS_ARRAY(matcache, shading_grp, materials_len, shgrps_array); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); - for (int renderpass_index = 0; - renderpass_index < stl->g_data->render_passes_material_count; - renderpass_index++) { - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].material_accum_grp[renderpass_index]; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); - } + MATCACHE_AS_ARRAY(matcache, depth_grp, materials_len, shgrps_array); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); - /* TODO(fclem): Support shadows in sculpt mode. */ + MATCACHE_AS_ARRAY(matcache, shadow_grp, materials_len, shgrps_array); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); } - else if (mat_geom) { - for (int i = 0; i < materials_len; i++) { - if (mat_geom[i] == NULL) { - continue; - } + else { + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + MATCACHE_AS_ARRAY(matcache, shading_gpumat, materials_len, gpumat_array); + /* Get per-material split surface */ + struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get( + ob, gpumat_array, materials_len); - /* Do not render surface if we are rendering a volume object - * and do not have a surface closure. */ - if (use_volume_material && - (gpumat_array[i] && !GPU_material_has_surface_output(gpumat_array[i]))) { - continue; - } + if (mat_geom) { + for (int i = 0; i < materials_len; i++) { + if (mat_geom[i] == NULL) { + continue; + } - /* XXX TODO rewrite this to include the dupli objects. - * This means we cannot exclude dupli objects from reflections!!! */ - EEVEE_ObjectEngineData *oedata = NULL; - if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { - oedata = EEVEE_object_data_ensure(ob); - oedata->ob = ob; - oedata->test_data = &sldata->probes->vis_data; - } - EeveeMaterialShadingGroups *shgrps = &shgrps_array[i]; - ADD_SHGROUP_CALL(shgrps->shading_grp, ob, mat_geom[i], oedata); - ADD_SHGROUP_CALL_SAFE(shgrps->depth_grp, ob, mat_geom[i], oedata); - ADD_SHGROUP_CALL_SAFE(shgrps->depth_clip_grp, ob, mat_geom[i], oedata); - for (int renderpass_index = 0; - renderpass_index < stl->g_data->render_passes_material_count; - renderpass_index++) { - ADD_SHGROUP_CALL_SAFE( - shgrps->material_accum_grp[renderpass_index], ob, mat_geom[i], oedata); - } + /* Do not render surface if we are rendering a volume object + * and do not have a surface closure. */ + if (use_volume_material && + (gpumat_array[i] && !GPU_material_has_surface_output(gpumat_array[i]))) { + continue; + } + + /* XXX TODO rewrite this to include the dupli objects. + * This means we cannot exclude dupli objects from reflections!!! */ + EEVEE_ObjectEngineData *oedata = NULL; + if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { + oedata = EEVEE_object_data_ensure(ob); + oedata->ob = ob; + oedata->test_data = &sldata->probes->vis_data; + } - /* Shadow Pass */ - struct GPUMaterial *gpumat; - const bool use_gpumat = (ma_array[i]->use_nodes && ma_array[i]->nodetree); - char blend_shadow = use_gpumat ? ma_array[i]->blend_shadow : MA_BS_SOLID; - switch (blend_shadow) { - case MA_BS_SOLID: - EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob); - *cast_shadow = true; - break; - case MA_BS_CLIP: - gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true); - EEVEE_shadows_caster_material_add( - sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold); - *cast_shadow = true; - break; - case MA_BS_HASHED: - gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true); - EEVEE_shadows_caster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL); - *cast_shadow = true; - break; - case MA_BS_NONE: - default: - break; + ADD_SHGROUP_CALL(matcache[i].shading_grp, ob, mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(matcache[i].depth_grp, ob, mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(matcache[i].shadow_grp, ob, mat_geom[i], oedata); + *cast_shadow = (matcache[i].shadow_grp != NULL); } } } @@ -2205,11 +948,12 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata, void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_EffectsInfo *effects = vedata->stl->effects; - BLI_ghash_free(stl->g_data->material_hash, NULL, MEM_freeN); + BLI_ghash_free(pd->material_hash, NULL, NULL); - SET_FLAG_FROM_TEST(stl->effects->enabled_effects, e_data.sss_count > 0, EFFECT_SSS); + SET_FLAG_FROM_TEST(effects->enabled_effects, effects->sss_surface_count > 0, EFFECT_SSS); /* TODO(fclem) this is not really clean. Init should not be done in cache finish. */ EEVEE_subsurface_draw_init(sldata, vedata); @@ -2217,38 +961,10 @@ void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat void EEVEE_materials_free(void) { - for (int i = 0; i < VAR_MAT_MAX; i++) { - DRW_SHADER_FREE_SAFE(e_data.default_lit[i]); - } - MEM_SAFE_FREE(e_data.frag_shader_lib); - MEM_SAFE_FREE(e_data.vert_shader_str); - MEM_SAFE_FREE(e_data.vert_shadow_shader_str); - MEM_SAFE_FREE(e_data.vert_background_shader_str); - MEM_SAFE_FREE(e_data.vert_volume_shader_str); - MEM_SAFE_FREE(e_data.geom_volume_shader_str); - MEM_SAFE_FREE(e_data.volume_shader_lib); - DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh); - DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh); - DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh); - DRW_SHADER_FREE_SAFE(e_data.default_prepass_clip_sh); - DRW_SHADER_FREE_SAFE(e_data.default_background); - DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); DRW_TEXTURE_FREE_SAFE(e_data.util_tex); DRW_TEXTURE_FREE_SAFE(e_data.noise_tex); } -void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_PassList *psl) -{ - for (int i = 0; i < VAR_MAT_MAX; i++) { - if (psl->default_pass[i]) { - DRW_draw_pass(psl->default_pass[i]); - } - } - - DRW_draw_pass(psl->material_pass); - DRW_draw_pass(psl->material_pass_cull); -} - /* -------------------------------------------------------------------- */ /** \name Render Passes @@ -2256,172 +972,140 @@ void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Pass void EEVEE_material_renderpasses_init(EEVEE_Data *vedata) { - EEVEE_StorageList *stl = vedata->stl; - EEVEE_PrivateData *g_data = stl->g_data; + EEVEE_PrivateData *pd = vedata->stl->g_data; /* For diffuse and glossy we calculate the final light + color buffer where we extract the * light from by dividing by the color buffer. When one the light is requested we also tag * the color buffer to do the extraction. */ - if (g_data->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { - g_data->render_passes |= EEVEE_RENDER_PASS_DIFFUSE_COLOR; + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { + pd->render_passes |= EEVEE_RENDER_PASS_DIFFUSE_COLOR; } - if (g_data->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { - g_data->render_passes |= EEVEE_RENDER_PASS_SPECULAR_COLOR; + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { + pd->render_passes |= EEVEE_RENDER_PASS_SPECULAR_COLOR; } +} - /* Calculate the number of material based render passes */ - uint num_render_passes = count_bits_i(stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL); - if ((num_render_passes != 0 && stl->g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) == - 0) { - num_render_passes += 1; +static void material_renderpass_init(EEVEE_FramebufferList *fbl, + GPUTexture **output_tx, + const eGPUTextureFormat format, + const bool do_clear) +{ + DRW_texture_ensure_fullscreen_2d(output_tx, format, 0); + /* Clear texture. */ + if (do_clear) { + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + /* TODO(fclem) replace by GPU_texture_clear once it is fast. */ + GPU_framebuffer_texture_attach(fbl->material_accum_fb, *output_tx, 0, 0); + GPU_framebuffer_bind(fbl->material_accum_fb); + GPU_framebuffer_clear_color(fbl->material_accum_fb, clear); + GPU_framebuffer_bind(fbl->main_fb); + GPU_framebuffer_texture_detach(fbl->material_accum_fb, *output_tx); } - stl->g_data->render_passes_material_count = num_render_passes; } void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples) { - const DRWContextState *draw_ctx = DRW_context_state_get(); EEVEE_FramebufferList *fbl = vedata->fbl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); EEVEE_TextureList *txl = vedata->txl; EEVEE_StorageList *stl = vedata->stl; - EEVEE_PassList *psl = vedata->psl; EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_PrivateData *pd = stl->g_data; - float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + /* Should be enough precision for many samples. */ + const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F; + const bool do_clear = DRW_state_is_image_render() || (effects->taa_current_sample == 1); /* Create FrameBuffer. */ + GPU_framebuffer_ensure_config(&fbl->material_accum_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); - /* Should be enough precision for many samples. */ - const eGPUTextureFormat texture_format_material_accum = (tot_samples > 128) ? GPU_RGBA32F : - GPU_RGBA16F; - const eViewLayerEEVEEPassType render_passes = stl->g_data->render_passes & - EEVEE_RENDERPASSES_MATERIAL; - if (render_passes != 0) { - GPU_framebuffer_ensure_config(&fbl->material_accum_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); - int render_pass_index = ((render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) != 0) ? 0 : 1; - for (int bit = 0; bit < 32; bit++) { - eViewLayerEEVEEPassType bitflag = (1 << bit); - if ((render_passes & bitflag) != 0) { - - DRW_texture_ensure_fullscreen_2d( - &txl->material_accum[render_pass_index], texture_format_material_accum, 0); - - /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { - GPU_framebuffer_texture_attach( - fbl->material_accum_fb, txl->material_accum[render_pass_index], 0, 0); - GPU_framebuffer_bind(fbl->material_accum_fb); - GPU_framebuffer_clear_color(fbl->material_accum_fb, clear); - GPU_framebuffer_bind(fbl->main_fb); - GPU_framebuffer_texture_detach(fbl->material_accum_fb, - txl->material_accum[render_pass_index]); - } - render_pass_index++; - } - } + if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { + material_renderpass_init(fbl, &txl->env_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) { + material_renderpass_init(fbl, &txl->emit_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) { + material_renderpass_init(fbl, &txl->diff_color_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { + material_renderpass_init(fbl, &txl->diff_light_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) { + material_renderpass_init(fbl, &txl->spec_color_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { + material_renderpass_init(fbl, &txl->spec_light_accum, texture_format, do_clear); - if ((render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) && - (effects->enabled_effects & EFFECT_SSR)) { + if (effects->enabled_effects & EFFECT_SSR) { EEVEE_reflection_output_init(sldata, vedata, tot_samples); } + } +} - if (render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { - Scene *scene = draw_ctx->scene; - World *wo = scene->world; +static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl, + DRWPass *renderpass, + EEVEE_PrivateData *pd, + GPUTexture *output_tx, + struct GPUUniformBuffer *renderpass_option_ubo) +{ + GPU_framebuffer_texture_attach(fbl->material_accum_fb, output_tx, 0, 0); + GPU_framebuffer_bind(fbl->material_accum_fb); - if (wo && wo->use_nodes && wo->nodetree) { - struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo); - if (GPU_material_status(gpumat) == GPU_MAT_SUCCESS) { - DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->material_accum_pass[0]); - add_background_uniforms(grp, sldata, vedata); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - } - } - } + pd->renderpass_ubo = renderpass_option_ubo; + DRW_draw_pass(renderpass); + + GPU_framebuffer_texture_detach(fbl->material_accum_fb, output_tx); } void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_EffectsInfo *effects = vedata->stl->effects; EEVEE_TextureList *txl = vedata->txl; if (fbl->material_accum_fb != NULL) { - for (int renderpass_index = 0; renderpass_index < stl->g_data->render_passes_material_count; - renderpass_index++) { - if (txl->material_accum[renderpass_index] != NULL) { - GPU_framebuffer_texture_attach( - fbl->material_accum_fb, txl->material_accum[renderpass_index], 0, 0); - GPU_framebuffer_bind(fbl->material_accum_fb); - DRW_draw_pass(psl->material_accum_pass[renderpass_index]); - GPU_framebuffer_bind(fbl->main_fb); - GPU_framebuffer_texture_detach(fbl->material_accum_fb, - txl->material_accum[renderpass_index]); - } + DRWPass *material_accum_ps = psl->material_accum_ps; + if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { + material_renderpass_accumulate( + fbl, psl->background_accum_ps, pd, txl->env_accum, sldata->renderpass_ubo.combined); } - if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) && - (stl->effects->enabled_effects & EFFECT_SSR)) { - EEVEE_reflection_output_accumulate(sldata, vedata); + if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->emit_accum, sldata->renderpass_ubo.emit); } - } -} - -int EEVEE_material_output_pass_index_get(EEVEE_ViewLayerData *UNUSED(sldata), - EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type) -{ - EEVEE_StorageList *stl = vedata->stl; - - BLI_assert((stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL) != 0); - BLI_assert((stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL & renderpass_type) != 0); - - /* pass_index 0 is reserved for the environment pass. */ - if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT & renderpass_type) != 0) { - return 0; - } - - /* pass_index 0 is reserved for the environment pass. Other passes start from index 1 */ - int index = 1; - eViewLayerEEVEEPassType active_material_passes = stl->g_data->render_passes & - EEVEE_RENDERPASSES_MATERIAL & - ~EEVEE_RENDER_PASS_ENVIRONMENT; + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->diff_color_accum, sldata->renderpass_ubo.diff_color); + } + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->diff_light_accum, sldata->renderpass_ubo.diff_light); - for (int bitshift = 0; bitshift < 32; bitshift++) { - eViewLayerEEVEEPassType pass_flag = (1 << bitshift); - if (pass_flag == renderpass_type) { - break; + if (effects->enabled_effects & EFFECT_SSS) { + EEVEE_subsurface_output_accumulate(sldata, vedata); + } } - if (active_material_passes & pass_flag) { - index++; + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->spec_color_accum, sldata->renderpass_ubo.spec_color); } - } + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->spec_light_accum, sldata->renderpass_ubo.spec_light); - return index; -} + if (effects->enabled_effects & EFFECT_SSR) { + EEVEE_reflection_output_accumulate(sldata, vedata); + } + } -/* Get the pass index that contains the color pass for the given renderpass_type. */ -int EEVEE_material_output_color_pass_index_get(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type) -{ - BLI_assert( - ELEM(renderpass_type, EEVEE_RENDER_PASS_DIFFUSE_LIGHT, EEVEE_RENDER_PASS_SPECULAR_LIGHT)); - eViewLayerEEVEEPassType color_pass_type; - switch (renderpass_type) { - case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: - color_pass_type = EEVEE_RENDER_PASS_DIFFUSE_COLOR; - break; - case EEVEE_RENDER_PASS_SPECULAR_LIGHT: - color_pass_type = EEVEE_RENDER_PASS_SPECULAR_COLOR; - break; - default: - color_pass_type = 0; - BLI_assert(false); + /* Restore default. */ + pd->renderpass_ubo = sldata->renderpass_ubo.combined; + GPU_framebuffer_bind(fbl->main_fb); } - return EEVEE_material_output_pass_index_get(sldata, vedata, color_pass_type); } + /* \} */ diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c index cdcfd64d995..7b942784ee9 100644 --- a/source/blender/draw/engines/eevee/eevee_mist.c +++ b/source/blender/draw/engines/eevee/eevee_mist.c @@ -114,8 +114,7 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRWShadingGroup *grp = DRW_shgroup_create(e_data.mist_sh, psl->mist_accum_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_vec3(grp, "mistSettings", &g_data->mist_start, 1); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index be4dfd07ce1..f5ebbe08dd1 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -170,8 +170,7 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } else { @@ -209,8 +208,7 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &effects->ao_src_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call(grp, quad, NULL); DRW_PASS_CREATE(psl->ao_horizon_search_layer, DRW_STATE_WRITE_COLOR); @@ -219,8 +217,7 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "depthBufferLayered", &effects->ao_src_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_int(grp, "layer", &stl->effects->ao_depth_layer, 1); DRW_shgroup_call(grp, quad, NULL); @@ -233,8 +230,7 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call(grp, quad, NULL); } } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 264f301e52c..40008c5c364 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -158,35 +158,34 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d) (EEVEE_RENDER_PASS_EMIT | EEVEE_RENDER_PASS_DIFFUSE_COLOR | EEVEE_RENDER_PASS_DIFFUSE_LIGHT | \ EEVEE_RENDER_PASS_SPECULAR_COLOR | EEVEE_RENDER_PASS_SPECULAR_LIGHT | \ EEVEE_RENDER_PASS_ENVIRONMENT) -#define MAX_MATERIAL_RENDER_PASSES 6 -#define MAX_MATERIAL_RENDER_PASSES_UBO 6 -/* World shader variations */ -enum { - VAR_WORLD_BACKGROUND = 0, - VAR_WORLD_PROBE = 1, - VAR_WORLD_VOLUME = 2, -}; /* Material shader variations */ enum { VAR_MAT_MESH = (1 << 0), - VAR_MAT_PROBE = (1 << 1), + VAR_MAT_VOLUME = (1 << 1), VAR_MAT_HAIR = (1 << 2), - VAR_MAT_BLEND = (1 << 3), - VAR_MAT_VOLUME = (1 << 4), + VAR_MAT_PROBE = (1 << 3), + VAR_MAT_BLEND = (1 << 4), VAR_MAT_LOOKDEV = (1 << 5), VAR_MAT_HOLDOUT = (1 << 6), - /* Max number of variation */ - /* IMPORTANT : Leave it last and set - * it's value accordingly. */ - VAR_MAT_MAX = (1 << 7), - /* These are options that are not counted in VAR_MAT_MAX - * because they are not cumulative with the others above. */ - VAR_MAT_CLIP = (1 << 9), - VAR_MAT_HASH = (1 << 10), - VAR_MAT_MULT = (1 << 11), - VAR_MAT_SHADOW = (1 << 12), - VAR_MAT_REFRACT = (1 << 13), + VAR_MAT_HASH = (1 << 7), + VAR_MAT_DEPTH = (1 << 8), + VAR_MAT_REFRACT = (1 << 9), + VAR_WORLD_BACKGROUND = (1 << 10), + VAR_WORLD_PROBE = (1 << 11), + VAR_WORLD_VOLUME = (1 << 12), + VAR_DEFAULT = (1 << 13), +}; + +/* Material shader cache keys */ +enum { + /* HACK: This assumes the struct GPUShader will never be smaller than our variations. + * This allow us to only keep one ghash and avoid bigger keys comparisons/hashing. + * We combine the GPUShader pointer with the key. */ + KEY_CULL = (1 << 0), + KEY_REFRACT = (1 << 1), + KEY_HAIR = (1 << 2), + KEY_SHADOW = (1 << 3), }; /* ************ PROBE UBO ************* */ @@ -272,23 +271,26 @@ typedef struct EEVEE_PassList { struct DRWPass *maxz_copydepth_ps; struct DRWPass *maxz_copydepth_layer_ps; - struct DRWPass *depth_pass; - struct DRWPass *depth_pass_cull; - struct DRWPass *depth_pass_clip; - struct DRWPass *depth_pass_clip_cull; - struct DRWPass *refract_depth_pass; - struct DRWPass *refract_depth_pass_cull; - struct DRWPass *refract_depth_pass_clip; - struct DRWPass *refract_depth_pass_clip_cull; - struct DRWPass *default_pass[VAR_MAT_MAX]; - struct DRWPass *sss_pass; - struct DRWPass *sss_pass_cull; - struct DRWPass *material_pass; - struct DRWPass *material_pass_cull; - struct DRWPass *material_accum_pass[MAX_MATERIAL_RENDER_PASSES]; - struct DRWPass *refract_pass; + /* Renderpass Accumulation. */ + struct DRWPass *material_accum_ps; + struct DRWPass *background_accum_ps; + + struct DRWPass *depth_ps; + struct DRWPass *depth_cull_ps; + struct DRWPass *depth_clip_ps; + struct DRWPass *depth_clip_cull_ps; + struct DRWPass *depth_refract_ps; + struct DRWPass *depth_refract_cull_ps; + struct DRWPass *depth_refract_clip_ps; + struct DRWPass *depth_refract_clip_cull_ps; + struct DRWPass *material_ps; + struct DRWPass *material_cull_ps; + struct DRWPass *material_refract_ps; + struct DRWPass *material_refract_cull_ps; + struct DRWPass *material_sss_ps; + struct DRWPass *material_sss_cull_ps; struct DRWPass *transparent_pass; - struct DRWPass *background_pass; + struct DRWPass *background_ps; struct DRWPass *update_noise_pass; struct DRWPass *lookdev_glossy_pass; struct DRWPass *lookdev_diffuse_pass; @@ -348,7 +350,12 @@ typedef struct EEVEE_TextureList { struct GPUTexture *mist_accum; struct GPUTexture *ao_accum; struct GPUTexture *sss_accum; - struct GPUTexture *material_accum[MAX_MATERIAL_RENDER_PASSES]; + struct GPUTexture *env_accum; + struct GPUTexture *diff_color_accum; + struct GPUTexture *diff_light_accum; + struct GPUTexture *spec_color_accum; + struct GPUTexture *spec_light_accum; + struct GPUTexture *emit_accum; struct GPUTexture *bloom_accum; struct GPUTexture *ssr_accum; struct GPUTexture *shadow_accum; @@ -574,6 +581,7 @@ typedef struct EEVEE_EffectsInfo { bool swap_double_buffer; /* SSSS */ int sss_sample_count; + int sss_surface_count; struct GPUTexture *sss_irradiance; /* Textures from pool */ struct GPUTexture *sss_radius; struct GPUTexture *sss_albedo; @@ -754,14 +762,22 @@ typedef struct EEVEE_ViewLayerData { struct GPUUniformBuffer *planar_ubo; /* Material Render passes */ - struct EEVEE_RenderPassData renderpass_data[MAX_MATERIAL_RENDER_PASSES_UBO]; - struct GPUUniformBuffer *renderpass_ubo[MAX_MATERIAL_RENDER_PASSES_UBO]; + struct { + struct GPUUniformBuffer *combined; + struct GPUUniformBuffer *diff_color; + struct GPUUniformBuffer *diff_light; + struct GPUUniformBuffer *spec_color; + struct GPUUniformBuffer *spec_light; + struct GPUUniformBuffer *emit; + } renderpass_ubo; /* Common Uniform Buffer */ struct EEVEE_CommonUniformBuffer common_data; struct GPUUniformBuffer *common_ubo; struct LightCache *fallback_lightcache; + + struct BLI_memblock *material_cache; } EEVEE_ViewLayerData; /* ************ OBJECT DATA ************ */ @@ -809,14 +825,6 @@ typedef struct EEVEE_Data { typedef struct EEVEE_PrivateData { struct DRWShadingGroup *shadow_shgrp; struct DRWShadingGroup *shadow_accum_shgrp; - struct DRWShadingGroup *depth_shgrp; - struct DRWShadingGroup *depth_shgrp_cull; - struct DRWShadingGroup *depth_shgrp_clip; - struct DRWShadingGroup *depth_shgrp_clip_cull; - struct DRWShadingGroup *refract_depth_shgrp; - struct DRWShadingGroup *refract_depth_shgrp_cull; - struct DRWShadingGroup *refract_depth_shgrp_clip; - struct DRWShadingGroup *refract_depth_shgrp_clip_cull; struct DRWCallBuffer *planar_display_shgrp; struct GHash *material_hash; float background_alpha; /* TODO find a better place for this. */ @@ -862,9 +870,8 @@ typedef struct EEVEE_PrivateData { GPUTexture *renderpass_input; GPUTexture *renderpass_col_input; GPUTexture *renderpass_light_input; - /* The number of active material based render passes */ - uint render_passes_material_count; - + /* Renderpass ubo reference used by material pass. */ + struct GPUUniformBuffer *renderpass_ubo; /** For rendering shadows. */ struct DRWView *cube_views[6]; /** For rendering probes. */ @@ -892,6 +899,7 @@ EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo); /* eevee_materials.c */ struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl); void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); @@ -908,31 +916,20 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata, Object *ob, bool *cast_shadow); void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo); -struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo); -struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo); -struct GPUMaterial *EEVEE_material_mesh_get( - struct Scene *scene, Material *ma, EEVEE_Data *vedata, bool use_blend, bool use_refract); -struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma); -struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, - Material *ma, - bool use_hashed_alpha, - bool is_shadow); -struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma); -struct GPUUniformBuffer *EEVEE_material_default_render_pass_ubo_get(EEVEE_ViewLayerData *sldata); void EEVEE_materials_free(void); -void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl); void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]); void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4]); void EEVEE_material_renderpasses_init(EEVEE_Data *vedata); void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -int EEVEE_material_output_pass_index_get(EEVEE_ViewLayerData *UNUSED(sldata), - EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type); -int EEVEE_material_output_color_pass_index_get(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type); +void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, + struct GPUMaterial *gpumat, + EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + int *ssr_id, + float *refract_depth, + bool use_ssrefraction, + bool use_alpha_blend); /* eevee_lights.c */ void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]); void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); @@ -943,16 +940,6 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh); void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata); void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *sldata, - EEVEE_StorageList *stl, - struct GPUBatch *geom, - Object *ob); -void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata, - EEVEE_PassList *psl, - struct GPUMaterial *gpumat, - struct GPUBatch *geom, - struct Object *ob, - const float *alpha_threshold); void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, struct Object *ob); void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob); @@ -986,6 +973,7 @@ void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]); /* eevee_shaders.c */ void EEVEE_shaders_lightprobe_shaders_init(void); +void EEVEE_shaders_material_shaders_init(void); struct GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void); struct GPUShader *EEVEE_shaders_probe_default_sh_get(void); struct GPUShader *EEVEE_shaders_probe_filter_diffuse_sh_get(void); @@ -993,12 +981,22 @@ struct GPUShader *EEVEE_shaders_probe_filter_visibility_sh_get(void); struct GPUShader *EEVEE_shaders_probe_grid_fill_sh_get(void); struct GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void); struct GPUShader *EEVEE_shaders_default_studiolight_sh_get(void); +struct GPUShader *EEVEE_shaders_default_background_sh_get(void); struct GPUShader *EEVEE_shaders_background_studiolight_sh_get(void); struct GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void); struct GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void); struct GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void); +struct GPUShader *EEVEE_shaders_update_noise_sh_get(void); struct GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void); struct GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects); +struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma); +struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo); +Material *EEVEE_material_default_diffuse_get(void); +Material *EEVEE_material_default_glossy_get(void); +Material *EEVEE_material_default_error_get(void); +struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options); +struct GPUMaterial *EEVEE_material_get( + EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options); void EEVEE_shaders_free(void); /* eevee_lightprobes.c */ @@ -1105,13 +1103,9 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *sldata, uint tot_samples); void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - uint sss_id, - struct GPUUniformBuffer *sss_profile); -void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - uint sss_id, - struct GPUUniformBuffer *sss_profile, - struct GPUTexture *sss_tex_profile); + Material *ma, + DRWShadingGroup *shgrp, + struct GPUMaterial *gpumat); void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 076738dcbdf..89a5ad2198a 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -151,7 +151,7 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * * `EEVEE_effects_init` needs to go second for TAA. */ EEVEE_renderpasses_init(vedata); EEVEE_effects_init(sldata, vedata, ob_camera_eval, false); - EEVEE_materials_init(sldata, stl, fbl); + EEVEE_materials_init(sldata, vedata, stl, fbl); EEVEE_shadows_init(sldata); EEVEE_lightprobes_init(sldata, vedata); @@ -463,7 +463,7 @@ static void eevee_render_draw_background(EEVEE_Data *vedata) GPU_ATTACHMENT_NONE}); GPU_framebuffer_bind(fbl->main_fb); - DRW_draw_pass(psl->background_pass); + DRW_draw_pass(psl->background_ps); GPU_framebuffer_ensure_config(&fbl->main_fb, {GPU_ATTACHMENT_LEAVE, @@ -556,7 +556,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl EEVEE_update_noise(psl, fbl, r); EEVEE_temporal_sampling_matrices_calc(stl->effects, r); EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1); - EEVEE_materials_init(sldata, stl, fbl); + EEVEE_materials_init(sldata, vedata, stl, fbl); /* Refresh Probes * Shadows needs to be updated for correct probes */ @@ -578,8 +578,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl GPU_framebuffer_bind(fbl->main_fb); GPU_framebuffer_clear_color_depth_stencil(fbl->main_fb, clear_col, clear_depth, clear_stencil); /* Depth prepass */ - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); + DRW_draw_pass(psl->depth_ps); /* Create minmax texture */ EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1); EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1); @@ -587,16 +586,15 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl /* Shading pass */ eevee_render_draw_background(vedata); GPU_framebuffer_bind(fbl->main_fb); - EEVEE_materials_draw_opaque(sldata, psl); + DRW_draw_pass(psl->material_ps); EEVEE_subsurface_data_render(sldata, vedata); /* Effects pre-transparency */ EEVEE_subsurface_compute(sldata, vedata); EEVEE_reflection_compute(sldata, vedata); EEVEE_refraction_compute(sldata, vedata); /* Opaque refraction */ - DRW_draw_pass(psl->refract_depth_pass); - DRW_draw_pass(psl->refract_depth_pass_cull); - DRW_draw_pass(psl->refract_pass); + DRW_draw_pass(psl->depth_refract_ps); + DRW_draw_pass(psl->material_refract_ps); /* Result NORMAL */ eevee_render_result_normal(rl, viewname, rect, vedata, sldata); /* Volumetrics Resolve Opaque */ diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 9112e14dcf5..9a47ca19e7b 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -201,8 +201,7 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, grp, "inputSecondLightBuffer", &g_data->renderpass_light_input); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_int(grp, "currentSample", &g_data->renderpass_current_sample, 1); DRW_shgroup_uniform_int(grp, "renderpassType", &g_data->renderpass_type, 1); DRW_shgroup_uniform_int(grp, "postProcessType", &g_data->renderpass_postprocess, 1); @@ -216,7 +215,7 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, } } -/* Postprocess data to construct a specific renderpass +/* Post-process data to construct a specific render-pass * * This method will create a shading group to perform the post-processing for the given * `renderpass_type`. The post-processing will be done and the result will be stored in the @@ -224,8 +223,8 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, * * Only invoke this function for passes that need post-processing. * - * After invoking this function the active framebuffer is set to `vedata->fbl->renderpass_fb`. */ -void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata, + * After invoking this function the active frame-buffer is set to `vedata->fbl->renderpass_fb`. */ +void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, eViewLayerEEVEEPassType renderpass_type) { @@ -276,22 +275,30 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata, g_data->renderpass_input = txl->shadow_accum; break; } - case EEVEE_RENDER_PASS_DIFFUSE_COLOR: - case EEVEE_RENDER_PASS_SPECULAR_COLOR: - case EEVEE_RENDER_PASS_ENVIRONMENT: + case EEVEE_RENDER_PASS_DIFFUSE_COLOR: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_input = txl->diff_color_accum; + break; + } + case EEVEE_RENDER_PASS_SPECULAR_COLOR: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_input = txl->spec_color_accum; + break; + } + case EEVEE_RENDER_PASS_ENVIRONMENT: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_input = txl->env_accum; + break; + } case EEVEE_RENDER_PASS_EMIT: { g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; - int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type); - g_data->renderpass_input = txl->material_accum[renderpass_index]; + g_data->renderpass_input = txl->emit_accum; break; } case EEVEE_RENDER_PASS_SPECULAR_LIGHT: { g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_LIGHT; - int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type); - int renderpass_index_color = EEVEE_material_output_color_pass_index_get( - sldata, vedata, renderpass_type); - g_data->renderpass_input = txl->material_accum[renderpass_index]; - g_data->renderpass_col_input = txl->material_accum[renderpass_index_color]; + g_data->renderpass_input = txl->spec_light_accum; + g_data->renderpass_col_input = txl->spec_color_accum; if ((stl->effects->enabled_effects & EFFECT_SSR) != 0) { g_data->renderpass_postprocess = PASS_POST_TWO_LIGHT_BUFFERS; g_data->renderpass_light_input = txl->ssr_accum; @@ -303,11 +310,8 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata, } case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: { g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_LIGHT; - int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type); - int renderpass_index_color = EEVEE_material_output_color_pass_index_get( - sldata, vedata, renderpass_type); - g_data->renderpass_input = txl->material_accum[renderpass_index]; - g_data->renderpass_col_input = txl->material_accum[renderpass_index_color]; + g_data->renderpass_input = txl->diff_light_accum; + g_data->renderpass_col_input = txl->diff_color_accum; if ((stl->effects->enabled_effects & EFFECT_SSS) != 0) { g_data->renderpass_postprocess = PASS_POST_TWO_LIGHT_BUFFERS; g_data->renderpass_light_input = txl->sss_accum; @@ -343,10 +347,6 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, if ((render_pass & EEVEE_RENDER_PASS_MIST) != 0) { EEVEE_mist_output_accumulate(sldata, vedata); } - if ((render_pass & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) != 0 && - (effects->enabled_effects & EFFECT_SSS) != 0) { - EEVEE_subsurface_output_accumulate(sldata, vedata); - } if ((render_pass & EEVEE_RENDER_PASS_AO) != 0) { EEVEE_occlusion_output_accumulate(sldata, vedata); } diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 2e467fe8535..cece67334c5 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -237,8 +237,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); if (!effects->reflection_trace_full) { DRW_shgroup_uniform_ivec2(grp, "halfresOffset", effects->ssr_halfres_ofs, 1); } @@ -259,8 +258,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1); if ((effects->enabled_effects & EFFECT_GTAO) != 0) { DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index 50b7c5c5f97..09e74c84948 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -22,12 +22,20 @@ #include "DRW_render.h" +#include "BKE_lib_id.h" +#include "BKE_node.h" + +#include "BLI_dynstr.h" #include "BLI_string_utils.h" #include "MEM_guardedalloc.h" +#include "GPU_material.h" #include "GPU_shader.h" +#include "NOD_shader.h" + +#include "eevee_engine.h" #include "eevee_private.h" static const char *filter_defines = "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n" @@ -61,6 +69,38 @@ static struct { struct GPUShader *taa_resolve_sh; struct GPUShader *taa_resolve_reproject_sh; + /* General purpose Shaders. */ + struct GPUShader *default_background; + struct GPUShader *update_noise_sh; + + /* Shader strings */ + char *frag_shader_lib; + char *vert_shader_str; + char *vert_shadow_shader_str; + char *vert_background_shader_str; + char *vert_volume_shader_str; + char *geom_volume_shader_str; + char *volume_shader_lib; + + /* LookDev Materials */ + Material *glossy_mat; + Material *diffuse_mat; + + Material *error_mat; + + /* Default Material */ + struct { + bNodeTree *ntree; + bNodeSocketValueRGBA *color_socket; + bNodeSocketValueFloat *metallic_socket; + bNodeSocketValueFloat *roughness_socket; + bNodeSocketValueFloat *specular_socket; + } surface; + + struct { + bNodeTree *ntree; + bNodeSocketValueRGBA *color_socket; + } world; } e_data = {NULL}; /* Engine data */ extern char datatoc_bsdf_common_lib_glsl[]; @@ -68,27 +108,42 @@ extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; +extern char datatoc_ambient_occlusion_lib_glsl[]; extern char datatoc_background_vert_glsl[]; +extern char datatoc_common_hair_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_default_world_frag_glsl[]; -extern char datatoc_lightprobe_geom_glsl[]; -extern char datatoc_lightprobe_vert_glsl[]; +extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lightprobe_cube_display_frag_glsl[]; extern char datatoc_lightprobe_cube_display_vert_glsl[]; extern char datatoc_lightprobe_filter_diffuse_frag_glsl[]; extern char datatoc_lightprobe_filter_glossy_frag_glsl[]; extern char datatoc_lightprobe_filter_visibility_frag_glsl[]; +extern char datatoc_lightprobe_geom_glsl[]; extern char datatoc_lightprobe_grid_display_frag_glsl[]; extern char datatoc_lightprobe_grid_display_vert_glsl[]; extern char datatoc_lightprobe_grid_fill_frag_glsl[]; +extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_lightprobe_planar_display_frag_glsl[]; extern char datatoc_lightprobe_planar_display_vert_glsl[]; extern char datatoc_lightprobe_planar_downsample_frag_glsl[]; extern char datatoc_lightprobe_planar_downsample_geom_glsl[]; extern char datatoc_lightprobe_planar_downsample_vert_glsl[]; -extern char datatoc_irradiance_lib_glsl[]; -extern char datatoc_lightprobe_lib_glsl[]; +extern char datatoc_lightprobe_vert_glsl[]; +extern char datatoc_lights_lib_glsl[]; +extern char datatoc_lit_surface_frag_glsl[]; +extern char datatoc_lit_surface_vert_glsl[]; +extern char datatoc_ltc_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; -extern char datatoc_cubemap_lib_glsl[]; +extern char datatoc_prepass_frag_glsl[]; +extern char datatoc_raytrace_lib_glsl[]; +extern char datatoc_shadow_vert_glsl[]; +extern char datatoc_ssr_lib_glsl[]; +extern char datatoc_update_noise_frag_glsl[]; +extern char datatoc_volumetric_frag_glsl[]; +extern char datatoc_volumetric_geom_glsl[]; +extern char datatoc_volumetric_lib_glsl[]; +extern char datatoc_volumetric_vert_glsl[]; /* Velocity Resolve */ extern char datatoc_effect_velocity_resolve_frag_glsl[]; @@ -150,6 +205,64 @@ void EEVEE_shaders_lightprobe_shaders_init(void) NULL); } +void EEVEE_shaders_material_shaders_init(void) +{ + e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl, + datatoc_ambient_occlusion_lib_glsl, + datatoc_raytrace_lib_glsl, + datatoc_ssr_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, + datatoc_irradiance_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_ltc_lib_glsl, + datatoc_lights_lib_glsl, + /* Add one for each Closure */ + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_volumetric_lib_glsl); + + e_data.volume_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_ambient_occlusion_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, + datatoc_irradiance_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_ltc_lib_glsl, + datatoc_lights_lib_glsl, + datatoc_volumetric_lib_glsl, + datatoc_volumetric_frag_glsl); + + e_data.vert_shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl); + + e_data.vert_shadow_shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl); + + e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_background_vert_glsl); + + e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_volumetric_vert_glsl); + + e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_volumetric_geom_glsl); +} + GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void) { return e_data.probe_filter_glossy_sh; @@ -292,6 +405,26 @@ GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void) return e_data.velocity_resolve_sh; } +GPUShader *EEVEE_shaders_default_background_sh_get(void) +{ + if (e_data.default_background == NULL) { + e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl, + NULL, + datatoc_default_world_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); + } + return e_data.default_background; +} + +GPUShader *EEVEE_shaders_update_noise_sh_get(void) +{ + if (e_data.update_noise_sh == NULL) { + e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL); + } + return e_data.update_noise_sh; +} + GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects) { GPUShader **sh; @@ -316,8 +449,330 @@ GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects) return *sh; } +Material *EEVEE_material_default_diffuse_get(void) +{ + if (!e_data.diffuse_mat) { + Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default diffuse"); + + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + ma->nodetree = ntree; + ma->use_nodes = true; + + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_DIFFUSE); + bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color"); + copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 0.8f); + + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + + nodeAddLink(ntree, + bsdf, + nodeFindSocket(bsdf, SOCK_OUT, "BSDF"), + output, + nodeFindSocket(output, SOCK_IN, "Surface")); + + nodeSetActive(ntree, output); + e_data.diffuse_mat = ma; + } + return e_data.diffuse_mat; +} + +Material *EEVEE_material_default_glossy_get(void) +{ + if (!e_data.glossy_mat) { + Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal"); + + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + ma->nodetree = ntree; + ma->use_nodes = true; + + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_GLOSSY); + bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color"); + copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 1.0f); + bNodeSocket *roughness = nodeFindSocket(bsdf, SOCK_IN, "Roughness"); + ((bNodeSocketValueFloat *)roughness->default_value)->value = 0.0f; + + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + + nodeAddLink(ntree, + bsdf, + nodeFindSocket(bsdf, SOCK_OUT, "BSDF"), + output, + nodeFindSocket(output, SOCK_IN, "Surface")); + + nodeSetActive(ntree, output); + e_data.glossy_mat = ma; + } + return e_data.glossy_mat; +} + +Material *EEVEE_material_default_error_get(void) +{ + if (!e_data.error_mat) { + Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal"); + + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + ma->nodetree = ntree; + ma->use_nodes = true; + + /* Use emission and output material to be compatible with both World and Material. */ + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_EMISSION); + bNodeSocket *color = nodeFindSocket(bsdf, SOCK_IN, "Color"); + copy_v3_fl3(((bNodeSocketValueRGBA *)color->default_value)->value, 1.0f, 0.0f, 1.0f); + + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + + nodeAddLink(ntree, + bsdf, + nodeFindSocket(bsdf, SOCK_OUT, "Emission"), + output, + nodeFindSocket(output, SOCK_IN, "Surface")); + + nodeSetActive(ntree, output); + e_data.error_mat = ma; + } + return e_data.error_mat; +} + +/* Configure a default nodetree with the given material. */ +struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma) +{ + /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */ + if (!e_data.surface.ntree) { + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_PRINCIPLED); + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + bNodeSocket *bsdf_out = nodeFindSocket(bsdf, SOCK_OUT, "BSDF"); + bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface"); + nodeAddLink(ntree, bsdf, bsdf_out, output, output_in); + nodeSetActive(ntree, output); + + e_data.surface.color_socket = nodeFindSocket(bsdf, SOCK_IN, "Base Color")->default_value; + e_data.surface.metallic_socket = nodeFindSocket(bsdf, SOCK_IN, "Metallic")->default_value; + e_data.surface.roughness_socket = nodeFindSocket(bsdf, SOCK_IN, "Roughness")->default_value; + e_data.surface.specular_socket = nodeFindSocket(bsdf, SOCK_IN, "Specular")->default_value; + e_data.surface.ntree = ntree; + } + /* Update */ + copy_v3_fl3(e_data.surface.color_socket->value, ma->r, ma->g, ma->b); + e_data.surface.metallic_socket->value = ma->metallic; + e_data.surface.roughness_socket->value = ma->roughness; + e_data.surface.specular_socket->value = ma->spec; + + return e_data.surface.ntree; +} + +/* Configure a default nodetree with the given world. */ +struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo) +{ + /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */ + if (!e_data.world.ntree) { + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + bNode *bg = nodeAddStaticNode(NULL, ntree, SH_NODE_BACKGROUND); + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_WORLD); + bNodeSocket *bg_out = nodeFindSocket(bg, SOCK_OUT, "Background"); + bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface"); + nodeAddLink(ntree, bg, bg_out, output, output_in); + nodeSetActive(ntree, output); + + e_data.world.color_socket = nodeFindSocket(bg, SOCK_IN, "Color")->default_value; + e_data.world.ntree = ntree; + } + + copy_v3_fl3(e_data.world.color_socket->value, wo->horr, wo->horg, wo->horb); + + return e_data.world.ntree; +} + +static char *eevee_get_defines(int options) +{ + char *str = NULL; + + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, SHADER_DEFINES); + + if ((options & VAR_WORLD_BACKGROUND) != 0) { + BLI_dynstr_append(ds, "#define WORLD_BACKGROUND\n"); + } + if ((options & VAR_MAT_VOLUME) != 0) { + BLI_dynstr_append(ds, "#define VOLUMETRICS\n"); + } + if ((options & VAR_MAT_MESH) != 0) { + BLI_dynstr_append(ds, "#define MESH_SHADER\n"); + } + if ((options & VAR_MAT_DEPTH) != 0) { + BLI_dynstr_append(ds, "#define DEPTH_SHADER\n"); + } + if ((options & VAR_MAT_HAIR) != 0) { + BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); + } + if ((options & (VAR_MAT_PROBE | VAR_WORLD_PROBE)) != 0) { + BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n"); + } + if ((options & VAR_MAT_HASH) != 0) { + BLI_dynstr_append(ds, "#define USE_ALPHA_HASH\n"); + } + if ((options & VAR_MAT_BLEND) != 0) { + BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND\n"); + } + if ((options & VAR_MAT_REFRACT) != 0) { + BLI_dynstr_append(ds, "#define USE_REFRACTION\n"); + } + if ((options & VAR_MAT_LOOKDEV) != 0) { + BLI_dynstr_append(ds, "#define LOOKDEV\n"); + } + if ((options & VAR_MAT_HOLDOUT) != 0) { + BLI_dynstr_append(ds, "#define HOLDOUT\n"); + } + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return str; +} + +static char *eevee_get_vert(int options) +{ + char *str = NULL; + + if ((options & VAR_MAT_VOLUME) != 0) { + str = BLI_strdup(e_data.vert_volume_shader_str); + } + else if ((options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0) { + str = BLI_strdup(e_data.vert_background_shader_str); + } + else { + str = BLI_strdup(e_data.vert_shader_str); + } + + return str; +} + +static char *eevee_get_geom(int options) +{ + char *str = NULL; + + if ((options & VAR_MAT_VOLUME) != 0) { + str = BLI_strdup(e_data.geom_volume_shader_str); + } + + return str; +} + +static char *eevee_get_frag(int options) +{ + char *str = NULL; + + if ((options & VAR_MAT_VOLUME) != 0) { + str = BLI_strdup(e_data.volume_shader_lib); + } + else if ((options & VAR_MAT_DEPTH) != 0) { + str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl); + } + else { + str = BLI_strdup(e_data.frag_shader_lib); + } + + return str; +} + +static struct GPUMaterial *eevee_material_get_ex( + struct Scene *scene, Material *ma, World *wo, int options, bool deferred) +{ + BLI_assert(ma || wo); + const bool is_volume = (options & VAR_MAT_VOLUME) != 0; + const bool is_default = (options & VAR_DEFAULT) != 0; + const void *engine = &DRW_engine_viewport_eevee_type; + + GPUMaterial *mat = NULL; + + if (ma) { + mat = DRW_shader_find_from_material(ma, engine, options, deferred); + } + else { + mat = DRW_shader_find_from_world(wo, engine, options, deferred); + } + + if (mat) { + return mat; + } + + char *defines = eevee_get_defines(options); + char *vert = eevee_get_vert(options); + char *geom = eevee_get_geom(options); + char *frag = eevee_get_frag(options); + + if (ma) { + bNodeTree *ntree = !is_default ? ma->nodetree : EEVEE_shader_default_surface_nodetree(ma); + mat = DRW_shader_create_from_material( + scene, ma, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred); + } + else { + bNodeTree *ntree = !is_default ? wo->nodetree : EEVEE_shader_default_world_nodetree(wo); + mat = DRW_shader_create_from_world( + scene, wo, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred); + } + + MEM_SAFE_FREE(defines); + MEM_SAFE_FREE(vert); + MEM_SAFE_FREE(geom); + MEM_SAFE_FREE(frag); + + return mat; +} + +/* Note: Compilation is not deferred. */ +struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options) +{ + Material *def_ma = (ma && (options & VAR_MAT_VOLUME)) ? BKE_material_default_volume() : + BKE_material_default_surface(); + BLI_assert(def_ma->use_nodes && def_ma->nodetree); + + return eevee_material_get_ex(scene, def_ma, NULL, options, false); +} + +struct GPUMaterial *EEVEE_material_get( + EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options) +{ + if ((ma && (!ma->use_nodes || !ma->nodetree)) || (wo && (!wo->use_nodes || !wo->nodetree))) { + options |= VAR_DEFAULT; + } + + /* Meh, implicit option. World probe cannot be deferred because they need + * to be rendered immediately. */ + const bool deferred = (options & VAR_WORLD_PROBE) == 0; + + GPUMaterial *mat = eevee_material_get_ex(scene, ma, wo, options, deferred); + + int status = GPU_material_status(mat); + switch (status) { + case GPU_MAT_SUCCESS: + break; + case GPU_MAT_QUEUED: + vedata->stl->g_data->queued_shaders_count++; + mat = EEVEE_material_default_get(scene, ma, options); + break; + case GPU_MAT_FAILED: + default: + ma = EEVEE_material_default_error_get(); + mat = eevee_material_get_ex(scene, ma, NULL, options, false); + break; + } + /* Returned material should be ready to be drawn. */ + BLI_assert(GPU_material_status(mat) == GPU_MAT_SUCCESS); + return mat; +} + void EEVEE_shaders_free(void) { + MEM_SAFE_FREE(e_data.frag_shader_lib); + MEM_SAFE_FREE(e_data.vert_shader_str); + MEM_SAFE_FREE(e_data.vert_shadow_shader_str); + MEM_SAFE_FREE(e_data.vert_background_shader_str); + MEM_SAFE_FREE(e_data.vert_volume_shader_str); + MEM_SAFE_FREE(e_data.geom_volume_shader_str); + MEM_SAFE_FREE(e_data.volume_shader_lib); + DRW_SHADER_FREE_SAFE(e_data.default_background); + DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); DRW_SHADER_FREE_SAFE(e_data.probe_default_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh); @@ -332,4 +787,27 @@ void EEVEE_shaders_free(void) DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.taa_resolve_reproject_sh); + + if (e_data.glossy_mat) { + BKE_id_free(NULL, e_data.glossy_mat); + e_data.glossy_mat = NULL; + } + if (e_data.diffuse_mat) { + BKE_id_free(NULL, e_data.diffuse_mat); + e_data.diffuse_mat = NULL; + } + if (e_data.error_mat) { + BKE_id_free(NULL, e_data.error_mat); + e_data.error_mat = NULL; + } + if (e_data.surface.ntree) { + ntreeFreeEmbeddedTree(e_data.surface.ntree); + MEM_freeN(e_data.surface.ntree); + e_data.surface.ntree = NULL; + } + if (e_data.world.ntree) { + ntreeFreeEmbeddedTree(e_data.world.ntree); + MEM_freeN(e_data.world.ntree); + e_data.world.ntree = NULL; + } } diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index fb338d85fde..84c50a22ae6 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -159,47 +159,6 @@ void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } } -/* Add a shadow caster to the shadowpasses */ -void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *UNUSED(sldata), - EEVEE_StorageList *stl, - struct GPUBatch *geom, - Object *ob) -{ - DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob); -} - -void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata, - EEVEE_PassList *psl, - struct GPUMaterial *gpumat, - struct GPUBatch *geom, - struct Object *ob, - const float *alpha_threshold) -{ - /* TODO / PERF : reuse the same shading group for objects with the same material */ - DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass); - - if (grp == NULL) { - return; - } - - /* Unfortunately needed for correctness but not 99% of the time not needed. - * TODO detect when needed? */ - DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - - if (alpha_threshold != NULL) { - DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1); - } - - DRW_shgroup_call(grp, geom, ob); -} - /* Make that object update shadow casting lights inside its influence bounding box. */ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob) { @@ -470,8 +429,7 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 3f4008eb8b9..7674148f76a 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -29,7 +29,9 @@ #include "DEG_depsgraph_query.h" #include "GPU_extensions.h" +#include "GPU_material.h" #include "GPU_texture.h" + #include "eevee_private.h" static struct { @@ -83,6 +85,7 @@ void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; + effects->sss_surface_count = 0; common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; } @@ -145,7 +148,7 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } else { GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); - txl->sss_accum = NULL; + DRW_TEXTURE_FREE_SAFE(txl->sss_accum); } } else { @@ -154,11 +157,11 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_resolve_fb); GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb); GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); + DRW_TEXTURE_FREE_SAFE(txl->sss_accum); effects->sss_stencil = NULL; effects->sss_blur = NULL; effects->sss_irradiance = NULL; effects->sss_radius = NULL; - txl->sss_accum = NULL; } } @@ -221,70 +224,77 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - uint sss_id, - struct GPUUniformBuffer *sss_profile) + Material *ma, + DRWShadingGroup *shgrp, + struct GPUMaterial *gpumat) { - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth; - DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance); - DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); - DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_stencil_mask(grp, sss_id); - DRW_shgroup_call(grp, quad, NULL); - - grp = DRW_shgroup_create(e_data.sss_sh[1], psl->sss_resolve_ps); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur); - DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); - DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); - DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_stencil_mask(grp, sss_id); - DRW_shgroup_call(grp, quad, NULL); -} + struct GPUTexture *sss_tex_profile = NULL; + struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get( + gpumat, stl->effects->sss_sample_count, &sss_tex_profile); -void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - uint sss_id, - struct GPUUniformBuffer *sss_profile, - GPUTexture *sss_tex_profile) -{ - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); - GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth; + if (!sss_profile) { + BLI_assert(0 && "SSS pass requested but no SSS data was found"); + return; + } + + /* Limit of 8 bit stencil buffer. ID 255 is refraction. */ + if (effects->sss_surface_count >= 254) { + /* TODO : display message. */ + printf("Error: Too many different Subsurface shader in the scene.\n"); + return; + } + + int sss_id = ++(effects->sss_surface_count); + /* Make main pass output stencil mask. */ + DRW_shgroup_stencil_mask(shgrp, sss_id); + + { + DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); + DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance); + DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); + DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_stencil_mask(grp, sss_id); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + grp = DRW_shgroup_create(e_data.sss_sh[1], psl->sss_resolve_ps); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); + DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur); + DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); + DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); + DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_stencil_mask(grp, sss_id); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } - DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_translucency_ps); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); - DRW_shgroup_uniform_texture_ref(grp, "sssShadowCubes", &sldata->shadow_cube_pool); - DRW_shgroup_uniform_texture_ref(grp, "sssShadowCascades", &sldata->shadow_cascade_pool); - DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_stencil_mask(grp, sss_id); - DRW_shgroup_call(grp, quad, NULL); + if (ma->blend_flag & MA_BL_TRANSLUCENCY) { + DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_translucency_ps); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); + DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); + DRW_shgroup_uniform_texture_ref(grp, "sssShadowCubes", &sldata->shadow_cube_pool); + DRW_shgroup_uniform_texture_ref(grp, "sssShadowCascades", &sldata->shadow_cascade_pool); + DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_stencil_mask(grp, sss_id); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } } void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) @@ -310,8 +320,7 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat GPU_ATTACHMENT_TEXTURE(effects->sss_albedo)}); GPU_framebuffer_bind(fbl->main_fb); - DRW_draw_pass(psl->sss_pass); - DRW_draw_pass(psl->sss_pass_cull); + DRW_draw_pass(psl->material_sss_ps); /* Restore */ GPU_framebuffer_ensure_config(&fbl->main_fb, @@ -350,23 +359,15 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) if (!DRW_pass_is_empty(psl->sss_translucency_ps)) { /* We sample the shadow-maps using normal sampler. We need to disable Comparison mode. * TODO(fclem) avoid this by using sampler objects.*/ - GPU_texture_bind(sldata->shadow_cube_pool, 0); GPU_texture_compare_mode(sldata->shadow_cube_pool, false); - GPU_texture_unbind(sldata->shadow_cube_pool); - GPU_texture_bind(sldata->shadow_cascade_pool, 0); GPU_texture_compare_mode(sldata->shadow_cascade_pool, false); - GPU_texture_unbind(sldata->shadow_cascade_pool); GPU_framebuffer_bind(fbl->sss_translucency_fb); DRW_draw_pass(psl->sss_translucency_ps); /* Reset original state. */ - GPU_texture_bind(sldata->shadow_cube_pool, 0); GPU_texture_compare_mode(sldata->shadow_cube_pool, true); - GPU_texture_unbind(sldata->shadow_cube_pool); - GPU_texture_bind(sldata->shadow_cascade_pool, 0); GPU_texture_compare_mode(sldata->shadow_cascade_pool, true); - GPU_texture_unbind(sldata->shadow_cascade_pool); } /* 1. horizontal pass */ diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index b70d872c4af..d57048f2c4e 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -292,8 +292,7 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data DRW_shgroup_uniform_texture_ref(grp, "colorHistoryBuffer", &txl->taa_history); DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); if (effects->enabled_effects & EFFECT_TAA_REPROJECT) { // DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 83bd4fcf8d2..90860e94270 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -355,7 +355,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) struct World *wo = scene->world; if (wo != NULL && wo->use_nodes && wo->nodetree && !LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) { - struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); + struct GPUMaterial *mat = EEVEE_material_get(vedata, scene, NULL, wo, VAR_MAT_VOLUME); if (GPU_material_has_volume_output(mat)) { grp = DRW_shgroup_material_create(mat, psl->volumetric_world_ps); @@ -369,8 +369,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); /* Fix principle volumetric not working with world materials. */ ListBase gpu_grids = GPU_material_volume_grids(mat); @@ -388,8 +387,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* If no world or volume material is present just clear the buffer with this drawcall */ grp = DRW_shgroup_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); } @@ -590,12 +588,10 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, return; } - struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma); + int mat_options = VAR_MAT_VOLUME | VAR_MAT_MESH; + struct GPUMaterial *mat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); eGPUMaterialStatus status = GPU_material_status(mat); - if (status == GPU_MAT_QUEUED) { - vedata->stl->g_data->queued_shaders_count++; - } /* If shader failed to compile or is currently compiling. */ if (status != GPU_MAT_SUCCESS) { return; @@ -609,8 +605,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); @@ -661,8 +656,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); @@ -671,8 +665,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_scatter); DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmit); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles( grp, NULL, USE_VOLUME_OPTI ? 1 : common_data->vol_tex_size[2]); @@ -683,8 +676,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit); DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } @@ -775,12 +767,8 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* We sample the shadow-maps using shadow sampler. We need to enable Comparison mode. * TODO(fclem) avoid this by using sampler objects.*/ - GPU_texture_bind(sldata->shadow_cube_pool, 0); GPU_texture_compare_mode(sldata->shadow_cube_pool, true); - GPU_texture_unbind(sldata->shadow_cube_pool); - GPU_texture_bind(sldata->shadow_cascade_pool, 0); GPU_texture_compare_mode(sldata->shadow_cascade_pool, true); - GPU_texture_unbind(sldata->shadow_cascade_pool); GPU_framebuffer_bind(fbl->volumetric_fb); DRW_draw_pass(psl->volumetric_world_ps); @@ -920,8 +908,7 @@ void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit); DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); } else { /* There is no volumetrics in the scene. Use a shader to fill the accum textures with a default diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 8662c0ecb6a..57b16418696 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -6,13 +6,9 @@ #if defined(MESH_SHADER) # if !defined(USE_ALPHA_HASH) -# if !defined(USE_ALPHA_CLIP) -# if !defined(SHADOW_SHADER) -# if !defined(USE_MULTIPLY) -# if !defined(USE_ALPHA_BLEND) -# define ENABLE_DEFERED_AO -# endif -# endif +# if !defined(DEPTH_SHADER) +# if !defined(USE_ALPHA_BLEND) +# define ENABLE_DEFERED_AO # endif # endif # endif diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index c3518198805..402d306df45 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -928,7 +928,7 @@ Closure closure_emission(vec3 rgb) /* Breaking this across multiple lines causes issues for some older GLSL compilers. */ /* clang-format off */ -# if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) +# if defined(MESH_SHADER) && !defined(DEPTH_SHADER) /* clang-format on */ # ifndef USE_ALPHA_BLEND layout(location = 0) out vec4 outRadiance; @@ -1001,6 +1001,10 @@ void main() outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac; # endif +# ifdef LOOKDEV + gl_FragDepth = 0.0; +# endif + # ifndef USE_ALPHA_BLEND float alpha_div = 1.0 / max(1e-8, alpha); outRadiance.rgb *= alpha_div; @@ -1011,6 +1015,6 @@ void main() # endif } -# endif /* MESH_SHADER && !SHADOW_SHADER */ +# endif /* MESH_SHADER */ #endif /* VOLUMETRICS */ diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl index 5277bfa32bb..d56890769a7 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl @@ -1,6 +1,4 @@ -uniform mat4 ProjectionMatrix; - uniform sampler2D colorBuffer; uniform sampler2D depthBuffer; diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 8c2619650b9..bc7879763c3 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -177,7 +177,7 @@ void CLOSURE_NAME(vec3 N out_refr = vec3(0.0); #endif -#if defined(SHADOW_SHADER) || defined(WORLD_BACKGROUND) +#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ return; #else diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl index cf20b3ff5b9..1b94fc2bee1 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl @@ -4,11 +4,12 @@ in vec3 pos; in vec3 nor; #endif +#ifdef MESH_SHADER out vec3 worldPosition; out vec3 viewPosition; - out vec3 worldNormal; out vec3 viewNormal; +#endif #ifdef HAIR_SHADER out vec3 hairTangent; @@ -41,22 +42,28 @@ void main() hairThickness, hairThickTime); worldNormal = cross(hairTangent, binor); - worldPosition = pos; + vec3 world_pos = pos; #else - worldPosition = point_object_to_world(pos); - worldNormal = normalize(normal_object_to_world(nor)); + vec3 world_pos = point_object_to_world(pos); #endif - /* No need to normalize since this is just a rotation. */ - viewNormal = normal_world_to_view(worldNormal); + gl_Position = point_world_to_ndc(world_pos); + /* Used for planar reflections */ + gl_ClipDistance[0] = dot(vec4(world_pos, 1.0), clipPlanes[0]); + +#ifdef MESH_SHADER + worldPosition = world_pos; viewPosition = point_world_to_view(worldPosition); - gl_Position = point_world_to_ndc(worldPosition); - /* Used for planar reflections */ - gl_ClipDistance[0] = dot(vec4(worldPosition, 1.0), clipPlanes[0]); +# ifndef HAIR_SHADER + worldNormal = normalize(normal_object_to_world(nor)); +# endif -#ifdef USE_ATTR + /* No need to normalize since this is just a rotation. */ + viewNormal = normal_world_to_view(worldNormal); +# ifdef USE_ATTR pass_attr(pos); +# endif #endif } diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl index b49dbfceba2..9acd8f998f6 100644 --- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl @@ -45,26 +45,22 @@ float hashed_alpha_threshold(vec3 co) /* Find our final, uniformly distributed alpha threshold. */ float threshold = (x < one_a) ? ((x < a) ? cases.x : cases.y) : cases.z; + /* Jitter the threshold for TAA accumulation. */ + threshold = fract(threshold + alphaHashOffset); + /* Avoids threshold == 0. */ threshold = clamp(threshold, 1.0e-6, 1.0); - /* Jitter the threshold for TAA accumulation. */ - return fract(threshold + alphaHashOffset); + return threshold; } #endif -#ifdef USE_ALPHA_CLIP -uniform float alphaThreshold; -#endif +#define NODETREE_EXEC void main() { - /* For now do nothing. - * In the future, output object motion blur. */ - -#if defined(USE_ALPHA_HASH) || defined(USE_ALPHA_CLIP) -# define NODETREE_EXEC +#if defined(USE_ALPHA_HASH) Closure cl = nodetree_exec(); @@ -75,11 +71,6 @@ void main() if (opacity < hashed_alpha_threshold(worldPosition)) { discard; } -# elif defined(USE_ALPHA_CLIP) - /* Alpha clip */ - if (opacity <= alphaThreshold) { - discard; - } # endif #endif } diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index 6e636e4dc93..2f448b784ed 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -44,6 +44,11 @@ #define EXTERNAL_ENGINE "BLENDER_EXTERNAL" +extern char datatoc_depth_frag_glsl[]; +extern char datatoc_depth_vert_glsl[]; + +extern char datatoc_common_view_lib_glsl[]; + /* *********** LISTS *********** */ /* GPUViewport.storage @@ -106,7 +111,16 @@ static void external_engine_init(void *vedata) /* Depth prepass */ if (!e_data.depth_sh) { - e_data.depth_sh = DRW_shader_create_3d_depth_only(GPU_SHADER_CFG_DEFAULT); + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[GPU_SHADER_CFG_DEFAULT]; + + e_data.depth_sh = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, NULL}, + }); } if (!stl->g_data) { @@ -277,7 +291,7 @@ static void external_draw_scene(void *vedata) static void external_engine_free(void) { - /* All shaders are builtin. */ + DRW_SHADER_FREE_SAFE(e_data.depth_sh); } static const DrawEngineDataSize external_data_size = DRW_VIEWPORT_DATA_SIZE(EXTERNAL_Data); diff --git a/source/blender/draw/engines/gpencil/gpencil_antialiasing.c b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c index 4dd5e3b2da1..8955240c549 100644 --- a/source/blender/draw/engines/gpencil/gpencil_antialiasing.c +++ b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c @@ -78,13 +78,8 @@ void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata) false, NULL); - GPU_texture_bind(txl->smaa_search_tx, 0); GPU_texture_filter_mode(txl->smaa_search_tx, true); - GPU_texture_unbind(txl->smaa_search_tx); - - GPU_texture_bind(txl->smaa_area_tx, 0); GPU_texture_filter_mode(txl->smaa_area_tx, true); - GPU_texture_unbind(txl->smaa_area_tx); } { diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 1344b649dff..2b811f1d52e 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -381,7 +381,7 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, struct GPUShader *sh = GPENCIL_shader_geometry_get(); DRWShadingGroup *grp = tgp_layer->base_shgrp = DRW_shgroup_create(sh, tgp_layer->geom_ps); - DRW_shgroup_uniform_texture_persistent(grp, "gpSceneDepthTexture", depth_tex); + DRW_shgroup_uniform_texture(grp, "gpSceneDepthTexture", depth_tex); DRW_shgroup_uniform_texture_ref(grp, "gpMaskTexture", mask_tex); DRW_shgroup_uniform_vec3_copy(grp, "gpNormal", tgp_ob->plane_normal); DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", tgp_ob->is_drawmode3d); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 50e4e8d2ec4..495de7ef10b 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -91,6 +91,7 @@ void GPENCIL_engine_init(void *ved) stl->pd->gp_object_pool = vldata->gp_object_pool; stl->pd->gp_layer_pool = vldata->gp_layer_pool; stl->pd->gp_vfx_pool = vldata->gp_vfx_pool; + stl->pd->view_layer = ctx->view_layer; stl->pd->scene = ctx->scene; stl->pd->v3d = ctx->v3d; stl->pd->last_light_pool = NULL; @@ -292,7 +293,7 @@ void GPENCIL_cache_init(void *ved) grp = DRW_shgroup_create(sh, psl->merge_depth_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuf", &pd->depth_tx); DRW_shgroup_uniform_bool(grp, "strokeOrder3d", &pd->is_stroke_order_3d, 1); - DRW_shgroup_uniform_vec4(grp, "gpModelMatrix[0]", pd->object_bound_mat[0], 4); + DRW_shgroup_uniform_vec4(grp, "gpModelMatrix", pd->object_bound_mat[0], 4); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { @@ -468,7 +469,7 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl, /* Iterator dependent uniforms. */ DRWShadingGroup *grp = iter->grp = tgp_layer->base_shgrp; - DRW_shgroup_uniform_block_persistent(grp, "gpLightBlock", iter->ubo_lights); + DRW_shgroup_uniform_block(grp, "gpLightBlock", iter->ubo_lights); DRW_shgroup_uniform_block(grp, "gpMaterialBlock", iter->ubo_mat); DRW_shgroup_uniform_texture(grp, "gpFillTexture", iter->tex_fill); DRW_shgroup_uniform_texture(grp, "gpStrokeTexture", iter->tex_stroke); @@ -598,6 +599,7 @@ void GPENCIL_cache_populate(void *ved, Object *ob) GPENCIL_Data *vedata = (GPENCIL_Data *)ved; GPENCIL_PrivateData *pd = vedata->stl->pd; GPENCIL_TextureList *txl = vedata->txl; + const bool is_final_render = DRW_state_is_image_render(); /* object must be visible */ if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { @@ -617,7 +619,8 @@ void GPENCIL_cache_populate(void *ved, Object *ob) bGPdata *gpd = (bGPdata *)ob->data; bool do_onion = (!pd->is_render) ? pd->do_onion : (gpd->onion_flag & GP_ONION_GHOST_ALWAYS); - BKE_gpencil_visible_stroke_iter(ob, + BKE_gpencil_visible_stroke_iter(is_final_render ? pd->view_layer : NULL, + ob, gpencil_layer_cache_populate, gpencil_stroke_cache_populate, &iter, diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index f765dcf73de..cedd75af813 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -307,6 +307,8 @@ typedef struct GPENCIL_PrivateData { float dof_params[2]; /* Used for DoF Setup. */ Object *camera; + /* Copy of draw_ctx->view_layer for convenience. */ + struct ViewLayer *view_layer; /* Copy of draw_ctx->scene for convenience. */ struct Scene *scene; /* Copy of draw_ctx->vie3d for convenience. */ diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl index fb5073b3dc7..1e75f6dd5bb 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl @@ -317,7 +317,7 @@ vec2 safe_normalize_len(vec2 v, out float len) } } -float stroke_thickness_modulate(float thickness) +float stroke_thickness_modulate(float thickness, out float opacity) { /* Modify stroke thickness by object and layer factors.-*/ thickness *= thicknessScale; @@ -333,6 +333,11 @@ float stroke_thickness_modulate(float thickness) /* World space point size. */ thickness *= thicknessWorldScale * ProjectionMatrix[1][1] * sizeViewport.y; } + /* To avoid aliasing artifact, we clamp the line thickness and reduce its opacity. */ + float min_thickness = gl_Position.w * 1.3; + opacity = smoothstep(0.0, gl_Position.w * 1.0, thickness); + thickness = max(min_thickness, thickness); + return thickness; } @@ -414,8 +419,9 @@ void stroke_vertex() vec2 line = safe_normalize_len(ss2 - ss1, line_len); vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2)); + float small_line_opacity; float thickness = abs((use_curr) ? thickness1 : thickness2); - thickness = stroke_thickness_modulate(thickness); + thickness = stroke_thickness_modulate(thickness, small_line_opacity); finalUvs = vec2(x, y) * 0.5 + 0.5; strokeHardeness = decode_hardness(use_curr ? hardness1 : hardness2); @@ -505,7 +511,7 @@ void stroke_vertex() vec4 stroke_col = MATERIAL(m).stroke_color; float mix_tex = MATERIAL(m).stroke_texture_mix; - color_output(stroke_col, vert_col, vert_strength, mix_tex); + color_output(stroke_col, vert_col, vert_strength * small_line_opacity, mix_tex); matFlag = MATERIAL(m).flag & ~GP_FILL_FLAGS; # endif diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index 624eef8fa47..95fd918f8c1 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -137,9 +137,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) pd->armature.do_pose_fade_geom = pd->armature.do_pose_xray && ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) && draw_ctx->object_pose != NULL; - - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD; - DRW_PASS_CREATE(psl->armature_transp_ps, state | pd->clipping_state); + DRWState state; if (pd->armature.do_pose_fade_geom) { state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; @@ -163,17 +161,21 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get(); OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[i]; - DRWPass **p_armature_ps = &psl->armature_ps[i]; cb->custom_shapes_ghash = BLI_ghash_ptr_new(__func__); cb->custom_shapes_transp_ghash = BLI_ghash_ptr_new(__func__); + DRWPass **p_armature_ps = &psl->armature_ps[i]; DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0; state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH; DRW_PASS_CREATE(*p_armature_ps, state | pd->clipping_state | infront_state); - DRWPass *armature_ps = *p_armature_ps; + DRWPass **p_armature_trans_ps = &psl->armature_transp_ps[i]; + state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD; + DRW_PASS_CREATE(*p_armature_trans_ps, state | pd->clipping_state); + DRWPass *armature_transp_ps = *p_armature_trans_ps; + #define BUF_INSTANCE DRW_shgroup_call_buffer_instance #define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES) @@ -182,7 +184,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_sphere(false); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); cb->point_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get()); @@ -194,7 +196,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_shape(false); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); cb->custom_solid = grp; cb->box_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get()); @@ -210,29 +212,29 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_sphere(true); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get()); sh = OVERLAY_shader_armature_shape(true); cb->custom_outline = grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get()); cb->octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get()); sh = OVERLAY_shader_armature_shape_wire(); cb->custom_wire = grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } { format = formats->instance_extra; sh = OVERLAY_shader_armature_degrees_of_freedom(); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get()); - grp = DRW_shgroup_create(sh, psl->armature_transp_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + grp = DRW_shgroup_create(sh, armature_transp_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get()); } { @@ -240,7 +242,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_stick(); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get()); } { @@ -249,7 +251,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_envelope(false); grp = DRW_shgroup_create(sh, armature_ps); DRW_shgroup_state_enable(grp, DRW_STATE_CULL_BACK); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "isDistance", false); DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); cb->envelope_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get()); @@ -264,14 +266,14 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_envelope(true); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->envelope_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_outline_get()); format = formats->instance_bone_envelope_distance; sh = OVERLAY_shader_armature_envelope(false); - grp = DRW_shgroup_create(sh, psl->armature_transp_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + grp = DRW_shgroup_create(sh, armature_transp_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "isDistance", true); DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); cb->envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get()); @@ -281,7 +283,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_wire(); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->wire = BUF_LINE(grp, format); } } @@ -2255,7 +2257,7 @@ void OVERLAY_armature_draw(OVERLAY_Data *vedata) { OVERLAY_PassList *psl = vedata->psl; - DRW_draw_pass(psl->armature_transp_ps); + DRW_draw_pass(psl->armature_transp_ps[0]); DRW_draw_pass(psl->armature_ps[0]); } @@ -2264,6 +2266,7 @@ void OVERLAY_armature_in_front_draw(OVERLAY_Data *vedata) OVERLAY_PassList *psl = vedata->psl; if (psl->armature_bone_select_ps == NULL || DRW_state_is_select()) { + DRW_draw_pass(psl->armature_transp_ps[1]); DRW_draw_pass(psl->armature_ps[1]); } } @@ -2285,6 +2288,7 @@ void OVERLAY_pose_draw(OVERLAY_Data *vedata) GPU_framebuffer_clear_depth(fbl->overlay_line_in_front_fb, 1.0f); } + DRW_draw_pass(psl->armature_transp_ps[1]); DRW_draw_pass(psl->armature_ps[1]); } } diff --git a/source/blender/draw/engines/overlay/overlay_edit_curve.c b/source/blender/draw/engines/overlay/overlay_edit_curve.c index 6456d6868a5..9a79c78c996 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_curve.c +++ b/source/blender/draw/engines/overlay/overlay_edit_curve.c @@ -36,7 +36,8 @@ void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata) GPUShader *sh; DRWState state; - pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0; + pd->edit_curve.show_handles = v3d->overlay.handle_display != CURVE_HANDLE_NONE; + pd->edit_curve.handle_display = v3d->overlay.handle_display; pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length; /* Run Twice for in-front passes. */ @@ -62,11 +63,13 @@ void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata) pd->edit_curve_handle_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles); + DRW_shgroup_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); sh = OVERLAY_shader_edit_curve_point(); pd->edit_curve_points_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps); DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles); + DRW_shgroup_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } } diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.c b/source/blender/draw/engines/overlay/overlay_edit_text.c index 3de0155d6e0..c4d020adc11 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_text.c +++ b/source/blender/draw/engines/overlay/overlay_edit_text.c @@ -38,7 +38,8 @@ void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata) GPUShader *sh; DRWState state; - pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0; + pd->edit_curve.show_handles = v3d->overlay.handle_display != CURVE_HANDLE_NONE; + pd->edit_curve.handle_display = v3d->overlay.handle_display; pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length; /* Run Twice for in-front passes. */ diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index e875f2c8291..61337ac8d1d 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -46,6 +46,8 @@ static void OVERLAY_engine_init(void *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); const RegionView3D *rv3d = draw_ctx->rv3d; const View3D *v3d = draw_ctx->v3d; + const Scene *scene = draw_ctx->scene; + const ToolSettings *ts = scene->toolsettings; if (!stl->pd) { /* Alloc transient pointers */ @@ -77,6 +79,15 @@ static void OVERLAY_engine_init(void *vedata) pd->overlay.flag |= V3D_OVERLAY_WIREFRAMES; } + if (ts->sculpt) { + if (ts->sculpt->flags & SCULPT_HIDE_FACE_SETS) { + pd->overlay.sculpt_mode_face_sets_opacity = 0.0f; + } + if (ts->sculpt->flags & SCULPT_HIDE_MASK) { + pd->overlay.sculpt_mode_mask_opacity = 0.0f; + } + } + pd->use_in_front = (v3d->shading.type <= OB_SOLID) || BKE_scene_uses_blender_workbench(draw_ctx->scene); pd->wireframe_mode = (v3d->shading.type == OB_WIRE); @@ -235,7 +246,8 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) const bool renderable = DRW_object_is_renderable(ob); const bool in_pose_mode = ob->type == OB_ARMATURE && OVERLAY_armature_is_pose_mode(ob, draw_ctx); const bool in_edit_mode = overlay_object_is_edit_mode(pd, ob); - const bool in_particle_edit_mode = ob->mode == OB_MODE_PARTICLE_EDIT; + const bool in_particle_edit_mode = (ob->mode == OB_MODE_PARTICLE_EDIT) && + (pd->ctx_mode == CTX_MODE_PARTICLE); const bool in_paint_mode = (ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT); const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL) && diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index 38fa9f06079..94732fb62ed 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -65,6 +65,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) OVERLAY_PassList *psl = vedata->psl; OVERLAY_TextureList *txl = vedata->txl; OVERLAY_PrivateData *pd = vedata->stl->pd; + const bool is_select = DRW_state_is_select(); DRWState state_blend = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; DRW_PASS_CREATE(psl->extra_blend_ps, state_blend | pd->clipping_state); @@ -80,8 +81,8 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) struct GPUTexture *tex = DRW_state_is_fbo() ? dtxl->depth : txl->dummy_depth_tx; pd->extra_grid_grp = grp = DRW_shgroup_create(sh, psl->extra_grid_ps); - DRW_shgroup_uniform_texture_persistent(grp, "depthBuffer", tex); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture(grp, "depthBuffer", tex); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); } @@ -108,10 +109,10 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) /* Sorted by shader to avoid state changes during render. */ { format = formats->instance_extra; - sh = OVERLAY_shader_extra(); + sh = OVERLAY_shader_extra(is_select); grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); grp_sub = DRW_shgroup_create_sub(grp); cb->camera_distances = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_distances_get()); @@ -156,7 +157,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) { format = formats->instance_extra; grp = DRW_shgroup_create(sh, psl->extra_blend_ps); /* NOTE: not the same pass! */ - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); grp_sub = DRW_shgroup_create_sub(grp); DRW_shgroup_state_enable(grp_sub, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK); @@ -173,38 +174,38 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_extra_groundline(); grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); cb->groundline = BUF_INSTANCE(grp, format, DRW_cache_groundline_get()); } { - sh = OVERLAY_shader_extra_wire(false); + sh = OVERLAY_shader_extra_wire(false, is_select); grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->extra_dashed_lines = BUF_LINE(grp, formats->pos_color); cb->extra_lines = BUF_LINE(grp, formats->wire_extra); } { - sh = OVERLAY_shader_extra_wire(true); + sh = OVERLAY_shader_extra_wire(true, is_select); cb->extra_wire = grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } { sh = OVERLAY_shader_extra_loose_point(); cb->extra_loose_points = grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } { format = formats->pos; sh = OVERLAY_shader_extra_point(); grp = DRW_shgroup_create(sh, psl->extra_centers_ps); /* NOTE: not the same pass! */ - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); grp_sub = DRW_shgroup_create_sub(grp); DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorActive); @@ -768,10 +769,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z; DRWShadingGroup *grp = DRW_shgroup_create_sub(vedata->stl->pd->extra_grid_grp); - DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[0]", instdata.mat[0]); - DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[1]", instdata.mat[1]); - DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[2]", instdata.mat[2]); - DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[3]", instdata.mat[3]); + DRW_shgroup_uniform_vec4_array_copy(grp, "gridModelMatrix", instdata.mat, 4); DRW_shgroup_call_procedural_points(grp, NULL, cell_count); } break; @@ -1373,9 +1371,9 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb, madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, mds->cell_size, mds->res_min); float voxel_cubemat[4][4] = {{0.0f}}; /* scale small cube to voxel size */ - voxel_cubemat[0][0] = 1.0f / (float)mds->base_res[0]; - voxel_cubemat[1][1] = 1.0f / (float)mds->base_res[1]; - voxel_cubemat[2][2] = 1.0f / (float)mds->base_res[2]; + voxel_cubemat[0][0] = mds->cell_size[0] / 2.0f; + voxel_cubemat[1][1] = mds->cell_size[1] / 2.0f; + voxel_cubemat[2][2] = mds->cell_size[2] / 2.0f; voxel_cubemat[3][3] = 1.0f; /* translate small cube to corner */ copy_v3_v3(voxel_cubemat[3], min); diff --git a/source/blender/draw/engines/overlay/overlay_facing.c b/source/blender/draw/engines/overlay/overlay_facing.c index 9216ae61b3e..4eb4b8ae85b 100644 --- a/source/blender/draw/engines/overlay/overlay_facing.c +++ b/source/blender/draw/engines/overlay/overlay_facing.c @@ -41,7 +41,7 @@ void OVERLAY_facing_cache_init(OVERLAY_Data *vedata) GPUShader *sh = OVERLAY_shader_facing(); pd->facing_grp[i] = DRW_shgroup_create(sh, psl->facing_ps[i]); - DRW_shgroup_uniform_block_persistent(pd->facing_grp[i], "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(pd->facing_grp[i], "globalsBlock", G_draw.block_ubo); } if (!pd->use_in_front) { diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c index 1397ef7b4b2..ccc914e0422 100644 --- a/source/blender/draw/engines/overlay/overlay_gpencil.c +++ b/source/blender/draw/engines/overlay/overlay_gpencil.c @@ -361,7 +361,7 @@ static void OVERLAY_gpencil_color_names(Object *ob) int cfra = DEG_get_ctime(draw_ctx->depsgraph); BKE_gpencil_visible_stroke_iter( - ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra); + NULL, ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra); } void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob) diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c index 531e1faf715..168f6f8a17f 100644 --- a/source/blender/draw/engines/overlay/overlay_motion_path.c +++ b/source/blender/draw/engines/overlay/overlay_motion_path.c @@ -49,11 +49,11 @@ void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_motion_path_line(); pd->motion_path_lines_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); sh = OVERLAY_shader_motion_path_vert(); pd->motion_path_points_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } /* Just convert the CPU cache to GPU cache. */ diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c index 142421f58d8..99d22fc380f 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.c +++ b/source/blender/draw/engines/overlay/overlay_outline.c @@ -259,7 +259,7 @@ static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob) } BKE_gpencil_visible_stroke_iter( - ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra); + NULL, ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra); } void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, diff --git a/source/blender/draw/engines/overlay/overlay_particle.c b/source/blender/draw/engines/overlay/overlay_particle.c index 98bc62ae66a..b891bb4ce4c 100644 --- a/source/blender/draw/engines/overlay/overlay_particle.c +++ b/source/blender/draw/engines/overlay/overlay_particle.c @@ -152,13 +152,13 @@ void OVERLAY_particle_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_particle_dot(); pd->particle_dots_grp = grp = DRW_shgroup_create(sh, psl->particle_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.ramp); sh = OVERLAY_shader_particle_shape(); pd->particle_shapes_grp = grp = DRW_shgroup_create(sh, psl->particle_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.ramp); } void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob) diff --git a/source/blender/draw/engines/overlay/overlay_pointcloud.c b/source/blender/draw/engines/overlay/overlay_pointcloud.c index a0de7aac1f1..b2a2d44bf73 100644 --- a/source/blender/draw/engines/overlay/overlay_pointcloud.c +++ b/source/blender/draw/engines/overlay/overlay_pointcloud.c @@ -46,7 +46,7 @@ void OVERLAY_pointcloud_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_pointcloud_dot(); pd->pointcloud_dots_grp = grp = DRW_shgroup_create(sh, psl->pointcloud_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } void OVERLAY_pointcloud_cache_populate(OVERLAY_Data *vedata, Object *ob) diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 257cf777ed2..ed0a9cf6981 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -54,7 +54,7 @@ typedef struct OVERLAY_PassList { DRWPass *antialiasing_ps; DRWPass *armature_ps[2]; DRWPass *armature_bone_select_ps; - DRWPass *armature_transp_ps; + DRWPass *armature_transp_ps[2]; DRWPass *background_ps; DRWPass *clipping_frustum_ps; DRWPass *edit_curve_wire_ps[2]; @@ -297,6 +297,7 @@ typedef struct OVERLAY_PrivateData { } antialiasing; struct { bool show_handles; + int handle_display; } edit_curve; struct { int ghost_ob; @@ -589,9 +590,9 @@ GPUShader *OVERLAY_shader_edit_mesh_skin_root(void); GPUShader *OVERLAY_shader_edit_mesh_vert(void); GPUShader *OVERLAY_shader_edit_particle_strand(void); GPUShader *OVERLAY_shader_edit_particle_point(void); -GPUShader *OVERLAY_shader_extra(void); +GPUShader *OVERLAY_shader_extra(bool is_select); GPUShader *OVERLAY_shader_extra_groundline(void); -GPUShader *OVERLAY_shader_extra_wire(bool use_object); +GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select); GPUShader *OVERLAY_shader_extra_loose_point(void); GPUShader *OVERLAY_shader_extra_point(void); GPUShader *OVERLAY_shader_facing(void); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index 59f388df4e3..0610b8397a1 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -164,8 +164,10 @@ typedef struct OVERLAY_Shaders { GPUShader *edit_particle_strand; GPUShader *edit_particle_point; GPUShader *extra; + GPUShader *extra_select; GPUShader *extra_groundline; GPUShader *extra_wire[2]; + GPUShader *extra_wire_select; GPUShader *extra_point; GPUShader *extra_lightprobe_grid; GPUShader *extra_loose_point; @@ -797,23 +799,24 @@ GPUShader *OVERLAY_shader_edit_particle_point(void) return sh_data->edit_particle_point; } -GPUShader *OVERLAY_shader_extra(void) +GPUShader *OVERLAY_shader_extra(bool is_select) { const DRWContextState *draw_ctx = DRW_context_state_get(); const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->extra) { - sh_data->extra = GPU_shader_create_from_arrays({ + GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra; + if (!*sh) { + *sh = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg->lib, datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl, datatoc_extra_vert_glsl, NULL}, .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, NULL}, + .defs = (const char *[]){sh_cfg->def, (is_select) ? "#define SELECT_EDGES\n" : NULL, NULL}, }); } - return sh_data->extra; + return *sh; } GPUShader *OVERLAY_shader_extra_grid(void) @@ -855,12 +858,13 @@ GPUShader *OVERLAY_shader_extra_groundline(void) return sh_data->extra_groundline; } -GPUShader *OVERLAY_shader_extra_wire(bool use_object) +GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select) { const DRWContextState *draw_ctx = DRW_context_state_get(); const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->extra_wire[use_object]) { + GPUShader **sh = (is_select) ? &sh_data->extra_wire_select : &sh_data->extra_wire[use_object]; + if (!*sh) { char colorids[1024]; /* NOTE: define all ids we need here. */ BLI_snprintf(colorids, @@ -875,7 +879,7 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object) TH_TRANSFORM, TH_WIRE, TH_CAMERA_PATH); - sh_data->extra_wire[use_object] = GPU_shader_create_from_arrays({ + *sh = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg->lib, datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl, @@ -884,11 +888,12 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object) .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_wire_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg->def, colorids, + (is_select) ? "#define SELECT_EDGES\n" : "", (use_object) ? "#define OBJECT_WIRE \n" : NULL, NULL}, }); } - return sh_data->extra_wire[use_object]; + return *sh; } GPUShader *OVERLAY_shader_extra_loose_point(void) diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index 309c7c1021a..eebfc88fdce 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -91,7 +91,7 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) for (int use_coloring = 0; use_coloring < 2; use_coloring++) { pd->wires_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", pd->shdata.wire_step_param); DRW_shgroup_uniform_bool_copy(grp, "useColoring", use_coloring); @@ -157,10 +157,7 @@ static void wireframe_hair_cache_populate(OVERLAY_Data *vedata, Object *ob, Part const bool use_coloring = true; DRWShadingGroup *shgrp = DRW_shgroup_create_sub(pd->wires_hair_grp[is_xray][use_coloring]); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[0]", dupli_mat[0]); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[1]", dupli_mat[1]); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[2]", dupli_mat[2]); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[3]", dupli_mat[3]); + DRW_shgroup_uniform_vec4_array_copy(shgrp, "hairDupliMatrix", dupli_mat, 4); DRW_shgroup_call_no_cull(shgrp, hairs, ob); } @@ -200,13 +197,15 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, struct GPUBatch *geom = NULL; switch (ob->type) { case OB_CURVE: - if (ob->runtime.curve_cache && BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) { + if (!pd->wireframe_mode && !use_wire && ob->runtime.curve_cache && + BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) { break; } geom = DRW_cache_curve_edge_wire_get(ob); break; case OB_FONT: - if (ob->runtime.curve_cache && BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) { + if (!pd->wireframe_mode && !use_wire && ob->runtime.curve_cache && + BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) { break; } geom = DRW_cache_text_loose_edges_get(ob); diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl index b444b3b0fec..306fbb473ee 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl @@ -4,10 +4,15 @@ #define EVEN_U_BIT 1 << 4 #define COLOR_SHIFT 5 +/* Keep the same value in `handle_display` in `DNA_view3d_types.h` */ +#define CURVE_HANDLE_SELECTED 0 +#define CURVE_HANDLE_ALL 1 + layout(lines) in; layout(triangle_strip, max_vertices = 10) out; uniform bool showCurveHandles; +uniform int curveHandleDisplay; flat in int vertFlag[]; @@ -46,6 +51,17 @@ void main() } bool edge_selected = (((vertFlag[1] | vertFlag[0]) & VERT_SELECTED) != 0); + bool handle_selected = (showCurveHandles && + (((vertFlag[1] | vertFlag[0]) & HANDLE_SELECTED) != 0)); + + /* If handle type is only selected and the edge is not selected, don't show. */ + if ((curveHandleDisplay != CURVE_HANDLE_ALL) && (!handle_selected)) { + /* Nurbs must show the handles always. */ + bool is_u_segment = (((vertFlag[1] ^ vertFlag[0]) & EVEN_U_BIT) != 0); + if (!is_u_segment) { + return; + } + } vec4 inner_color; if (color_id == 0) { diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl index 6fa4576ae71..b1e1c0879a5 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl @@ -2,7 +2,11 @@ /* Keep the same value of `BEZIER_HANDLE` in `draw_cache_imp_curve.c` */ #define BEZIER_HANDLE 1 << 3 +/* Keep the same value in `handle_display` in `DNA_view3d_types.h` */ +#define CURVE_HANDLE_SELECTED 0 + uniform bool showCurveHandles; +uniform int curveHandleDisplay; in vec3 pos; in int data; @@ -32,7 +36,12 @@ void main() world_clip_planes_calc_clip_distance(world_pos); #endif - if (!showCurveHandles && ((data & BEZIER_HANDLE) != 0)) { + bool show_handle = showCurveHandles; + if ((curveHandleDisplay == CURVE_HANDLE_SELECTED) && ((data & HANDLE_SELECTED) == 0)) { + show_handle = false; + } + + if (!show_handle && ((data & BEZIER_HANDLE) != 0)) { /* We set the vertex at the camera origin to generate 0 fragments. */ gl_Position = vec4(0.0, 0.0, -3e36, 0.0); } diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl index 035fab1040e..2168d8065fc 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl @@ -221,6 +221,13 @@ void main() /* Convert to screen position [0..sizeVp]. */ edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; +#ifdef SELECT_EDGES + /* HACK: to avoid loosing sub pixel object in selections, we add a bit of randomness to the + * wire to at least create one fragment that will pass the occlusion query. */ + /* TODO(fclem) Limit this workaround to selection. It's not very noticeable but still... */ + gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0); +#endif + #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl index 474f3254389..0fbf9ba8137 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl @@ -17,6 +17,13 @@ void main() vec3 world_pos = point_object_to_world(pos); gl_Position = point_world_to_ndc(world_pos); +#ifdef SELECT_EDGES + /* HACK: to avoid loosing sub pixel object in selections, we add a bit of randomness to the + * wire to at least create one fragment that will pass the occlusion query. */ + /* TODO(fclem) Limit this workaround to selection. It's not very noticeable but still... */ + gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0); +#endif + stipple_coord = stipple_start = screen_position(gl_Position); #ifdef OBJECT_WIRE @@ -34,6 +41,10 @@ void main() } #endif +#ifdef SELECT_EDGES + finalColor.a = 0.0; /* No Stipple */ +#endif + #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl index 0efcfb35929..51007a9f246 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl @@ -4,7 +4,6 @@ * Converted and adapted from HLSL to GLSL by Clément Foucault */ -uniform mat4 ProjectionMatrix; uniform vec2 invertedViewportSize; uniform vec2 nearFar; uniform vec3 dofParams; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl index 6f99739f259..e45f7a7b9e3 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl @@ -24,11 +24,17 @@ bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling) { - vec2 tex_size = vec2(textureSize(image, 0).xy); /* TODO(fclem) We could do the same with sampler objects. * But this is a quick workaround instead of messing with the GPUTexture itself. */ - vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord; - return texture(image, uv); + if (nearest_sampling) { + /* Use texelFetch for nearest_sampling to reduce glitches. See: T73726 */ + vec2 tex_size = vec2(textureSize(image, 0).xy); + ivec2 uv = ivec2(floor(coord * tex_size) + 0.5); + return texelFetch(image, uv, 0); + } + else { + return texture(image, coord); + } } vec4 workbench_sample_texture_array(sampler2DArray tile_array, @@ -36,7 +42,6 @@ vec4 workbench_sample_texture_array(sampler2DArray tile_array, vec2 coord, bool nearest_sampling) { - vec2 tex_size = vec2(textureSize(tile_array, 0).xy); vec3 uv = vec3(coord, 0); if (!node_tex_tile_lookup(uv, tile_array, tile_data)) @@ -44,8 +49,15 @@ vec4 workbench_sample_texture_array(sampler2DArray tile_array, /* TODO(fclem) We could do the same with sampler objects. * But this is a quick workaround instead of messing with the GPUTexture itself. */ - uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy; - return texture(tile_array, uv); + if (nearest_sampling) { + /* Use texelFetch for nearest_sampling to reduce glitches. See: T73726 */ + vec3 tex_size = vec3(textureSize(tile_array, 0)); + uv.xy = floor(uv.xy * tex_size.xy) + 0.5; + return texelFetch(tile_array, ivec3(uv), 0); + } + else { + return texture(tile_array, uv); + } } uniform sampler2DArray imageTileArray; diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c index d2bd653a656..0e896c4b7bb 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c +++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c @@ -19,7 +19,7 @@ /** \file * \ingroup draw_engine * - * Anti-aliasing: + * Anti-Aliasing: * * We use SMAA (Smart Morphological Anti-Aliasing) as a fast antialiasing solution. * @@ -266,13 +266,8 @@ void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata) false, NULL); - GPU_texture_bind(txl->smaa_search_tx, 0); GPU_texture_filter_mode(txl->smaa_search_tx, true); - GPU_texture_unbind(txl->smaa_search_tx); - - GPU_texture_bind(txl->smaa_area_tx, 0); GPU_texture_filter_mode(txl->smaa_area_tx, true); - GPU_texture_unbind(txl->smaa_area_tx); } } else { diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 0b7d313342b..b36a4a3a494 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -284,11 +284,11 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, *grp_tex = grp = DRW_shgroup_create_sub(grp); if (tex_tile_data) { - DRW_shgroup_uniform_texture_persistent(grp, "imageTileArray", tex); - DRW_shgroup_uniform_texture_persistent(grp, "imageTileData", tex_tile_data); + DRW_shgroup_uniform_texture(grp, "imageTileArray", tex); + DRW_shgroup_uniform_texture(grp, "imageTileData", tex_tile_data); } else { - DRW_shgroup_uniform_texture_persistent(grp, "imageTexture", tex); + DRW_shgroup_uniform_texture(grp, "imageTexture", tex); } DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL)); DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c index c9c43e785ca..27d5b71f35c 100644 --- a/source/blender/draw/engines/workbench/workbench_opaque.c +++ b/source/blender/draw/engines/workbench/workbench_opaque.c @@ -95,21 +95,21 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data) DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); wpd->prepass[opaque][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); sh = workbench_shader_opaque_image_get(wpd, hair, false); wpd->prepass[opaque][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); sh = workbench_shader_opaque_image_get(wpd, hair, true); wpd->prepass[opaque][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); } @@ -123,9 +123,9 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data) sh = workbench_shader_composite_get(wpd); grp = DRW_shgroup_create(sh, psl->composite_ps); - DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_texture_persistent(grp, "materialBuffer", wpd->material_buffer_tx); - DRW_shgroup_uniform_texture_persistent(grp, "normalBuffer", wpd->normal_buffer_tx); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_texture(grp, "materialBuffer", wpd->material_buffer_tx); + DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx); DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false); DRW_shgroup_stencil_mask(grp, 0x00); @@ -137,8 +137,8 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data) struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture; const bool use_spec = workbench_is_specular_highlight_enabled(wpd); spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx; - DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx); - DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx); + DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx); + DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", spec_tx); } DRW_shgroup_call_procedural_triangles(grp, NULL, 1); diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c index 2e796056029..99366779b22 100644 --- a/source/blender/draw/engines/workbench/workbench_shader.c +++ b/source/blender/draw/engines/workbench/workbench_shader.c @@ -23,6 +23,7 @@ #include "DRW_render.h" #include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "workbench_engine.h" #include "workbench_private.h" @@ -359,32 +360,24 @@ void workbench_shader_depth_of_field_get(GPUShader **prepare_sh, GPUShader **resolve_sh) { if (e_data.dof_prepare_sh == NULL) { - e_data.dof_prepare_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, - "#define PREPARE\n"); - - e_data.dof_downsample_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, - "#define DOWNSAMPLE\n"); + char *frag = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_workbench_effect_dof_frag_glsl); + e_data.dof_prepare_sh = DRW_shader_create_fullscreen(frag, "#define PREPARE\n"); + e_data.dof_downsample_sh = DRW_shader_create_fullscreen(frag, "#define DOWNSAMPLE\n"); #if 0 /* TODO(fclem) finish COC min_max optimization */ - e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(frag, "#define FLATTEN_VERTICAL\n"); - - e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(frag, "#define FLATTEN_HORIZONTAL\n"); - - e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(frag, "#define DILATE_VERTICAL\n"); - - e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(frag, "#define DILATE_HORIZONTAL\n"); #endif - e_data.dof_blur1_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, - "#define BLUR1\n"); - - e_data.dof_blur2_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, - "#define BLUR2\n"); - - e_data.dof_resolve_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, - "#define RESOLVE\n"); + e_data.dof_blur1_sh = DRW_shader_create_fullscreen(frag, "#define BLUR1\n"); + e_data.dof_blur2_sh = DRW_shader_create_fullscreen(frag, "#define BLUR2\n"); + e_data.dof_resolve_sh = DRW_shader_create_fullscreen(frag, "#define RESOLVE\n"); + MEM_freeN(frag); } *prepare_sh = e_data.dof_prepare_sh; diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c index 39aa721a41c..5fd8229304a 100644 --- a/source/blender/draw/engines/workbench/workbench_transparent.c +++ b/source/blender/draw/engines/workbench/workbench_transparent.c @@ -67,7 +67,7 @@ void workbench_transparent_engine_init(WORKBENCH_Data *data) static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp) { - DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false); if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { @@ -78,8 +78,8 @@ static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd, struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture; const bool use_spec = workbench_is_specular_highlight_enabled(wpd); spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx; - DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx); - DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx); + DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx); + DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", spec_tx); } } @@ -116,20 +116,20 @@ void workbench_transparent_cache_init(WORKBENCH_Data *data) workbench_transparent_lighting_uniforms(wpd, grp); wpd->prepass[transp][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */ sh = workbench_shader_transparent_image_get(wpd, hair, false); wpd->prepass[transp][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ workbench_transparent_lighting_uniforms(wpd, grp); sh = workbench_shader_transparent_image_get(wpd, hair, true); wpd->prepass[transp][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ workbench_transparent_lighting_uniforms(wpd, grp); } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index c4d9396307a..e7dd9e449b7 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -210,10 +210,7 @@ struct GPUShader *DRW_shader_create_with_transform_feedback(const char *vert, const eGPUShaderTFBType prim_type, const char **varying_names, const int varying_count); -struct GPUShader *DRW_shader_create_2d(const char *frag, const char *defines); -struct GPUShader *DRW_shader_create_3d(const char *frag, const char *defines); struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines); -struct GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig slot); struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, const int options, @@ -224,6 +221,7 @@ struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, bool deferred); struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, struct World *wo, + struct bNodeTree *ntree, const void *engine_type, const int options, const bool is_volume_shader, @@ -234,6 +232,7 @@ struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, bool deferred); struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, struct Material *ma, + struct bNodeTree *ntree, const void *engine_type, const int options, const bool is_volume_shader, @@ -365,6 +364,8 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, DRWPass *pass, struct GPUVertBuf *tf_target); +void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material); + /* return final visibility */ typedef bool(DRWCallVisibilityFn)(bool vis_in, void *user_data); @@ -460,18 +461,15 @@ void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup, void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); -void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, - const char *name, - const struct GPUTexture *tex); -void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, - const char *name, - const struct GPUUniformBuffer *ubo); -void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, - const char *name, - const struct GPUUniformBuffer *ubo); void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex); +void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, + const char *name, + const struct GPUUniformBuffer *ubo); +void DRW_shgroup_uniform_block_ref(DRWShadingGroup *shgroup, + const char *name, + struct GPUUniformBuffer **ubo); void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, @@ -521,11 +519,17 @@ void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value); void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value); void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value); +void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, + const char *name, + const float (*value)[4], + int arraysize); bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup); /* Passes */ DRWPass *DRW_pass_create(const char *name, DRWState state); +DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state); +void DRW_pass_link(DRWPass *first, DRWPass *second); /* TODO Replace with passes inheritance. */ void DRW_pass_state_set(DRWPass *pass, DRWState state); void DRW_pass_state_add(DRWPass *pass, DRWState state); @@ -539,6 +543,8 @@ void DRW_pass_sort_shgroup_reverse(DRWPass *pass); bool DRW_pass_is_empty(DRWPass *pass); #define DRW_PASS_CREATE(pass, state) (pass = DRW_pass_create(#pass, state)) +#define DRW_PASS_INSTANCE_CREATE(pass, original, state) \ + (pass = DRW_pass_create_instance(#pass, (original), state)) /* Views */ DRWView *DRW_view_create(const float viewmat[4][4], @@ -692,6 +698,8 @@ typedef struct DRWContextState { struct Depsgraph *depsgraph; + struct TaskGraph *task_graph; + eObjectMode object_mode; eGPUShaderConfig sh_cfg; diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 23d0d74534d..c23ea3d7c82 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -3534,13 +3534,15 @@ void drw_batch_cache_generate_requested(Object *ob) struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); switch (ob->type) { case OB_MESH: - DRW_mesh_batch_cache_create_requested(ob, (Mesh *)ob->data, scene, is_paint_mode, use_hide); + DRW_mesh_batch_cache_create_requested( + DST.task_graph, ob, (Mesh *)ob->data, scene, is_paint_mode, use_hide); break; case OB_CURVE: case OB_FONT: case OB_SURF: if (mesh_eval) { - DRW_mesh_batch_cache_create_requested(ob, mesh_eval, scene, is_paint_mode, use_hide); + DRW_mesh_batch_cache_create_requested( + DST.task_graph, ob, mesh_eval, scene, is_paint_mode, use_hide); } DRW_curve_batch_cache_create_requested(ob); break; diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index b2fea957227..f203c2ff1ea 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -23,6 +23,8 @@ #ifndef __DRAW_CACHE_EXTRACT_H__ #define __DRAW_CACHE_EXTRACT_H__ +struct TaskGraph; + /* Vertex Group Selection and display options */ typedef struct DRW_MeshWeightState { int defgroup_active; @@ -249,7 +251,8 @@ typedef struct MeshBatchCache { bool no_loose_wire; } MeshBatchCache; -void mesh_buffer_cache_create_requested(MeshBatchCache *cache, +void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, + MeshBatchCache *cache, MeshBufferCache mbc, Mesh *me, const bool is_editmode, diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index 401f5c76a02..06462d5b9c5 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -105,6 +105,14 @@ typedef struct MeshRenderData { BMEditMesh *edit_bmesh; BMesh *bm; EditMeshData *edit_data; + + /* For deformed edit-mesh data. */ + /* Use for #ME_WRAPPER_TYPE_BMESH. */ + const float (*bm_vert_coords)[3]; + const float (*bm_vert_normals)[3]; + const float (*bm_poly_normals)[3]; + const float (*bm_poly_centers)[3]; + int *v_origindex, *e_origindex, *p_origindex; int crease_ofs; int bweight_ofs; @@ -126,15 +134,12 @@ typedef struct MeshRenderData { float (*poly_normals)[3]; int *lverts, *ledges; } MeshRenderData; - static MeshRenderData *mesh_render_data_create(Mesh *me, const bool is_editmode, const bool is_paint_mode, const float obmat[4][4], const bool do_final, const bool do_uvedit, - const eMRIterType iter_type, - const eMRDataType data_flag, const DRW_MeshCDMask *UNUSED(cd_used), const ToolSettings *ts) { @@ -144,16 +149,28 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, copy_m4_m4(mr->obmat, obmat); - const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0; - const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI; - if (is_editmode) { BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final); mr->bm = me->edit_mesh->bm; mr->edit_bmesh = me->edit_mesh; - mr->edit_data = me->runtime.edit_data; mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage; - bool use_mapped = !do_uvedit && mr->me && !mr->me->runtime.is_original; + mr->edit_data = mr->me->runtime.edit_data; + + if (mr->edit_data) { + EditMeshData *emd = mr->edit_data; + if (emd->vertexCos) { + BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd); + BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd); + } + + mr->bm_vert_coords = mr->edit_data->vertexCos; + mr->bm_vert_normals = mr->edit_data->vertexNos; + mr->bm_poly_normals = mr->edit_data->polyNos; + mr->bm_poly_centers = mr->edit_data->polyCos; + } + + bool has_mdata = (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA); + bool use_mapped = has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original; int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE; @@ -184,7 +201,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, /* Seems like the mesh_eval_final do not have the right origin indices. * Force not mapped in this case. */ - if (do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) { + if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) { // mr->edit_bmesh = NULL; mr->extract_type = MR_EXTRACT_MESH; } @@ -221,7 +238,32 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); + } + else { + /* BMesh */ + BMesh *bm = mr->bm; + mr->vert_len = bm->totvert; + mr->edge_len = bm->totedge; + mr->loop_len = bm->totloop; + mr->poly_len = bm->totface; + mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); + } + + return mr; +} + +/* Part of the creation of the MeshRenderData that happens in a thread. */ +static void mesh_render_data_update(MeshRenderData *mr, + const eMRIterType iter_type, + const eMRDataType data_flag) +{ + Mesh *me = mr->me; + const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0; + const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI; + + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) { mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__); BKE_mesh_calc_normals_poly((MVert *)mr->mvert, @@ -300,23 +342,27 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, else { /* BMesh */ BMesh *bm = mr->bm; - - mr->vert_len = bm->totvert; - mr->edge_len = bm->totedge; - mr->loop_len = bm->totloop; - mr->poly_len = bm->totface; - mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); - if (data_flag & MR_DATA_POLY_NOR) { /* Use bmface->no instead. */ } if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { + + const float(*vert_coords)[3] = NULL; + const float(*vert_normals)[3] = NULL; + const float(*poly_normals)[3] = NULL; + + if (mr->edit_data && mr->edit_data->vertexCos) { + vert_coords = mr->bm_vert_coords; + vert_normals = mr->bm_vert_normals; + poly_normals = mr->bm_poly_normals; + } + mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); BM_loops_calc_normal_vcos(mr->bm, - NULL, - NULL, - NULL, + vert_coords, + vert_normals, + poly_normals, is_auto_smooth, split_angle, mr->loop_normals, @@ -360,7 +406,6 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2; } } - return mr; } static void mesh_render_data_free(MeshRenderData *mr) @@ -396,6 +441,42 @@ BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx) NULL; } +BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve) +{ + const float(*vert_coords)[3] = mr->bm_vert_coords; + if (vert_coords != NULL) { + return vert_coords[BM_elem_index_get(eve)]; + } + else { + UNUSED_VARS(mr); + return eve->co; + } +} + +BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve) +{ + const float(*vert_normals)[3] = mr->bm_vert_normals; + if (vert_normals != NULL) { + return vert_normals[BM_elem_index_get(eve)]; + } + else { + UNUSED_VARS(mr); + return eve->co; + } +} + +BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa) +{ + const float(*poly_normals)[3] = mr->bm_poly_normals; + if (poly_normals != NULL) { + return poly_normals[BM_elem_index_get(efa)]; + } + else { + UNUSED_VARS(mr); + return efa->no; + } +} + /** \} */ /* ---------------------------------------------------------------------- */ @@ -672,46 +753,15 @@ static const MeshExtract extract_lines = { 0, false, }; - /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Loose Edges Indices +/** \name Extract Loose Edges Sub Buffer * \{ */ -static void *extract_lines_loose_init(const MeshRenderData *UNUSED(mr), void *UNUSED(buf)) -{ - return NULL; -} - -static void extract_lines_loose_ledge_mesh(const MeshRenderData *UNUSED(mr), - int UNUSED(e), - const MEdge *UNUSED(medge), - void *UNUSED(elb)) -{ - /* This function is intentionally empty. The existence of this functions ensures that - * `iter_type` `MR_ITER_LVERT` is set when initializing the `MeshRenderData` (See - * `mesh_extract_iter_type`). This flag ensures that `mr->edge_loose_len` field is filled. This - * field we use in the `extract_lines_loose_finish` function to create a subrange from the - * `ibo.lines`. */ -} - -static void extract_lines_loose_ledge_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(e), - BMEdge *UNUSED(eed), - void *UNUSED(elb)) -{ - /* This function is intentionally empty. The existence of this functions ensures that - * `iter_type` `MR_ITER_LVERT` is set when initializing the `MeshRenderData` (See - * `mesh_extract_iter_type`). This flag ensures that `mr->edge_loose_len` field is filled. This - * field we use in the `extract_lines_loose_finish` function to create a subrange from the - * `ibo.lines`. */ -} - -static void extract_lines_loose_finish(const MeshRenderData *mr, - void *UNUSED(ibo), - void *UNUSED(elb)) +static void extract_lines_loose_subbuffer(const MeshRenderData *mr) { + BLI_assert(mr->cache->final.ibo.lines); /* Multiply by 2 because these are edges indices. */ const int start = mr->edge_len * 2; const int len = mr->edge_loose_len * 2; @@ -720,17 +770,24 @@ static void extract_lines_loose_finish(const MeshRenderData *mr, mr->cache->no_loose_wire = (len == 0); } -static const MeshExtract extract_lines_loose = { - extract_lines_loose_init, - NULL, - NULL, +static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, void *ibo, void *elb) +{ + GPU_indexbuf_build_in_place(elb, ibo); + extract_lines_loose_subbuffer(mr); + MEM_freeN(elb); +} + +static const MeshExtract extract_lines_with_lines_loose = { + extract_lines_init, NULL, NULL, - extract_lines_loose_ledge_bmesh, - extract_lines_loose_ledge_mesh, + extract_lines_loop_bmesh, + extract_lines_loop_mesh, + extract_lines_ledge_bmesh, + extract_lines_ledge_mesh, NULL, NULL, - extract_lines_loose_finish, + extract_lines_with_lines_loose_finish, 0, false, }; @@ -1480,7 +1537,7 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf) BMVert *eve; int v; BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) { - data->packed_nor[v] = GPU_normal_convert_i10_v3(eve->no); + data->packed_nor[v] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, eve)); } } else { @@ -1492,14 +1549,11 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_pos_nor_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *_data) +static void extract_pos_nor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) { MeshExtract_PosNor_Data *data = _data; PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, loop->v->co); + copy_v3_v3(vert->pos, bm_vert_co_get(mr, loop->v)); vert->nor = data->packed_nor[BM_elem_index_get(loop->v)]; BMFace *efa = loop->f; vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; @@ -1536,8 +1590,8 @@ static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge int l = mr->loop_len + e * 2; MeshExtract_PosNor_Data *data = _data; PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert[0].pos, eed->v1->co); - copy_v3_v3(vert[1].pos, eed->v2->co); + copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); + copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)]; vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)]; } @@ -1561,7 +1615,7 @@ static void extract_pos_nor_lvert_bmesh(const MeshRenderData *mr, int v, BMVert int l = mr->loop_len + mr->edge_loose_len * 2 + v; MeshExtract_PosNor_Data *data = _data; PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, eve->co); + copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); vert->nor = data->packed_nor[BM_elem_index_get(eve)]; } @@ -1627,10 +1681,10 @@ static void extract_lnor_hq_loop_bmesh(const MeshRenderData *mr, int l, BMLoop * normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->loop_normals[l]); } else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, loop->v->no); + normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_vert_no_get(mr, loop->v)); } else { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, loop->f->no); + normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_face_no_get(mr, loop->f)); } } @@ -1649,8 +1703,8 @@ static void extract_lnor_hq_loop_mesh( } /* Flag for paint mode overlay. - * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In paint - * mode it will use the unmapped data to draw the wireframe. */ + * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In + * paint mode it will use the unmapped data to draw the wireframe. */ if (mpoly->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) { @@ -1704,10 +1758,10 @@ static void extract_lnor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loo ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]); } else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->v->no); + ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, loop->v)); } else { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->f->no); + ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, loop->f)); } BMFace *efa = loop->f; ((GPUPackedNormal *)data)[l].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; @@ -1728,8 +1782,8 @@ static void extract_lnor_loop_mesh( } /* Flag for paint mode overlay. - * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In paint - * mode it will use the unmapped data to draw the wireframe. */ + * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In + * paint mode it will use the unmapped data to draw the wireframe. */ if (mpoly->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) { @@ -1915,7 +1969,10 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool if (mr->extract_type == MR_EXTRACT_BMESH) { BMesh *bm = mr->bm; for (int v = 0; v < mr->vert_len; v++) { - copy_v3_v3(orco[v], BM_vert_at_index(bm, v)->co); + const BMVert *eve = BM_vert_at_index(bm, v); + /* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords. + * not the distorted ones. */ + copy_v3_v3(orco[v], eve->co); } } else { @@ -2092,10 +2149,10 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) GPUVertFormat format = {0}; GPU_vertformat_deinterleave(&format); - CustomData *cd_ldata = &mr->me->ldata; + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; uint32_t vcol_layers = mr->cache->cd_used.vcol; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i); @@ -2127,14 +2184,32 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) } gpuMeshVcol; gpuMeshVcol *vcol_data = (gpuMeshVcol *)vbo->data; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { - MLoopCol *mcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); - for (int l = 0; l < mr->loop_len; l++, mcol++, vcol_data++) { - vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); - vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); - vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); - vcol_data->a = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); + if (mr->extract_type == MR_EXTRACT_BMESH) { + int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i); + BMIter f_iter, l_iter; + BMFace *efa; + BMLoop *loop; + BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { + const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); + vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); + vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); + vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); + vcol_data++; + } + } + } + else { + const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); + for (int l = 0; l < mr->loop_len; l++, mloopcol++, vcol_data++) { + vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); + vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); + vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); + vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); + } } } } @@ -2301,14 +2376,14 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_edge_fac_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *_data) +static void extract_edge_fac_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) { MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; if (BM_edge_is_manifold(loop->e)) { - float ratio = loop_edge_factor_get(loop->f->no, loop->v->co, loop->v->no, loop->next->v->co); + float ratio = loop_edge_factor_get(bm_face_no_get(mr, loop->f), + bm_vert_co_get(mr, loop->v), + bm_vert_no_get(mr, loop->v), + bm_vert_co_get(mr, loop->next->v)); data->vbo_data[l] = ratio * 253 + 1; } else { @@ -3133,7 +3208,7 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr), +static void extract_stretch_angle_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) @@ -3150,8 +3225,12 @@ static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr), BMLoop *l_next_tmp = loop; luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs); luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs); - compute_normalize_edge_vectors( - auv, av, luv->uv, luv_next->uv, l_tmp->v->co, l_next_tmp->v->co); + compute_normalize_edge_vectors(auv, + av, + luv->uv, + luv_next->uv, + bm_vert_co_get(mr, l_tmp->v), + bm_vert_co_get(mr, l_next_tmp->v)); /* Save last edge. */ copy_v2_v2(last_auv, auv[1]); copy_v3_v3(last_av, av[1]); @@ -3167,7 +3246,12 @@ static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr), else { luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs); luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); - compute_normalize_edge_vectors(auv, av, luv->uv, luv_next->uv, loop->v->co, l_next->v->co); + compute_normalize_edge_vectors(auv, + av, + luv->uv, + luv_next->uv, + bm_vert_co_get(mr, loop->v), + bm_vert_co_get(mr, l_next->v)); } edituv_get_stretch_angle(auv, av, data->vbo_data + l); } @@ -3307,7 +3391,7 @@ static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang) if (mr->extract_type == MR_EXTRACT_BMESH) { int l = 0; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - float fac = angle_normalized_v3v3(f->no, dir) / (float)M_PI; + float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI; fac = overhang_remap(fac, min, max, minmax_irange); for (int i = 0; i < f->len; i++, l++) { r_overhang[l] = fac; @@ -3385,7 +3469,11 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) for (int i = 0; i < mr->tri_len; i++) { BMLoop **ltri = looptris[i]; const int index = BM_elem_index_get(ltri[0]->f); - const float *cos[3] = {ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co}; + const float *cos[3] = { + bm_vert_co_get(mr, ltri[0]->v), + bm_vert_co_get(mr, ltri[1]->v), + bm_vert_co_get(mr, ltri[2]->v), + }; float ray_co[3]; float ray_no[3]; @@ -3398,7 +3486,8 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) BMFace *f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL); if (f_hit && dist < face_dists[index]) { - float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no)); + float angle_fac = fabsf( + dot_v3v3(bm_face_no_get(mr, ltri[0]->f), bm_face_no_get(mr, f_hit))); angle_fac = 1.0f - angle_fac; angle_fac = angle_fac * angle_fac * angle_fac; angle_fac = 1.0f - angle_fac; @@ -3603,8 +3692,17 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) BMesh *bm = em->bm; BMFace *f; + if (mr->bm_vert_coords != NULL) { + BKE_editmesh_cache_ensure_poly_normals(em, mr->edit_data); + + /* Most likely this is already valid, ensure just in case. + * Needed for #BM_loop_calc_face_normal_safe_vcos. */ + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + } + int l = 0; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + int p = 0; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, p) { float fac = -1.0f; if (f->len > 3) { @@ -3613,13 +3711,23 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) fac = 0.0f; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { + const float *no_face; float no_corner[3]; - BM_loop_calc_face_normal_safe(l_iter, no_corner); + if (mr->bm_vert_coords != NULL) { + no_face = mr->bm_poly_normals[p]; + BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner); + } + else { + no_face = f->no; + BM_loop_calc_face_normal_safe(l_iter, no_corner); + } + /* simple way to detect (what is most likely) concave */ - if (dot_v3v3(f->no, no_corner) < 0.0f) { + if (dot_v3v3(no_face, no_corner) < 0.0f) { negate_v3(no_corner); } - fac = max_ff(fac, angle_normalized_v3v3(f->no, no_corner)); + fac = max_ff(fac, angle_normalized_v3v3(no_face, no_corner)); + } while ((l_iter = l_iter->next) != l_first); fac *= 2.0f; } @@ -3842,14 +3950,14 @@ static void *extract_fdots_pos_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_fdots_pos_loop_bmesh(const MeshRenderData *UNUSED(mr), +static void extract_fdots_pos_loop_bmesh(const MeshRenderData *mr, int UNUSED(l), BMLoop *loop, void *data) { float(*center)[3] = (float(*)[3])data; float w = 1.0f / (float)loop->f->len; - madd_v3_v3fl(center[BM_elem_index_get(loop->f)], loop->v->co, w); + madd_v3_v3fl(center[BM_elem_index_get(loop->f)], bm_vert_co_get(mr, loop->v), w); } static void extract_fdots_pos_loop_mesh(const MeshRenderData *mr, @@ -3928,7 +4036,7 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void * nor[f].w = NOR_AND_FLAG_HIDDEN; } else { - nor[f] = GPU_normal_convert_i10_v3(efa->no); + nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa)); /* Select / Active Flag. */ nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : @@ -3946,7 +4054,7 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void * nor[f].w = NOR_AND_FLAG_HIDDEN; } else { - nor[f] = GPU_normal_convert_i10_v3(efa->no); + nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa)); /* Select / Active Flag. */ nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : @@ -4171,7 +4279,7 @@ static void *extract_skin_roots_init(const MeshRenderData *mr, void *buf) const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_ofs); if (vs->flag & MVERT_SKIN_ROOT) { vbo_data->size = (vs->radius[0] + vs->radius[1]) * 0.5f; - copy_v3_v3(vbo_data->local_pos, eve->co); + copy_v3_v3(vbo_data->local_pos, bm_vert_co_get(mr, eve)); vbo_data++; root_len++; } @@ -4419,10 +4527,14 @@ static const MeshExtract extract_fdot_idx = { /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Loop +/** \name ExtractTaskData * \{ */ +typedef struct ExtractUserData { + void *user_data; +} ExtractUserData; typedef struct ExtractTaskData { + void *next, *prev; const MeshRenderData *mr; const MeshExtract *extract; eMRIterType iter_type; @@ -4430,9 +4542,16 @@ typedef struct ExtractTaskData { /** Decremented each time a task is finished. */ int32_t *task_counter; void *buf; - void *user_data; + ExtractUserData *user_data; } ExtractTaskData; +static void extract_task_data_free(void *data) +{ + ExtractTaskData *task_data = data; + MEM_SAFE_FREE(task_data->user_data); + MEM_freeN(task_data); +} + BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, const eMRIterType iter_type, int start, @@ -4509,31 +4628,184 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, } } -static void extract_run(TaskPool *__restrict UNUSED(pool), void *taskdata) +static void extract_init(ExtractTaskData *data) { - ExtractTaskData *data = taskdata; - mesh_extract_iter( - data->mr, data->iter_type, data->start, data->end, data->extract, data->user_data); + data->user_data->user_data = data->extract->init(data->mr, data->buf); +} + +static void extract_run(void *__restrict taskdata) +{ + ExtractTaskData *data = (ExtractTaskData *)taskdata; + mesh_extract_iter(data->mr, + data->iter_type, + data->start, + data->end, + data->extract, + data->user_data->user_data); /* If this is the last task, we do the finish function. */ int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1); if (remainin_tasks == 0 && data->extract->finish != NULL) { - data->extract->finish(data->mr, data->buf, data->user_data); + data->extract->finish(data->mr, data->buf, data->user_data->user_data); } } -static void extract_range_task_create( - TaskPool *task_pool, ExtractTaskData *taskdata, const eMRIterType type, int start, int length) +static void extract_init_and_run(void *__restrict taskdata) +{ + extract_init((ExtractTaskData *)taskdata); + extract_run(taskdata); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Task Node - Update Mesh Render Data + * \{ */ +typedef struct MeshRenderDataUpdateTaskData { + MeshRenderData *mr; + eMRIterType iter_type; + eMRDataType data_flag; +} MeshRenderDataUpdateTaskData; + +static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata) +{ + BLI_assert(taskdata); + mesh_render_data_free(taskdata->mr); + MEM_freeN(taskdata); +} + +static void mesh_extract_render_data_node_exec(void *__restrict task_data) +{ + MeshRenderDataUpdateTaskData *update_task_data = task_data; + mesh_render_data_update( + update_task_data->mr, update_task_data->iter_type, update_task_data->data_flag); +} + +static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph, + MeshRenderData *mr, + const eMRIterType iter_type, + const eMRDataType data_flag) +{ + MeshRenderDataUpdateTaskData *task_data = MEM_mallocN(sizeof(MeshRenderDataUpdateTaskData), + __func__); + task_data->mr = mr; + task_data->iter_type = iter_type; + task_data->data_flag = data_flag; + + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, + mesh_extract_render_data_node_exec, + task_data, + (TaskGraphNodeFreeFunction)mesh_render_data_update_task_data_free); + return task_node; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Task Node - Extract Single Threaded + * \{ */ +typedef struct ExtractSingleThreadedTaskData { + ListBase task_datas; +} ExtractSingleThreadedTaskData; + +static void extract_single_threaded_task_data_free(ExtractSingleThreadedTaskData *taskdata) +{ + BLI_assert(taskdata); + LISTBASE_FOREACH_MUTABLE (ExtractTaskData *, td, &taskdata->task_datas) { + extract_task_data_free(td); + } + BLI_listbase_clear(&taskdata->task_datas); + MEM_freeN(taskdata); +} + +static void extract_single_threaded_task_node_exec(void *__restrict task_data) +{ + ExtractSingleThreadedTaskData *extract_task_data = task_data; + LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) { + extract_init_and_run(td); + } +} + +static struct TaskNode *extract_single_threaded_task_node_create( + struct TaskGraph *task_graph, ExtractSingleThreadedTaskData *task_data) +{ + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, + extract_single_threaded_task_node_exec, + task_data, + (TaskGraphNodeFreeFunction)extract_single_threaded_task_data_free); + return task_node; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Task Node - UserData Initializer + * \{ */ +typedef struct UserDataInitTaskData { + ListBase task_datas; + int32_t *task_counters; + +} UserDataInitTaskData; + +static void user_data_init_task_data_free(UserDataInitTaskData *taskdata) +{ + BLI_assert(taskdata); + LISTBASE_FOREACH_MUTABLE (ExtractTaskData *, td, &taskdata->task_datas) { + extract_task_data_free(td); + } + BLI_listbase_clear(&taskdata->task_datas); + MEM_SAFE_FREE(taskdata->task_counters); + MEM_freeN(taskdata); +} + +static void user_data_init_task_data_exec(void *__restrict task_data) +{ + UserDataInitTaskData *extract_task_data = task_data; + LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) { + extract_init(td); + } +} + +static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph, + UserDataInitTaskData *task_data) +{ + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, + user_data_init_task_data_exec, + task_data, + (TaskGraphNodeFreeFunction)user_data_init_task_data_free); + return task_node; +} + +/** \} */ +/* ---------------------------------------------------------------------- */ +/** \name Extract Loop + * \{ */ + +static void extract_range_task_create(struct TaskGraph *task_graph, + struct TaskNode *task_node_user_data_init, + ExtractTaskData *taskdata, + const eMRIterType type, + int start, + int length) { taskdata = MEM_dupallocN(taskdata); atomic_add_and_fetch_int32(taskdata->task_counter, 1); taskdata->iter_type = type; taskdata->start = start; taskdata->end = start + length; - BLI_task_pool_push(task_pool, extract_run, taskdata, true, NULL); + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, extract_run, taskdata, MEM_freeN); + BLI_task_graph_edge_create(task_node_user_data_init, task_node); } -static void extract_task_create(TaskPool *task_pool, +static void extract_task_create(struct TaskGraph *task_graph, + struct TaskNode *task_node_mesh_render_data, + struct TaskNode *task_node_user_data_init, + ListBase *single_threaded_task_datas, + ListBase *user_data_init_task_datas, const Scene *scene, const MeshRenderData *mr, const MeshExtract *extract, @@ -4551,58 +4823,75 @@ static void extract_task_create(TaskPool *task_pool, /* Divide extraction of the VBO/IBO into sensible chunks of works. */ ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), "ExtractTaskData"); + taskdata->next = NULL; + taskdata->prev = NULL; taskdata->mr = mr; taskdata->extract = extract; taskdata->buf = buf; - taskdata->user_data = extract->init(mr, buf); + + /* ExtractUserData is shared between the iterations as it holds counters to detect if the + * extraction is finished. To make sure the duplication of the userdata does not create a new + * instance of the counters we allocate the userdata in its own container. + * + * This structure makes sure that when extract_init is called, that the user data of all + * iterations are updated. */ + taskdata->user_data = MEM_callocN(sizeof(ExtractUserData), __func__); taskdata->iter_type = mesh_extract_iter_type(extract); taskdata->task_counter = task_counter; taskdata->start = 0; taskdata->end = INT_MAX; /* Simple heuristic. */ - const bool use_thread = (mr->loop_len + mr->loop_loose_len) > 8192; + const int chunk_size = 8192; + const bool use_thread = (mr->loop_len + mr->loop_loose_len) > chunk_size; if (use_thread && extract->use_threading) { + /* Divide task into sensible chunks. */ - const int chunk_size = 8192; if (taskdata->iter_type & MR_ITER_LOOPTRI) { for (int i = 0; i < mr->tri_len; i += chunk_size) { - extract_range_task_create(task_pool, taskdata, MR_ITER_LOOPTRI, i, chunk_size); + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOPTRI, i, chunk_size); } } if (taskdata->iter_type & MR_ITER_LOOP) { for (int i = 0; i < mr->poly_len; i += chunk_size) { - extract_range_task_create(task_pool, taskdata, MR_ITER_LOOP, i, chunk_size); + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOP, i, chunk_size); } } if (taskdata->iter_type & MR_ITER_LEDGE) { for (int i = 0; i < mr->edge_loose_len; i += chunk_size) { - extract_range_task_create(task_pool, taskdata, MR_ITER_LEDGE, i, chunk_size); + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata, MR_ITER_LEDGE, i, chunk_size); } } if (taskdata->iter_type & MR_ITER_LVERT) { for (int i = 0; i < mr->vert_loose_len; i += chunk_size) { - extract_range_task_create(task_pool, taskdata, MR_ITER_LVERT, i, chunk_size); + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata, MR_ITER_LVERT, i, chunk_size); } } - MEM_freeN(taskdata); + BLI_addtail(user_data_init_task_datas, taskdata); } else if (use_thread) { /* One task for the whole VBO. */ (*task_counter)++; - BLI_task_pool_push(task_pool, extract_run, taskdata, true, NULL); + struct TaskNode *one_task = BLI_task_graph_node_create( + task_graph, extract_init_and_run, taskdata, extract_task_data_free); + BLI_task_graph_edge_create(task_node_mesh_render_data, one_task); } else { /* Single threaded extraction. */ (*task_counter)++; - extract_run(NULL, taskdata); - MEM_freeN(taskdata); + BLI_addtail(single_threaded_task_datas, taskdata); } } -void mesh_buffer_cache_create_requested(MeshBatchCache *cache, +void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, + MeshBatchCache *cache, MeshBufferCache mbc, Mesh *me, + const bool is_editmode, const bool is_paint_mode, const float obmat[4][4], @@ -4614,9 +4903,41 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, const ToolSettings *ts, const bool use_hide) { + /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph. + * This sub-graph starts with an extract_render_data_node. This fills/converts the required data + * from Mesh. + * + * Small extractions and extractions that can't be multi-threaded are grouped in a single + * `extract_single_threaded_task_node`. + * + * Other extractions will create a node for each loop exceeding 8192 items. these nodes are + * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the userdata + * needed for the extraction based on the data extracted from the mesh. counters are used to + * check if the finalize of a task has to be called. + * + * Mesh extraction sub graph + * + * +----------------------+ + * +-----> | extract_task1_loop_1 | + * | +----------------------+ + * +------------------+ +----------------------+ +----------------------+ + * | mesh_render_data | --> | | --> | extract_task1_loop_2 | + * +------------------+ | | +----------------------+ + * | | | +----------------------+ + * | | user_data_init | --> | extract_task2_loop_1 | + * v | | +----------------------+ + * +------------------+ | | +----------------------+ + * | single_threaded | | | --> | extract_task2_loop_2 | + * +------------------+ +----------------------+ +----------------------+ + * | +----------------------+ + * +-----> | extract_task2_loop_3 | + * +----------------------+ + */ eMRIterType iter_flag = 0; eMRDataType data_flag = 0; + const bool do_lines_loose_subbuffer = mbc.ibo.lines_loose != NULL; + #define TEST_ASSIGN(type, type_lowercase, name) \ do { \ if (DRW_TEST_ASSIGN_##type(mbc.type_lowercase.name)) { \ @@ -4654,7 +4975,6 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, TEST_ASSIGN(IBO, ibo, fdots); TEST_ASSIGN(IBO, ibo, lines_paint_mask); TEST_ASSIGN(IBO, ibo, lines_adjacency); - TEST_ASSIGN(IBO, ibo, lines_loose); TEST_ASSIGN(IBO, ibo, edituv_tris); TEST_ASSIGN(IBO, ibo, edituv_lines); TEST_ASSIGN(IBO, ibo, edituv_points); @@ -4666,16 +4986,8 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, double rdata_start = PIL_check_seconds_timer(); #endif - MeshRenderData *mr = mesh_render_data_create(me, - is_editmode, - is_paint_mode, - obmat, - do_final, - do_uvedit, - iter_flag, - data_flag, - cd_layer_used, - ts); + MeshRenderData *mr = mesh_render_data_create( + me, is_editmode, is_paint_mode, obmat, do_final, do_uvedit, cd_layer_used, ts); mr->cache = cache; /* HACK */ mr->use_hide = use_hide; mr->use_subsurf_fdots = use_subsurf_fdots; @@ -4685,20 +4997,32 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, double rdata_end = PIL_check_seconds_timer(); #endif - TaskPool *task_pool; - - /* Create a suspended pool as the finalize method could be called too early. - * See `extract_run`. */ - task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH); - size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t); int32_t *task_counters = MEM_callocN(counters_size, __func__); int counter_used = 0; + struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create( + task_graph, mr, iter_flag, data_flag); + ExtractSingleThreadedTaskData *single_threaded_task_data = MEM_callocN( + sizeof(ExtractSingleThreadedTaskData), __func__); + UserDataInitTaskData *user_data_init_task_data = MEM_callocN(sizeof(UserDataInitTaskData), + __func__); + user_data_init_task_data->task_counters = task_counters; + struct TaskNode *task_node_user_data_init = user_data_init_task_node_create( + task_graph, user_data_init_task_data); + #define EXTRACT(buf, name) \ if (mbc.buf.name) { \ - extract_task_create( \ - task_pool, scene, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \ + extract_task_create(task_graph, \ + task_node_mesh_render_data, \ + task_node_user_data_init, \ + &single_threaded_task_data->task_datas, \ + &user_data_init_task_data->task_datas, \ + scene, \ + mr, \ + &extract_##name, \ + mbc.buf.name, \ + &task_counters[counter_used++]); \ } \ ((void)0) @@ -4726,7 +5050,33 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, EXTRACT(vbo, skin_roots); EXTRACT(ibo, tris); - EXTRACT(ibo, lines); + if (mbc.ibo.lines) { + /* When `lines` and `lines_loose` are requested, schedule lines extraction that also creates + * the `lines_loose` sub-buffer. */ + const MeshExtract *lines_extractor = do_lines_loose_subbuffer ? + &extract_lines_with_lines_loose : + &extract_lines; + extract_task_create(task_graph, + task_node_mesh_render_data, + task_node_user_data_init, + &single_threaded_task_data->task_datas, + &user_data_init_task_data->task_datas, + scene, + mr, + lines_extractor, + mbc.ibo.lines, + &task_counters[counter_used++]); + } + else { + if (do_lines_loose_subbuffer) { + /* When `lines_loose` is requested without `lines` we can create the sub-buffer on the fly as + * the `lines` buffer should then already be up-to-date. + * (see `DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)` in + * `DRW_mesh_batch_cache_create_requested`). + */ + extract_lines_loose_subbuffer(mr); + } + } EXTRACT(ibo, points); EXTRACT(ibo, fdots); EXTRACT(ibo, lines_paint_mask); @@ -4736,27 +5086,29 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, EXTRACT(ibo, edituv_points); EXTRACT(ibo, edituv_fdots); - /* TODO(fclem) Ideally, we should have one global pool for all - * objects and wait for finish only before drawing when buffers - * need to be ready. */ - BLI_task_pool_work_and_wait(task_pool); - - /* The next task(s) rely on the result of the tasks above. */ + /* Only create the edge when there is user data that needs to be initialized. + * The task is still part of the graph so the task_data will be freed when the graph is freed. + */ + if (!BLI_listbase_is_empty(&user_data_init_task_data->task_datas)) { + BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init); + } - /* The `lines_loose` is a sub buffer from `ibo.lines`. - * We schedule it here due to potential synchronization issues.*/ - EXTRACT(ibo, lines_loose); + if (!BLI_listbase_is_empty(&single_threaded_task_data->task_datas)) { + struct TaskNode *task_node = extract_single_threaded_task_node_create( + task_graph, single_threaded_task_data); + BLI_task_graph_edge_create(task_node_mesh_render_data, task_node); + } + else { + extract_single_threaded_task_data_free(single_threaded_task_data); + } - BLI_task_pool_work_and_wait(task_pool); + /* Trigger the sub-graph for this mesh. */ + BLI_task_graph_node_push_work(task_node_mesh_render_data); #undef EXTRACT - BLI_task_pool_free(task_pool); - MEM_freeN(task_counters); - - mesh_render_data_free(mr); - #ifdef DEBUG_TIME + BLI_task_graph_work_and_wait(task_graph); double end = PIL_check_seconds_timer(); static double avg = 0; diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index de0cd027ece..80649143537 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -31,6 +31,7 @@ struct ListBase; struct ModifierData; struct PTCacheEdit; struct ParticleSystem; +struct TaskGraph; struct Curve; struct Hair; @@ -150,7 +151,8 @@ int DRW_volume_material_count_get(struct Volume *volume); struct GPUBatch *DRW_volume_batch_cache_get_wireframes_face(struct Volume *volume); /* Mesh */ -void DRW_mesh_batch_cache_create_requested(struct Object *ob, +void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, + struct Object *ob, struct Mesh *me, const struct Scene *scene, const bool is_paint_mode, @@ -208,6 +210,7 @@ enum { VFLAG_EDGE_SEAM = 1 << 4, VFLAG_EDGE_SHARP = 1 << 5, VFLAG_EDGE_FREESTYLE = 1 << 6, + VFLAG_HANDLE_SELECTED = 1 << 7, /* Beware to not go over 1 << 7 (it's a byte flag) * (see gpu_shader_edit_mesh_overlay_geom.glsl) */ }; diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index 5642ffba4f1..c6112994b65 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -685,14 +685,20 @@ static void curve_create_edit_curves_nor(CurveRenderData *rdata, GPUVertBuf *vbo BLI_assert(vbo_len_used == verts_len_capacity); } -static char beztriple_vflag_get( - CurveRenderData *rdata, char flag, char col_id, int v_idx, int nu_id, bool handle_point) +static char beztriple_vflag_get(CurveRenderData *rdata, + char flag, + char col_id, + int v_idx, + int nu_id, + bool handle_point, + const bool handle_selected) { char vflag = 0; SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERT_SELECTED); SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert && nu_id == rdata->actnu), VFLAG_VERT_ACTIVE); SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB); SET_FLAG_FROM_TEST(vflag, handle_point, BEZIER_HANDLE); + SET_FLAG_FROM_TEST(vflag, handle_selected, VFLAG_HANDLE_SELECTED); /* handle color id */ vflag |= col_id << COLOR_SHIFT; return vflag; @@ -754,11 +760,13 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata, for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, nu_id++) { const BezTriple *bezt = nu->bezt; const BPoint *bp = nu->bp; + if (bezt) { for (int a = 0; a < nu->pntsu; a++, bezt++) { if (bezt->hide == true) { continue; } + const bool handle_selected = BEZT_ISSEL_ANY(bezt); if (elbp_verts) { GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used + 0); @@ -771,9 +779,9 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata, } if (vbo_data) { const char vflag[3] = { - beztriple_vflag_get(rdata, bezt->f1, bezt->h1, a, nu_id, true), - beztriple_vflag_get(rdata, bezt->f2, bezt->h1, a, nu_id, false), - beztriple_vflag_get(rdata, bezt->f3, bezt->h2, a, nu_id, true), + beztriple_vflag_get(rdata, bezt->f1, bezt->h1, a, nu_id, true, handle_selected), + beztriple_vflag_get(rdata, bezt->f2, bezt->h1, a, nu_id, false, handle_selected), + beztriple_vflag_get(rdata, bezt->f3, bezt->h2, a, nu_id, true, handle_selected), }; for (int j = 0; j < 3; j++) { GPU_vertbuf_attr_set(vbo_data, attr_id.data, vbo_len_used + j, &vflag[j]); diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index ee148e0934d..b4974330043 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -102,6 +102,7 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra) cache->is_dirty = true; cache->cache_frame = cfra; + return cache; } @@ -385,7 +386,8 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr .vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */ .tri_len = 0, }; - BKE_gpencil_visible_stroke_iter(ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter( + NULL, ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra); /* Create VBOs. */ GPUVertFormat *format = gpencil_stroke_format(); @@ -401,7 +403,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, iter.vert_len); /* Fill buffers with data. */ - BKE_gpencil_visible_stroke_iter(ob, NULL, gpencil_stroke_iter_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter(NULL, ob, NULL, gpencil_stroke_iter_cb, &iter, do_onion, cfra); /* Mark last 2 verts as invalid. */ for (int i = 0; i < 2; i++) { @@ -475,7 +477,7 @@ GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob) /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */ bool do_onion = true; - BKE_gpencil_visible_stroke_iter(ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter(NULL, ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra); GPUIndexBuf *ibo = GPU_indexbuf_build(&iter.ibo); @@ -724,7 +726,8 @@ static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, in iter.verts = (gpEditVert *)cache->edit_vbo->data; /* Fill buffers with data. */ - BKE_gpencil_visible_stroke_iter(ob, NULL, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter( + NULL, ob, NULL, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra); /* Create the batches */ cache->edit_points_batch = GPU_batch_create(GPU_PRIM_POINTS, cache->vbo, NULL); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 649bcd7bbaa..99e285a18f1 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -33,6 +33,7 @@ #include "BLI_math_bits.h" #include "BLI_math_vector.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BLI_utildefines.h" #include "DNA_mesh_types.h" @@ -96,11 +97,25 @@ static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *c cd_used->edit_uv = 1; } +BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_MDATA: + return &me->ldata; + break; + case ME_WRAPPER_TYPE_BMESH: + return &me->edit_mesh->bm->ldata; + break; + } + + BLI_assert(0); + return &me->ldata; +} + static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = &me_final->ldata; - + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { cd_used->uv |= (1 << layer); @@ -110,8 +125,7 @@ static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = &me_final->ldata; - + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { cd_used->uv |= (1 << layer); @@ -121,8 +135,7 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = &me_final->ldata; - + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); if (layer != -1) { cd_used->vcol |= (1 << layer); @@ -134,7 +147,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, int gpumat_array_len) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = &me_final->ldata; + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); /* See: DM_vertex_attributes_from_gpu for similar logic */ DRW_MeshCDMask cd_used; @@ -302,7 +315,7 @@ static void drw_mesh_weight_state_extract(Object *ob, wstate->alert_mode = ts->weightuser; if (paint_mode && ts->multipaint) { - /* Multipaint needs to know all selected bones, not just the active group. + /* Multi-paint needs to know all selected bones, not just the active group. * This is actually a relatively expensive operation, but caching would be difficult. */ wstate->defgroup_sel = BKE_object_defgroup_selected_get( ob, wstate->defgroup_len, &wstate->defgroup_sel_count); @@ -1007,9 +1020,14 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime) } /* Can be called for any surface type. Mesh *me is the final mesh. */ -void DRW_mesh_batch_cache_create_requested( - Object *ob, Mesh *me, const Scene *scene, const bool is_paint_mode, const bool use_hide) -{ +void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, + Object *ob, + Mesh *me, + const Scene *scene, + const bool is_paint_mode, + const bool use_hide) +{ + BLI_assert(task_graph); GPUIndexBuf **saved_elem_ranges = NULL; const ToolSettings *ts = NULL; if (scene) { @@ -1366,7 +1384,8 @@ void DRW_mesh_batch_cache_create_requested( false; if (do_uvcage) { - mesh_buffer_cache_create_requested(cache, + mesh_buffer_cache_create_requested(task_graph, + cache, cache->uv_cage, me, is_editmode, @@ -1382,7 +1401,8 @@ void DRW_mesh_batch_cache_create_requested( } if (do_cage) { - mesh_buffer_cache_create_requested(cache, + mesh_buffer_cache_create_requested(task_graph, + cache, cache->cage, me, is_editmode, @@ -1397,7 +1417,8 @@ void DRW_mesh_batch_cache_create_requested( true); } - mesh_buffer_cache_create_requested(cache, + mesh_buffer_cache_create_requested(task_graph, + cache, cache->final, me, is_editmode, @@ -1410,10 +1431,12 @@ void DRW_mesh_batch_cache_create_requested( scene, ts, use_hide); - #ifdef DEBUG check: /* Make sure all requested batches have been setup. */ + /* TODO(jbakker): we should move this to the draw_manager but that needs refactoring and + * additional looping.*/ + BLI_task_graph_work_and_wait(task_graph); for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) { BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index f14cdc0dbde..656d72b2808 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -172,23 +172,11 @@ bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis); /* This creates a shading group with display hairs. * The draw call is already added by this function, just add additional uniforms. */ -struct DRWShadingGroup *DRW_shgroup_hair_create(struct Object *object, - struct ParticleSystem *psys, - struct ModifierData *md, - struct DRWPass *hair_pass, - struct GPUShader *shader); - struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, struct DRWShadingGroup *shgrp); -struct DRWShadingGroup *DRW_shgroup_material_hair_create(struct Object *object, - struct ParticleSystem *psys, - struct ModifierData *md, - struct DRWPass *hair_pass, - struct GPUMaterial *material); - void DRW_hair_init(void); void DRW_hair_update(void); void DRW_hair_free(void); diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index ed7c72ac116..2fdaf0d5345 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -124,13 +124,10 @@ void DRW_hair_init(void) } } -static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, - ParticleSystem *psys, - ModifierData *md, - DRWPass *hair_pass, - DRWShadingGroup *shgrp_parent, - struct GPUMaterial *gpu_mat, - GPUShader *gpu_shader) +DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, + ParticleSystem *psys, + ModifierData *md, + DRWShadingGroup *shgrp_parent) { /* TODO(fclem): Pass the scene as parameter */ const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -154,24 +151,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, need_ft_update = hair_ensure_procedural_data(object, &hair_cache, subdiv, thickness_res); } - DRWShadingGroup *shgrp; - if (shgrp_parent) { - shgrp = DRW_shgroup_create_sub(shgrp_parent); - } - else if (gpu_mat) { - shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass); - } - else if (gpu_shader) { - shgrp = DRW_shgroup_create(gpu_shader, hair_pass); - } - else { - shgrp = NULL; - BLI_assert(0); - } - - if (shgrp == NULL) { - return NULL; - } + DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); /* TODO optimize this. Only bind the ones GPUMaterial needs. */ for (int i = 0; i < hair_cache->num_uv_layers; i++) { @@ -240,10 +220,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res); DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[0]", dupli_mat[0]); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[1]", dupli_mat[1]); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[2]", dupli_mat[2]); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[3]", dupli_mat[3]); + DRW_shgroup_uniform_vec4_array_copy(shgrp, "hairDupliMatrix", dupli_mat, 4); DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root); DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip); DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip); @@ -287,29 +264,6 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, return shgrp; } -DRWShadingGroup *DRW_shgroup_hair_create( - Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, GPUShader *shader) -{ - return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, NULL, shader); -} - -DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, - ParticleSystem *psys, - ModifierData *md, - DRWShadingGroup *shgrp) -{ - return drw_shgroup_create_hair_procedural_ex(object, psys, md, NULL, shgrp, NULL, NULL); -} - -DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object, - ParticleSystem *psys, - ModifierData *md, - DRWPass *hair_pass, - struct GPUMaterial *material) -{ - return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, material, NULL); -} - void DRW_hair_update(void) { #ifndef USE_TRANSFORM_FEEDBACK diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 970578c7438..e7dff422105 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -27,6 +27,7 @@ #include "BLI_memblock.h" #include "BLI_rect.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BLI_threads.h" #include "BLF_api.h" @@ -111,17 +112,6 @@ static ListBase DRW_engines = {NULL, NULL}; static void drw_state_prepare_clean_for_draw(DRWManager *dst) { memset(dst, 0x0, offsetof(DRWManager, gl_context)); - - /* Maybe not the best place for this. */ - if (!DST.uniform_names.buffer) { - DST.uniform_names.buffer = MEM_callocN(DRW_UNIFORM_BUFFER_NAME, "Name Buffer"); - DST.uniform_names.buffer_len = DRW_UNIFORM_BUFFER_NAME; - } - else if (DST.uniform_names.buffer_len > DRW_UNIFORM_BUFFER_NAME) { - DST.uniform_names.buffer = MEM_reallocN(DST.uniform_names.buffer, DRW_UNIFORM_BUFFER_NAME); - DST.uniform_names.buffer_len = DRW_UNIFORM_BUFFER_NAME; - } - DST.uniform_names.buffer_ofs = 0; } /* This function is used to reset draw manager to a state @@ -136,6 +126,23 @@ static void drw_state_ensure_not_reused(DRWManager *dst) #endif /* -------------------------------------------------------------------- */ +/** \name Threading + * \{ */ +static void drw_task_graph_init(void) +{ + BLI_assert(DST.task_graph == NULL); + DST.task_graph = BLI_task_graph_create(); +} + +static void drw_task_graph_deinit(void) +{ + BLI_task_graph_work_and_wait(DST.task_graph); + BLI_task_graph_free(DST.task_graph); + DST.task_graph = NULL; +} +/* \} */ + +/* -------------------------------------------------------------------- */ /** \name Settings * \{ */ @@ -584,9 +591,6 @@ static void drw_viewport_var_init(void) ED_view3d_init_mats_rv3d(DST.draw_ctx.object_edit, rv3d); } - /* Alloc array of texture reference. */ - memset(&DST.RST, 0x0, sizeof(DST.RST)); - if (G_draw.view_ubo == NULL) { G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(DRWViewUboStorage), NULL); } @@ -1424,6 +1428,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, /* reuse if caller sets */ .evil_C = DST.draw_ctx.evil_C, }; + drw_task_graph_init(); drw_context_state_init(); drw_viewport_var_init(); @@ -1488,6 +1493,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, #endif } + drw_task_graph_deinit(); DRW_stats_begin(); GPU_framebuffer_bind(DST.default_framebuffer); @@ -1768,7 +1774,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) DST.options.is_image_render = true; DST.options.is_scene_render = true; DST.options.draw_background = scene->r.alphamode == R_ADDSKY; - DST.draw_ctx = (DRWContextState){ .scene = scene, .view_layer = view_layer, @@ -1853,9 +1858,9 @@ void DRW_render_object_iter( void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph)) { const DRWContextState *draw_ctx = DRW_context_state_get(); - DRW_hair_init(); + drw_task_graph_init(); const int object_type_exclude_viewport = draw_ctx->v3d ? draw_ctx->v3d->object_type_exclude_viewport : 0; @@ -1878,6 +1883,7 @@ void DRW_render_object_iter( DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; drw_duplidata_free(); + drw_task_graph_deinit(); } /* Assume a valid gl context is bound (and that the gl_context_mutex has been acquired). @@ -2049,7 +2055,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, DST.viewport = viewport; DST.options.is_select = true; - + drw_task_graph_init(); /* Get list of enabled engines */ if (use_obedit) { drw_engines_enable_overlays(); @@ -2159,6 +2165,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, } drw_duplidata_free(); + drw_task_graph_deinit(); drw_engines_cache_finish(); DRW_render_instance_buffer_finish(); @@ -2239,7 +2246,7 @@ static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph, .engine_type = engine_type, .depsgraph = depsgraph, }; - + drw_task_graph_init(); drw_engines_data_validate(); /* Setup framebuffer */ @@ -2283,6 +2290,7 @@ static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph, DRW_render_instance_buffer_finish(); } + drw_task_graph_deinit(); /* Start Drawing */ DRW_state_reset(); @@ -2372,7 +2380,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons .obact = OBACT(view_layer), .depsgraph = depsgraph, }; - + drw_task_graph_init(); drw_context_state_init(); /* Setup viewport */ @@ -2407,6 +2415,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons drw_resource_buffer_finish(DST.vmempool); #endif } + drw_task_graph_deinit(); /* Start Drawing */ DRW_state_reset(); @@ -2470,8 +2479,10 @@ void DRW_draw_depth_object( else { batch = DRW_mesh_batch_cache_get_surface(me); } - - DRW_mesh_batch_cache_create_requested(object, me, scene, false, true); + struct TaskGraph *task_graph = BLI_task_graph_create(); + DRW_mesh_batch_cache_create_requested(task_graph, object, me, scene, false, true); + BLI_task_graph_work_and_wait(task_graph); + BLI_task_graph_free(task_graph); const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : GPU_SHADER_CFG_DEFAULT; @@ -2714,8 +2725,6 @@ void DRW_engines_free(void) DRW_TEXTURE_FREE_SAFE(G_draw.ramp); DRW_TEXTURE_FREE_SAFE(G_draw.weight_ramp); - MEM_SAFE_FREE(DST.uniform_names.buffer); - if (DST.draw_list) { GPU_draw_list_discard(DST.draw_list); } diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index f6d8179b193..6cae2a4f9f6 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -31,6 +31,7 @@ #include "BLI_assert.h" #include "BLI_linklist.h" #include "BLI_memblock.h" +#include "BLI_task.h" #include "BLI_threads.h" #include "GPU_batch.h" @@ -276,10 +277,9 @@ typedef enum { DRW_UNIFORM_FLOAT, DRW_UNIFORM_FLOAT_COPY, DRW_UNIFORM_TEXTURE, - DRW_UNIFORM_TEXTURE_PERSIST, DRW_UNIFORM_TEXTURE_REF, DRW_UNIFORM_BLOCK, - DRW_UNIFORM_BLOCK_PERSIST, + DRW_UNIFORM_BLOCK_REF, DRW_UNIFORM_TFEEDBACK_TARGET, /** Per drawcall uniforms/UBO */ DRW_UNIFORM_BLOCK_OBMATS, @@ -290,7 +290,6 @@ typedef enum { DRW_UNIFORM_BASE_INSTANCE, DRW_UNIFORM_MODEL_MATRIX, DRW_UNIFORM_MODEL_MATRIX_INVERSE, - DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX, /* WARNING: set DRWUniform->type * bit length accordingly. */ } DRWUniformType; @@ -299,15 +298,28 @@ struct DRWUniform { union { /* For reference or array/vector types. */ const void *pvalue; - /* Single values. */ + /* DRW_UNIFORM_TEXTURE */ + struct { + union { + GPUTexture *texture; + GPUTexture **texture_ref; + }; + eGPUSamplerState sampler_state; + }; + /* DRW_UNIFORM_BLOCK */ + union { + GPUUniformBuffer *block; + GPUUniformBuffer **block_ref; + }; + /* DRW_UNIFORM_FLOAT_COPY */ float fvalue[4]; + /* DRW_UNIFORM_INT_COPY */ int ivalue[4]; }; - int location; - uint32_t type : 5; /* DRWUniformType */ - uint32_t length : 5; /* cannot be more than 16 */ - uint32_t arraysize : 5; /* cannot be more than 16 too */ - uint32_t name_ofs : 17; /* name offset in name buffer. */ + int location; /* Uniform location or binding point for textures and ubos. */ + uint8_t type; /* DRWUniformType */ + uint8_t length; /* Length of vector types. */ + uint8_t arraysize; /* Array size of scalar/vector types. */ }; struct DRWShadingGroup { @@ -322,10 +334,13 @@ struct DRWShadingGroup { } cmd; union { + /* This struct is used during cache populate. */ struct { int objectinfo; /* Equal to 1 if the shader needs obinfos. */ DRWResourceHandle pass_handle; /* Memblock key to parent pass. */ }; + /* This struct is used after cache populate if using the Z sorting. + * It will not conflict with the above struct. */ struct { float distance; /* Distance from camera. */ uint original_index; /* Original position inside the shgroup list. */ @@ -342,6 +357,13 @@ struct DRWPass { DRWShadingGroup *last; } shgroups; + /* Draw the shgroups of this pass instead. + * This avoid duplicating drawcalls/shgroups + * for similar passes. */ + DRWPass *original; + /* Link list of additional passes to render. */ + DRWPass *next; + DRWResourceHandle handle; DRWState state; char name[MAX_PASS_NAME]; @@ -525,6 +547,8 @@ typedef struct DRWManager { uint select_id; #endif + struct TaskGraph *task_graph; + /* ---------- Nothing after this point is cleared after use ----------- */ /* gl_context serves as the offset for clearing only @@ -537,31 +561,11 @@ typedef struct DRWManager { GPUDrawList *draw_list; - /** GPU Resource State: Memory storage between drawing. */ - struct { - /* High end GPUs supports up to 32 binds per shader stage. - * We only use textures during the vertex and fragment stage, - * so 2 * 32 slots is a nice limit. */ - GPUTexture *bound_texs[DST_MAX_SLOTS]; - uint64_t bound_tex_slots; - uint64_t bound_tex_slots_persist; - - GPUUniformBuffer *bound_ubos[DST_MAX_SLOTS]; - uint64_t bound_ubo_slots; - uint64_t bound_ubo_slots_persist; - } RST; - struct { /* TODO(fclem) optimize: use chunks. */ DRWDebugLine *lines; DRWDebugSphere *spheres; } debug; - - struct { - char *buffer; - uint buffer_len; - uint buffer_ofs; - } uniform_names; } DRWManager; extern DRWManager DST; /* TODO: get rid of this and allow multi-threaded rendering. */ diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index ff27fa958ef..ea67dd87772 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -170,13 +170,20 @@ void drw_resource_buffer_finish(ViewportMemoryPool *vmempool) /** \name Uniforms (DRW_shgroup_uniform) * \{ */ -static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, - int loc, - DRWUniformType type, - const void *value, - int length, - int arraysize) -{ +static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, + int loc, + DRWUniformType type, + const void *value, + eGPUSamplerState sampler_state, + int length, + int arraysize) +{ + if (loc == -1) { + /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + // BLI_assert(0); + return; + } + DRWUniformChunk *unichunk = shgroup->uniforms; /* Happens on first uniform or if chunk is full. */ if (!unichunk || unichunk->uniform_used == unichunk->uniform_len) { @@ -202,22 +209,24 @@ static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, BLI_assert(length <= 4); memcpy(uni->fvalue, value, sizeof(float) * length); break; + case DRW_UNIFORM_BLOCK: + uni->block = (GPUUniformBuffer *)value; + break; + case DRW_UNIFORM_BLOCK_REF: + uni->block_ref = (GPUUniformBuffer **)value; + break; + case DRW_UNIFORM_TEXTURE: + uni->texture = (GPUTexture *)value; + uni->sampler_state = sampler_state; + break; + case DRW_UNIFORM_TEXTURE_REF: + uni->texture_ref = (GPUTexture **)value; + uni->sampler_state = sampler_state; + break; default: uni->pvalue = (const float *)value; break; } - - return uni; -} - -static void drw_shgroup_builtin_uniform( - DRWShadingGroup *shgroup, int builtin, const void *value, int length, int arraysize) -{ - int loc = GPU_shader_get_builtin_uniform(shgroup->shader, builtin); - - if (loc != -1) { - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_FLOAT, value, length, arraysize); - } } static void drw_shgroup_uniform(DRWShadingGroup *shgroup, @@ -227,61 +236,29 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup, int length, int arraysize) { - int location; - if (ELEM(type, DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_PERSIST)) { - location = GPU_shader_get_uniform_block(shgroup->shader, name); - } - else { - location = GPU_shader_get_uniform(shgroup->shader, name); - } - - if (location == -1) { - /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ - // BLI_assert(0); - return; - } - BLI_assert(arraysize > 0 && arraysize <= 16); BLI_assert(length >= 0 && length <= 16); - - DRWUniform *uni = drw_shgroup_uniform_create_ex( - shgroup, location, type, value, length, arraysize); - - /* If location is -2, the uniform has not yet been queried. - * We save the name for query just before drawing. */ - if (location == -2 || DRW_DEBUG_USE_UNIFORM_NAME) { - int ofs = DST.uniform_names.buffer_ofs; - int max_len = DST.uniform_names.buffer_len - ofs; - size_t len = strlen(name) + 1; - - if (len >= max_len) { - DST.uniform_names.buffer_len += MAX2(DST.uniform_names.buffer_len, len); - DST.uniform_names.buffer = MEM_reallocN(DST.uniform_names.buffer, - DST.uniform_names.buffer_len); - } - - char *dst = DST.uniform_names.buffer + ofs; - memcpy(dst, name, len); /* Copies NULL terminator. */ - - DST.uniform_names.buffer_ofs += len; - uni->name_ofs = ofs; - } + BLI_assert(!ELEM(type, + DRW_UNIFORM_BLOCK, + DRW_UNIFORM_BLOCK_REF, + DRW_UNIFORM_TEXTURE, + DRW_UNIFORM_TEXTURE_REF)); + int location = GPU_shader_get_uniform(shgroup->shader, name); + drw_shgroup_uniform_create_ex(shgroup, location, type, value, 0, length, arraysize); } void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex) { BLI_assert(tex != NULL); - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1); + int loc = GPU_shader_get_texture_binding(shgroup->shader, name); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE, tex, GPU_SAMPLER_MAX, 0, 1); } -/* Same as DRW_shgroup_uniform_texture but is guaranteed to be bound if shader does not change - * between shgrp. */ -void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, - const char *name, - const GPUTexture *tex) +void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) { BLI_assert(tex != NULL); - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_PERSIST, tex, 0, 1); + int loc = GPU_shader_get_texture_binding(shgroup->shader, name); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE_REF, tex, GPU_SAMPLER_MAX, 0, 1); } void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, @@ -289,22 +266,17 @@ void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const GPUUniformBuffer *ubo) { BLI_assert(ubo != NULL); - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1); + int loc = GPU_shader_get_uniform_block_binding(shgroup->shader, name); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK, ubo, 0, 0, 1); } -/* Same as DRW_shgroup_uniform_block but is guaranteed to be bound if shader does not change - * between shgrp. */ -void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, - const char *name, - const GPUUniformBuffer *ubo) +void DRW_shgroup_uniform_block_ref(DRWShadingGroup *shgroup, + const char *name, + GPUUniformBuffer **ubo) { BLI_assert(ubo != NULL); - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK_PERSIST, ubo, 0, 1); -} - -void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) -{ - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_REF, tex, 0, 1); + int loc = GPU_shader_get_uniform_block_binding(shgroup->shader, name); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK_REF, ubo, 0, 0, 1); } void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, @@ -436,6 +408,25 @@ void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, c drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 4, 1); } +void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, + const char *name, + const float (*value)[4], + int arraysize) +{ + int location = GPU_shader_get_uniform(shgroup->shader, name); + + if (location == -1) { + /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + // BLI_assert(0); + return; + } + + for (int i = 0; i < arraysize; i++) { + drw_shgroup_uniform_create_ex( + shgroup, location + i, DRW_UNIFORM_FLOAT_COPY, &value[i], 0, 4, 1); + } +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1177,53 +1168,49 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) { shgroup->uniforms = NULL; - /* TODO(fclem) make them builtin. */ - int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock"); - int model_ubo_location = GPU_shader_get_uniform_block(shader, "modelBlock"); - int info_ubo_location = GPU_shader_get_uniform_block(shader, "infoBlock"); + int view_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_VIEW); + int model_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_MODEL); + int info_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_INFO); int baseinst_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_BASE_INSTANCE); int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK); int resourceid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_ID); if (chunkid_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 1); + shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 0, 1); } if (resourceid_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, NULL, 0, 1); + shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, NULL, 0, 0, 1); } if (baseinst_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 1); + shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 0, 1); } if (model_ubo_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 1); + shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 0, 1); } else { + /* Note: This is only here to support old hardware fallback where uniform buffer is still + * too slow or buggy. */ int model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL); int modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV); - int modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP); if (model != -1) { - drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 0, 1); } if (modelinverse != -1) { drw_shgroup_uniform_create_ex( - shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 1); - } - if (modelviewprojection != -1) { - drw_shgroup_uniform_create_ex( - shgroup, modelviewprojection, DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX, NULL, 0, 1); + shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 0, 1); } } if (info_ubo_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 1); + shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 0, 1); /* Abusing this loc to tell shgroup we need the obinfos. */ shgroup->objectinfo = 1; @@ -1234,25 +1221,21 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) if (view_ubo_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, view_ubo_location, DRW_UNIFORM_BLOCK_PERSIST, G_draw.view_ubo, 0, 1); - } - else { - /* Only here to support builtin shaders. This should not be used by engines. */ - /* TODO remove. */ - DRWViewUboStorage *storage = &DST.view_storage_cpy; - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW, storage->viewmat, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW_INV, storage->viewinv, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION, storage->persmat, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION_INV, storage->persinv, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION, storage->winmat, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION_INV, storage->wininv, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_CLIPPLANES, storage->clipplanes, 4, 6); + shgroup, view_ubo_location, DRW_UNIFORM_BLOCK, G_draw.view_ubo, 0, 0, 1); } /* Not supported. */ BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV) == -1); BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW) == -1); BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEW) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEW_INV) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEWPROJECTION) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEWPROJECTION_INV) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION_INV) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CLIPPLANES) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP) == -1); } static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass) @@ -1290,18 +1273,20 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass static void drw_shgroup_material_texture(DRWShadingGroup *grp, GPUMaterialTexture *tex, const char *name, + eGPUSamplerState state, int textarget) { GPUTexture *gputex = GPU_texture_from_blender(tex->ima, tex->iuser, NULL, textarget); - DRW_shgroup_uniform_texture(grp, name, gputex); + + int loc = GPU_shader_get_texture_binding(grp->shader, name); + drw_shgroup_uniform_create_ex(grp, loc, DRW_UNIFORM_TEXTURE, gputex, state, 0, 1); GPUTexture **gputex_ref = BLI_memblock_alloc(DST.vmempool->images); *gputex_ref = gputex; GPU_texture_ref(gputex); } -static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, - struct GPUMaterial *material) +void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material) { ListBase textures = GPU_material_textures(material); @@ -1310,11 +1295,14 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, if (tex->ima) { /* Image */ if (tex->tiled_mapping_name[0]) { - drw_shgroup_material_texture(grp, tex, tex->sampler_name, GL_TEXTURE_2D_ARRAY); - drw_shgroup_material_texture(grp, tex, tex->tiled_mapping_name, GL_TEXTURE_1D_ARRAY); + drw_shgroup_material_texture( + grp, tex, tex->sampler_name, tex->sampler_state, GL_TEXTURE_2D_ARRAY); + drw_shgroup_material_texture( + grp, tex, tex->tiled_mapping_name, tex->sampler_state, GL_TEXTURE_1D_ARRAY); } else { - drw_shgroup_material_texture(grp, tex, tex->sampler_name, GL_TEXTURE_2D); + drw_shgroup_material_texture( + grp, tex, tex->sampler_name, tex->sampler_state, GL_TEXTURE_2D); } } else if (tex->colorband) { @@ -1327,8 +1315,6 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, if (ubo != NULL) { DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo); } - - return grp; } GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttrFormat attrs[], @@ -1353,7 +1339,7 @@ DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPa if (shgroup) { drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass)); - drw_shgroup_material_inputs(shgroup, material); + DRW_shgroup_add_material_resources(shgroup, material); } return shgroup; } @@ -1372,7 +1358,7 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, BLI_assert(tf_target != NULL); DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); drw_shgroup_init(shgroup, shader); - drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 0, 1); return shgroup; } @@ -1904,9 +1890,28 @@ DRWPass *DRW_pass_create(const char *name, DRWState state) pass->handle = DST.pass_handle; DRW_handle_increment(&DST.pass_handle); + pass->original = NULL; + pass->next = NULL; + return pass; } +DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state) +{ + DRWPass *pass = DRW_pass_create(name, state); + pass->original = original; + + return pass; +} + +/* Link two passes so that they are both rendered if the first one is being drawn. */ +void DRW_pass_link(DRWPass *first, DRWPass *second) +{ + BLI_assert(first != second); + BLI_assert(first->next == NULL); + first->next = second; +} + bool DRW_pass_is_empty(DRWPass *pass) { LISTBASE_FOREACH (DRWShadingGroup *, shgroup, &pass->shgroups) { diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 6c62d4d2405..59b4e9af14e 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -22,6 +22,7 @@ #include "draw_manager.h" +#include "BLI_alloca.h" #include "BLI_math.h" #include "BLI_math_bits.h" #include "BLI_memblock.h" @@ -65,7 +66,6 @@ typedef struct DRWCommandsState { /* Legacy matrix support. */ int obmat_loc; int obinv_loc; - int mvp_loc; /* Selection ID state. */ GPUVertBuf *select_buf; uint select_id; @@ -454,6 +454,8 @@ void DRW_state_reset(void) { DRW_state_reset_ex(DRW_STATE_DEFAULT); + GPU_texture_unbind_all(); + /* Should stay constant during the whole rendering. */ GPU_point_size(5); GPU_line_smooth(false); @@ -655,8 +657,7 @@ static void draw_compute_culling(DRWView *view) BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup, DRWResourceHandle *handle, float obmat_loc, - float obinv_loc, - float mvp_loc) + float obinv_loc) { /* Still supported for compatibility with gpu_shader_* but should be forbidden. */ DRWObjectMatrix *ob_mats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, handle); @@ -666,13 +667,6 @@ BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup, if (obinv_loc != -1) { GPU_shader_uniform_vector(shgroup->shader, obinv_loc, 16, 1, (float *)ob_mats->modelinverse); } - /* Still supported for compatibility with gpu_shader_* but should be forbidden - * and is slow (since it does not cache the result). */ - if (mvp_loc != -1) { - float mvp[4][4]; - mul_m4_m4m4(mvp, DST.view_active->storage.persmat, ob_mats->model); - GPU_shader_uniform_vector(shgroup->shader, mvp_loc, 16, 1, (float *)mvp); - } } BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom) @@ -744,107 +738,6 @@ BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *s } } -enum { - BIND_NONE = 0, - BIND_TEMP = 1, /* Release slot after this shading group. */ - BIND_PERSIST = 2, /* Release slot only after the next shader change. */ -}; - -static void set_bound_flags(uint64_t *slots, uint64_t *persist_slots, int slot_idx, char bind_type) -{ - uint64_t slot = 1llu << (unsigned long)slot_idx; - *slots |= slot; - if (bind_type == BIND_PERSIST) { - *persist_slots |= slot; - } -} - -static int get_empty_slot_index(uint64_t slots) -{ - uint64_t empty_slots = ~slots; - /* Find first empty slot using bitscan. */ - if (empty_slots != 0) { - if ((empty_slots & 0xFFFFFFFFlu) != 0) { - return (int)bitscan_forward_uint(empty_slots); - } - else { - return (int)bitscan_forward_uint(empty_slots >> 32) + 32; - } - } - else { - /* Greater than GPU_max_textures() */ - return 99999; - } -} - -static void bind_texture(GPUTexture *tex, char bind_type) -{ - int idx = GPU_texture_bound_number(tex); - if (idx == -1) { - /* Texture isn't bound yet. Find an empty slot and bind it. */ - idx = get_empty_slot_index(DST.RST.bound_tex_slots); - - if (idx < GPU_max_textures()) { - GPUTexture **gpu_tex_slot = &DST.RST.bound_texs[idx]; - /* Unbind any previous texture. */ - if (*gpu_tex_slot != NULL) { - GPU_texture_unbind(*gpu_tex_slot); - } - GPU_texture_bind(tex, idx); - *gpu_tex_slot = tex; - } - else { - printf("Not enough texture slots! Reduce number of textures used by your shader.\n"); - return; - } - } - else { - /* This texture slot was released but the tex - * is still bound. Just flag the slot again. */ - BLI_assert(DST.RST.bound_texs[idx] == tex); - } - set_bound_flags(&DST.RST.bound_tex_slots, &DST.RST.bound_tex_slots_persist, idx, bind_type); -} - -static void bind_ubo(GPUUniformBuffer *ubo, char bind_type) -{ - int idx = GPU_uniformbuffer_bindpoint(ubo); - if (idx == -1) { - /* UBO isn't bound yet. Find an empty slot and bind it. */ - idx = get_empty_slot_index(DST.RST.bound_ubo_slots); - - /* [0..1] are reserved ubo slots. */ - idx += 2; - - if (idx < GPU_max_ubo_binds()) { - GPUUniformBuffer **gpu_ubo_slot = &DST.RST.bound_ubos[idx]; - /* Unbind any previous UBO. */ - if (*gpu_ubo_slot != NULL) { - GPU_uniformbuffer_unbind(*gpu_ubo_slot); - } - GPU_uniformbuffer_bind(ubo, idx); - *gpu_ubo_slot = ubo; - } - else { - /* printf so user can report bad behavior */ - printf("Not enough ubo slots! This should not happen!\n"); - /* This is not depending on user input. - * It is our responsibility to make sure there is enough slots. */ - BLI_assert(0); - return; - } - } - else { - BLI_assert(idx < 64); - /* This UBO slot was released but the UBO is - * still bound here. Just flag the slot again. */ - BLI_assert(DST.RST.bound_ubos[idx] == ubo); - } - /* Remove offset for flag bitfield. */ - idx -= 2; - set_bound_flags(&DST.RST.bound_ubo_slots, &DST.RST.bound_ubo_slots_persist, idx, bind_type); -} - #ifndef NDEBUG /** * Opengl specification is strict on buffer binding. @@ -900,28 +793,6 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup) } #endif -static void release_texture_slots(bool with_persist) -{ - if (with_persist) { - DST.RST.bound_tex_slots = 0; - DST.RST.bound_tex_slots_persist = 0; - } - else { - DST.RST.bound_tex_slots &= DST.RST.bound_tex_slots_persist; - } -} - -static void release_ubo_slots(bool with_persist) -{ - if (with_persist) { - DST.RST.bound_ubo_slots = 0; - DST.RST.bound_ubo_slots_persist = 0; - } - else { - DST.RST.bound_ubo_slots &= DST.RST.bound_ubo_slots_persist; - } -} - static void draw_update_uniforms(DRWShadingGroup *shgroup, DRWCommandsState *state, bool *use_tfeedback) @@ -929,69 +800,42 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, for (DRWUniformChunk *unichunk = shgroup->uniforms; unichunk; unichunk = unichunk->next) { DRWUniform *uni = unichunk->uniforms; for (int i = 0; i < unichunk->uniform_used; i++, uni++) { - GPUTexture *tex; - GPUUniformBuffer *ubo; - if (uni->location == -2) { - uni->location = GPU_shader_get_uniform_ensure(shgroup->shader, - DST.uniform_names.buffer + uni->name_ofs); - if (uni->location == -1) { - continue; - } - } - const void *data = uni->pvalue; - if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) { - data = uni->fvalue; - } switch (uni->type) { case DRW_UNIFORM_INT_COPY: + GPU_shader_uniform_vector_int( + shgroup->shader, uni->location, uni->length, uni->arraysize, uni->ivalue); + break; case DRW_UNIFORM_INT: GPU_shader_uniform_vector_int( - shgroup->shader, uni->location, uni->length, uni->arraysize, data); + shgroup->shader, uni->location, uni->length, uni->arraysize, uni->pvalue); break; case DRW_UNIFORM_FLOAT_COPY: + GPU_shader_uniform_vector( + shgroup->shader, uni->location, uni->length, uni->arraysize, uni->fvalue); + break; case DRW_UNIFORM_FLOAT: GPU_shader_uniform_vector( - shgroup->shader, uni->location, uni->length, uni->arraysize, data); + shgroup->shader, uni->location, uni->length, uni->arraysize, uni->pvalue); break; case DRW_UNIFORM_TEXTURE: - tex = (GPUTexture *)uni->pvalue; - BLI_assert(tex); - bind_texture(tex, BIND_TEMP); - GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); - break; - case DRW_UNIFORM_TEXTURE_PERSIST: - tex = (GPUTexture *)uni->pvalue; - BLI_assert(tex); - bind_texture(tex, BIND_PERSIST); - GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); + GPU_texture_bind_ex(uni->texture, uni->sampler_state, uni->location, false); break; case DRW_UNIFORM_TEXTURE_REF: - tex = *((GPUTexture **)uni->pvalue); - BLI_assert(tex); - bind_texture(tex, BIND_TEMP); - GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); + GPU_texture_bind_ex(*uni->texture_ref, uni->sampler_state, uni->location, false); break; case DRW_UNIFORM_BLOCK: - ubo = (GPUUniformBuffer *)uni->pvalue; - bind_ubo(ubo, BIND_TEMP); - GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + GPU_uniformbuffer_bind(uni->block, uni->location); break; - case DRW_UNIFORM_BLOCK_PERSIST: - ubo = (GPUUniformBuffer *)uni->pvalue; - bind_ubo(ubo, BIND_PERSIST); - GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + case DRW_UNIFORM_BLOCK_REF: + GPU_uniformbuffer_bind(*uni->block_ref, uni->location); break; case DRW_UNIFORM_BLOCK_OBMATS: state->obmats_loc = uni->location; - ubo = DST.vmempool->matrices_ubo[0]; - GPU_uniformbuffer_bind(ubo, 0); - GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[0], uni->location); break; case DRW_UNIFORM_BLOCK_OBINFOS: state->obinfos_loc = uni->location; - ubo = DST.vmempool->obinfos_ubo[0]; - GPU_uniformbuffer_bind(ubo, 1); - GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[0], uni->location); break; case DRW_UNIFORM_RESOURCE_CHUNK: state->chunkid_loc = uni->location; @@ -1001,9 +845,9 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, state->resourceid_loc = uni->location; break; case DRW_UNIFORM_TFEEDBACK_TARGET: - BLI_assert(data && (*use_tfeedback == false)); - *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader, - ((GPUVertBuf *)data)->vbo_id); + BLI_assert(uni->pvalue && (*use_tfeedback == false)); + *use_tfeedback = GPU_shader_transform_feedback_enable( + shgroup->shader, ((GPUVertBuf *)uni->pvalue)->vbo_id); break; /* Legacy/Fallback support. */ case DRW_UNIFORM_BASE_INSTANCE: @@ -1015,9 +859,6 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, case DRW_UNIFORM_MODEL_MATRIX_INVERSE: state->obinv_loc = uni->location; break; - case DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX: - state->mvp_loc = uni->location; - break; } } } @@ -1110,11 +951,11 @@ static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHa } if (state->obmats_loc != -1) { GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]); - GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], 0); + GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], state->obmats_loc); } if (state->obinfos_loc != -1) { GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]); - GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[chunk], 1); + GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[chunk], state->obinfos_loc); } state->resource_chunk = chunk; } @@ -1153,10 +994,8 @@ static void draw_call_single_do(DRWShadingGroup *shgroup, draw_call_resource_bind(state, &handle); /* TODO This is Legacy. Need to be removed. */ - if (state->obmats_loc == -1 && - (state->obmat_loc != -1 || state->obinv_loc != -1 || state->mvp_loc != -1)) { - draw_legacy_matrix_update( - shgroup, &handle, state->obmat_loc, state->obinv_loc, state->mvp_loc); + if (state->obmats_loc == -1 && (state->obmat_loc != -1 || state->obinv_loc != -1)) { + draw_legacy_matrix_update(shgroup, &handle, state->obmat_loc, state->obinv_loc); } if (G.f & G_FLAG_PICKSEL) { @@ -1262,7 +1101,6 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) .resourceid_loc = -1, .obmat_loc = -1, .obinv_loc = -1, - .mvp_loc = -1, .drw_state_enabled = 0, .drw_state_disabled = 0, }; @@ -1273,6 +1111,11 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) if (shader_changed) { if (DST.shader) { GPU_shader_unbind(); + + /* Unbinding can be costly. Skip in normal condition. */ + if (G.debug & G_DEBUG_GPU) { + GPU_texture_unbind_all(); + } } GPU_shader_bind(shgroup->shader); DST.shader = shgroup->shader; @@ -1283,9 +1126,6 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) DST.batch = NULL; } - release_ubo_slots(shader_changed); - release_texture_slots(shader_changed); - draw_update_uniforms(shgroup, &state, &use_tfeedback); drw_state_set(pass_state); @@ -1426,6 +1266,11 @@ static void drw_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group) { + if (pass->original) { + start_group = pass->original->shgroups.first; + end_group = pass->original->shgroups.last; + } + if (start_group == NULL) { return; } @@ -1462,22 +1307,6 @@ static void drw_draw_pass_ex(DRWPass *pass, } } - /* Clear Bound textures */ - for (int i = 0; i < DST_MAX_SLOTS; i++) { - if (DST.RST.bound_texs[i] != NULL) { - GPU_texture_unbind(DST.RST.bound_texs[i]); - DST.RST.bound_texs[i] = NULL; - } - } - - /* Clear Bound Ubos */ - for (int i = 0; i < DST_MAX_SLOTS; i++) { - if (DST.RST.bound_ubos[i] != NULL) { - GPU_uniformbuffer_unbind(DST.RST.bound_ubos[i]); - DST.RST.bound_ubos[i] = NULL; - } - } - if (DST.shader) { GPU_shader_unbind(); DST.shader = NULL; @@ -1511,7 +1340,9 @@ static void drw_draw_pass_ex(DRWPass *pass, void DRW_draw_pass(DRWPass *pass) { - drw_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last); + for (; pass; pass = pass->next) { + drw_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last); + } } /* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */ diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 0d6527421d0..6304b707cb9 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -343,27 +343,12 @@ GPUShader *DRW_shader_create_with_transform_feedback(const char *vert, __func__); } -GPUShader *DRW_shader_create_2d(const char *frag, const char *defines) -{ - return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines, __func__); -} - -GPUShader *DRW_shader_create_3d(const char *frag, const char *defines) -{ - return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines, __func__); -} - GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines) { return GPU_shader_create( datatoc_common_fullscreen_vert_glsl, frag, NULL, NULL, defines, __func__); } -GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig sh_cfg) -{ - return GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_DEPTH_ONLY, sh_cfg); -} - GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, const int options, @@ -398,6 +383,7 @@ GPUMaterial *DRW_shader_find_from_material(Material *ma, GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, World *wo, + struct bNodeTree *ntree, const void *engine_type, const int options, const bool is_volume_shader, @@ -408,7 +394,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, bool deferred) { GPUMaterial *mat = NULL; - if (DRW_state_is_image_render()) { + if (DRW_state_is_image_render() || !deferred) { mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options); } @@ -416,7 +402,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id); mat = GPU_material_from_nodetree(scene, NULL, - wo->nodetree, + ntree, &wo->gpumaterial, engine_type, options, @@ -437,6 +423,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, Material *ma, + struct bNodeTree *ntree, const void *engine_type, const int options, const bool is_volume_shader, @@ -447,7 +434,7 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, bool deferred) { GPUMaterial *mat = NULL; - if (DRW_state_is_image_render()) { + if (DRW_state_is_image_render() || !deferred) { mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options); } @@ -455,7 +442,7 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id); mat = GPU_material_from_nodetree(scene, ma, - ma->nodetree, + ntree, &ma->gpumaterial, engine_type, options, diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index 810a2e9389b..77b0462303d 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -61,17 +61,17 @@ static bool drw_texture_format_supports_framebuffer(eGPUTextureFormat format) void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags) { - GPU_texture_bind(tex, 0); if (flags & DRW_TEX_MIPMAP) { GPU_texture_mipmap_mode(tex, true, flags & DRW_TEX_FILTER); + GPU_texture_bind(tex, 0); GPU_texture_generate_mipmap(tex); + GPU_texture_unbind(tex); } else { GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER); } GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP, true); GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE); - GPU_texture_unbind(tex); } GPUTexture *DRW_texture_create_1d(int w, diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl index 9dfd48cc21a..a479a87e14b 100644 --- a/source/blender/draw/intern/shaders/common_globals_lib.glsl +++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl @@ -140,3 +140,4 @@ layout(std140) uniform globalsBlock #define EDGE_SEAM (1 << 4) #define EDGE_SHARP (1 << 5) #define EDGE_FREESTYLE (1 << 6) +#define HANDLE_SELECTED (1 << 7) diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index cd17a490240..0947023e071 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -4959,7 +4959,9 @@ static void draw_setting_widget(bAnimContext *ac, "Temporarily disable NLA stack evaluation (i.e. only the active action is evaluated)"); } else if (ale->type == ANIMTYPE_GPLAYER) { - tooltip = TIP_("Lock current frame displayed by layer (i.e. disable animation playback)"); + tooltip = TIP_( + "Shows all keyframes during animation playback and enabled all frames for editing " + "(uncheck to use only the current keyframe during animation playback and editing)"); } else { tooltip = TIP_("Do channels contribute to result (toggle channel muting)"); diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index a7ca84eb6c6..1ca3452e8d8 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -671,7 +671,7 @@ void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *f } /* free the F-Curve itself */ - free_fcurve(fcu); + BKE_fcurve_free(fcu); } /* If the action has no F-Curves, unlink it from AnimData if it did not @@ -1806,7 +1806,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op)) /* remove from group and action, then free */ action_groups_remove_channel(adt->action, fcu); - free_fcurve(fcu); + BKE_fcurve_free(fcu); } /* free the group itself */ @@ -1860,7 +1860,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op)) /* unlink and free the F-Curve */ BLI_remlink(&strip->fcurves, fcu); - free_fcurve(fcu); + BKE_fcurve_free(fcu); tag_update_animation_element(ale); break; } diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 4203c2677b7..a2a1f7eb1d2 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -62,67 +62,6 @@ /* *************************************************** */ /* CURRENT FRAME DRAWING */ -/* Draw current frame number in a little green box beside the current frame indicator */ -void ANIM_draw_cfra_number(const bContext *C, View2D *v2d, short flag) -{ - Scene *scene = CTX_data_scene(C); - const float time = scene->r.cfra + scene->r.subframe; - const float cfra = (float)(time * scene->r.framelen); - const bool show_time = (flag & DRAWCFRA_UNIT_SECONDS) != 0; - - const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - uchar col[4]; - float color[4]; - float xscale, x, y; - char numstr[32] = " t "; /* t is the character to start replacing from */ - float hlen; - int slen; - - /* because the frame number text is subject to the same scaling as the contents of the view */ - UI_view2d_scale_get(v2d, &xscale, NULL); - GPU_matrix_push(); - GPU_matrix_scale_2f(1.0f / xscale, 1.0f); - - /* get timecode string - * - padding on str-buf passed so that it doesn't sit on the frame indicator - */ - if (show_time) { - BLI_timecode_string_from_time( - &numstr[2], sizeof(numstr) - 2, 0, FRA2TIME(cfra), FPS, U.timecode_style); - } - else { - BLI_timecode_string_from_time_seconds(&numstr[2], sizeof(numstr) - 2, 1, cfra); - } - - slen = UI_fontstyle_string_width(fstyle, numstr) - 1; - hlen = slen * 0.5f; - - /* get starting coordinates for drawing */ - x = cfra * xscale; - y = -0.1f * U.widget_unit; - - /* draw green box around/behind text */ - UI_GetThemeColor4fv(TH_CFRAME, color); - color[3] = 3.0f; - - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa(true, - x - hlen - 0.1f * U.widget_unit, - y + 3.0f, - x + hlen + 0.1f * U.widget_unit, - y - 3.0f + U.widget_unit, - 0.1f * U.widget_unit, - color); - - /* draw current frame number */ - UI_GetThemeColor4ubv(TH_TEXT_HI, col); - UI_fontstyle_draw_simple( - fstyle, x - hlen - 0.15f * U.widget_unit, y + 0.28f * U.widget_unit, numstr, col); - - /* restore view transform */ - GPU_matrix_pop(); -} - /* General call for drawing current frame indicator in animation editor */ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag) { diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 2b9dfe105bc..bd83bdae31b 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -988,7 +988,7 @@ static bAnimListElem *make_new_animlistelem(void *data, * then free the MEM_alloc'd string */ if (rna_path) { - ale->key_data = (void *)list_find_fcurve(&act->curves, rna_path, 0); + ale->key_data = (void *)BKE_fcurve_find(&act->curves, rna_path, 0); MEM_freeN(rna_path); } } diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 82e24eaa6e3..328e435877c 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -92,7 +92,7 @@ FCurve *verify_driver_fcurve(ID *id, * - add if not found and allowed to add one * TODO: add auto-grouping support? how this works will need to be resolved */ - fcu = list_find_fcurve(&adt->drivers, rna_path, array_index); + fcu = BKE_fcurve_find(&adt->drivers, rna_path, array_index); if (fcu == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) { /* use default settings to make a F-Curve */ @@ -110,7 +110,7 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, eDriverFCurveCreationMode creation_mode) { - FCurve *fcu = MEM_callocN(sizeof(FCurve), "FCurve"); + FCurve *fcu = BKE_fcurve_create(); fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); fcu->auto_smoothing = U.auto_smoothing_new; @@ -570,13 +570,13 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports), /* step through all drivers, removing all of those with the same base path */ FCurve *fcu_iter = adt->drivers.first; - while ((fcu = iter_step_fcurve(fcu_iter, rna_path)) != NULL) { + while ((fcu = BKE_fcurve_iter_step(fcu_iter, rna_path)) != NULL) { /* store the next fcurve for looping */ fcu_iter = fcu->next; /* remove F-Curve from driver stack, then free it */ BLI_remlink(&adt->drivers, fcu); - free_fcurve(fcu); + BKE_fcurve_free(fcu); /* done successfully */ success = true; @@ -590,7 +590,7 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports), fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY); if (fcu) { BLI_remlink(&adt->drivers, fcu); - free_fcurve(fcu); + BKE_fcurve_free(fcu); success = true; } @@ -611,7 +611,7 @@ void ANIM_drivers_copybuf_free(void) { /* free the buffer F-Curve if it exists, as if it were just another F-Curve */ if (channeldriver_copypaste_buf) { - free_fcurve(channeldriver_copypaste_buf); + BKE_fcurve_free(channeldriver_copypaste_buf); } channeldriver_copypaste_buf = NULL; } @@ -662,7 +662,7 @@ bool ANIM_copy_driver( fcu->rna_path = NULL; /* make a copy of the F-Curve with */ - channeldriver_copypaste_buf = copy_fcurve(fcu); + channeldriver_copypaste_buf = BKE_fcurve_copy(fcu); /* restore the path */ fcu->rna_path = tmp_path; @@ -981,7 +981,8 @@ static bool add_driver_button_poll(bContext *C) } /* Don't do anything if there is an fcurve for animation without a driver. */ - FCurve *fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special); + FCurve *fcu = BKE_fcurve_find_by_rna_context_ui( + C, &ptr, prop, index, NULL, NULL, &driven, &special); return (fcu == NULL || fcu->driver); } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 04061ceea51..2aa8d468e2d 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -184,7 +184,7 @@ FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], const if (ELEM(NULL, act, rna_path)) { return NULL; } - return list_find_fcurve(&act->curves, rna_path, array_index); + return BKE_fcurve_find(&act->curves, rna_path, array_index); } /** @@ -210,11 +210,11 @@ FCurve *ED_action_fcurve_ensure(struct Main *bmain, * - add if not found and allowed to add one * TODO: add auto-grouping support? how this works will need to be resolved */ - fcu = list_find_fcurve(&act->curves, rna_path, array_index); + fcu = BKE_fcurve_find(&act->curves, rna_path, array_index); if (fcu == NULL) { /* use default settings to make a F-Curve */ - fcu = MEM_callocN(sizeof(FCurve), "FCurve"); + fcu = BKE_fcurve_create(); fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); fcu->auto_smoothing = U.auto_smoothing_new; @@ -1120,7 +1120,7 @@ static bool insert_keyframe_value(ReportList *reports, eInsertKeyFlags flag) { /* F-Curve not editable? */ - if (fcurve_is_keyframable(fcu) == 0) { + if (BKE_fcurve_is_keyframable(fcu) == 0) { BKE_reportf( reports, RPT_ERROR, @@ -1827,7 +1827,7 @@ static int insert_key_exec(bContext *C, wmOperator *op) * updated since the last switching to the edit mode will be keyframed correctly */ if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) { - ED_object_mode_toggle(C, OB_MODE_EDIT); + ED_object_mode_set(C, OB_MODE_OBJECT); ob_edit_mode = true; } @@ -1843,7 +1843,7 @@ static int insert_key_exec(bContext *C, wmOperator *op) /* restore the edit mode if necessary */ if (ob_edit_mode) { - ED_object_mode_toggle(C, OB_MODE_EDIT); + ED_object_mode_set(C, OB_MODE_EDIT); } /* report failure or do updates? */ @@ -2400,7 +2400,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) * not have any effect. */ NlaStrip *strip = ptr.data; - FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); + FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index); if (fcu) { changed = insert_keyframe_direct( @@ -2417,7 +2417,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) FCurve *fcu; bool driven, special; - fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special); + fcu = BKE_fcurve_find_by_rna_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special); if (fcu && driven) { changed = insert_keyframe_direct( @@ -2560,7 +2560,7 @@ static int delete_key_button_exec(bContext *C, wmOperator *op) */ ID *id = ptr.owner_id; NlaStrip *strip = ptr.data; - FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0); + FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), 0); if (fcu) { if (BKE_fcurve_is_protected(fcu)) { @@ -3001,7 +3001,8 @@ bool ED_autokeyframe_property( bool special; bool changed = false; - fcu = rna_get_fcurve_context_ui(C, ptr, prop, rnaindex, NULL, &action, &driven, &special); + fcu = BKE_fcurve_find_by_rna_context_ui( + C, ptr, prop, rnaindex, NULL, &action, &driven, &special); if (fcu == NULL) { return changed; diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index d941f8ce95f..895b4953992 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -516,11 +516,11 @@ static void updateDuplicateActionConstraintSettings(EditBone *dup_bone, /* See if there is any channels that uses this bone */ ListBase ani_curves; BLI_listbase_clear(&ani_curves); - if (list_find_data_fcurves(&ani_curves, &act->curves, "pose.bones[", orig_bone->name)) { + if (BKE_fcurves_filter(&ani_curves, &act->curves, "pose.bones[", orig_bone->name)) { /* Create a copy and mirror the animation */ for (LinkData *ld = ani_curves.first; ld; ld = ld->next) { FCurve *old_curve = ld->data; - FCurve *new_curve = copy_fcurve(old_curve); + FCurve *new_curve = BKE_fcurve_copy(old_curve); bActionGroup *agrp; char *old_path = new_curve->rna_path; diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index b946c19dbe5..8e03dbc7dc3 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -184,78 +184,74 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode for (i = 0; i < hits; i++) { hitresult = buffer[3 + (i * 4)]; - if (!(hitresult & BONESEL_NOSEL)) { - if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */ - Base *base = NULL; - bool sel; - - hitresult &= ~(BONESEL_ANY); - /* Determine what the current bone is */ - if (is_editmode == false) { - base = ED_armature_base_and_pchan_from_select_buffer( - bases, bases_len, hitresult, &pchan); - if (pchan != NULL) { - if (findunsel) { - sel = (pchan->bone->flag & BONE_SELECTED); - } - else { - sel = !(pchan->bone->flag & BONE_SELECTED); - } - - data = pchan; + if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */ + Base *base = NULL; + bool sel; + + hitresult &= ~(BONESEL_ANY); + /* Determine what the current bone is */ + if (is_editmode == false) { + base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hitresult, &pchan); + if (pchan != NULL) { + if (findunsel) { + sel = (pchan->bone->flag & BONE_SELECTED); } else { - data = NULL; - sel = 0; + sel = !(pchan->bone->flag & BONE_SELECTED); } + + data = pchan; } else { - base = ED_armature_base_and_ebone_from_select_buffer( - bases, bases_len, hitresult, &ebone); - if (findunsel) { - sel = (ebone->flag & BONE_SELECTED); + data = NULL; + sel = 0; + } + } + else { + base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone); + if (findunsel) { + sel = (ebone->flag & BONE_SELECTED); + } + else { + sel = !(ebone->flag & BONE_SELECTED); + } + + data = ebone; + } + + if (data) { + if (sel) { + if (do_nearest) { + if (minsel > buffer[4 * i + 1]) { + firstSel = data; + firstSel_base = base; + minsel = buffer[4 * i + 1]; + } } else { - sel = !(ebone->flag & BONE_SELECTED); + if (!firstSel) { + firstSel = data; + firstSel_base = base; + } + takeNext = 1; } - - data = ebone; } - - if (data) { - if (sel) { - if (do_nearest) { - if (minsel > buffer[4 * i + 1]) { - firstSel = data; - firstSel_base = base; - minsel = buffer[4 * i + 1]; - } - } - else { - if (!firstSel) { - firstSel = data; - firstSel_base = base; - } - takeNext = 1; + else { + if (do_nearest) { + if (minunsel > buffer[4 * i + 1]) { + firstunSel = data; + firstunSel_base = base; + minunsel = buffer[4 * i + 1]; } } else { - if (do_nearest) { - if (minunsel > buffer[4 * i + 1]) { - firstunSel = data; - firstunSel_base = base; - minunsel = buffer[4 * i + 1]; - } + if (!firstunSel) { + firstunSel = data; + firstunSel_base = base; } - else { - if (!firstunSel) { - firstunSel = data; - firstunSel_base = base; - } - if (takeNext) { - *r_base = base; - return data; - } + if (takeNext) { + *r_base = base; + return data; } } } @@ -659,8 +655,8 @@ static EditBone *get_nearest_editbonepoint( EditBone *ebone; } *result = NULL, - result_cycle = {.hitresult = BONESEL_NOSEL, .base = NULL, .ebone = NULL}, - result_bias = {.hitresult = BONESEL_NOSEL, .base = NULL, .ebone = NULL}; + result_cycle = {.hitresult = -1, .base = NULL, .ebone = NULL}, + result_bias = {.hitresult = -1, .base = NULL, .ebone = NULL}; /* find the bone after the current active bone, so as to bump up its chances in selection. * this way overlapping bones will cycle selection state as with objects. */ @@ -732,11 +728,9 @@ cache_end: /* See if there are any selected bones in this group */ if (hits > 0) { if (hits == 1) { - if (!(buffer[3] & BONESEL_NOSEL)) { - result_bias.hitresult = buffer[3]; - result_bias.base = ED_armature_base_and_ebone_from_select_buffer( - bases, bases_len, result_bias.hitresult, &result_bias.ebone); - } + result_bias.hitresult = buffer[3]; + result_bias.base = ED_armature_base_and_ebone_from_select_buffer( + bases, bases_len, result_bias.hitresult, &result_bias.ebone); } else { int bias_max = INT_MIN; @@ -774,84 +768,82 @@ cache_end: for (int i = 0; i < hits; i++) { const uint hitresult = buffer[3 + (i * 4)]; - if (!(hitresult & BONESEL_NOSEL)) { - Base *base = NULL; - EditBone *ebone; - base = ED_armature_base_and_ebone_from_select_buffer( - bases, bases_len, hitresult, &ebone); - /* If this fails, selection code is setting the selection ID's incorrectly. */ - BLI_assert(base && ebone); - - /* Prioritized selection. */ - { - int bias; - /* clicks on bone points get advantage */ - if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) { - /* but also the unselected one */ - if (findunsel) { - if ((hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) { - bias = 4; - } - else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) { - bias = 4; - } - else { - bias = 3; - } + + Base *base = NULL; + EditBone *ebone; + base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone); + /* If this fails, selection code is setting the selection ID's incorrectly. */ + BLI_assert(base && ebone); + + /* Prioritized selection. */ + { + int bias; + /* clicks on bone points get advantage */ + if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) { + /* but also the unselected one */ + if (findunsel) { + if ((hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) { + bias = 4; } - else { + else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) { bias = 4; } + else { + bias = 3; + } } else { - /* bone found */ - if (findunsel) { - if ((ebone->flag & BONE_SELECTED) == 0) { - bias = 2; - } - else { - bias = 1; - } + bias = 4; + } + } + else { + /* bone found */ + if (findunsel) { + if ((ebone->flag & BONE_SELECTED) == 0) { + bias = 2; } else { - bias = 2; + bias = 1; } } + else { + bias = 2; + } + } - if (bias > bias_max) { - bias_max = bias; + if (bias > bias_max) { + bias_max = bias; - result_bias.hitresult = hitresult; - result_bias.base = base; - result_bias.ebone = ebone; - } + result_bias.hitresult = hitresult; + result_bias.base = base; + result_bias.ebone = ebone; } + } - /* Cycle selected items (objects & bones). */ - if (use_cycle) { - cycle_order.test.ob = hitresult & 0xFFFF; - cycle_order.test.bone = (hitresult & ~BONESEL_ANY) >> 16; - if (ebone == ebone_active_orig) { - BLI_assert(cycle_order.test.ob == cycle_order.offset.ob); - BLI_assert(cycle_order.test.bone == cycle_order.offset.bone); - } - /* Subtraction as a single value is needed to support cycling through bones - * from multiple objects. So once the last bone is selected, - * the bits for the bone index wrap into the object, - * causing the next object to be stepped onto. */ - cycle_order.test.as_u32 -= cycle_order.offset.as_u32; - - /* Even though this logic avoids stepping onto the active bone, - * always set the 'best' value for the first time. - * Otherwise ensure the value is the smallest it can be, - * relative to the active bone, as long as it's not the active bone. */ - if ((cycle_order.best.as_u32 == 0) || - (cycle_order.test.as_u32 && (cycle_order.test.as_u32 < cycle_order.best.as_u32))) { - cycle_order.best = cycle_order.test; - result_cycle.hitresult = hitresult; - result_cycle.base = base; - result_cycle.ebone = ebone; - } + /* Cycle selected items (objects & bones). */ + if (use_cycle) { + cycle_order.test.ob = hitresult & 0xFFFF; + cycle_order.test.bone = (hitresult & ~BONESEL_ANY) >> 16; + if (ebone == ebone_active_orig) { + BLI_assert(cycle_order.test.ob == cycle_order.offset.ob); + BLI_assert(cycle_order.test.bone == cycle_order.offset.bone); + } + /* Subtraction as a single value is needed to support cycling through bones + * from multiple objects. So once the last bone is selected, + * the bits for the bone index wrap into the object, + * causing the next object to be stepped onto. */ + cycle_order.test.as_u32 -= cycle_order.offset.as_u32; + + /* Even though this logic avoids stepping onto the active bone, + * always set the 'best' value for the first time. + * Otherwise ensure the value is the smallest it can be, + * relative to the active bone, as long as it's not the active bone. */ + if ((cycle_order.best.as_u32 == 0) || + (cycle_order.test.as_u32 && (cycle_order.test.as_u32 < cycle_order.best.as_u32))) { + cycle_order.best = cycle_order.test; + result_cycle.hitresult = hitresult; + result_cycle.base = base; + result_cycle.ebone = ebone; } } } @@ -859,7 +851,7 @@ cache_end: result = (use_cycle && result_cycle.ebone) ? &result_cycle : &result_bias; - if (!(result->hitresult & BONESEL_NOSEL)) { + if (result->hitresult != -1) { *r_base = result->base; *r_selmask = 0; @@ -1213,8 +1205,8 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op) ebone->temp.i = ebone->flag; /* When there is a partial selection without both endpoints, only select an endpoint. */ - if ((is_inside_flag & BONESEL_BONE) && (is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) && - ((is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) != (BONESEL_ROOT | BONESEL_TIP))) { + if ((is_inside_flag & BONESEL_BONE) && + ELEM(is_inside_flag & (BONESEL_ROOT | BONESEL_TIP), BONESEL_ROOT, BONESEL_TIP)) { is_inside_flag &= ~BONESEL_BONE; } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index d6256f67066..4e1c07af001 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -936,13 +936,13 @@ static void fcurve_path_rename(AnimData *adt, nextfcu = fcu->next; if (STREQLEN(fcu->rna_path, orig_rna_path, len)) { char *spath, *suffix = fcu->rna_path + len; - nfcu = copy_fcurve(fcu); + nfcu = BKE_fcurve_copy(fcu); spath = nfcu->rna_path; nfcu->rna_path = BLI_sprintfN("%s%s", rna_path, suffix); - /* copy_fcurve() sets nfcu->grp to NULL. To maintain the groups, we need to keep the pointer. - * As a result, the group's 'channels' pointers will be wrong, which is fixed by calling - * `action_groups_reconstruct(action)` later, after all fcurves have been renamed. */ + /* BKE_fcurve_copy() sets nfcu->grp to NULL. To maintain the groups, we need to keep the + * pointer. As a result, the group's 'channels' pointers will be wrong, which is fixed by + * calling `action_groups_reconstruct(action)` later, after all fcurves have been renamed. */ nfcu->grp = fcu->grp; BLI_addtail(curves, nfcu); @@ -956,7 +956,7 @@ static void fcurve_path_rename(AnimData *adt, BLI_remlink(&adt->drivers, fcu); } - free_fcurve(fcu); + BKE_fcurve_free(fcu); MEM_freeN(spath); } @@ -972,7 +972,7 @@ static void fcurve_remove(AnimData *adt, ListBase *orig_curves, FCurve *fcu) action_groups_remove_channel(adt->action, fcu); } - free_fcurve(fcu); + BKE_fcurve_free(fcu); } static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves) @@ -4923,7 +4923,7 @@ bool ED_curve_editnurb_select_pick( } } else { - BKE_nurbList_flag_set(editnurb, 0); + BKE_nurbList_flag_set(editnurb, SELECT, false); if (bezt) { @@ -5635,7 +5635,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) const float mval[2] = {UNPACK2(event->mval)}; struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - vc.bmain, vc.scene, 0, vc.region, vc.v3d); + vc.scene, 0, vc.region, vc.v3d); ED_transform_snap_object_project_view3d( snap_context, diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c index 91d5ea58361..bacdd5b69b5 100644 --- a/source/blender/editors/curve/editcurve_add.c +++ b/source/blender/editors/curve/editcurve_add.c @@ -138,7 +138,7 @@ Nurb *ED_curve_add_nurbs_primitive( copy_v3_v3(zvec, rv3d->viewinv[2]); } - BKE_nurbList_flag_set(editnurb, 0); + BKE_nurbList_flag_set(editnurb, SELECT, false); /* these types call this function to return a Nurb */ if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) { @@ -521,7 +521,7 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/curve/editcurve_query.c b/source/blender/editors/curve/editcurve_query.c index 0b15d9e55b9..132f7e58e71 100644 --- a/source/blender/editors/curve/editcurve_query.c +++ b/source/blender/editors/curve/editcurve_query.c @@ -44,8 +44,13 @@ /** \name Cursor Picking API * \{ */ -static void ED_curve_pick_vert__do_closest( - void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) +static void ED_curve_pick_vert__do_closest(void *userData, + Nurb *nu, + BPoint *bp, + BezTriple *bezt, + int beztindex, + bool handles_visible, + const float screen_co[2]) { struct { BPoint *bp; @@ -64,6 +69,8 @@ static void ED_curve_pick_vert__do_closest( flag = bp->f1; } else { + BLI_assert(handles_visible || beztindex == 1); + if (beztindex == 0) { flag = bezt->f1; } @@ -92,6 +99,8 @@ static void ED_curve_pick_vert__do_closest( data->hpoint = bezt ? beztindex : 0; data->is_changed = true; } + + UNUSED_VARS_NDEBUG(handles_visible); } bool ED_curve_pick_vert(ViewContext *vc, diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index 9cf61d02677..9294bc6e91b 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -590,8 +590,8 @@ static int de_select_all_exec(bContext *C, wmOperator *op) changed = ED_curve_deselect_all(cu->editnurb); break; case SEL_INVERT: - changed = ED_curve_select_swap( - cu->editnurb, (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0); + changed = ED_curve_select_swap(cu->editnurb, + v3d->overlay.handle_display == CURVE_HANDLE_NONE); break; } @@ -772,7 +772,7 @@ static int select_row_exec(bContext *C, wmOperator *UNUSED(op)) if (last == bp) { direction = 1 - direction; - BKE_nurbList_flag_set(editnurb, 0); + BKE_nurbList_flag_set(editnurb, SELECT, false); } last = bp; @@ -826,8 +826,10 @@ static int select_next_exec(bContext *C, wmOperator *UNUSED(op)) for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); select_adjacent_cp(editnurb, 1, 0, SELECT); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -861,8 +863,10 @@ static int select_previous_exec(bContext *C, wmOperator *UNUSED(op)) for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); select_adjacent_cp(editnurb, -1, 0, SELECT); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -1392,6 +1396,7 @@ static int select_nth_exec(bContext *C, wmOperator *op) if (ed_curve_select_nth(obedit->data, &op_params) == true) { changed = true; + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c index af492de638b..1fd1e217649 100644 --- a/source/blender/editors/curve/editcurve_undo.c +++ b/source/blender/editors/curve/editcurve_undo.c @@ -88,12 +88,12 @@ static void undocurve_to_editcurve(Main *bmain, UndoCurve *ucu, Curve *cu, short if (ad) { if (ad->action) { - free_fcurves(&ad->action->curves); - copy_fcurves(&ad->action->curves, &ucu->fcurves); + BKE_fcurves_free(&ad->action->curves); + BKE_fcurves_copy(&ad->action->curves, &ucu->fcurves); } - free_fcurves(&ad->drivers); - copy_fcurves(&ad->drivers, &ucu->drivers); + BKE_fcurves_free(&ad->drivers); + BKE_fcurves_copy(&ad->drivers, &ucu->drivers); } /* copy */ @@ -132,10 +132,10 @@ static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu, const short shap if (ad) { if (ad->action) { - copy_fcurves(&ucu->fcurves, &ad->action->curves); + BKE_fcurves_copy(&ucu->fcurves, &ad->action->curves); } - copy_fcurves(&ucu->drivers, &ad->drivers); + BKE_fcurves_copy(&ucu->drivers, &ad->drivers); } /* copy */ @@ -167,8 +167,8 @@ static void undocurve_free_data(UndoCurve *uc) BKE_curve_editNurb_keyIndex_free(&uc->undoIndex); - free_fcurves(&uc->fcurves); - free_fcurves(&uc->drivers); + BKE_fcurves_free(&uc->fcurves); + BKE_fcurves_free(&uc->drivers); } static Object *editcurve_object_from_context(bContext *C) diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index af591e0c7c5..ef9bb7e0c88 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -359,7 +359,7 @@ static void font_undosys_step_decode( struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final)) { /* TODO(campbell): undo_system: use low-level API to set mode. */ - ED_object_mode_set(C, OB_MODE_EDIT); + ED_object_mode_set_ex(C, OB_MODE_EDIT, false, NULL); BLI_assert(font_undosys_poll(C)); FontUndoStep *us = (FontUndoStep *)us_p; diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt index 68a204c04a7..1f3edf31b19 100644 --- a/source/blender/editors/gizmo_library/CMakeLists.txt +++ b/source/blender/editors/gizmo_library/CMakeLists.txt @@ -53,6 +53,7 @@ set(SRC gizmo_types/dial3d_gizmo.c gizmo_types/move3d_gizmo.c gizmo_types/primitive3d_gizmo.c + gizmo_types/snap3d_gizmo.c ) set(LIB diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c index 374b7b1f6a2..db57a33f543 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c @@ -382,7 +382,7 @@ static int gizmo_move_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) switch (area->spacetype) { case SPACE_VIEW3D: { inter->snap_context_v3d = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C)); + CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C)); break; } default: diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c new file mode 100644 index 00000000000..a3921791427 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c @@ -0,0 +1,560 @@ +/* + * 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 snap3d_gizmo.c + * \ingroup edgizmolib + * + * \name Snap Gizmo + * + * 3D Gizmo + * + * \brief Snap gizmo which exposes the location, normal and index in the props. + */ + +#include "BLI_math.h" + +#include "DNA_scene_types.h" + +#include "BKE_context.h" + +#include "GPU_immediate.h" +#include "GPU_state.h" + +#include "ED_gizmo_library.h" +#include "ED_screen.h" +#include "ED_transform_snap_object_context.h" +#include "ED_view3d.h" + +#include "UI_resources.h" /* icons */ + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "DEG_depsgraph_query.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm.h" + +/* own includes */ +#include "../gizmo_geometry.h" +#include "../gizmo_library_intern.h" + +typedef struct SnapGizmo3D { + wmGizmo gizmo; + PropertyRNA *prop_prevpoint; + PropertyRNA *prop_location; + PropertyRNA *prop_normal; + PropertyRNA *prop_elem_index; + PropertyRNA *prop_snap_force; + + /* We could have other snap contexts, for now only support 3D view. */ + SnapObjectContext *snap_context_v3d; + int mval[2]; + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + wmKeyMap *keymap; + int snap_on; + bool invert_snap; +#endif + int use_snap_override; + short snap_elem; +} SnapGizmo3D; + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK +static bool invert_snap(const wmGizmo *gz, const wmWindowManager *wm, const wmEvent *event) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + wmKeyMap *keymap = WM_keymap_active(wm, gizmo_snap->keymap); + + const int snap_on = gizmo_snap->snap_on; + for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + if (kmi->flag & KMI_INACTIVE) { + continue; + } + + if (kmi->propvalue == snap_on) { + if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) || + (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) || + (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) || + ((kmi->type == EVT_OSKEY) && event->oskey)) { + return true; + } + } + } + return false; +} +#endif + +/* -------------------------------------------------------------------- */ +/** \name ED_gizmo_library specific API + * \{ */ + +void ED_gizmotypes_snap_3d_draw_util(RegionView3D *rv3d, + const float loc_prev[3], + const float loc_curr[3], + const float normal[3], + const uchar color_line[4], + const uchar color_point[4], + const short snap_elem_type) +{ + if (!loc_prev && !loc_curr) { + return; + } + + float view_inv[4][4]; + copy_m4_m4(view_inv, rv3d->viewinv); + + /* The size of the circle is larger than the vertex size. + * This prevents a drawing overlaps the other. */ + float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + if (loc_curr) { + immUniformColor4ubv(color_point); + imm_drawcircball(loc_curr, ED_view3d_pixel_size(rv3d, loc_curr) * radius, view_inv, pos); + + /* draw normal if needed */ + if (normal) { + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, loc_curr); + immVertex3f(pos, loc_curr[0] + normal[0], loc_curr[1] + normal[1], loc_curr[2] + normal[2]); + immEnd(); + } + } + + if (loc_prev) { + /* Draw an "X" indicating where the previous snap point is. + * This is useful for indicating perpendicular snap. */ + + /* v1, v2, v3 and v4 indicate the coordinates of the ends of the "X". */ + float vx[3], vy[3], v1[3], v2[3], v3[3], v4[4]; + + /* Multiply by 0.75f so that the final size of the "X" is close to that of + * the circle. + * (A closer value is 0.7071f, but we don't need to be exact here). */ + float x_size = 0.75f * radius * ED_view3d_pixel_size(rv3d, loc_prev); + + mul_v3_v3fl(vx, view_inv[0], x_size); + mul_v3_v3fl(vy, view_inv[1], x_size); + + add_v3_v3v3(v1, vx, vy); + sub_v3_v3v3(v2, vx, vy); + negate_v3_v3(v3, v1); + negate_v3_v3(v4, v2); + + add_v3_v3(v1, loc_prev); + add_v3_v3(v2, loc_prev); + add_v3_v3(v3, loc_prev); + add_v3_v3(v4, loc_prev); + + immUniformColor4ubv(color_line); + immBegin(GPU_PRIM_LINES, 4); + immVertex3fv(pos, v3); + immVertex3fv(pos, v1); + immVertex3fv(pos, v4); + immVertex3fv(pos, v2); + immEnd(); + + if (loc_curr && (snap_elem_type & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + /* Dashed line. */ + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + immUniform1f("dash_width", 6.0f * U.pixelsize); + immUniform1f("dash_factor", 1.0f / 4.0f); + immUniformColor4ubv(color_line); + + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, loc_prev); + immVertex3fv(pos, loc_curr); + immEnd(); + } + } + + immUnbindProgram(); +} + +SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene, + const ARegion *region, + const View3D *v3d, + wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + if (gizmo_snap->snap_context_v3d == NULL) { + gizmo_snap->snap_context_v3d = ED_transform_snap_object_context_create_view3d( + scene, 0, region, v3d); + } + return gizmo_snap->snap_context_v3d; +} + +bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + return gizmo_snap->invert_snap; +} +void ED_gizmotypes_snap_3d_toggle_set(wmGizmo *gz, bool enable) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + gizmo_snap->use_snap_override = (int)enable; +} + +void ED_gizmotypes_snap_3d_toggle_clear(wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + gizmo_snap->use_snap_override = -1; +} + +short ED_gizmotypes_snap_3d_update(wmGizmo *gz, + struct Depsgraph *depsgraph, + const ARegion *region, + const View3D *v3d, + const wmWindowManager *wm, + const float mval_fl[2], + float r_loc[3], + float r_nor[3]) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + Scene *scene = DEG_get_input_scene(depsgraph); + float co[3], no[3]; + short snap_elem = 0; + int snap_elem_index[3] = {-1, -1, -1}; + int index = -1; + + if (gizmo_snap->use_snap_override != -1) { + if (gizmo_snap->use_snap_override == false) { + gizmo_snap->snap_elem = 0; + return 0; + } + } + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + if (wm && wm->winactive) { + gizmo_snap->invert_snap = invert_snap(gz, wm, wm->winactive->eventstate); + } + + if (gizmo_snap->use_snap_override == -1) { + const ToolSettings *ts = scene->toolsettings; + if (gizmo_snap->invert_snap != !(ts->snap_flag & SCE_SNAP)) { + gizmo_snap->snap_elem = 0; + return 0; + } + } +#else + UNUSED_VARS(wm); +#endif + + wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "snap_elements"); + int snap_elements = RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop); + if (gz_prop->prop != gizmo_snap->prop_snap_force) { + int snap_elements_force = RNA_property_enum_get(gz->ptr, gizmo_snap->prop_snap_force); + snap_elements |= snap_elements_force; + } + snap_elements &= (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR); + + if (snap_elements) { + float prev_co[3] = {0.0f}; + if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) { + RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_co); + } + else { + snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR; + } + + float dist_px = 12.0f * U.pixelsize; + + ED_gizmotypes_snap_3d_context_ensure(scene, region, v3d, gz); + snap_elem = ED_transform_snap_object_project_view3d_ex(gizmo_snap->snap_context_v3d, + depsgraph, + snap_elements, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .use_object_edit_cage = true, + .use_occlusion_test = true, + }, + mval_fl, + prev_co, + &dist_px, + co, + no, + &index, + NULL, + NULL); + } + + if (snap_elem == 0) { + RegionView3D *rv3d = region->regiondata; + ED_view3d_win_to_3d(v3d, region, rv3d->ofs, mval_fl, co); + zero_v3(no); + } + else if (snap_elem == SCE_SNAP_MODE_VERTEX) { + snap_elem_index[0] = index; + } + else if (snap_elem & + (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + snap_elem_index[1] = index; + } + else if (snap_elem == SCE_SNAP_MODE_FACE) { + snap_elem_index[2] = index; + } + + gizmo_snap->snap_elem = snap_elem; + RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_location, co); + RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_normal, no); + RNA_property_int_set_array(gz->ptr, gizmo_snap->prop_elem_index, snap_elem_index); + + if (r_loc) { + copy_v3_v3(r_loc, co); + } + if (r_nor) { + copy_v3_v3(r_nor, no); + } + + return snap_elem; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name GIZMO_GT_snap_3d + * \{ */ + +static void gizmo_snap_setup(wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + + /* For quick access to the props. */ + gizmo_snap->prop_prevpoint = RNA_struct_find_property(gz->ptr, "prev_point"); + gizmo_snap->prop_location = RNA_struct_find_property(gz->ptr, "location"); + gizmo_snap->prop_normal = RNA_struct_find_property(gz->ptr, "normal"); + gizmo_snap->prop_elem_index = RNA_struct_find_property(gz->ptr, "snap_elem_index"); + gizmo_snap->prop_snap_force = RNA_struct_find_property(gz->ptr, "snap_elements_force"); + + gizmo_snap->use_snap_override = -1; + + /* Prop fallback. */ + WM_gizmo_target_property_def_rna(gz, "snap_elements", gz->ptr, "snap_elements_force", -1); + + /* Flags. */ + gz->flag |= WM_GIZMO_NO_TOOLTIP; +} + +static void gizmo_snap_draw(const bContext *C, wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + if (gizmo_snap->snap_elem == 0) { + return; + } + + ARegion *region = CTX_wm_region(C); + RegionView3D *rv3d = region->regiondata; + + /* Ideally, we shouldn't assign values here. + * But `test_select` is not called during navigation. + * And `snap_elem` is not really useful in this case. */ + if ((rv3d->rflag & RV3D_NAVIGATING) || + (!(gz->state & WM_GIZMO_STATE_HIGHLIGHT) && !wm_gizmomap_modal_get(region->gizmo_map))) { + gizmo_snap->snap_elem = 0; + return; + } + + float location[3], prev_point_stack[3], *prev_point = NULL; + uchar color_line[4], color_point[4]; + + RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_location, location); + + UI_GetThemeColor3ubv(TH_TRANSFORM, color_line); + color_line[3] = 128; + + rgba_float_to_uchar(color_point, gz->color); + + if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) { + RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_point_stack); + prev_point = prev_point_stack; + } + + GPU_line_smooth(false); + + GPU_line_width(1.0f); + ED_gizmotypes_snap_3d_draw_util( + rv3d, prev_point, location, NULL, color_line, color_point, gizmo_snap->snap_elem); +} + +static int gizmo_snap_test_select(bContext *C, wmGizmo *gz, const int mval[2]) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + wmWindowManager *wm = CTX_wm_manager(C); + if (gizmo_snap->keymap == NULL) { + gizmo_snap->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map"); + RNA_enum_value_from_id(gizmo_snap->keymap->modal_items, "SNAP_ON", &gizmo_snap->snap_on); + } + + const bool invert = wm->winactive ? invert_snap(gz, wm, wm->winactive->eventstate) : false; + if (gizmo_snap->invert_snap == invert && gizmo_snap->mval[0] == mval[0] && + gizmo_snap->mval[1] == mval[1]) { + /* Performance, do not update. */ + return gizmo_snap->snap_elem ? 0 : -1; + } + + gizmo_snap->invert_snap = invert; +#else + if (gizmo_snap->mval[0] == mval[0] && gizmo_snap->mval[1] == mval[1]) { + /* Performance, do not update. */ + return gizmo_snap->snap_elem ? 0 : -1; + } +#endif + copy_v2_v2_int(gizmo_snap->mval, mval); + + ARegion *region = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + const float mval_fl[2] = {UNPACK2(mval)}; + short snap_elem = ED_gizmotypes_snap_3d_update( + gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, mval_fl, NULL, NULL); + + if (snap_elem) { + ED_region_tag_redraw_editor_overlays(region); + return 0; + } + + return -1; +} + +static int gizmo_snap_modal(bContext *UNUSED(C), + wmGizmo *UNUSED(gz), + const wmEvent *UNUSED(event), + eWM_GizmoFlagTweak UNUSED(tweak_flag)) +{ + return OPERATOR_RUNNING_MODAL; +} + +static int gizmo_snap_invoke(bContext *UNUSED(C), + wmGizmo *UNUSED(gz), + const wmEvent *UNUSED(event)) +{ + return OPERATOR_RUNNING_MODAL; +} + +static void gizmo_snap_free(wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + if (gizmo_snap->snap_context_v3d) { + ED_transform_snap_object_context_destroy(gizmo_snap->snap_context_v3d); + gizmo_snap->snap_context_v3d = NULL; + } +} + +static void GIZMO_GT_snap_3d(wmGizmoType *gzt) +{ + /* identifiers */ + gzt->idname = "GIZMO_GT_snap_3d"; + + /* api callbacks */ + gzt->setup = gizmo_snap_setup; + gzt->draw = gizmo_snap_draw; + gzt->test_select = gizmo_snap_test_select; + gzt->modal = gizmo_snap_modal; + gzt->invoke = gizmo_snap_invoke; + gzt->free = gizmo_snap_free; + + gzt->struct_size = sizeof(SnapGizmo3D); + + const EnumPropertyItem *rna_enum_snap_element_items; + { + /* Get Snap Element Items enum. */ + bool free; + PointerRNA toolsettings_ptr; + RNA_pointer_create(NULL, &RNA_ToolSettings, NULL, &toolsettings_ptr); + PropertyRNA *prop = RNA_struct_find_property(&toolsettings_ptr, "snap_elements"); + RNA_property_enum_items( + NULL, &toolsettings_ptr, prop, &rna_enum_snap_element_items, NULL, &free); + + BLI_assert(free == false); + } + + /* Setup. */ + RNA_def_enum_flag(gzt->srna, + "snap_elements_force", + rna_enum_snap_element_items, + SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE, + "Snap Elements", + ""); + + RNA_def_float_vector(gzt->srna, + "prev_point", + 3, + NULL, + FLT_MIN, + FLT_MAX, + "Previous Point", + "Point that defines the location of the perpendicular snap", + FLT_MIN, + FLT_MAX); + + /* Returns. */ + RNA_def_float_vector(gzt->srna, + "location", + 3, + NULL, + FLT_MIN, + FLT_MAX, + "Location", + "Snap Point Location", + FLT_MIN, + FLT_MAX); + + RNA_def_float_vector(gzt->srna, + "normal", + 3, + NULL, + FLT_MIN, + FLT_MAX, + "Normal", + "Snap Point Normal", + FLT_MIN, + FLT_MAX); + + RNA_def_int_vector(gzt->srna, + "snap_elem_index", + 3, + NULL, + INT_MIN, + INT_MAX, + "Snap Element", + "Array index of face, edge and vert snapped", + INT_MIN, + INT_MAX); + + /* Read/Write. */ + WM_gizmotype_target_property_def(gzt, "snap_elements", PROP_ENUM, 1); +} + +void ED_gizmotypes_snap_3d(void) +{ + WM_gizmotype_append(GIZMO_GT_snap_3d); +} + +/** \} */ diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index c53b90fbfee..723c7d214e3 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -1729,17 +1729,16 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) } /* Turn brush cursor in 3D view on/off */ -static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable) +static void gpencil_draw_toggle_eraser_cursor(tGPsdata *p, short enable) { if (p->erasercursor && !enable) { /* clear cursor */ - WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor); + WM_paint_cursor_end(p->erasercursor); p->erasercursor = NULL; } else if (enable && !p->erasercursor) { /* enable cursor */ - p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, + p->erasercursor = WM_paint_cursor_activate(SPACE_TYPE_ANY, RGN_TYPE_ANY, NULL, /* XXX */ gpencil_draw_eraser, @@ -1794,17 +1793,17 @@ static void gpencil_draw_stabilizer(bContext *C, int x, int y, void *p_ptr) } /* Turn *stabilizer* brush cursor in 3D view on/off */ -static void gpencil_draw_toggle_stabilizer_cursor(bContext *C, tGPsdata *p, short enable) +static void gpencil_draw_toggle_stabilizer_cursor(tGPsdata *p, short enable) { if (p->stabilizer_cursor && !enable) { /* clear cursor */ - WM_paint_cursor_end(CTX_wm_manager(C), p->stabilizer_cursor); + WM_paint_cursor_end(p->stabilizer_cursor); p->stabilizer_cursor = NULL; } else if (enable && !p->stabilizer_cursor) { /* enable cursor */ p->stabilizer_cursor = WM_paint_cursor_activate( - CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, NULL, gpencil_draw_stabilizer, p); + SPACE_TYPE_ANY, RGN_TYPE_ANY, NULL, gpencil_draw_stabilizer, p); } } @@ -1828,10 +1827,10 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op) /* check size of buffer before cleanup, to determine if anything happened here */ if (p->paintmode == GP_PAINTMODE_ERASER) { /* turn off radial brush cursor */ - gpencil_draw_toggle_eraser_cursor(C, p, false); + gpencil_draw_toggle_eraser_cursor(p, false); } else if (p->paintmode == GP_PAINTMODE_DRAW) { - gpencil_draw_toggle_stabilizer_cursor(C, p, false); + gpencil_draw_toggle_stabilizer_cursor(p, false); } /* always store the new eraser size to be used again next time @@ -2039,7 +2038,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph /* handle draw event */ static void annotation_draw_apply_event( - bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y) + wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y) { tGPsdata *p = op->customdata; PointerRNA itemptr; @@ -2056,14 +2055,14 @@ static void annotation_draw_apply_event( /* Using permanent stabilization, shift will deactivate the flag. */ if (p->flags & (GP_PAINTFLAG_USE_STABILIZER)) { if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) { - gpencil_draw_toggle_stabilizer_cursor(C, p, false); + gpencil_draw_toggle_stabilizer_cursor(p, false); p->flags &= ~GP_PAINTFLAG_USE_STABILIZER_TEMP; } } /* Not using any stabilization flag. Activate temporal one. */ else if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) { p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP; - gpencil_draw_toggle_stabilizer_cursor(C, p, true); + gpencil_draw_toggle_stabilizer_cursor(p, true); } } /* verify key status for straight lines */ @@ -2092,7 +2091,7 @@ static void annotation_draw_apply_event( so activate the temp flag back again. */ if (p->flags & GP_PAINTFLAG_USE_STABILIZER) { if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) { - gpencil_draw_toggle_stabilizer_cursor(C, p, true); + gpencil_draw_toggle_stabilizer_cursor(p, true); p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP; } } @@ -2102,7 +2101,7 @@ static void annotation_draw_apply_event( else if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) { /* Reset temporal stabilizer flag and remove cursor. */ p->flags &= ~GP_PAINTFLAG_USE_STABILIZER_TEMP; - gpencil_draw_toggle_stabilizer_cursor(C, p, false); + gpencil_draw_toggle_stabilizer_cursor(p, false); } } @@ -2296,7 +2295,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event /* if eraser is on, draw radial aid */ if (p->paintmode == GP_PAINTMODE_ERASER) { - gpencil_draw_toggle_eraser_cursor(C, p, true); + gpencil_draw_toggle_eraser_cursor(p, true); } else if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { if (RNA_enum_get(op->ptr, "arrowstyle_start") != GP_STROKE_ARROWSTYLE_NONE) { @@ -2313,11 +2312,11 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event p->stabilizer_radius = RNA_int_get(op->ptr, "stabilizer_radius"); if (RNA_boolean_get(op->ptr, "use_stabilizer")) { p->flags |= GP_PAINTFLAG_USE_STABILIZER | GP_PAINTFLAG_USE_STABILIZER_TEMP; - gpencil_draw_toggle_stabilizer_cursor(C, p, true); + gpencil_draw_toggle_stabilizer_cursor(p, true); } else if (event->shift > 0) { p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP; - gpencil_draw_toggle_stabilizer_cursor(C, p, true); + gpencil_draw_toggle_stabilizer_cursor(p, true); } } /* set cursor @@ -2333,7 +2332,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event p->status = GP_STATUS_PAINTING; /* handle the initial drawing - i.e. for just doing a simple dot */ - annotation_draw_apply_event(C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f); + annotation_draw_apply_event(op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f); op->flag |= OP_IS_MODAL_CURSOR_REGION; } else { @@ -2425,7 +2424,7 @@ static void annotation_add_missing_events(bContext *C, interp_v2_v2v2(pt, a, b, 0.5f); sub_v2_v2v2(pt, b, pt); /* create fake event */ - annotation_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]); + annotation_draw_apply_event(op, event, depsgraph, pt[0], pt[1]); } else if (dist >= factor) { int slices = 2 + (int)((dist - 1.0) / factor); @@ -2434,7 +2433,7 @@ static void annotation_add_missing_events(bContext *C, interp_v2_v2v2(pt, a, b, n * i); sub_v2_v2v2(pt, b, pt); /* create fake event */ - annotation_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]); + annotation_draw_apply_event(op, event, depsgraph, pt[0], pt[1]); } } } @@ -2562,7 +2561,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) * Just hiding this makes it seem like * you can paint again... */ - gpencil_draw_toggle_eraser_cursor(C, p, false); + gpencil_draw_toggle_eraser_cursor(p, false); } } @@ -2647,7 +2646,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) p->paintmode = RNA_enum_get(op->ptr, "mode"); } - gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER); + gpencil_draw_toggle_eraser_cursor(p, p->paintmode == GP_PAINTMODE_ERASER); /* not painting, so start stroke (this should be mouse-button down) */ p = gpencil_stroke_begin(C, op); @@ -2681,8 +2680,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* TODO(sergey): Possibly evaluating dependency graph from modal operator? */ - annotation_draw_apply_event( - C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f); + annotation_draw_apply_event(op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f); /* finish painting operation if anything went wrong just now */ if (p->status == GP_STATUS_ERROR) { diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 4444396558b..8771fcb0c8d 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -354,10 +354,6 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op) /* set mode */ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) { mode = OB_MODE_PAINT_GPENCIL; - BKE_brush_gpencil_paint_presets(bmain, ts, false); - - /* Ensure Palette by default. */ - BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C)); } else { mode = OB_MODE_OBJECT; @@ -373,8 +369,16 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op) } if (mode == OB_MODE_PAINT_GPENCIL) { - /* be sure we have brushes */ + /* Be sure we have brushes and Paint settings. + * Need Draw and Vertex (used for Tint). */ BKE_paint_ensure(ts, (Paint **)&ts->gp_paint); + BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint); + + BKE_brush_gpencil_paint_presets(bmain, ts, false); + + /* Ensure Palette by default. */ + BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C)); + Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { @@ -466,7 +470,6 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op) /* set mode */ if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) { mode = OB_MODE_SCULPT_GPENCIL; - BKE_brush_gpencil_sculpt_presets(bmain, ts, false); } else { mode = OB_MODE_OBJECT; @@ -482,8 +485,12 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op) } if (mode == OB_MODE_SCULPT_GPENCIL) { - /* be sure we have brushes */ + /* Be sure we have brushes. */ BKE_paint_ensure(ts, (Paint **)&ts->gp_sculptpaint); + + const bool reset_mode = (ts->gp_sculptpaint->paint.brush == NULL); + BKE_brush_gpencil_sculpt_presets(bmain, ts, reset_mode); + BKE_paint_toolslots_brush_validate(bmain, &ts->gp_sculptpaint->paint); } @@ -572,7 +579,6 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op) /* set mode */ if (gpd->flag & GP_DATA_STROKE_WEIGHTMODE) { mode = OB_MODE_WEIGHT_GPENCIL; - BKE_brush_gpencil_weight_presets(bmain, ts, false); } else { mode = OB_MODE_OBJECT; @@ -588,8 +594,12 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op) } if (mode == OB_MODE_WEIGHT_GPENCIL) { - /* be sure we have brushes */ + /* Be sure we have brushes. */ BKE_paint_ensure(ts, (Paint **)&ts->gp_weightpaint); + + const bool reset_mode = (ts->gp_weightpaint->paint.brush == NULL); + BKE_brush_gpencil_weight_presets(bmain, ts, reset_mode); + BKE_paint_toolslots_brush_validate(bmain, &ts->gp_weightpaint->paint); } @@ -675,10 +685,6 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op) /* set mode */ if (gpd->flag & GP_DATA_STROKE_VERTEXMODE) { mode = OB_MODE_VERTEX_GPENCIL; - BKE_brush_gpencil_vertex_presets(bmain, ts, false); - - /* Ensure Palette by default. */ - BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C)); } else { mode = OB_MODE_OBJECT; @@ -694,9 +700,16 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op) } if (mode == OB_MODE_VERTEX_GPENCIL) { - /* be sure we have brushes */ + /* Be sure we have brushes. */ BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint); + + const bool reset_mode = (ts->gp_vertexpaint->paint.brush == NULL); + BKE_brush_gpencil_vertex_presets(bmain, ts, reset_mode); + BKE_paint_toolslots_brush_validate(bmain, &ts->gp_vertexpaint->paint); + + /* Ensure Palette by default. */ + BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C)); } /* setup other modes */ @@ -3656,7 +3669,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) int cfra_prv = INT_MIN; /* init snap context for geometry projection */ - sctx = ED_transform_snap_object_context_create_view3d(bmain, scene, 0, region, CTX_wm_view3d(C)); + sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C)); /* Go through each editable + selected stroke, adjusting each of its points one by one... */ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 4e83c4fb11c..06079c34d12 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -2299,18 +2299,17 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) } /* Turn brush cursor in 3D view on/off */ -static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable) +static void gpencil_draw_toggle_eraser_cursor(tGPsdata *p, short enable) { if (p->erasercursor && !enable) { /* clear cursor */ - WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor); + WM_paint_cursor_end(p->erasercursor); p->erasercursor = NULL; } else if (enable && !p->erasercursor) { ED_gpencil_toggle_brush_cursor(p->C, false, NULL); /* enable cursor */ - p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, + p->erasercursor = WM_paint_cursor_activate(SPACE_TYPE_ANY, RGN_TYPE_ANY, NULL, /* XXX */ gpencil_draw_eraser, @@ -2335,7 +2334,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op) /* check size of buffer before cleanup, to determine if anything happened here */ if (p->paintmode == GP_PAINTMODE_ERASER) { /* turn off radial brush cursor */ - gpencil_draw_toggle_eraser_cursor(C, p, false); + gpencil_draw_toggle_eraser_cursor(p, false); } /* always store the new eraser size to be used again next time @@ -3154,7 +3153,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event /* TODO: set any additional settings that we can take from the events? * if eraser is on, draw radial aid */ if (p->paintmode == GP_PAINTMODE_ERASER) { - gpencil_draw_toggle_eraser_cursor(C, p, true); + gpencil_draw_toggle_eraser_cursor(p, true); } else { ED_gpencil_toggle_brush_cursor(C, true, NULL); @@ -3700,7 +3699,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) p->paintmode = RNA_enum_get(op->ptr, "mode"); } - gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER); + gpencil_draw_toggle_eraser_cursor(p, p->paintmode == GP_PAINTMODE_ERASER); /* not painting, so start stroke (this should be mouse-button down) */ p = gpencil_stroke_begin(C, op); diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 69d22b52ded..c41b2993a80 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -43,6 +43,7 @@ #include "BKE_context.h" #include "BKE_gpencil.h" +#include "BKE_material.h" #include "BKE_report.h" #include "UI_interface.h" @@ -1118,10 +1119,8 @@ typedef bool (*GPencilTestFn)(bGPDstroke *gps, const float diff_mat[4][4], void *user_data); -static int gpencil_generic_select_exec(bContext *C, - wmOperator *op, - GPencilTestFn is_inside_fn, - void *user_data) +static int gpencil_generic_select_exec( + bContext *C, wmOperator *op, GPencilTestFn is_inside_fn, rcti box, void *user_data) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -1143,7 +1142,6 @@ static int gpencil_generic_select_exec(bContext *C, ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)); const bool segmentmode = ((selectmode == GP_SELECTMODE_SEGMENT) && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)); - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); const float scale = ts->gp_sculpt.isect_threshold; @@ -1180,15 +1178,13 @@ static int gpencil_generic_select_exec(bContext *C, /* select/deselect points */ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; + bool whole = false; bGPDspoint *pt; int i; bool hit = false; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if (pt->runtime.pt_orig == NULL) { - continue; - } - bGPDspoint *pt_active = pt->runtime.pt_orig; + bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; /* convert point coords to screenspace */ const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data); @@ -1198,9 +1194,10 @@ static int gpencil_generic_select_exec(bContext *C, if (sel_op_result != -1) { SET_FLAG_FROM_TEST(pt_active->flag, sel_op_result, GP_SPOINT_SELECT); changed = true; + hit = true; - /* expand selection to segment */ - if ((sel_op_result != -1) && (segmentmode)) { + /* Expand selection to segment. */ + if (segmentmode) { bool hit_select = (bool)(pt_active->flag & GP_SPOINT_SELECT); float r_hita[3], r_hitb[3]; ED_gpencil_select_stroke_segment( @@ -1216,16 +1213,28 @@ static int gpencil_generic_select_exec(bContext *C, } } - /* if stroke mode expand selection */ - if (strokemode) { - const bool is_select = BKE_gpencil_stroke_select_check(gps_active); - const bool is_inside = hit; + /* If nothing hit, check if the mouse is inside a filled stroke using the center or + * Box or lasso area. */ + if (!hit) { + /* Only check filled strokes. */ + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + if ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0) { + continue; + } + int mval[2]; + mval[0] = (box.xmax + box.xmin) / 2; + mval[1] = (box.ymax + box.ymin) / 2; + + whole = ED_gpencil_stroke_point_is_inside(gps_active, &gsc, mval, gpstroke_iter.diff_mat); + } + + /* if stroke mode expand selection. */ + if ((strokemode) || (whole)) { + const bool is_select = BKE_gpencil_stroke_select_check(gps_active) || whole; + const bool is_inside = hit || whole; const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) { - continue; - } bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; if (sel_op_result) { @@ -1261,7 +1270,6 @@ static int gpencil_generic_select_exec(bContext *C, WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); } - return OPERATOR_FINISHED; } @@ -1293,7 +1301,8 @@ static int gpencil_box_select_exec(bContext *C, wmOperator *op) { struct GP_SelectBoxUserData data = {0}; WM_operator_properties_border_to_rcti(op, &data.rect); - return gpencil_generic_select_exec(C, op, gpencil_test_box, &data); + rcti rect = data.rect; + return gpencil_generic_select_exec(C, op, gpencil_test_box, rect, &data); } void GPENCIL_OT_select_box(wmOperatorType *ot) @@ -1360,7 +1369,8 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) /* Compute boundbox of lasso (for faster testing later). */ BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len); - int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, &data); + rcti rect = data.rect; + int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, rect, &data); MEM_freeN((void *)data.mcoords); @@ -1424,7 +1434,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */ - const float radius = 0.50f * U.widget_unit; + const float radius = 0.4f * U.widget_unit; const int radius_squared = (int)(radius * radius); const bool use_shift_extend = RNA_boolean_get(op->ptr, "use_shift_extend"); @@ -1469,12 +1479,19 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) RNA_int_get_array(op->ptr, "location", mval); /* First Pass: Find stroke point which gets hit */ - /* XXX: maybe we should go from the top of the stack down instead... */ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt; int i; + /* Check boundbox to speedup. */ + float fmval[2]; + copy_v2fl_v2i(fmval, mval); + if (!ED_gpencil_stroke_check_collision( + &gsc, gps_active, fmval, radius, gpstroke_iter.diff_mat)) { + continue; + } + /* firstly, check for hit-point */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { int xy[2]; @@ -1502,11 +1519,27 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) } } } + if (ELEM(NULL, hit_stroke, hit_point)) { + /* If nothing hit, check if the mouse is inside any filled stroke. + * Only check filling materials. */ + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + if ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0) { + continue; + } + bool hit_fill = ED_gpencil_stroke_point_is_inside(gps, &gsc, mval, gpstroke_iter.diff_mat); + if (hit_fill) { + hit_stroke = gps_active; + hit_point = &gps_active->points[0]; + /* Extend selection to all stroke. */ + whole = true; + } + } } GP_EVALUATED_STROKES_END(gpstroke_iter); /* Abort if nothing hit... */ if (ELEM(NULL, hit_stroke, hit_point)) { + if (deselect_all) { /* since left mouse select change, deselect all if click outside any hit */ deselect_all_selected(C); diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 3cab26eab44..876fa7c9874 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -31,6 +31,7 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" #include "BLI_hash.h" +#include "BLI_lasso_2d.h" #include "BLI_math.h" #include "BLI_rand.h" #include "BLI_utildefines.h" @@ -1871,19 +1872,18 @@ void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata) if (gset->paintcursor && !enable) { /* clear cursor */ - WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor); + WM_paint_cursor_end(gset->paintcursor); gset->paintcursor = NULL; } else if (enable) { /* in some situations cursor could be duplicated, so it is better disable first if exist */ if (gset->paintcursor) { /* clear cursor */ - WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor); + WM_paint_cursor_end(gset->paintcursor); gset->paintcursor = NULL; } /* enable cursor */ - gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, + gset->paintcursor = WM_paint_cursor_activate(SPACE_TYPE_ANY, RGN_TYPE_ANY, gp_brush_cursor_poll, gp_brush_cursor_draw, @@ -2800,3 +2800,49 @@ bool ED_gpencil_stroke_check_collision(GP_SpaceConversion *gsc, /* Check collision between both rectangles. */ return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL); } + +/** + * Check if a point is inside of the stroke + * \param gps: Stroke to check + * \param gsc: SpaceConversion data + * \param mouse: Mouse position + * \param diff_mat: View matrix + * \return True if the point is inside + */ +bool ED_gpencil_stroke_point_is_inside(bGPDstroke *gps, + GP_SpaceConversion *gsc, + int mouse[2], + const float diff_mat[4][4]) +{ + bool hit = false; + if (gps->totpoints == 0) { + return hit; + } + + int(*mcoords)[2] = NULL; + int len = gps->totpoints; + mcoords = MEM_mallocN(sizeof(int) * 2 * len, __func__); + + /* Convert stroke to 2D array of points. */ + bGPDspoint *pt; + int i; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + bGPDspoint pt2; + gp_point_to_parent_space(pt, diff_mat, &pt2); + gp_point_to_xy(gsc, gps, &pt2, &mcoords[i][0], &mcoords[i][1]); + } + + /* Compute boundbox of lasso (for faster testing later). */ + rcti rect; + BLI_lasso_boundbox(&rect, mcoords, len); + + /* Test if point inside stroke. */ + hit = ((!ELEM(V2D_IS_CLIPPED, mouse[0], mouse[1])) && + BLI_rcti_isect_pt(&rect, mouse[0], mouse[1]) && + BLI_lasso_is_point_inside(mcoords, len, mouse[0], mouse[1], INT_MAX)); + + /* Free memory. */ + MEM_SAFE_FREE(mcoords); + + return hit; +} diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c index 2238d768bcd..0dfc7e0728e 100644 --- a/source/blender/editors/gpencil/gpencil_uv.c +++ b/source/blender/editors/gpencil/gpencil_uv.c @@ -59,8 +59,8 @@ typedef struct GpUvData { float ob_scale; float initial_length; + float initial_transform[2]; float pixel_size; /* use when mouse input is interpreted as spatial distance */ - bool is_modal; /* Arrays of original loc/rot/scale by stroke. */ float (*array_loc)[2]; @@ -140,19 +140,12 @@ static void gpencil_stroke_center(bGPDstroke *gps, float r_center[3]) } } -static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is_modal) +static bool gpencil_uv_transform_init(bContext *C, wmOperator *op) { GpUvData *opdata; - if (is_modal) { - float zero[2] = {0.0f}; - RNA_float_set_array(op->ptr, "location", zero); - RNA_float_set(op->ptr, "rotation", 0.0f); - RNA_float_set(op->ptr, "scale", 1.0f); - } op->customdata = opdata = MEM_mallocN(sizeof(GpUvData), __func__); - opdata->is_modal = is_modal; opdata->ob = CTX_data_active_object(C); opdata->gpd = (bGPdata *)opdata->ob->data; gp_point_conversion_init(C, &opdata->gsc); @@ -164,12 +157,10 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is opdata->vinit_rotation[0] = 1.0f; opdata->vinit_rotation[1] = 0.0f; - if (is_modal) { - ARegion *region = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); - opdata->draw_handle_pixel = ED_region_draw_cb_activate( - region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); - } + opdata->draw_handle_pixel = ED_region_draw_cb_activate( + region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); /* Calc selected strokes center. */ zero_v2(opdata->mcenter); @@ -205,7 +196,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is } GP_EDITABLE_STROKES_END(gpstroke_iter); } - /* convert to 2D */ + /* Convert to 2D. */ gp_point_3d_to_xy(&opdata->gsc, GP_STROKE_3DSPACE, center, opdata->mcenter); return true; @@ -218,11 +209,9 @@ static void gpencil_uv_transform_exit(bContext *C, wmOperator *op) opdata = op->customdata; - if (opdata->is_modal) { - ARegion *region = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); - ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel); - } + ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel); WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT); @@ -253,66 +242,54 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) const int mode = RNA_enum_get(op->ptr, "mode"); GpUvData *opdata = op->customdata; bGPdata *gpd = opdata->gpd; + bool changed = false; /* Get actual vector. */ float vr[2]; + float mdiff[2]; + sub_v2_v2v2(vr, opdata->mouse, opdata->mcenter); normalize_v2(vr); - float location[2]; - RNA_float_get_array(op->ptr, "location", location); - - float uv_rotation = (opdata->is_modal) ? angle_signed_v2v2(opdata->vinit_rotation, vr) : - RNA_float_get(op->ptr, "rotation"); - uv_rotation *= SMOOTH_FACTOR; - - if (opdata->is_modal) { - RNA_float_set(op->ptr, "rotation", uv_rotation); - } + float uv_rotation = angle_signed_v2v2(opdata->vinit_rotation, vr); int i = 0; - /* Apply transformations to all strokes. */ - if ((mode == GP_UV_TRANSLATE) || (!opdata->is_modal)) { - float mdiff[2]; - mdiff[0] = opdata->mcenter[0] - opdata->mouse[0]; - mdiff[1] = opdata->mcenter[1] - opdata->mouse[1]; + /* Translate. */ + if (mode == GP_UV_TRANSLATE) { + + mdiff[0] = opdata->mouse[0] - opdata->initial_transform[0]; + /* Y axis is inverted. */ + mdiff[1] = (opdata->mouse[1] - opdata->initial_transform[1]) * -1.0f; /* Apply a big amount of smooth always for translate to get smooth result. */ - mul_v2_fl(mdiff, 0.006f); + mul_v2_fl(mdiff, 0.002f); + RNA_float_set_array(op->ptr, "location", mdiff); - /* Apply angle in translation. */ - mdiff[0] *= cos(uv_rotation); - mdiff[1] *= sin(uv_rotation); - if (opdata->is_modal) { - RNA_float_set_array(op->ptr, "location", mdiff); - } + GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { + if (gps->flag & GP_STROKE_SELECT) { - changed = (bool)((mdiff[0] != 0.0f) || (mdiff[1] != 0.0f)); - if (changed) { - GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { - if (gps->flag & GP_STROKE_SELECT) { - if (opdata->is_modal) { - add_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff); - } - else { - copy_v2_v2(gps->uv_translation, location); - } - /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gps); - i++; - } + sub_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff); + changed = true; + + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); + i++; } - GP_EDITABLE_STROKES_END(gpstroke_iter); } + GP_EDITABLE_STROKES_END(gpstroke_iter); } - if ((mode == GP_UV_ROTATE) || (!opdata->is_modal)) { - changed = (bool)(uv_rotation != 0.0f); + /* Rotate. */ + if (mode == GP_UV_ROTATE) { + changed |= (bool)(uv_rotation != 0.0f); + RNA_float_set(op->ptr, "rotation", uv_rotation); + if (changed) { GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { if (gps->flag & GP_STROKE_SELECT) { - gps->uv_rotation = (opdata->is_modal) ? opdata->array_rot[i] + uv_rotation : uv_rotation; + gps->uv_rotation = opdata->array_rot[i] - uv_rotation; + /* Calc geometry data. */ BKE_gpencil_stroke_geometry_update(gps); i++; @@ -322,25 +299,22 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) } } - if ((mode == GP_UV_SCALE) || (!opdata->is_modal)) { - float mdiff[2]; + /* Scale. */ + if (mode == GP_UV_SCALE) { mdiff[0] = opdata->mcenter[0] - opdata->mouse[0]; mdiff[1] = opdata->mcenter[1] - opdata->mouse[1]; - float scale = (opdata->is_modal) ? - ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) / - opdata->ob_scale : - RNA_float_get(op->ptr, "scale"); + float scale = ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) / + opdata->ob_scale; + scale *= SMOOTH_FACTOR; + RNA_float_set(op->ptr, "scale", scale); - if (opdata->is_modal) { - RNA_float_set(op->ptr, "scale", scale); - } + changed |= (bool)(scale != 0.0f); - changed = (bool)(scale != 0.0f); if (changed) { GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { if (gps->flag & GP_STROKE_SELECT) { - gps->uv_scale = (opdata->is_modal) ? opdata->array_scale[i] + scale : scale; + gps->uv_scale = opdata->array_scale[i] + scale; /* Calc geometry data. */ BKE_gpencil_stroke_geometry_update(gps); i++; @@ -350,7 +324,7 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) } } - if ((!opdata->is_modal) || (changed)) { + if (changed) { /* Update cursor line. */ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, NULL); @@ -360,21 +334,6 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) return changed; } -static int gpencil_transform_fill_exec(bContext *C, wmOperator *op) -{ - if (!gpencil_uv_transform_init(C, op, false)) { - return OPERATOR_CANCELLED; - } - - if (!gpencil_uv_transform_calc(C, op)) { - gpencil_uv_transform_exit(C, op); - return OPERATOR_CANCELLED; - } - - gpencil_uv_transform_exit(C, op); - return OPERATOR_FINISHED; -} - static bool gpencil_transform_fill_poll(bContext *C) { if (!ED_operator_view3d_active(C)) { @@ -404,7 +363,7 @@ static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEv float mlen[2]; float center_3d[3]; - if (!gpencil_uv_transform_init(C, op, true)) { + if (!gpencil_uv_transform_init(C, op)) { return OPERATOR_CANCELLED; } @@ -414,16 +373,22 @@ static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEv opdata->mouse[1] = event->mval[1]; copy_v3_v3(center_3d, opdata->ob->loc); - mlen[0] = opdata->mcenter[0] - event->mval[0]; - mlen[1] = opdata->mcenter[1] - event->mval[1]; + mlen[0] = event->mval[0] - opdata->mcenter[0]; + mlen[1] = event->mval[1] - opdata->mcenter[1]; opdata->initial_length = len_v2(mlen); - opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; + /* Consider initial offset as zero position. */ + copy_v2fl_v2i(opdata->initial_transform, event->mval); + + /* Consider initial position as the orientation vector. */ + const int mode = RNA_enum_get(op->ptr, "mode"); + if (mode == GP_UV_ROTATE) { + opdata->vinit_rotation[0] = mlen[0]; + opdata->vinit_rotation[1] = mlen[1]; + normalize_v2(opdata->vinit_rotation); + } - /* Calc init rotation vector. */ - float mouse[2] = {event->mval[0], event->mval[1]}; - sub_v2_v2v2(opdata->vinit_rotation, mouse, opdata->mcenter); - normalize_v2(opdata->vinit_rotation); + opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; gpencil_uv_transform_calc(C, op); @@ -492,7 +457,6 @@ void GPENCIL_OT_transform_fill(wmOperatorType *ot) /* api callbacks */ ot->invoke = gpencil_transform_fill_invoke; ot->modal = gpencil_transform_fill_modal; - ot->exec = gpencil_transform_fill_exec; ot->cancel = gpencil_transform_fill_cancel; ot->poll = gpencil_transform_fill_poll; diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index 10867bd1e0d..581a5d977c2 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -36,6 +36,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_gpencil.h" +#include "BKE_material.h" #include "BKE_report.h" #include "WM_api.h" @@ -433,10 +434,9 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso, CLAMP(inf, 0.0f, 1.0f); CLAMP(inf_fill, 0.0f, 1.0f); - bGPDspoint *pt = &gps->points[pt_index]; - /* Apply color to Stroke point. */ - if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) { + if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush) && (pt_index > -1)) { + bGPDspoint *pt = &gps->points[pt_index]; if (brush_invert_check(gso)) { pt->vert_color[3] -= inf; CLAMP_MIN(pt->vert_color[3], 0.0f); @@ -813,15 +813,18 @@ static void gp_save_selected_point(tGP_BrushVertexpaintData *gso, selected = &gso->pbuffer[gso->pbuffer_used]; selected->gps = gps; selected->pt_index = index; - copy_v2_v2_int(selected->pc, pc); - copy_v4_v4(selected->color, pt->vert_color); - + /* Check the index is not a special case for fill. */ + if (index > -1) { + copy_v2_v2_int(selected->pc, pc); + copy_v4_v4(selected->color, pt->vert_color); + } gso->pbuffer_used++; } /* Select points in this stroke and add to an array to be used later. */ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, + const char tool, const float diff_mat[4][4]) { GP_SpaceConversion *gsc = &gso->gsc; @@ -869,6 +872,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, /* Loop over the points in the stroke, checking for intersections * - an intersection means that we touched the stroke */ + bool hit = false; for (i = 0; (i + 1) < gps->totpoints; i++) { /* Get points to work with */ pt1 = gps->points + i; @@ -904,6 +908,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { + hit = true; gp_save_selected_point(gso, gps_active, index, pc1); } @@ -920,6 +925,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1; if (pt_active != NULL) { + hit = true; gp_save_selected_point(gso, gps_active, index, pc2); include_last = false; } @@ -938,6 +944,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { + hit = true; gp_save_selected_point(gso, gps_active, index, pc1); include_last = false; @@ -945,6 +952,24 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, } } } + + /* If nothing hit, check if the mouse is inside any filled stroke. */ + if ((!hit) && (ELEM(tool, GPAINT_TOOL_TINT, GPVERTEX_TOOL_DRAW))) { + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(gso->object, + gps_active->mat_nr + 1); + if (gp_style->flag & GP_MATERIAL_FILL_SHOW) { + int mval[2]; + round_v2i_v2fl(mval, gso->mval); + bool hit_fill = ED_gpencil_stroke_point_is_inside(gps_active, gsc, mval, diff_mat); + if (hit_fill) { + /* Need repeat the effect because if we don't do that the tint process + * is very slow. */ + for (int repeat = 0; repeat < 50; repeat++) { + gp_save_selected_point(gso, gps_active, -1, NULL); + } + } + } + } } } @@ -956,8 +981,8 @@ static bool gp_vertexpaint_brush_do_frame(bContext *C, const float diff_mat[4][4]) { Object *ob = CTX_data_active_object(C); - char tool = ob->mode == OB_MODE_VERTEX_GPENCIL ? gso->brush->gpencil_vertex_tool : - gso->brush->gpencil_tool; + const char tool = ob->mode == OB_MODE_VERTEX_GPENCIL ? gso->brush->gpencil_vertex_tool : + gso->brush->gpencil_tool; const int radius = (gso->brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : gso->brush->size; @@ -980,7 +1005,7 @@ static bool gp_vertexpaint_brush_do_frame(bContext *C, } /* Check points below the brush. */ - gp_vertexpaint_select_stroke(gso, gps, diff_mat); + gp_vertexpaint_select_stroke(gso, gps, tool, diff_mat); } /* For Average tool, need calculate the average resulting color from all colors diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 7d38792f332..426a470b128 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -652,9 +652,6 @@ enum eAnimEditDraw_CurrentFrame { /* main call to draw current-frame indicator in an Animation Editor */ void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag); -/* main call to draw "number box" in scrollbar for current frame indicator */ -void ANIM_draw_cfra_number(const struct bContext *C, struct View2D *v2d, short flag); - /* ------------- Preview Range Drawing -------------- */ /* main call to draw preview range curtains */ diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 102c0dc0659..ac9eb415b23 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -120,13 +120,11 @@ typedef struct EditBone { } temp; } EditBone; -#define BONESEL_ROOT (1 << 28) -#define BONESEL_TIP (1 << 29) -#define BONESEL_BONE (1 << 30) +#define BONESEL_ROOT (2 << 29u) +#define BONESEL_TIP (1 << 30u) +#define BONESEL_BONE (1 << 31u) #define BONESEL_ANY (BONESEL_TIP | BONESEL_ROOT | BONESEL_BONE) -#define BONESEL_NOSEL (1u << 31u) - /* useful macros */ #define EBONE_VISIBLE(arm, ebone) \ (CHECK_TYPE_INLINE(arm, bArmature *), \ diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h index 07eade23506..a1a5d65b61d 100644 --- a/source/blender/editors/include/ED_gizmo_library.h +++ b/source/blender/editors/include/ED_gizmo_library.h @@ -40,9 +40,15 @@ void ED_gizmotypes_facemap_3d(void); void ED_gizmotypes_preselect_3d(void); void ED_gizmotypes_primitive_3d(void); void ED_gizmotypes_blank_3d(void); +void ED_gizmotypes_snap_3d(void); -struct Object; +struct ARegion; struct bContext; +struct Depsgraph; +struct Object; +struct SnapObjectContext; +struct wmWindowManager; +struct View3D; struct wmGizmo; /* -------------------------------------------------------------------- */ @@ -223,8 +229,9 @@ enum { }; /* -------------------------------------------------------------------- */ -/* Gizmo Drawing Functions */ +/* Specific gizmos utils */ +/* dial3d_gizmo.c */ struct Dial3dParams { int draw_options; float angle_ofs; @@ -241,6 +248,33 @@ void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4], const bool select, struct Dial3dParams *params); +/* snap3d_gizmo.c */ +#define USE_SNAP_DETECT_FROM_KEYMAP_HACK +void ED_gizmotypes_snap_3d_draw_util(struct RegionView3D *rv3d, + const float loc_prev[3], + const float loc_curr[3], + const float normal[3], + const uchar color_line[4], + const uchar color_point[4], + const short snap_elem_type); +struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene, + const struct ARegion *region, + const struct View3D *v3d, + struct wmGizmo *gz); + +bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz); +void ED_gizmotypes_snap_3d_toggle_set(struct wmGizmo *gz, bool enable); +void ED_gizmotypes_snap_3d_toggle_clear(struct wmGizmo *gz); + +short ED_gizmotypes_snap_3d_update(struct wmGizmo *gz, + struct Depsgraph *depsgraph, + const struct ARegion *region, + const struct View3D *v3d, + const struct wmWindowManager *wm, + const float mval_fl[2], + float r_loc[3], + float r_nor[3]); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 2dbd979564e..0c228fc962b 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -34,13 +34,13 @@ struct PointerRNA; struct Brush; struct GP_SpaceConversion; +struct GpRandomSettings; struct bGPDframe; struct bGPDlayer; struct bGPDspoint; struct bGPDstroke; struct bGPdata; struct tGPspoint; -struct GpRandomSettings; struct ARegion; struct Depsgraph; @@ -317,6 +317,10 @@ bool ED_gpencil_stroke_check_collision(struct GP_SpaceConversion *gsc, float mouse[2], const int radius, const float diff_mat[4][4]); +bool ED_gpencil_stroke_point_is_inside(struct bGPDstroke *gps, + struct GP_SpaceConversion *gsc, + int mouse[2], + const float diff_mat[4][4]); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 1dc98cfee2f..3471f9dcce9 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -107,7 +107,10 @@ void ED_node_texture_default(const struct bContext *C, struct Tex *tex); bool ED_node_select_check(ListBase *lb); void ED_node_select_all(ListBase *lb, int action); void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree); -void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node); +void ED_node_set_active(struct Main *bmain, + struct bNodeTree *ntree, + struct bNode *node, + bool *r_active_texture_changed); void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 146dd3eb8b8..f25f8225976 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -212,13 +212,11 @@ bool ED_object_editmode_load(struct Main *bmain, struct Object *obedit); void ED_object_vpaintmode_enter_ex(struct Main *bmain, struct Depsgraph *depsgraph, - struct wmWindowManager *wm, struct Scene *scene, struct Object *ob); void ED_object_vpaintmode_enter(struct bContext *C, struct Depsgraph *depsgraph); void ED_object_wpaintmode_enter_ex(struct Main *bmain, struct Depsgraph *depsgraph, - struct wmWindowManager *wm, struct Scene *scene, struct Object *ob); void ED_object_wpaintmode_enter(struct bContext *C, struct Depsgraph *depsgraph); @@ -228,6 +226,20 @@ void ED_object_vpaintmode_exit(struct bContext *C); void ED_object_wpaintmode_exit_ex(struct Object *ob); void ED_object_wpaintmode_exit(struct bContext *C); +void ED_object_texture_paint_mode_enter_ex(struct Main *bmain, struct Scene *scene, Object *ob); +void ED_object_texture_paint_mode_enter(struct bContext *C); + +void ED_object_texture_paint_mode_exit_ex(struct Main *bmain, struct Scene *scene, Object *ob); +void ED_object_texture_paint_mode_exit(struct bContext *C); + +void ED_object_particle_edit_mode_enter_ex(struct Depsgraph *depsgraph, + struct Scene *scene, + Object *ob); +void ED_object_particle_edit_mode_enter(struct bContext *C); + +void ED_object_particle_edit_mode_exit_ex(struct Scene *scene, Object *ob); +void ED_object_particle_edit_mode_exit(struct bContext *C); + void ED_object_sculptmode_enter_ex(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, @@ -269,6 +281,7 @@ bool ED_object_add_generic_get_opts(struct bContext *C, const char view_align_axis, float loc[3], float rot[3], + float scale[3], bool *enter_editmode, unsigned short *local_view_bits, bool *is_view_aligned); @@ -303,15 +316,15 @@ void ED_objects_recalculate_paths(struct bContext *C, eObjectPathCalcRange range); /* constraints */ -struct ListBase *get_active_constraints(struct Object *ob); -struct ListBase *get_constraint_lb(struct Object *ob, - struct bConstraint *con, - struct bPoseChannel **r_pchan); -struct bConstraint *get_active_constraint(struct Object *ob); +struct ListBase *ED_object_constraint_list_from_context(struct Object *ob); +struct ListBase *ED_object_constraint_list_from_constraint(struct Object *ob, + struct bConstraint *con, + struct bPoseChannel **r_pchan); +struct bConstraint *ED_object_constraint_active_get(struct Object *ob); void object_test_constraints(struct Main *bmain, struct Object *ob); -void ED_object_constraint_set_active(struct Object *ob, struct bConstraint *con); +void ED_object_constraint_active_set(struct Object *ob, struct bConstraint *con); void ED_object_constraint_update(struct Main *bmain, struct Object *ob); void ED_object_constraint_dependency_update(struct Main *bmain, struct Object *ob); @@ -328,11 +341,12 @@ bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, eObjectMode mode, struct ReportList *reports); -void ED_object_mode_toggle(struct bContext *C, eObjectMode mode); -void ED_object_mode_set(struct bContext *C, eObjectMode mode); -void ED_object_mode_exit(struct bContext *C, struct Depsgraph *depsgraph); +bool ED_object_mode_set_ex(struct bContext *C, + eObjectMode mode, + bool use_undo, + struct ReportList *reports); +bool ED_object_mode_set(struct bContext *C, eObjectMode mode); -bool ED_object_mode_generic_enter(struct bContext *C, eObjectMode object_mode); void ED_object_mode_generic_exit(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h index d3fc5174dd9..0325ad9fdba 100644 --- a/source/blender/editors/include/ED_outliner.h +++ b/source/blender/editors/include/ED_outliner.h @@ -29,6 +29,7 @@ extern "C" { struct Base; struct ListBase; +struct SpaceOutliner; struct bContext; bool ED_outliner_collections_editor_poll(struct bContext *C); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 9969acd04b7..a62deb9d69f 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -162,6 +162,19 @@ int BIF_countTransformOrientation(const struct bContext *C); void Transform_Properties(struct wmOperatorType *ot, int flags); +/* *** transform_orientations.c *** */ +void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat[3][3]); +short ED_transform_calc_orientation_from_type_ex(const struct bContext *C, + float r_mat[3][3], + /* extra args */ + struct Scene *scene, + struct RegionView3D *rv3d, + struct Object *ob, + struct Object *obedit, + const short orientation_type, + int orientation_index_custom, + const int pivot_point); + /* transform gizmos */ void VIEW3D_GGT_xform_gizmo(struct wmGizmoGroupType *gzgt); @@ -180,18 +193,6 @@ void ED_widgetgroup_gizmo2d_rotate_callbacks_set(struct wmGizmoGroupType *gzgt); #define SNAP_INCREMENTAL_ANGLE DEG2RAD(5.0) -void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat[3][3]); -void ED_transform_calc_orientation_from_type_ex(const struct bContext *C, - float r_mat[3][3], - /* extra args */ - struct Scene *scene, - struct RegionView3D *rv3d, - struct Object *ob, - struct Object *obedit, - const short orientation_type, - int orientation_index_custom, - const int pivot_point); - struct TransformBounds { float center[3]; /* Center for transform widget. */ float min[3], max[3]; /* Boundbox of selection for transform widget. */ diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index b998ac87819..8feb73436a6 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -77,11 +77,8 @@ struct SnapObjectParams { }; typedef struct SnapObjectContext SnapObjectContext; -SnapObjectContext *ED_transform_snap_object_context_create(struct Main *bmain, - struct Scene *scene, - int flag); -SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Main *bmain, - struct Scene *scene, +SnapObjectContext *ED_transform_snap_object_context_create(struct Scene *scene, int flag); +SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Scene *scene, int flag, /* extra args for view3d */ const struct ARegion *region, diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 8c565536c71..f656aaf9c07 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -50,20 +50,17 @@ void ED_operatortypes_uvedit(void); void ED_keymap_uvedit(struct wmKeyConfig *keyconf); bool ED_uvedit_minmax(const struct Scene *scene, - struct Image *ima, struct Object *obedit, float min[2], float max[2]); void ED_uvedit_select_all(struct BMesh *bm); bool ED_uvedit_minmax_multi(const struct Scene *scene, - struct Image *ima, struct Object **objects_edit, uint objects_len, float r_min[2], float r_max[2]); bool ED_uvedit_center_multi(const struct Scene *scene, - Image *ima, struct Object **objects_edit, uint objects_len, float r_cent[2], @@ -95,11 +92,7 @@ void ED_object_assign_active_image(struct Main *bmain, bool ED_uvedit_test(struct Object *obedit); /* visibility and selection */ -bool uvedit_face_visible_nolocal_ex(const struct ToolSettings *ts, struct BMFace *efa); -bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, - struct Object *obedit, - struct Image *ima, - struct BMFace *efa); +bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, struct BMFace *efa); bool uvedit_face_select_test_ex(const struct ToolSettings *ts, struct BMFace *efa, const int cd_loop_uv_offset); @@ -110,11 +103,7 @@ bool uvedit_uv_select_test_ex(const struct ToolSettings *ts, struct BMLoop *l, const int cd_loop_uv_offset); -bool uvedit_face_visible_nolocal(const struct Scene *scene, struct BMFace *efa); -bool uvedit_face_visible_test(const struct Scene *scene, - struct Object *obedit, - struct Image *ima, - struct BMFace *efa); +bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa); bool uvedit_face_select_test(const struct Scene *scene, struct BMFace *efa, const int cd_loop_uv_offset); @@ -175,12 +164,10 @@ void uvedit_uv_select_disable(struct BMEditMesh *em, bool ED_uvedit_nearest_uv(const struct Scene *scene, struct Object *obedit, - struct Image *ima, const float co[2], float *dist_sq, float r_uv[2]); bool ED_uvedit_nearest_uv_multi(const struct Scene *scene, - struct Image *ima, struct Object **objects, const uint objects_len, const float co[2], diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 668ca3c6437..beca517f0a6 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -129,6 +129,9 @@ enum eV3DCursorOrient { void ED_view3d_background_color_get(const struct Scene *scene, const struct View3D *v3d, float r_color[3]); +bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene, + const struct Object *ob, + const struct View3D *v3d); void ED_view3d_cursor3d_position(struct bContext *C, const int mval[2], const bool use_depth, @@ -246,6 +249,7 @@ void nurbs_foreachScreenVert(struct ViewContext *vc, struct BPoint *bp, struct BezTriple *bezt, int beztindex, + bool handle_visible, const float screen_co[2]), void *userData, const eV3DProjTest clip_flag); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index cb4325d7851..09cde4df8a8 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1938,7 +1938,7 @@ uiLayout *uiLayoutRadial(uiLayout *layout); /* templates */ void uiTemplateHeader(uiLayout *layout, struct bContext *C); void uiTemplateID(uiLayout *layout, - struct bContext *C, + const struct bContext *C, struct PointerRNA *ptr, const char *propname, const char *newop, @@ -2113,7 +2113,7 @@ void uiTemplateComponentMenu(uiLayout *layout, const char *name); void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color); void uiTemplateCacheFile(uiLayout *layout, - struct bContext *C, + const struct bContext *C, struct PointerRNA *ptr, const char *propname); @@ -2146,7 +2146,7 @@ void uiTemplateNodeView(uiLayout *layout, struct bNodeSocket *input); void uiTemplateTextureUser(uiLayout *layout, struct bContext *C); void uiTemplateTextureShow(uiLayout *layout, - struct bContext *C, + const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop); diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index c2c27af9770..e4fb0631f06 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -68,9 +68,9 @@ set(SRC interface_region_tooltip.c interface_regions.c interface_style.c - interface_templates.c interface_template_search_menu.c interface_template_search_operator.c + interface_templates.c interface_undo.c interface_utils.c interface_widgets.c diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c index 6529bf8fc5d..32cae609395 100644 --- a/source/blender/editors/interface/interface_align.c +++ b/source/blender/editors/interface/interface_align.c @@ -124,7 +124,11 @@ bool ui_but_can_align(const uiBut *but) int ui_but_align_opposite_to_area_align_get(const ARegion *region) { - switch (RGN_ALIGN_ENUM_FROM_MASK(region->alignment)) { + const ARegion *align_region = (region->alignment & RGN_SPLIT_PREV && region->prev) ? + region->prev : + region; + + switch (RGN_ALIGN_ENUM_FROM_MASK(align_region->alignment)) { case RGN_ALIGN_TOP: return UI_BUT_ALIGN_DOWN; case RGN_ALIGN_BOTTOM: diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 8c9768f523d..5bf2147aff5 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -61,7 +61,7 @@ static FCurve *ui_but_get_fcurve( * but works well enough in typical cases */ int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex; - return rna_get_fcurve_context_ui( + return BKE_fcurve_find_by_rna_context_ui( but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special); } diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index ace367fd513..c917ffb3f3e 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -138,11 +138,26 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) { /* we could use some clever */ Main *bmain = CTX_data_main(C); - bScreen *screen = CTX_wm_screen(C); - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); + wmWindowManager *wm = CTX_wm_manager(C); const char *display_device = CTX_data_scene(C)->display_settings.display_device; struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); + wmWindow *win = CTX_wm_window(C); + bScreen *screen = CTX_wm_screen(C); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); + if (area == NULL) { + int mval[2] = {mx, my}; + if (WM_window_find_under_cursor(wm, NULL, win, mval, &win, mval)) { + mx = mval[0]; + my = mval[1]; + screen = WM_window_get_active_screen(win); + area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); + } + else { + win = NULL; + } + } + if (area) { if (area->spacetype == SPACE_IMAGE) { ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my); @@ -179,12 +194,15 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) } } - /* fallback to simple opengl picker */ - glReadBuffer(GL_FRONT); - glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col); - glReadBuffer(GL_BACK); - - IMB_colormanagement_display_to_scene_linear_v3(r_col, display); + if (win) { + /* Fallback to simple opengl picker. */ + int mval[2] = {mx, my}; + WM_window_pixel_sample_read(wm, win, mval, r_col); + IMB_colormanagement_display_to_scene_linear_v3(r_col, display); + } + else { + zero_v3(r_col); + } } /* sets the sample color RGB, maintaining A */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 6db21ea93a5..eb99d044e17 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -5559,7 +5559,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co } else if (but->type == UI_BTYPE_MENU) { if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) { - const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1; + const int direction = (event->type == WHEELDOWNMOUSE) ? 1 : -1; data->value = ui_but_menu_step(but, direction); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index c94a95890c0..deea3028354 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1603,8 +1603,8 @@ static void icon_draw_cache_texture_flush_ex(GLuint texture, GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR); GPU_shader_bind(shader); - int img_loc = GPU_shader_get_uniform_ensure(shader, "image"); - int data_loc = GPU_shader_get_uniform_ensure(shader, "calls_data[0]"); + int img_loc = GPU_shader_get_uniform(shader, "image"); + int data_loc = GPU_shader_get_uniform(shader, "calls_data"); glUniform1i(img_loc, 0); glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache); @@ -1750,9 +1750,9 @@ static void icon_draw_texture(float x, GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), alpha, alpha, alpha, alpha); } - glUniform1i(GPU_shader_get_uniform_ensure(shader, "image"), 0); - glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_icon"), x1, y1, x2, y2); - glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_geom"), x, y, x + w, y + h); + glUniform1i(GPU_shader_get_uniform(shader, "image"), 0); + glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), x1, y1, x2, y2); + glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), x, y, x + w, y + h); GPU_draw_primitive(GPU_PRIM_TRI_STRIP, 4); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index e0a202e0bd9..33f600f30a1 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -107,6 +107,7 @@ typedef struct uiHandlePanelData { int startx, starty; int startofsx, startofsy; int startsizex, startsizey; + float start_cur_xmin, start_cur_ymin; } uiHandlePanelData; typedef struct PanelSort { @@ -373,8 +374,8 @@ void UI_panels_free_instanced(bContext *C, ARegion *region) * don't match in any way. * * \param data: The list of data to check against the instanced panels. - * \param panel_type_func: Function to find the panel type idname for each item in the data list. - * For a readabilty and generality, this lookup happens separately for each type of panel list. + * \param panel_idname_func: Function to find the panel type idname for each item in the data list. + * For a readability and generality, this lookup happens separately for each type of panel list. */ bool UI_panel_list_matches_data(ARegion *region, ListBase *data, @@ -997,7 +998,7 @@ void ui_draw_aligned_panel(uiStyle *style, rcti box_rect = {rect->xmin, rect->xmax, (is_closed_x || is_closed_y) ? headrect.ymin : rect->ymin, - headrect.ymax}; + headrect.ymax + U.pixelsize}; ui_draw_box_opaque(&box_rect, UI_CNR_ALL); /* Mimick the border between aligned box widgets for the bottom of the header. */ @@ -1143,8 +1144,8 @@ void ui_draw_aligned_panel(uiStyle *style, immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); GPU_blend(true); - /* Draw panel backdrop if it wasn't aleady been drawn by the single opauque round box earlier. - * Note: Subpanels blend with panels, so they can't be opaque. */ + /* Draw panel backdrop if it wasn't already been drawn by the single opaque round box earlier. + * Note: Sub-panels blend with panels, so they can't be opaque. */ if (show_background && !(draw_box_style && !is_subpanel)) { /* Draw the bottom subpanels . */ if (draw_box_style) { @@ -1448,7 +1449,7 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co ps->panel->ofsx = 0; ps->panel->ofsy = -get_panel_size_y(ps->panel); ps->panel->ofsx += ps->panel->runtime.region_ofsx; - /* Extra margin if the panel happens to be a instanced panel. */ + /* Extra margin if the panel is a box style panel. */ if (ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX) { ps->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN; ps->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN; @@ -1731,21 +1732,22 @@ static void check_panel_overlap(ARegion *region, Panel *panel) /************************ panel dragging ****************************/ +#define DRAG_REGION_PAD (PNL_HEADER * 0.5) static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel) { uiHandlePanelData *data = panel->activedata; ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); - short align = panel_aligned(area, region), dx = 0, dy = 0; + short align = panel_aligned(area, region); - /* first clip for window, no dragging outside */ - if (!BLI_rcti_isect_pt_v(®ion->winrct, &event->x)) { - return; - } + /* Keep the drag position in the region with a small pad to keep the panel visible. */ + int x = clamp_i(event->x, region->winrct.xmin, region->winrct.xmax + DRAG_REGION_PAD); + int y = clamp_i(event->y, region->winrct.ymin, region->winrct.ymax + DRAG_REGION_PAD); - dx = (event->x - data->startx); - dy = (event->y - data->starty); + float dx = (float)(x - data->startx); + float dy = (float)(y - data->starty); + /* Adjust for region zoom. */ dx *= (float)BLI_rctf_size_x(®ion->v2d.cur) / (float)BLI_rcti_size_x(®ion->winrct); dy *= (float)BLI_rctf_size_y(®ion->v2d.cur) / (float)BLI_rcti_size_y(®ion->winrct); @@ -1763,17 +1765,21 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel) /* reset the panel snapping, to allow dragging away from snapped edges */ panel->snap = PNL_SNAP_NONE; - panel->ofsx = data->startofsx + dx; - panel->ofsy = data->startofsy + dy; + /* Add the movement of the view due to edge scrolling while dragging. */ + dx += ((float)region->v2d.cur.xmin - data->start_cur_xmin); + dy += ((float)region->v2d.cur.ymin - data->start_cur_ymin); + panel->ofsx = data->startofsx + round_fl_to_int(dx); + panel->ofsy = data->startofsy + round_fl_to_int(dy); check_panel_overlap(region, panel); if (align) { - uiAlignPanelStep(area, region, 0.2, true); + uiAlignPanelStep(area, region, 0.2f, true); } } ED_region_tag_redraw(region); } +#undef DRAG_REGION_PAD /******************* region level panel interaction *****************/ @@ -2967,6 +2973,12 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS data->animtimer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, ANIMATION_INTERVAL); } + /* Initiate edge panning during drags so we can move beyond the initial region view. */ + if (state == PANEL_STATE_DRAG) { + wmOperatorType *ot = WM_operatortype_find("VIEW2D_OT_edge_pan", true); + ui_handle_afterfunc_add_operator(ot, WM_OP_INVOKE_DEFAULT, true); + } + data->state = state; data->startx = win->eventstate->x; data->starty = win->eventstate->y; @@ -2974,6 +2986,8 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS data->startofsy = panel->ofsy; data->startsizex = panel->sizex; data->startsizey = panel->sizey; + data->start_cur_xmin = region->v2d.cur.xmin; + data->start_cur_ymin = region->v2d.cur.ymin; data->starttime = PIL_check_seconds_timer(); /* Remember drag drop state even when animating to the aligned position after dragging. */ diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c index 34ac58c1dca..1f8af7b9e6e 100644 --- a/source/blender/editors/interface/interface_region_hud.c +++ b/source/blender/editors/interface/interface_region_hud.c @@ -177,11 +177,13 @@ static void hud_region_layout(const bContext *C, ARegion *region) return; } + ScrArea *area = CTX_wm_area(C); int size_y = region->sizey; ED_region_panels_layout(C, region); - if (region->panels.first && (region->sizey != size_y)) { + if (region->panels.first && + ((area->flag & AREA_FLAG_REGION_SIZE_UPDATE) || (region->sizey != size_y))) { int winx_new = UI_DPI_FAC * (region->sizex + 0.5f); int winy_new = UI_DPI_FAC * (region->sizey + 0.5f); View2D *v2d = ®ion->v2d; @@ -339,6 +341,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *area) } else { if (region->flag & RGN_FLAG_HIDDEN) { + /* Also forces recalculating HUD size in hud_region_layout(). */ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE; } region->flag &= ~RGN_FLAG_HIDDEN; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 46a0fd43a7f..0661dce1869 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -799,7 +799,7 @@ static uiBut *template_id_def_new_but(uiBlock *block, return but; } -static void template_ID(bContext *C, +static void template_ID(const bContext *C, uiLayout *layout, TemplateID *template_ui, StructRNA *type, @@ -1140,7 +1140,7 @@ ID *UI_context_active_but_get_tab_ID(bContext *C) } } -static void template_ID_tabs(bContext *C, +static void template_ID_tabs(const bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, @@ -1150,7 +1150,7 @@ static void template_ID_tabs(bContext *C, { const ARegion *region = CTX_wm_region(C); const PointerRNA active_ptr = RNA_property_pointer_get(&template->ptr, template->prop); - MenuType *mt = WM_menutype_find(menu, false); + MenuType *mt = menu ? WM_menutype_find(menu, false) : NULL; const int but_align = ui_but_align_opposite_to_area_align_get(region); const int but_height = UI_UNIT_Y * 1.1; @@ -1214,12 +1214,14 @@ static void template_ID_tabs(bContext *C, } static void ui_template_id(uiLayout *layout, - bContext *C, + const bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, + /* Only respected by tabs (use_tabs). */ + const char *menu, const char *text, int flag, int prv_rows, @@ -1274,7 +1276,7 @@ static void ui_template_id(uiLayout *layout, if (template_ui->idlb) { if (use_tabs) { layout = uiLayoutRow(layout, true); - template_ID_tabs(C, layout, template_ui, type, flag, newop, unlinkop); + template_ID_tabs(C, layout, template_ui, type, flag, newop, menu); } else { layout = uiLayoutRow(layout, true); @@ -1296,7 +1298,7 @@ static void ui_template_id(uiLayout *layout, } void uiTemplateID(uiLayout *layout, - bContext *C, + const bContext *C, PointerRNA *ptr, const char *propname, const char *newop, @@ -1313,6 +1315,7 @@ void uiTemplateID(uiLayout *layout, newop, openop, unlinkop, + NULL, text, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, 0, @@ -1341,6 +1344,7 @@ void uiTemplateIDBrowse(uiLayout *layout, newop, openop, unlinkop, + NULL, text, UI_ID_BROWSE | UI_ID_RENAME, 0, @@ -1372,6 +1376,7 @@ void uiTemplateIDPreview(uiLayout *layout, openop, unlinkop, NULL, + NULL, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS, rows, cols, @@ -1399,6 +1404,7 @@ void uiTemplateGpencilColorPreview(uiLayout *layout, NULL, NULL, NULL, + NULL, UI_ID_BROWSE | UI_ID_PREVIEWS | UI_ID_DELETE, rows, cols, @@ -1417,7 +1423,7 @@ void uiTemplateIDTabs(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *newop, - const char *unlinkop, + const char *menu, int filter) { ui_template_id(layout, @@ -1426,7 +1432,8 @@ void uiTemplateIDTabs(uiLayout *layout, propname, newop, NULL, - unlinkop, + NULL, + menu, NULL, UI_ID_BROWSE | UI_ID_RENAME, 0, @@ -1824,7 +1831,15 @@ void uiTemplateModifiers(uiLayout *UNUSED(layout), bContext *C) { ScrArea *sa = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); - Object *ob = CTX_data_active_object(C); + + Object *ob; + SpaceProperties *sbuts = CTX_wm_space_properties(C); + if (sbuts != NULL && (sbuts->pinid != NULL) && GS(sbuts->pinid->name) == ID_OB) { + ob = (Object *)sbuts->pinid; + } + else { + ob = CTX_data_active_object(C); + } ListBase *modifiers = &ob->modifiers; bool panels_match = UI_panel_list_matches_data(region, modifiers, modifier_panel_id); @@ -2337,7 +2352,7 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C) static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v) { - ED_object_constraint_set_active(ob_v, con_v); + ED_object_constraint_active_set(ob_v, con_v); } static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con) @@ -7055,7 +7070,10 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color) /** \name Cache File Template * \{ */ -void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname) +void uiTemplateCacheFile(uiLayout *layout, + const bContext *C, + PointerRNA *ptr, + const char *propname) { if (!ptr->data) { return; diff --git a/source/blender/editors/interface/view2d_draw.c b/source/blender/editors/interface/view2d_draw.c index 36213f919a3..677043c1ccf 100644 --- a/source/blender/editors/interface/view2d_draw.c +++ b/source/blender/editors/interface/view2d_draw.c @@ -203,7 +203,7 @@ static void draw_parallel_lines(const ParallelLinesSet *lines, immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); immUniform2fv("viewportSize", &viewport[2]); - /* -1.0f offset here is because the line is too fat due to the builtin antialiasing. + /* -1.0f offset here is because the line is too fat due to the builtin anti-aliasing. * TODO make a variant or a uniform to toggle it off. */ immUniform1f("lineWidth", U.pixelsize - 1.0f); } diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 5b1e5f746ef..98bbd7af943 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -100,6 +100,10 @@ typedef struct v2dViewPanData { /** for MMB in scrollers (old feature in past, but now not that useful) */ short in_scroller; + + /* View2D Edge Panning */ + double edge_pan_last_time; + double edge_pan_start_time_x, edge_pan_start_time_y; } v2dViewPanData; /* initialize panning customdata */ @@ -357,6 +361,186 @@ static void VIEW2D_OT_pan(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name View Edge Pan Operator (modal) + * + * Scroll the region if the mouse is dragged to an edge. "Invisible" operator that always + * passes through. + * \{ */ + +/** Distance from the edge of the region within which to start panning. */ +#define EDGE_PAN_REGION_PAD (U.widget_unit) +/** Speed factor in pixels per second per pixel of distance from edge pan zone beginning. */ +#define EDGE_PAN_SPEED_PER_PIXEL (25.0f * (float)U.dpi_fac) +/** Delay before drag panning in seconds. */ +#define EDGE_PAN_DELAY 1.0f + +/* set up modal operator and relevant settings */ +static int view_edge_pan_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* Set up customdata. */ + if (!view_pan_init(C, op)) { + return OPERATOR_PASS_THROUGH; + } + + v2dViewPanData *vpd = op->customdata; + + vpd->edge_pan_start_time_x = 0.0; + vpd->edge_pan_start_time_y = 0.0; + vpd->edge_pan_last_time = PIL_check_seconds_timer(); + + WM_event_add_modal_handler(C, op); + + return (OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH); +} + +/** + * Reset the edge pan timers if the mouse isn't in the scroll zone and + * start the timers when the mouse enters a scroll zone. + */ +static void edge_pan_manage_delay_timers(v2dViewPanData *vpd, + int pan_dir_x, + int pan_dir_y, + const double current_time) +{ + if (pan_dir_x == 0) { + vpd->edge_pan_start_time_x = 0.0; + } + else if (vpd->edge_pan_start_time_x == 0.0) { + vpd->edge_pan_start_time_x = current_time; + } + if (pan_dir_y == 0) { + vpd->edge_pan_start_time_y = 0.0; + } + else if (vpd->edge_pan_start_time_y == 0.0) { + vpd->edge_pan_start_time_y = current_time; + } +} + +/** + * Used to calculate a "fade in" factor for edge panning to make the interaction feel smooth + * and more purposeful. + * + * \note Assumes a domain_min of 0.0f. + */ +static float smootherstep(const float domain_max, float x) +{ + x = clamp_f(x / domain_max, 0.0, 1.0); + return x * x * x * (x * (x * 6.0 - 15.0) + 10.0); +} + +static float edge_pan_speed(v2dViewPanData *vpd, + int event_loc, + bool x_dir, + const double current_time) +{ + ARegion *region = vpd->region; + + /* Find the distance from the start of the drag zone. */ + int min = (x_dir ? region->winrct.xmin : region->winrct.ymin) + EDGE_PAN_REGION_PAD; + int max = (x_dir ? region->winrct.xmax : region->winrct.ymax) - EDGE_PAN_REGION_PAD; + int distance = 0.0; + if (event_loc > max) { + distance = event_loc - max; + } + else if (event_loc < min) { + distance = min - event_loc; + } + else { + BLI_assert(!"Calculating speed outside of pan zones"); + return 0.0f; + } + + /* Apply a fade in to the speed based on a start time delay. */ + double start_time = x_dir ? vpd->edge_pan_start_time_x : vpd->edge_pan_start_time_y; + float delay_factor = smootherstep(EDGE_PAN_DELAY, (float)(current_time - start_time)); + + return distance * EDGE_PAN_SPEED_PER_PIXEL * delay_factor; +} + +static int view_edge_pan_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + v2dViewPanData *vpd = op->customdata; + ARegion *region = vpd->region; + + if (event->val == KM_RELEASE || event->type == EVT_ESCKEY) { + view_pan_exit(op); + return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); + } + /* Only mousemove events matter here, ignore others. */ + if (event->type != MOUSEMOVE) { + return OPERATOR_PASS_THROUGH; + } + + /* This operator is supposed to run together with some drag action. + * On successful handling, always pass events on to other handlers. */ + const int success_retval = OPERATOR_PASS_THROUGH; + + /* Find whether the mouse is beyond X and Y edges. */ + int pan_dir_x = 0; + int pan_dir_y = 0; + if (event->x > region->winrct.xmax - EDGE_PAN_REGION_PAD) { + pan_dir_x = 1; + } + else if (event->x < region->winrct.xmin + EDGE_PAN_REGION_PAD) { + pan_dir_x = -1; + } + if (event->y > region->winrct.ymax - EDGE_PAN_REGION_PAD) { + pan_dir_y = 1; + } + else if (event->y < region->winrct.ymin + EDGE_PAN_REGION_PAD) { + pan_dir_y = -1; + } + + const double current_time = PIL_check_seconds_timer(); + edge_pan_manage_delay_timers(vpd, pan_dir_x, pan_dir_y, current_time); + + /* Calculate the delta since the last time the operator was called. */ + float dtime = (float)(current_time - vpd->edge_pan_last_time); + float dx = 0.0f, dy = 0.0f; + if (pan_dir_x != 0) { + float speed = edge_pan_speed(vpd, event->x, true, current_time); + dx = dtime * speed * (float)pan_dir_x; + } + if (pan_dir_y != 0) { + float speed = edge_pan_speed(vpd, event->y, false, current_time); + dy = dtime * speed * (float)pan_dir_y; + } + vpd->edge_pan_last_time = current_time; + + /* Pan, clamping inside the regions's total bounds. */ + view_pan_apply_ex(C, vpd, dx, dy); + + return success_retval; +} + +static void view_edge_pan_cancel(bContext *UNUSED(C), wmOperator *op) +{ + view_pan_exit(op); +} + +static void VIEW2D_OT_edge_pan(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "View Edge Pan"; + ot->description = "Pan the view when the mouse is held at an edge"; + ot->idname = "VIEW2D_OT_edge_pan"; + + /* api callbacks */ + ot->invoke = view_edge_pan_invoke; + ot->modal = view_edge_pan_modal; + ot->cancel = view_edge_pan_cancel; + + /* operator is modal */ + ot->flag = OPTYPE_INTERNAL; +} + +#undef EDGE_PAN_REGION_PAD +#undef EDGE_PAN_SPEED_PER_PIXEL +#undef EDGE_PAN_DELAY + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name View Pan Operator (single step) * \{ */ @@ -2246,6 +2430,7 @@ static void VIEW2D_OT_reset(wmOperatorType *ot) void ED_operatortypes_view2d(void) { WM_operatortype_append(VIEW2D_OT_pan); + WM_operatortype_append(VIEW2D_OT_edge_pan); WM_operatortype_append(VIEW2D_OT_scroll_left); WM_operatortype_append(VIEW2D_OT_scroll_right); diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index 551f7989d53..dc8ad858a9f 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -663,7 +663,7 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op) /* Switch out of edit mode to avoid being stuck in it (T54326). */ Object *obedit = CTX_data_edit_object(C); if (obedit) { - ED_object_mode_toggle(C, OB_MODE_EDIT); + ED_object_mode_set(C, OB_MODE_OBJECT); } bool ok = ABC_import(C, diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index bea44ee89f8..3786ed2789c 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -752,7 +752,7 @@ void ED_mask_draw_region( } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_uniform_vector( - state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red); + state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); immDrawPixelsTex( &state, 0.0f, 0.0f, width, height, GL_RED, GL_FLOAT, GL_NEAREST, buffer, 1.0f, 1.0f, NULL); diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index 1484dcfa92d..3c426e5d2b1 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -59,6 +59,7 @@ static Object *make_prim_init(bContext *C, const char *idname, const float loc[3], const float rot[3], + const float scale[3], ushort local_view_bits, MakePrimitiveData *r_creation_data) { @@ -76,6 +77,13 @@ static Object *make_prim_init(bContext *C, ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat); + if (scale && !equals_v3v3(scale, (const float[3]){1.0f, 1.0f, 1.0f})) { + float scale_half[3]; + copy_v3_v3(scale_half, scale); + mul_v3_fl(scale_half, 0.5f); + rescale_m4(r_creation_data->mat, scale_half); + } + return obedit; } @@ -112,9 +120,16 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op) const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), + loc, + rot, + NULL, + local_view_bits, + &creation_data); + em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -164,15 +179,22 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op) MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3]; + float loc[3], rot[3], scale[3]; bool enter_editmode; ushort local_view_bits; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), + loc, + rot, + scale, + local_view_bits, + &creation_data); + em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -237,9 +259,16 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) cap_tri = (cap_end == 2); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), + loc, + rot, + NULL, + local_view_bits, + &creation_data); + em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -294,7 +323,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3]; + float loc[3], rot[3], scale[3]; bool enter_editmode; ushort local_view_bits; const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); @@ -303,11 +332,13 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), loc, rot, + scale, local_view_bits, &creation_data); em = BKE_editmesh_from_object(obedit); @@ -368,7 +399,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3]; + float loc[3], rot[3], scale[3]; bool enter_editmode; ushort local_view_bits; const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); @@ -377,9 +408,15 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), + loc, + rot, + scale, + local_view_bits, + &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -447,9 +484,15 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op) const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), + loc, + rot, + NULL, + local_view_bits, + &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -514,10 +557,16 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op) const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &local_view_bits, NULL); + ED_object_add_generic_get_opts( + C, op, 'Y', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, local_view_bits, &creation_data); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), + loc, + rot, + NULL, + local_view_bits, + &creation_data); dia = RNA_float_get(op->ptr, "size") / 2.0f; mul_mat3_m4_fl(creation_data.mat, dia); @@ -567,15 +616,21 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3]; + float loc[3], rot[3], scale[3]; bool enter_editmode; ushort local_view_bits; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), + loc, + rot, + scale, + local_view_bits, + &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -629,17 +684,19 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3]; + float loc[3], rot[3], scale[3]; bool enter_editmode; ushort local_view_bits; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), loc, rot, + scale, local_view_bits, &creation_data); em = BKE_editmesh_from_object(obedit); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index f94cd778e13..5f5599b53df 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -2998,6 +2998,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) case MOUSEROTATE: case WHEELUPMOUSE: case WHEELDOWNMOUSE: + case NDOF_MOTION: return OPERATOR_PASS_THROUGH; case MOUSEMOVE: /* mouse moved somewhere to select another loop */ if (kcd->mode != MODE_PANNING) { diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 3861676c2cf..0f52911c603 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -515,6 +515,10 @@ static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op) static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) { + if (event->type == NDOF_MOTION) { + return OPERATOR_PASS_THROUGH; + } + RingSelOpData *lcd = op->customdata; float cuts = lcd->cuts; float smoothness = lcd->smoothness; @@ -606,7 +610,8 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) } handled = true; break; - case MOUSEMOVE: /* mouse moved somewhere to select another loop */ + case MOUSEMOVE: { + /* mouse moved somewhere to select another loop */ /* This is normally disabled for all modal operators. * This is an exception since mouse movement doesn't relate to numeric input. @@ -615,14 +620,16 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) #if 0 if (!has_numinput) #endif - { - lcd->vc.mval[0] = event->mval[0]; - lcd->vc.mval[1] = event->mval[1]; - loopcut_mouse_move(lcd, (int)lcd->cuts); + { + lcd->vc.mval[0] = event->mval[0]; + lcd->vc.mval[1] = event->mval[1]; + loopcut_mouse_move(lcd, (int)lcd->cuts); - ED_region_tag_redraw(lcd->region); - handled = true; - } break; + ED_region_tag_redraw(lcd->region); + handled = true; + } + break; + } } /* Modal numinput inactive, try to handle numeric inputs last... */ diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index eed2cbcce39..739bc5bdf7c 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -224,7 +224,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "add_solidify")) { ED_object_modifier_add( op->reports, bmain, scene, new_ob, "mask_extract_solidify", eModifierType_Solidify); - SolidifyModifierData *sfmd = (SolidifyModifierData *)BKE_modifiers_findny_name( + SolidifyModifierData *sfmd = (SolidifyModifierData *)BKE_modifiers_findby_name( new_ob, "mask_extract_solidify"); if (sfmd) { sfmd->offset = -0.05f; diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index a26003d78ed..b5346a9061a 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1647,14 +1647,13 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, void EDBM_project_snap_verts( bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em) { - Main *bmain = CTX_data_main(C); BMIter iter; BMVert *eve; ED_view3d_init_mats_rv3d(obedit, region->regiondata); struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - bmain, CTX_data_scene(C), 0, region, CTX_wm_view3d(C)); + CTX_data_scene(C), 0, region, CTX_wm_view3d(C)); BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 2ee98f39306..8289f52b0c8 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -350,6 +350,18 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode) DEG2RADF(-360.0f), DEG2RADF(360.0f)); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_float_vector_xyz(ot->srna, + "scale", + 3, + NULL, + -OBJECT_ADD_SIZE_MAXF, + OBJECT_ADD_SIZE_MAXF, + "Scale", + "Scale for the newly added object", + -1000.0f, + 1000.0f); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } void ED_object_add_mesh_props(wmOperatorType *ot) @@ -362,6 +374,7 @@ bool ED_object_add_generic_get_opts(bContext *C, const char view_align_axis, float loc[3], float rot[3], + float scale[3], bool *enter_editmode, ushort *local_view_bits, bool *is_view_aligned) @@ -470,6 +483,26 @@ bool ED_object_add_generic_get_opts(bContext *C, } } + /* Scale! */ + { + float _scale[3]; + if (!scale) { + scale = _scale; + } + + /* For now this is optional, we can make it always use. */ + copy_v3_fl(scale, 1.0f); + if ((prop = RNA_struct_find_property(op->ptr, "scale"))) { + if (RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_get_array(op->ptr, prop, scale); + } + else { + copy_v3_fl(scale, 1.0f); + RNA_property_float_set_array(op->ptr, prop, scale); + } + } + } + return true; } @@ -535,7 +568,7 @@ static int object_add_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } radius = RNA_float_get(op->ptr, "radius"); @@ -609,7 +642,7 @@ static int lightprobe_add_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } type = RNA_enum_get(op->ptr, "type"); @@ -668,7 +701,7 @@ static int effector_add_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } type = RNA_enum_get(op->ptr, "type"); @@ -746,7 +779,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) RNA_enum_set(op->ptr, "align", ALIGN_VIEW); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, local_view_bits); @@ -807,7 +840,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } if (obedit == NULL || obedit->type != OB_MBALL) { @@ -872,7 +905,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } if (obedit && obedit->type == OB_FONT) { @@ -924,7 +957,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) { @@ -987,7 +1020,7 @@ static int object_empty_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, local_view_bits); @@ -1047,7 +1080,8 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv ushort local_view_bits; float rot[3]; - if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts( + C, op, 'Z', NULL, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, local_view_bits); @@ -1134,7 +1168,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) /* Note: We use 'Y' here (not 'Z'), as */ WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } /* add new object if not currently editing a GP object, @@ -1264,7 +1298,7 @@ static int object_light_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } ob = ED_object_add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false, local_view_bits); @@ -1349,7 +1383,7 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op) collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection")); } - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } if (collection) { @@ -1422,7 +1456,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; Scene *scene = CTX_data_scene(C); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, local_view_bits); @@ -1479,7 +1513,7 @@ static int object_hair_add_exec(bContext *C, wmOperator *op) ushort local_view_bits; float loc[3], rot[3]; - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } Object *object = ED_object_add_type(C, OB_HAIR, NULL, loc, rot, false, local_view_bits); @@ -1516,7 +1550,7 @@ static int object_pointcloud_add_exec(bContext *C, wmOperator *op) ushort local_view_bits; float loc[3], rot[3]; - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } Object *object = ED_object_add_type(C, OB_POINTCLOUD, NULL, loc, rot, false, local_view_bits); @@ -2865,6 +2899,7 @@ static int add_named_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index fcf8a8dc2fe..19974655cbb 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -81,7 +81,7 @@ * \{ */ /* if object in posemode, active bone constraints, else object constraints */ -ListBase *get_active_constraints(Object *ob) +ListBase *ED_object_constraint_list_from_context(Object *ob) { if (ob == NULL) { return NULL; @@ -104,7 +104,9 @@ ListBase *get_active_constraints(Object *ob) /* Find the list that a given constraint belongs to, * and/or also get the posechannel this is from (if applicable) */ -ListBase *get_constraint_lb(Object *ob, bConstraint *con, bPoseChannel **r_pchan) +ListBase *ED_object_constraint_list_from_constraint(Object *ob, + bConstraint *con, + bPoseChannel **r_pchan) { if (r_pchan) { *r_pchan = NULL; @@ -143,9 +145,9 @@ ListBase *get_constraint_lb(Object *ob, bConstraint *con, bPoseChannel **r_pchan } /* single constraint */ -bConstraint *get_active_constraint(Object *ob) +bConstraint *ED_object_constraint_active_get(Object *ob) { - return BKE_constraints_active_get(get_active_constraints(ob)); + return BKE_constraints_active_get(ED_object_constraint_list_from_context(ob)); } /** \} */ @@ -721,7 +723,7 @@ static int edit_constraint_invoke_properties(bContext *C, wmOperator *op) con = ptr.data; RNA_string_set(op->ptr, "constraint", con->name); - list = get_constraint_lb(ob, con, NULL); + list = ED_object_constraint_list_from_constraint(ob, con, NULL); if (&ob->constraints == list) { RNA_enum_set(op->ptr, "owner", EDIT_CONSTRAINT_OWNER_OBJECT); @@ -769,7 +771,7 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int printf("edit_constraint_property_get: defaulting to getting list in the standard way\n"); } #endif - list = get_active_constraints(ob); + list = ED_object_constraint_list_from_context(ob); } con = BKE_constraints_find_name(list, constraint_name); @@ -1061,7 +1063,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op) Curve *cu = (Curve *)data->tar->data; if (ELEM(NULL, cu->adt, cu->adt->action) || - (list_find_fcurve(&cu->adt->action->curves, "eval_time", 0) == NULL)) { + (BKE_fcurve_find(&cu->adt->action->curves, "eval_time", 0) == NULL)) { /* create F-Curve for path animation */ act = ED_id_action_ensure(bmain, &cu->id); fcu = ED_action_fcurve_ensure(bmain, act, NULL, NULL, "eval_time", 0); @@ -1305,9 +1307,9 @@ void CONSTRAINT_OT_objectsolver_clear_inverse(wmOperatorType *ot) /** \name Constraint Management Utilities * \{ */ -void ED_object_constraint_set_active(Object *ob, bConstraint *con) +void ED_object_constraint_active_set(Object *ob, bConstraint *con) { - ListBase *lb = get_constraint_lb(ob, con, NULL); + ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, NULL); /* lets be nice and escape if its active already */ /* NOTE: this assumes that the stack doesn't have other active ones set... */ @@ -1409,7 +1411,7 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); Object *ob = (Object *)ptr.owner_id; bConstraint *con = ptr.data; - ListBase *lb = get_constraint_lb(ob, con, NULL); + ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, NULL); /* free the constraint */ if (BKE_constraint_remove_ex(lb, ob, con, true)) { @@ -1459,7 +1461,7 @@ static int constraint_move_down_exec(bContext *C, wmOperator *op) bConstraint *con = edit_constraint_property_get(op, ob, 0); if (con && con->next) { - ListBase *conlist = get_constraint_lb(ob, con, NULL); + ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL); bConstraint *nextCon = con->next; /* insert the nominated constraint after the one that used to be after it */ @@ -1515,7 +1517,7 @@ static int constraint_move_up_exec(bContext *C, wmOperator *op) bConstraint *con = edit_constraint_property_get(op, ob, 0); if (con && con->prev) { - ListBase *conlist = get_constraint_lb(ob, con, NULL); + ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL); bConstraint *prevCon = con->prev; /* insert the nominated constraint before the one that used to be before it */ @@ -2128,7 +2130,8 @@ static int pose_constraint_add_exec(bContext *C, wmOperator *op) with_targets = 1; } - return constraint_add_exec(C, op, ob, get_active_constraints(ob), type, with_targets); + return constraint_add_exec( + C, op, ob, ED_object_constraint_list_from_context(ob), type, with_targets); } /* ------------------ */ @@ -2329,8 +2332,12 @@ static int pose_ik_add_exec(bContext *C, wmOperator *op) /* add the constraint - all necessary checks should have * been done by the invoke() callback already... */ - return constraint_add_exec( - C, op, ob, get_active_constraints(ob), CONSTRAINT_TYPE_KINEMATIC, with_targets); + return constraint_add_exec(C, + op, + ob, + ED_object_constraint_list_from_context(ob), + CONSTRAINT_TYPE_KINEMATIC, + with_targets); } void POSE_OT_ik_add(wmOperatorType *ot) diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 53a557c5871..d522dcabae3 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1475,10 +1475,9 @@ static bool object_mode_set_poll(bContext *C) static int object_mode_set_exec(bContext *C, wmOperator *op) { - bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_with_submode"); + const bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_with_submode"); Object *ob = CTX_data_active_object(C); eObjectMode mode = RNA_enum_get(op->ptr, "mode"); - eObjectMode restore_mode = ob->mode; const bool toggle = RNA_boolean_get(op->ptr, "toggle"); /* by default the operator assume is a mesh, but if gp object change mode */ @@ -1490,43 +1489,63 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) return OPERATOR_PASS_THROUGH; } + /** + * Mode Switching Logic (internal details). + * + * Notes: + * - Code below avoids calling mode switching functions more than once, + * as this causes unnecessary calculations and undo steps to be added. + * - The previous mode (#Object.restore_mode) is object mode by default. + * + * Supported Cases: + * - Setting the mode (when the 'toggle' setting is off). + * - Toggle the mode: + * - Toggle between object mode and non-object mode property. + * - Toggle between the previous mode (#Object.restore_mode) and the mode property. + * - Toggle object mode. + * While this is similar to regular toggle, + * this operator depends on there being a previous mode set + * (this isn't bound to a key with the default key-map). + */ if (toggle == false) { if (ob->mode != mode) { - if (mode != OB_MODE_OBJECT) { - /* Enter new mode. */ - ED_object_mode_toggle(C, mode); - } - else { - ED_object_mode_compat_set(C, ob, mode, op->reports); - } + ED_object_mode_set_ex(C, mode, true, op->reports); } } else { - /* Exit current mode if it's not the mode we're setting */ - if (mode != OB_MODE_OBJECT) { - /* Enter new mode. */ - ED_object_mode_toggle(C, mode); - } - - /* Special case for Object mode! */ - if ((mode == OB_MODE_OBJECT) && (restore_mode == OB_MODE_OBJECT) && - (ob->restore_mode != OB_MODE_OBJECT)) { - ED_object_mode_toggle(C, ob->restore_mode); - } - else if (ob->mode == mode) { - /* For toggling, store old mode so we know what to go back to */ - ob->restore_mode = restore_mode; - } - else if ((ob->restore_mode != OB_MODE_OBJECT) && (ob->restore_mode != mode)) { - ED_object_mode_toggle(C, ob->restore_mode); + const eObjectMode mode_prev = ob->mode; + /* When toggling object mode, we always use the restore mode, + * otherwise there is nothing to do. */ + if (mode == OB_MODE_OBJECT) { + if (ob->mode != OB_MODE_OBJECT) { + if (ED_object_mode_set_ex(C, OB_MODE_OBJECT, true, op->reports)) { + /* Store old mode so we know what to go back to. */ + ob->restore_mode = mode_prev; + } + } + else { + if (ob->restore_mode != OB_MODE_OBJECT) { + ED_object_mode_set_ex(C, ob->restore_mode, true, op->reports); + } + } } - } - - /* if type is OB_GPENCIL, set cursor mode */ - if (ob->type == OB_GPENCIL) { - if (ob->data) { - bGPdata *gpd = (bGPdata *)ob->data; - ED_gpencil_setup_modes(C, gpd, ob->mode); + else { + /* Non-object modes, enter the 'mode' unless it's already set, + * in that case use restore mode. */ + if (ob->mode != mode) { + if (ED_object_mode_set_ex(C, mode, true, op->reports)) { + /* Store old mode so we know what to go back to. */ + ob->restore_mode = mode_prev; + } + } + else { + if (ob->restore_mode != OB_MODE_OBJECT) { + ED_object_mode_set_ex(C, ob->restore_mode, true, op->reports); + } + else { + ED_object_mode_set_ex(C, OB_MODE_OBJECT, true, op->reports); + } + } } } diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index f06b6a4db2a..c518fd32c7f 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -167,41 +167,6 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, Report return ok; } -void ED_object_mode_toggle(bContext *C, eObjectMode mode) -{ - if (mode != OB_MODE_OBJECT) { - const char *opstring = object_mode_op_string(mode); - - if (opstring) { - wmOperatorType *ot = WM_operatortype_find(opstring, false); - WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_REGION_WIN, NULL); - } - } -} - -/* Wrapper for operator */ -void ED_object_mode_set(bContext *C, eObjectMode mode) -{ - wmWindowManager *wm = CTX_wm_manager(C); - wm->op_undo_depth++; - /* needed so we don't do undo pushes. */ - ED_object_mode_generic_enter(C, mode); - wm->op_undo_depth--; -} - -void ED_object_mode_exit(bContext *C, Depsgraph *depsgraph) -{ - struct Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - FOREACH_OBJECT_BEGIN (view_layer, ob) { - if (ob->mode & OB_MODE_ALL_MODE_DATA) { - ED_object_mode_generic_exit(bmain, depsgraph, scene, ob); - } - } - FOREACH_OBJECT_END; -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -212,23 +177,50 @@ void ED_object_mode_exit(bContext *C, Depsgraph *depsgraph) * * \{ */ -bool ED_object_mode_generic_enter(struct bContext *C, eObjectMode object_mode) +bool ED_object_mode_set_ex(bContext *C, eObjectMode mode, bool use_undo, ReportList *reports) { + wmWindowManager *wm = CTX_wm_manager(C); ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); if (ob == NULL) { - return (object_mode == OB_MODE_OBJECT); + return (mode == OB_MODE_OBJECT); } - if (ob->mode == object_mode) { + + if ((ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) { + mode = OB_MODE_EDIT_GPENCIL; + } + + if (ob->mode == mode) { return true; } - wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false); - PointerRNA ptr; - WM_operator_properties_create_ptr(&ptr, ot); - RNA_enum_set(&ptr, "mode", object_mode); - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); - WM_operator_properties_free(&ptr); - return (ob->mode == object_mode); + + if (!ED_object_mode_compat_test(ob, mode)) { + return false; + } + + const char *opstring = object_mode_op_string((mode == OB_MODE_OBJECT) ? ob->mode : mode); + wmOperatorType *ot = WM_operatortype_find(opstring, false); + + if (!use_undo) { + wm->op_undo_depth++; + } + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_REGION_WIN, NULL); + if (!use_undo) { + wm->op_undo_depth--; + } + + if (ob->mode != mode) { + BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name); + return false; + } + + return true; +} + +bool ED_object_mode_set(bContext *C, eObjectMode mode) +{ + /* Don't do undo push by default, since this may be called by lower level code. */ + return ED_object_mode_set_ex(C, mode, true, NULL); } /** @@ -282,6 +274,18 @@ static bool ed_object_mode_generic_exit_ex(struct Main *bmain, ED_object_posemode_exit_ex(bmain, ob); } } + else if (ob->mode & OB_MODE_TEXTURE_PAINT) { + if (only_test) { + return true; + } + ED_object_texture_paint_mode_exit_ex(bmain, scene, ob); + } + else if (ob->mode & OB_MODE_PARTICLE_EDIT) { + if (only_test) { + return true; + } + ED_object_particle_edit_mode_exit_ex(scene, ob); + } else if (ob->type == OB_GPENCIL) { /* Accounted for above. */ BLI_assert((ob->mode & OB_MODE_OBJECT) == 0); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 862bdcee8ce..0bd49f74db9 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -847,7 +847,7 @@ bool ED_object_modifier_apply(Main *bmain, /* Get evaluated modifier, so object links pointer to evaluated data, * but still use original object it is applied to the original mesh. */ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findny_name(ob_eval, md->name) : md; + ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findby_name(ob_eval, md->name) : md; /* allow apply of a not-realtime modifier, by first re-enabling realtime. */ prev_mode = md_eval->mode; @@ -1062,7 +1062,7 @@ ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type) ModifierData *md; RNA_string_get(op->ptr, "modifier", modifier_name); - md = BKE_modifiers_findny_name(ob, modifier_name); + md = BKE_modifiers_findby_name(ob, modifier_name); if (md && type != 0 && md->type != type) { md = NULL; diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index bfceaef4644..0e8545e07ba 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2072,7 +2072,7 @@ void ED_object_single_users(Main *bmain, /* Duplicating obdata and other IDs may require another update of the collections and objects * pointers, especially regarding drivers and custom props, see T66641. - * Note that this whole scene duplication code and 'make single user' functions have te be + * Note that this whole scene duplication code and 'make single user' functions have to be * rewritten at some point to make use of proper modern ID management code, * but that is no small task. * For now we are doomed to that kind of band-aid to try to cover most of remapping cases. */ @@ -2516,7 +2516,8 @@ static int make_override_library_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); Collection *new_collection = (Collection *)collection->id.newid; - BKE_collection_child_add(bmain, scene->master_collection, new_collection); + BKE_collection_add_from_object(bmain, scene, obcollection, new_collection); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (new_collection, new_ob) { if (new_ob != NULL && new_ob->id.override_library != NULL) { if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) { @@ -2524,14 +2525,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op) base = BKE_view_layer_base_find(view_layer, new_ob); DEG_id_tag_update_ex(bmain, &new_ob->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); } - /* parent to 'collection' empty */ - /* Disabled for now, according to some artist this is probably not really useful anyway. - * And it breaks things like objects parented to bones - * (most likely due to missing proper setting of inverse parent matrix?)... */ - /* Note: we might even actually want to get rid of that instantiating empty... */ - if (0 && new_ob->parent == NULL) { - new_ob->parent = obcollection; - } + if (new_ob == (Object *)obact->id.newid) { /* TODO: is setting active needed? */ BKE_view_layer_base_select_and_set_active(view_layer, base); @@ -2546,9 +2540,9 @@ static int make_override_library_exec(bContext *C, wmOperator *op) } FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - /* obcollection is no more duplicollection-ing, - * it merely parents whole collection of overriding instantiated objects. */ - obcollection->instance_collection = NULL; + /* Remove the instance empty from this scene, the items now have an overridden collection + * instead. */ + ED_object_base_free_and_unlink(bmain, scene, obcollection); /* Also, we'd likely want to lock by default things like * transformations of implicitly overridden objects? */ diff --git a/source/blender/editors/object/object_volume.c b/source/blender/editors/object/object_volume.c index 3c1f7da2bd6..4cdbbea492b 100644 --- a/source/blender/editors/object/object_volume.c +++ b/source/blender/editors/object/object_volume.c @@ -59,7 +59,7 @@ static Object *object_volume_add(bContext *C, wmOperator *op, const char *name) ushort local_view_bits; float loc[3], rot[3]; - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return false; } return ED_object_add_type(C, OB_VOLUME, name, loc, rot, false, local_view_bits); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index ca2dec75160..ef5ed806c1e 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3230,17 +3230,17 @@ static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata) } } -static void toggle_particle_cursor(bContext *C, int enable) +static void toggle_particle_cursor(Scene *scene, bool enable) { - ParticleEditSettings *pset = PE_settings(CTX_data_scene(C)); + ParticleEditSettings *pset = PE_settings(scene); if (pset->paintcursor && !enable) { - WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor); + WM_paint_cursor_end(pset->paintcursor); pset->paintcursor = NULL; } else if (enable) { pset->paintcursor = WM_paint_cursor_activate( - CTX_wm_manager(C), SPACE_VIEW3D, RGN_TYPE_WINDOW, PE_poll_view3d, brush_drawcursor, NULL); + SPACE_VIEW3D, RGN_TYPE_WINDOW, PE_poll_view3d, brush_drawcursor, NULL); } } @@ -5127,7 +5127,7 @@ void PE_create_particle_edit( int totpoint; if (psmd != NULL) { - psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findny_name(ob_eval, + psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name(ob_eval, psmd->modifier.name); } @@ -5268,10 +5268,60 @@ static void free_all_psys_edit(Object *object) } } +void ED_object_particle_edit_mode_enter_ex(Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + PTCacheEdit *edit; + + ob->mode |= OB_MODE_PARTICLE_EDIT; + + edit = PE_create_current(depsgraph, scene, ob); + + /* Mesh may have changed since last entering editmode. + * note, this may have run before if the edit data was just created, + * so could avoid this and speed up a little. */ + if (edit && edit->psys) { + /* Make sure pointer to the evaluated modifier data is up to date, + * with possible changes applied when object was outside of the + * edit mode. */ + Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); + edit->psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name( + object_eval, edit->psmd->modifier.name); + recalc_emitter_field(depsgraph, ob, edit->psys); + } + + toggle_particle_cursor(scene, true); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_PARTICLE, NULL); +} + +void ED_object_particle_edit_mode_enter(bContext *C) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + ED_object_particle_edit_mode_enter_ex(depsgraph, scene, ob); +} + +void ED_object_particle_edit_mode_exit_ex(Scene *scene, Object *ob) +{ + ob->mode &= ~OB_MODE_PARTICLE_EDIT; + toggle_particle_cursor(scene, false); + free_all_psys_edit(ob); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); +} + +void ED_object_particle_edit_mode_exit(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + ED_object_particle_edit_mode_exit_ex(scene, ob); +} + static int particle_edit_toggle_exec(bContext *C, wmOperator *op) { struct wmMsgBus *mbus = CTX_wm_message_bus(C); - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); const int mode_flag = OB_MODE_PARTICLE_EDIT; @@ -5284,37 +5334,13 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op) } if (!is_mode_set) { - PTCacheEdit *edit; - - ob->mode |= mode_flag; - - edit = PE_create_current(depsgraph, scene, ob); - - /* Mesh may have changed since last entering editmode. - * note, this may have run before if the edit data was just created, - * so could avoid this and speed up a little. */ - if (edit && edit->psys) { - /* Make sure pointer to the evaluated modifier data is up to date, - * with possible changes applied when object was outside of the - * edit mode. */ - Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); - edit->psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findny_name( - object_eval, edit->psmd->modifier.name); - recalc_emitter_field(depsgraph, ob, edit->psys); - } - - toggle_particle_cursor(C, 1); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_PARTICLE, NULL); + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + ED_object_particle_edit_mode_enter_ex(depsgraph, scene, ob); } else { - ob->mode &= ~mode_flag; - toggle_particle_cursor(C, 0); - free_all_psys_edit(ob); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); + ED_object_particle_edit_mode_exit_ex(scene, ob); } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); - WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); WM_toolsystem_update_from_context_view3d(C); diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c index 5b363bdca78..205c04f54a9 100644 --- a/source/blender/editors/physics/particle_edit_undo.c +++ b/source/blender/editors/physics/particle_edit_undo.c @@ -253,7 +253,7 @@ static void particle_undosys_step_decode(struct bContext *C, { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); /* TODO(campbell): undo_system: use low-level API to set mode. */ - ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT); + ED_object_mode_set_ex(C, OB_MODE_PARTICLE_EDIT, false, NULL); BLI_assert(particle_undosys_poll(C)); ParticleUndoStep *us = (ParticleUndoStep *)us_p; diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index ceaac201da3..8524870c15e 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -52,6 +52,7 @@ #include "DEG_depsgraph.h" +#include "ED_object.h" #include "ED_screen.h" #include "PIL_time.h" @@ -154,7 +155,7 @@ static bool fluid_initjob( { FluidModifierData *mmd = NULL; FluidDomainSettings *mds; - Object *ob = CTX_data_active_object(C); + Object *ob = ED_object_active_context(C); mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid); if (!mmd) { @@ -170,7 +171,7 @@ static bool fluid_initjob( job->bmain = CTX_data_main(C); job->scene = CTX_data_scene(C); job->depsgraph = CTX_data_depsgraph_pointer(C); - job->ob = CTX_data_active_object(C); + job->ob = ob; job->mmd = mmd; job->type = op->type->idname; job->name = op->type->name; @@ -616,7 +617,7 @@ static int fluid_free_exec(struct bContext *C, struct wmOperator *op) { FluidModifierData *mmd = NULL; FluidDomainSettings *mds; - Object *ob = CTX_data_active_object(C); + Object *ob = ED_object_active_context(C); Scene *scene = CTX_data_scene(C); /* @@ -679,7 +680,7 @@ static int fluid_pause_exec(struct bContext *C, struct wmOperator *op) { FluidModifierData *mmd = NULL; FluidDomainSettings *mds; - Object *ob = CTX_data_active_object(C); + Object *ob = ED_object_active_context(C); /* * Get modifier data diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 46827940b57..1db7bf5a766 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -437,7 +437,7 @@ static void make_renderinfo_string(const RenderStats *rs, } } else { - if (rs->totvert || rs->totface || rs->tothalo || rs->totstrand || rs->totlamp) { + if (rs->totvert || rs->totface || rs->totlamp) { spos += sprintf(spos, "| "); } @@ -447,12 +447,6 @@ static void make_renderinfo_string(const RenderStats *rs, if (rs->totface) { spos += sprintf(spos, TIP_("Fa:%d "), rs->totface); } - if (rs->tothalo) { - spos += sprintf(spos, TIP_("Ha:%d "), rs->tothalo); - } - if (rs->totstrand) { - spos += sprintf(spos, TIP_("St:%d "), rs->totstrand); - } if (rs->totlamp) { spos += sprintf(spos, TIP_("Li:%d "), rs->totlamp); } @@ -463,18 +457,6 @@ static void make_renderinfo_string(const RenderStats *rs, else { spos += sprintf(spos, TIP_("| Mem:%.2fM, Peak: %.2fM "), rs->mem_used, rs->mem_peak); } - - if (rs->curfield) { - spos += sprintf(spos, TIP_("Field %d "), rs->curfield); - } - if (rs->curblur) { - spos += sprintf(spos, TIP_("Blur %d "), rs->curblur); - } - } - - /* full sample */ - if (rs->curfsa) { - spos += sprintf(spos, TIP_("| Full Sample %d "), rs->curfsa); } /* extra info */ diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index ddb345ab65e..a9380debbdc 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -83,7 +83,7 @@ static void immDrawPixelsTexSetupAttributes(IMMDrawPixelsTexState *state) /* To be used before calling immDrawPixelsTex * Default shader is GPU_SHADER_2D_IMAGE_COLOR * You can still set uniforms with : - * GPU_shader_uniform_int(shader, GPU_shader_get_uniform_ensure(shader, "name"), 0); + * GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0); * */ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin) { @@ -191,7 +191,7 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state, /* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since * it does not need color. */ - if (state->shader != NULL && GPU_shader_get_uniform_ensure(state->shader, "color") != -1) { + if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) { immUniformColor4fv((color) ? color : white); } diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index b383930ddda..3202dc68f37 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -118,8 +118,8 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult ScrArea *area = CTX_wm_area(C); Scene *scene = WM_window_get_active_scene(win); ViewLayer *view_layer = WM_window_get_active_view_layer(win); - Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL; - Object *obedit = view_layer ? OBEDIT_FROM_VIEW_LAYER(view_layer) : NULL; + Object *obact = view_layer->basact ? view_layer->basact->object : NULL; + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); if (CTX_data_dir(member)) { CTX_data_dir_set(result, screen_context_dir); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 00afbf452dd..6f004238522 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -305,30 +305,28 @@ int area_getorientation(ScrArea *area, ScrArea *sb) ScrVert *sbTR = sb->v3; ScrVert *sbBR = sb->v4; - int tolerance = U.pixelsize * 4; - if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* area to right of sb = W */ - if ((abs(saBL->vec.y - sbBR->vec.y) <= tolerance) && - (abs(saTL->vec.y - sbTR->vec.y) <= tolerance)) { + if ((abs(saBL->vec.y - sbBR->vec.y) <= AREAJOINTOLERANCE) && + (abs(saTL->vec.y - sbTR->vec.y) <= AREAJOINTOLERANCE)) { return 0; } } else if (saTL->vec.y == sbBL->vec.y && saTR->vec.y == sbBR->vec.y) { /* area to bottom of sb = N */ - if ((abs(saTL->vec.x - sbBL->vec.x) <= tolerance) && - (abs(saTR->vec.x - sbBR->vec.x) <= tolerance)) { + if ((abs(saTL->vec.x - sbBL->vec.x) <= AREAJOINTOLERANCE) && + (abs(saTR->vec.x - sbBR->vec.x) <= AREAJOINTOLERANCE)) { return 1; } } else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* area to left of sb = E */ - if ((abs(saTR->vec.y - sbTL->vec.y) <= tolerance) && - (abs(saBR->vec.y - sbBL->vec.y) <= tolerance)) { + if ((abs(saTR->vec.y - sbTL->vec.y) <= AREAJOINTOLERANCE) && + (abs(saBR->vec.y - sbBL->vec.y) <= AREAJOINTOLERANCE)) { return 2; } } else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* area on top of sb = S*/ - if ((abs(saBL->vec.x - sbTL->vec.x) <= tolerance) && - (abs(saBR->vec.x - sbTR->vec.x) <= tolerance)) { + if ((abs(saBL->vec.x - sbTL->vec.x) <= AREAJOINTOLERANCE) && + (abs(saBR->vec.x - sbTR->vec.x) <= AREAJOINTOLERANCE)) { return 3; } } @@ -336,6 +334,69 @@ int area_getorientation(ScrArea *area, ScrArea *sb) return -1; } +/* Screen verts with horizontal position equal to from_x are moved to to_x. */ +static void screen_verts_halign(const wmWindow *win, + const bScreen *screen, + const short from_x, + const short to_x) +{ + ED_screen_verts_iter(win, screen, v1) + { + if (v1->vec.x == from_x) { + v1->vec.x = to_x; + } + } +} + +/* Screen verts with vertical position equal to from_y are moved to to_y. */ +static void screen_verts_valign(const wmWindow *win, + const bScreen *screen, + const short from_y, + const short to_y) +{ + ED_screen_verts_iter(win, screen, v1) + { + if (v1->vec.y == from_y) { + v1->vec.y = to_y; + } + } +} + +/* Adjust all screen edges to allow joining two areas. 'dir' value is like area_getorientation(). + */ +static void screen_areas_align( + bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const int dir) +{ + wmWindow *win = CTX_wm_window(C); + + if (dir == 0 || dir == 2) { + /* horizontal join, use average for new top and bottom. */ + int top = (sa1->v2->vec.y + sa2->v2->vec.y) / 2; + int bottom = (sa1->v4->vec.y + sa2->v4->vec.y) / 2; + + /* Move edges exactly matching source top and bottom. */ + screen_verts_valign(win, screen, sa1->v2->vec.y, top); + screen_verts_valign(win, screen, sa1->v4->vec.y, bottom); + + /* Move edges exactly matching target top and bottom. */ + screen_verts_valign(win, screen, sa2->v2->vec.y, top); + screen_verts_valign(win, screen, sa2->v4->vec.y, bottom); + } + else { + /* Vertical join, use averages for new left and right. */ + int left = (sa1->v1->vec.x + sa2->v1->vec.x) / 2; + int right = (sa1->v3->vec.x + sa2->v3->vec.x) / 2; + + /* Move edges exactly matching source left and right. */ + screen_verts_halign(win, screen, sa1->v1->vec.x, left); + screen_verts_halign(win, screen, sa1->v3->vec.x, right); + + /* Move edges exactly matching target left and right */ + screen_verts_halign(win, screen, sa2->v1->vec.x, left); + screen_verts_halign(win, screen, sa2->v3->vec.x, right); + } +} + /* Helper function to join 2 areas, it has a return value, 0=failed 1=success * used by the split, join operators */ @@ -348,21 +409,7 @@ int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2) } /* Align areas if they are not. Do sanity checking before getting here. */ - - if (dir == 0 || dir == 2) { - /* horizontal join, so vertically align source vert to target */ - sa2->v1->vec.y = sa1->v1->vec.y; /* vertical align sa1 BL */ - sa2->v2->vec.y = sa1->v2->vec.y; /* vertical align sa1 TL */ - sa2->v3->vec.y = sa1->v3->vec.y; /* vertical align sa1 TR */ - sa2->v4->vec.y = sa1->v4->vec.y; /* vertical align sa1 BR */ - } - else { - /* vertical join, so horizontally align source verts to target */ - sa2->v1->vec.x = sa1->v1->vec.x; /* vertical align sa1 BL */ - sa2->v2->vec.x = sa1->v2->vec.x; /* vertical align sa1 TL */ - sa2->v3->vec.x = sa1->v3->vec.x; /* vertical align sa1 TR */ - sa2->v4->vec.x = sa1->v4->vec.x; /* vertical align sa1 BR */ - } + screen_areas_align(C, screen, sa1, sa2, dir); if (dir == 0) { /* sa1 to right of sa2 = W */ sa1->v1 = sa2->v1; /* BL */ @@ -690,8 +737,10 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2]) ARegion *region_prev = screen->active_region; ED_screen_areas_iter (win, screen, area_iter) { - if (xy[0] > area_iter->totrct.xmin && xy[0] < area_iter->totrct.xmax) { - if (xy[1] > area_iter->totrct.ymin && xy[1] < area_iter->totrct.ymax) { + if (xy[0] > (area_iter->totrct.xmin + BORDERPADDING) && + xy[0] < (area_iter->totrct.xmax - BORDERPADDING)) { + if (xy[1] > (area_iter->totrct.ymin + BORDERPADDING) && + xy[1] < (area_iter->totrct.ymax - BORDERPADDING)) { if (ED_area_azones_update(area_iter, xy) == NULL) { area = area_iter; break; diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c index 4069795657e..47580c2f4b3 100644 --- a/source/blender/editors/screen/screen_geometry.c +++ b/source/blender/editors/screen/screen_geometry.c @@ -92,7 +92,7 @@ ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map, const int mx, const int my) { - int safety = U.widget_unit / 10; + int safety = BORDERPADDING; CLAMP_MIN(safety, 2); diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index 3dfc147bc73..2d42313d528 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -35,6 +35,11 @@ struct bContextDataResult; #define AZONEFADEIN (5.0f * U.widget_unit) /* when azone is totally visible */ #define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the azone */ +#define AREAJOINTOLERANCE (1.0f * U.widget_unit) /* Edges must be close to allow joining. */ + +/* Expanded interaction influence of area borders. */ +#define BORDERPADDING (U.dpi_fac + U.pixelsize) + /* area.c */ void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free); void ED_area_data_swap(ScrArea *sa1, ScrArea *sa2); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 4d690ddce72..b2243f2ccb9 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -4866,8 +4866,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot) /** \name Show User Preferences Operator * \{ */ -static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int userpref_show_exec(bContext *C, wmOperator *op) { + wmWindow *win_cur = CTX_wm_window(C); + /* Use eventstate, not event from _invoke, so this can be called through exec(). */ + const wmEvent *event = win_cur->eventstate; int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_DPI_FAC; int sizey = 520 * UI_DPI_FAC; @@ -4904,7 +4907,7 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot) ot->idname = "SCREEN_OT_userpref_show"; /* api callbacks */ - ot->invoke = userpref_show_invoke; + ot->exec = userpref_show_exec; ot->poll = ED_operator_screenactive; } @@ -4914,8 +4917,11 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot) /** \name Show Drivers Editor Operator * \{ */ -static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int drivers_editor_show_exec(bContext *C, wmOperator *op) { + wmWindow *win_cur = CTX_wm_window(C); + /* Use eventstate, not event from _invoke, so this can be called through exec(). */ + const wmEvent *event = win_cur->eventstate; PointerRNA ptr = {NULL}; PropertyRNA *prop = NULL; int index = -1; @@ -4946,7 +4952,7 @@ static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent FCurve *fcu; bool driven, special; - fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special); + fcu = BKE_fcurve_find_by_rna_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special); if (fcu) { /* Isolate this F-Curve... */ bAnimContext ac; @@ -4979,7 +4985,7 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot) ot->idname = "SCREEN_OT_drivers_editor_show"; /* api callbacks */ - ot->invoke = drivers_editor_show_invoke; + ot->exec = drivers_editor_show_exec; ot->poll = ED_operator_screenactive; } @@ -4989,8 +4995,11 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot) /** \name Show Info Log Operator * \{ */ -static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int info_log_show_exec(bContext *C, wmOperator *op) { + wmWindow *win_cur = CTX_wm_window(C); + /* Use eventstate, not event from _invoke, so this can be called through exec(). */ + const wmEvent *event = win_cur->eventstate; int sizex = 900 * UI_DPI_FAC; int sizey = 580 * UI_DPI_FAC; int shift_y = 480; @@ -5020,7 +5029,7 @@ static void SCREEN_OT_info_log_show(struct wmOperatorType *ot) ot->idname = "SCREEN_OT_info_log_show"; /* api callbacks */ - ot->invoke = info_log_show_invoke; + ot->exec = info_log_show_exec; ot->poll = ED_operator_screenactive; } diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 8feef0c675a..478a0adfd9a 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -83,8 +83,7 @@ static void workspace_change_update(WorkSpace *workspace_new, eObjectMode mode_new = workspace_new->object_mode; if (mode_old != mode_new) { - ED_object_mode_compat_set(C, ob_act, mode_new, &wm->reports); - ED_object_mode_toggle(C, mode_new); + ED_object_mode_set(C, mode_new); } #endif } @@ -109,9 +108,9 @@ static WorkSpaceLayout *workspace_change_get_new_layout(Main *bmain, layout_new = win->workspace_hook->temp_layout_store; } else { - layout_new = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, workspace_new); + layout_new = BKE_workspace_active_layout_for_workspace_get(win->workspace_hook, workspace_new); if (!layout_new) { - layout_new = BKE_workspace_layouts_get(workspace_new)->first; + layout_new = workspace_new->layouts.first; } } screen_new = BKE_workspace_layout_screen_get(layout_new); @@ -163,7 +162,7 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager return false; } - BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace_new, layout_new); + BKE_workspace_active_layout_set(win->workspace_hook, workspace_new, layout_new); BKE_workspace_active_set(win->workspace_hook, workspace_new); /* update screen *after* changing workspace - which also causes the @@ -175,7 +174,7 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager /* Automatic mode switching. */ if (workspace_new->object_mode != workspace_old->object_mode) { - ED_object_mode_generic_enter(C, workspace_new->object_mode); + ED_object_mode_set(C, workspace_new->object_mode); } return true; @@ -188,7 +187,6 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindow *win) { WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook); - ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old); WorkSpace *workspace_new = ED_workspace_add(bmain, workspace_old->id.name + 2); workspace_new->flags = workspace_old->flags; @@ -198,7 +196,7 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo /* TODO(campbell): tools */ - LISTBASE_FOREACH (WorkSpaceLayout *, layout_old, layouts_old) { + LISTBASE_FOREACH (WorkSpaceLayout *, layout_old, &workspace_old->layouts) { WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate( bmain, workspace_new, layout_old, win); diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c index cf9637788a9..7ce92bc3e4d 100644 --- a/source/blender/editors/screen/workspace_layout_edit.c +++ b/source/blender/editors/screen/workspace_layout_edit.c @@ -140,7 +140,7 @@ bool ED_workspace_layout_delete(WorkSpace *workspace, WorkSpaceLayout *layout_ol const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old); WorkSpaceLayout *layout_new; - BLI_assert(BLI_findindex(BKE_workspace_layouts_get(workspace), layout_old) != -1); + BLI_assert(BLI_findindex(&workspace->layouts, layout_old) != -1); /* don't allow deleting temp fullscreens for now */ if (BKE_screen_is_fullscreen_area(screen_old)) { diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 191a064a95c..4222a466a7b 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1674,23 +1674,13 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* Public API */ -void paint_cursor_start(bContext *C, bool (*poll)(bContext *C)) +void paint_cursor_start(Paint *p, bool (*poll)(bContext *C)) { - Paint *p = BKE_paint_get_active_from_context(C); - if (p && !p->paint_cursor) { p->paint_cursor = WM_paint_cursor_activate( - CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL); + SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL); } /* Invalidate the paint cursors. */ BKE_paint_invalidate_overlay_all(); } - -void paint_cursor_start_explicit(Paint *p, wmWindowManager *wm, bool (*poll)(bContext *C)) -{ - if (p && !p->paint_cursor) { - p->paint_cursor = WM_paint_cursor_activate( - wm, SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL); - } -} diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index fd5018f76ff..08af3bdd16c 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -511,12 +511,8 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo } if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) { - pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, - RGN_TYPE_ANY, - image_paint_poll, - gradient_draw_line, - pop); + pop->cursor = WM_paint_cursor_activate( + SPACE_TYPE_ANY, RGN_TYPE_ANY, image_paint_poll, gradient_draw_line, pop); } settings->imapaint.flag |= IMAGEPAINT_DRAWING; @@ -655,7 +651,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) } if (pop->cursor) { - WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor); + WM_paint_cursor_end(pop->cursor); } ED_image_undo_push_end(); @@ -785,19 +781,18 @@ bool get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) /************************ cursor drawing *******************************/ -static void toggle_paint_cursor(bContext *C, int enable) +static void toggle_paint_cursor(Scene *scene, bool enable) { - wmWindowManager *wm = CTX_wm_manager(C); - Scene *scene = CTX_data_scene(C); ToolSettings *settings = scene->toolsettings; + Paint *p = &settings->imapaint.paint; - if (settings->imapaint.paintcursor && !enable) { - WM_paint_cursor_end(wm, settings->imapaint.paintcursor); - settings->imapaint.paintcursor = NULL; + if (p->paint_cursor && !enable) { + WM_paint_cursor_end(p->paint_cursor); + p->paint_cursor = NULL; paint_cursor_delete_textures(); } else if (enable) { - paint_cursor_start(C, image_paint_poll); + paint_cursor_start(p, image_paint_poll); } } @@ -827,7 +822,7 @@ void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene) if (enabled) { BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT); - paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_poll); + paint_cursor_start(&imapaint->paint, image_paint_poll); } else { paint_cursor_delete_textures(); @@ -1121,6 +1116,100 @@ void PAINT_OT_sample_color(wmOperatorType *ot) /******************** texture paint toggle operator ********************/ +void ED_object_texture_paint_mode_enter_ex(Main *bmain, Scene *scene, Object *ob) +{ + bScreen *screen; + Image *ima = NULL; + ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + + /* This has to stay here to regenerate the texture paint + * cache in case we are loading a file */ + BKE_texpaint_slots_refresh_object(scene, ob); + + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + + /* entering paint mode also sets image to editors */ + if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) { + /* set the current material active paint slot on image editor */ + Material *ma = BKE_object_material_get(ob, ob->actcol); + + if (ma && ma->texpaintslot) { + ima = ma->texpaintslot[ma->paint_active_slot].ima; + } + } + else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { + ima = imapaint->canvas; + } + + if (ima) { + for (screen = bmain->screens.first; screen; screen = screen->id.next) { + ScrArea *area; + for (area = screen->areabase.first; area; area = area->next) { + SpaceLink *sl; + for (sl = area->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)sl; + + if (!sima->pin) { + ED_space_image_set(bmain, sima, NULL, ima, true); + } + } + } + } + } + } + + ob->mode |= OB_MODE_TEXTURE_PAINT; + + BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT); + + BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint); + + if (U.glreslimit != 0) { + GPU_free_images(bmain); + } + GPU_paint_set_mipmap(bmain, 0); + + toggle_paint_cursor(scene, true); + + Mesh *me = BKE_mesh_from_object(ob); + BLI_assert(me != NULL); + DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE); + WM_main_add_notifier(NC_SCENE | ND_MODE, scene); +} + +void ED_object_texture_paint_mode_enter(bContext *C) +{ + Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + ED_object_texture_paint_mode_enter_ex(bmain, scene, ob); +} + +void ED_object_texture_paint_mode_exit_ex(Main *bmain, Scene *scene, Object *ob) +{ + ob->mode &= ~OB_MODE_TEXTURE_PAINT; + + if (U.glreslimit != 0) { + GPU_free_images(bmain); + } + GPU_paint_set_mipmap(bmain, 1); + toggle_paint_cursor(scene, false); + + Mesh *me = BKE_mesh_from_object(ob); + BLI_assert(me != NULL); + DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE); + WM_main_add_notifier(NC_SCENE | ND_MODE, scene); +} + +void ED_object_texture_paint_mode_exit(bContext *C) +{ + Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + ED_object_texture_paint_mode_exit_ex(bmain, scene, ob); +} + static bool texture_paint_toggle_poll(bContext *C) { Object *ob = CTX_data_active_object(C); @@ -1150,78 +1239,12 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) } if (ob->mode & mode_flag) { - ob->mode &= ~mode_flag; - - if (U.glreslimit != 0) { - GPU_free_images(bmain); - } - GPU_paint_set_mipmap(bmain, 1); - - toggle_paint_cursor(C, 0); + ED_object_texture_paint_mode_exit_ex(bmain, scene, ob); } else { - bScreen *screen; - Image *ima = NULL; - ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - - /* This has to stay here to regenerate the texture paint - * cache in case we are loading a file */ - BKE_texpaint_slots_refresh_object(scene, ob); - - BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - - /* entering paint mode also sets image to editors */ - if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) { - /* set the current material active paint slot on image editor */ - Material *ma = BKE_object_material_get(ob, ob->actcol); - - if (ma && ma->texpaintslot) { - ima = ma->texpaintslot[ma->paint_active_slot].ima; - } - } - else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { - ima = imapaint->canvas; - } - - if (ima) { - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *sl; - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)sl; - - if (!sima->pin) { - Object *obedit = CTX_data_edit_object(C); - ED_space_image_set(bmain, sima, obedit, ima, true); - } - } - } - } - } - } - - ob->mode |= mode_flag; - - BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT); - - BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint); - - if (U.glreslimit != 0) { - GPU_free_images(bmain); - } - GPU_paint_set_mipmap(bmain, 0); - - toggle_paint_cursor(C, 1); + ED_object_texture_paint_mode_enter_ex(bmain, scene, ob); } - Mesh *me = BKE_mesh_from_object(ob); - BLI_assert(me != NULL); - DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE); - - WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); - WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); WM_toolsystem_update_from_context_view3d(C); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 018d7f72bb6..0d4e957c77b 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -90,10 +90,7 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke); float paint_stroke_distance_get(struct PaintStroke *stroke); void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data); bool paint_poll(struct bContext *C); -void paint_cursor_start(struct bContext *C, bool (*poll)(struct bContext *C)); -void paint_cursor_start_explicit(struct Paint *p, - struct wmWindowManager *wm, - bool (*poll)(struct bContext *C)); +void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C)); void paint_cursor_delete_textures(void); /* paint_vertex.c */ diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 634e29ca400..0f54d5e0821 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -1147,24 +1147,24 @@ static int stencil_fit_image_aspect_exec(bContext *C, wmOperator *op) aspy *= tex->yrepeat; } - orig_area = aspx * aspy; + orig_area = fabsf(aspx * aspy); if (do_mask) { - stencil_area = br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1]; + stencil_area = fabsf(br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1]); } else { - stencil_area = br->stencil_dimension[0] * br->stencil_dimension[1]; + stencil_area = fabsf(br->stencil_dimension[0] * br->stencil_dimension[1]); } factor = sqrtf(stencil_area / orig_area); if (do_mask) { - br->mask_stencil_dimension[0] = factor * aspx; - br->mask_stencil_dimension[1] = factor * aspy; + br->mask_stencil_dimension[0] = fabsf(factor * aspx); + br->mask_stencil_dimension[1] = fabsf(factor * aspy); } else { - br->stencil_dimension[0] = factor * aspx; - br->stencil_dimension[1] = factor * aspy; + br->stencil_dimension[0] = fabsf(factor * aspx); + br->stencil_dimension[1] = fabsf(factor * aspy); } } diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 458c24e5194..2c6f708d82a 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -230,8 +230,7 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode) SCULPT_TOOL_THUMB)) { return false; } - else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH && - brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) { + else if (SCULPT_is_cloth_deform_brush(brush)) { return false; } else { @@ -963,7 +962,7 @@ void paint_stroke_free(bContext *C, wmOperator *op) } if (stroke->stroke_cursor) { - WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor); + WM_paint_cursor_end(stroke->stroke_cursor); } BLI_freelistN(&stroke->line); @@ -1386,12 +1385,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) } if (paint_supports_smooth_stroke(br, mode)) { - stroke->stroke_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, - RGN_TYPE_ANY, - paint_poll, - paint_draw_smooth_cursor, - stroke); + stroke->stroke_cursor = WM_paint_cursor_activate( + SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_smooth_cursor, stroke); } stroke->stroke_init = true; @@ -1417,12 +1412,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) } if (br->flag & BRUSH_LINE) { - stroke->stroke_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, - RGN_TYPE_ANY, - paint_poll, - paint_draw_line_cursor, - stroke); + stroke->stroke_cursor = WM_paint_cursor_activate( + SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_line_cursor, stroke); } first_dab = true; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index a18a0145faa..6de54b3ae6a 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1193,12 +1193,8 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob) /** \name Enter Vertex/Weight Paint Mode * \{ */ -static void ed_vwpaintmode_enter_generic(Main *bmain, - Depsgraph *depsgraph, - wmWindowManager *wm, - Scene *scene, - Object *ob, - const eObjectMode mode_flag) +static void ed_vwpaintmode_enter_generic( + Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, const eObjectMode mode_flag) { ob->mode |= mode_flag; Mesh *me = BKE_mesh_from_object(ob); @@ -1214,7 +1210,7 @@ static void ed_vwpaintmode_enter_generic(Main *bmain, BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint); Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); - paint_cursor_start_explicit(paint, wm, vertex_paint_poll); + paint_cursor_start(paint, vertex_paint_poll); BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT); } else if (mode_flag == OB_MODE_WEIGHT_PAINT) { @@ -1222,7 +1218,7 @@ static void ed_vwpaintmode_enter_generic(Main *bmain, BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->wpaint); Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); - paint_cursor_start_explicit(paint, wm, weight_paint_poll); + paint_cursor_start(paint, weight_paint_poll); BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT); /* weight paint specific */ @@ -1248,32 +1244,28 @@ static void ed_vwpaintmode_enter_generic(Main *bmain, DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); } -void ED_object_vpaintmode_enter_ex( - Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm, Scene *scene, Object *ob) +void ED_object_vpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) { - ed_vwpaintmode_enter_generic(bmain, depsgraph, wm, scene, ob, OB_MODE_VERTEX_PAINT); + ed_vwpaintmode_enter_generic(bmain, depsgraph, scene, ob, OB_MODE_VERTEX_PAINT); } void ED_object_vpaintmode_enter(struct bContext *C, Depsgraph *depsgraph) { Main *bmain = CTX_data_main(C); - wmWindowManager *wm = CTX_wm_manager(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob); + ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob); } -void ED_object_wpaintmode_enter_ex( - Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm, Scene *scene, Object *ob) +void ED_object_wpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) { - ed_vwpaintmode_enter_generic(bmain, depsgraph, wm, scene, ob, OB_MODE_WEIGHT_PAINT); + ed_vwpaintmode_enter_generic(bmain, depsgraph, scene, ob, OB_MODE_WEIGHT_PAINT); } void ED_object_wpaintmode_enter(struct bContext *C, Depsgraph *depsgraph) { Main *bmain = CTX_data_main(C); - wmWindowManager *wm = CTX_wm_manager(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob); + ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob); } /** \} */ @@ -1384,8 +1376,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) if (depsgraph) { depsgraph = CTX_data_ensure_evaluated_depsgraph(C); } - wmWindowManager *wm = CTX_wm_manager(C); - ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob); + ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob); BKE_paint_toolslots_brush_validate(bmain, &ts->wpaint->paint); } @@ -2651,8 +2642,7 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) if (depsgraph) { depsgraph = CTX_data_ensure_evaluated_depsgraph(C); } - wmWindowManager *wm = CTX_wm_manager(C); - ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob); + ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob); BKE_paint_toolslots_brush_validate(bmain, &ts->vpaint->paint); } @@ -2694,19 +2684,19 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) /* Implementation notes: * * Operator->invoke() - * - validate context (add mcol) - * - create customdata storage - * - call paint once (mouse click) - * - add modal handler + * - Validate context (add #Mesh.mloopcol). + * - Create custom-data storage. + * - Call paint once (mouse click). + * - Add modal handler. * * Operator->modal() - * - for every mousemove, apply vertex paint - * - exit on mouse release, free customdata + * - For every mouse-move, apply vertex paint. + * - Exit on mouse release, free custom-data. * (return OPERATOR_FINISHED also removes handler and operator) * * For future: - * - implement a stroke event (or mousemove with past positions) - * - revise whether op->customdata should be added in object, in set_vpaint + * - implement a stroke event (or mouse-move with past positions). + * - revise whether op->customdata should be added in object, in set_vpaint. */ struct VPaintData { @@ -2718,8 +2708,10 @@ struct VPaintData { struct VertProjHandle *vp_handle; struct CoNo *vertexcosnos; - /* modify 'me->mcol' directly, since the derived mesh is drawing from this - * array, otherwise we need to refresh the modifier stack */ + /** + * Modify #Mesh.mloopcol directly, since the derived mesh is drawing from this + * array, otherwise we need to refresh the modifier stack. + */ bool use_fast_update; /* loops tagged as having been painted, to apply shared vertex color diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 855e7503e3b..b4ae9c96ba7 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -156,9 +156,16 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index) void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]) { switch (BKE_pbvh_type(ss->pbvh)) { - case PBVH_FACES: - normal_short_to_float_v3(no, ss->mvert[index].no); - return; + case PBVH_FACES: { + if (ss->shapekey_active || ss->deform_modifiers_active) { + const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh); + normal_short_to_float_v3(no, mverts[index].no); + } + else { + normal_short_to_float_v3(no, ss->mvert[index].no); + } + break; + } case PBVH_BMESH: copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no); break; @@ -254,8 +261,15 @@ bool SCULPT_vertex_visible_get(SculptSession *ss, int index) return !(ss->mvert[index].flag & ME_HIDE); case PBVH_BMESH: return !BM_elem_flag_test(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN); - case PBVH_GRIDS: - return true; + case PBVH_GRIDS: { + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + const int grid_index = index / key->grid_area; + const int vertex_index = index - grid_index * key->grid_area; + BLI_bitmap **grid_hidden = BKE_pbvh_get_grid_visibility(ss->pbvh); + if (grid_hidden && grid_hidden[grid_index]) { + return !BLI_BITMAP_TEST(grid_hidden[grid_index], vertex_index); + } + } } return true; } @@ -851,7 +865,7 @@ void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood) SCULPT_vertex_random_access_init(ss); flood->queue = BLI_gsqueue_new(sizeof(int)); - flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices"); + flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices"); } void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index) @@ -919,8 +933,8 @@ void SCULPT_floodfill_execute( SculptVertexNeighborIter ni; SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { const int to_v = ni.index; - if (flood->visited_vertices[to_v] == 0 && SCULPT_vertex_visible_get(ss, to_v)) { - flood->visited_vertices[to_v] = 1; + if (!BLI_BITMAP_TEST(flood->visited_vertices, to_v) && SCULPT_vertex_visible_get(ss, to_v)) { + BLI_BITMAP_ENABLE(flood->visited_vertices, to_v); if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) { BLI_gsqueue_push(flood->queue, &to_v); @@ -2084,9 +2098,13 @@ static float brush_strength(const Sculpt *sd, case SCULPT_TOOL_LAYER: return alpha * flip * pressure * overlap * feather; case SCULPT_TOOL_CLOTH: - /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over - * the same vertices. */ - if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) { + if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) { + /* Grab deform uses the same falloff as a regular grab brush. */ + return root_alpha * feather; + } + else if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) { + /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over + * the same vertices. */ return 0.1f * alpha * flip * pressure * overlap * feather; } else { @@ -5468,7 +5486,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe } /* The cloth brush adds the gravity as a regular force and it is processed in the solver. */ - if (ss->cache->supports_gravity && brush->sculpt_tool != SCULPT_TOOL_CLOTH) { + if (ss->cache->supports_gravity && + !ELEM(brush->sculpt_tool, SCULPT_TOOL_CLOTH, SCULPT_TOOL_DRAW_FACE_SETS)) { do_gravity(sd, ob, nodes, totnode, sd->gravity_factor); } @@ -6208,6 +6227,34 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo } } +/* In these brushes the grab delta is calculated always from the initial stroke location, which is + * generally used to create grab deformations. */ +static bool sculpt_needs_delta_from_anchored_origin(Brush *brush) +{ + return ELEM(brush->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_POSE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_ELASTIC_DEFORM) || + SCULPT_is_cloth_deform_brush(brush); +} + +/* In these brushes the grab delta is calculated from the previous stroke location, which is used + * to calculate to orientate the brush tip and deformation towards the stroke direction. */ +static bool sculpt_needs_delta_for_tip_orientation(Brush *brush) +{ + if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) { + return !SCULPT_is_cloth_deform_brush(brush); + } + return ELEM(brush->sculpt_tool, + SCULPT_TOOL_CLAY_STRIPS, + SCULPT_TOOL_PINCH, + SCULPT_TOOL_MULTIPLANE_SCRAPE, + SCULPT_TOOL_CLAY_THUMB, + SCULPT_TOOL_NUDGE, + SCULPT_TOOL_SNAKE_HOOK); +} + static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush) { SculptSession *ss = ob->sculpt; @@ -6251,38 +6298,27 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru /* Compute delta to move verts by. */ if (!cache->first_time) { - switch (tool) { - case SCULPT_TOOL_GRAB: - case SCULPT_TOOL_POSE: - case SCULPT_TOOL_THUMB: - case SCULPT_TOOL_ELASTIC_DEFORM: - sub_v3_v3v3(delta, grab_location, cache->old_grab_location); - invert_m4_m4(imat, ob->obmat); - mul_mat3_m4_v3(imat, delta); - add_v3_v3(cache->grab_delta, delta); - break; - case SCULPT_TOOL_CLAY_STRIPS: - case SCULPT_TOOL_PINCH: - case SCULPT_TOOL_CLOTH: - case SCULPT_TOOL_MULTIPLANE_SCRAPE: - case SCULPT_TOOL_CLAY_THUMB: - case SCULPT_TOOL_NUDGE: - case SCULPT_TOOL_SNAKE_HOOK: - if (brush->flag & BRUSH_ANCHORED) { - float orig[3]; - mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location); - sub_v3_v3v3(cache->grab_delta, grab_location, orig); - } - else { - sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); - } - invert_m4_m4(imat, ob->obmat); - mul_mat3_m4_v3(imat, cache->grab_delta); - break; - default: - /* Use for 'Brush.topology_rake_factor'. */ + if (sculpt_needs_delta_from_anchored_origin(brush)) { + sub_v3_v3v3(delta, grab_location, cache->old_grab_location); + invert_m4_m4(imat, ob->obmat); + mul_mat3_m4_v3(imat, delta); + add_v3_v3(cache->grab_delta, delta); + } + else if (sculpt_needs_delta_for_tip_orientation(brush)) { + if (brush->flag & BRUSH_ANCHORED) { + float orig[3]; + mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location); + sub_v3_v3v3(cache->grab_delta, grab_location, orig); + } + else { sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); - break; + } + invert_m4_m4(imat, ob->obmat); + mul_mat3_m4_v3(imat, cache->grab_delta); + } + else { + /* Use for 'Brush.topology_rake_factor'. */ + sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); } } else { @@ -6303,18 +6339,14 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru copy_v3_v3(cache->anchored_location, cache->true_location); } } - else if (tool == SCULPT_TOOL_ELASTIC_DEFORM) { + else if (tool == SCULPT_TOOL_ELASTIC_DEFORM || SCULPT_is_cloth_deform_brush(brush)) { copy_v3_v3(cache->anchored_location, cache->true_location); } else if (tool == SCULPT_TOOL_THUMB) { copy_v3_v3(cache->anchored_location, cache->orig_grab_location); } - if (ELEM(tool, - SCULPT_TOOL_GRAB, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_ELASTIC_DEFORM, - SCULPT_TOOL_POSE)) { + if (sculpt_needs_delta_from_anchored_origin(brush)) { /* Location stays the same for finding vertices in brush radius. */ copy_v3_v3(cache->true_location, cache->orig_grab_location); @@ -6385,9 +6417,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po if (cache->first_time || !((brush->flag & BRUSH_ANCHORED) || (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) || - (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || - (brush->sculpt_tool == SCULPT_TOOL_CLOTH && - brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB))) { + (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || SCULPT_is_cloth_deform_brush(brush))) { RNA_float_get_array(ptr, "location", cache->true_location); } @@ -7606,7 +7636,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain, Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT); BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT); - paint_cursor_start_explicit(paint, bmain->wm.first, SCULPT_poll_view3d); + paint_cursor_start(paint, SCULPT_poll_view3d); /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, * As long as no data was added that is not supported. */ @@ -7813,8 +7843,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float float brush_co[3]; copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss)); - char *visited_vertices = MEM_callocN(SCULPT_vertex_count_get(ss) * sizeof(char), - "visited vertices"); + BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices"); /* Assuming an average of 6 edges per vertex in a triangulated mesh. */ const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2; @@ -7838,8 +7867,8 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float totpoints++; ss->preview_vert_index_list[totpoints] = to_v; totpoints++; - if (visited_vertices[to_v] == 0) { - visited_vertices[to_v] = 1; + if (!BLI_BITMAP_TEST(visited_vertices, to_v)) { + BLI_BITMAP_ENABLE(visited_vertices, to_v); const float *co = SCULPT_vertex_co_get(ss, to_v); if (len_squared_v3v3(brush_co, co) < radius * radius) { BLI_gsqueue_push(not_visited_vertices, &to_v); @@ -7877,4 +7906,5 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_face_sets_change_visibility); WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors); WM_operatortype_append(SCULPT_OT_face_sets_init); + WM_operatortype_append(SCULPT_OT_cloth_filter); } diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c index f0f6478d3a6..bfa657147fd 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.c +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c @@ -91,7 +91,7 @@ bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, co float SCULPT_automasking_factor_get(SculptSession *ss, int vert) { - if (ss->cache->automask) { + if (ss->cache && ss->cache->automask) { return ss->cache->automask[vert]; } else { diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index 62a7f1925ab..3203282c30c 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -106,9 +106,11 @@ #define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024 #define CLOTH_SIMULATION_TIME_STEP 0.01f -static void cloth_brush_add_length_constraint(SculptSession *ss, const int v1, const int v2) +static void cloth_brush_add_length_constraint(SculptSession *ss, + SculptClothSimulation *cloth_sim, + const int v1, + const int v2) { - SculptClothSimulation *cloth_sim = ss->cache->cloth_sim; cloth_sim->length_constraints[cloth_sim->tot_length_constraints].v1 = v1; cloth_sim->length_constraints[cloth_sim->tot_length_constraints].v2 = v2; cloth_sim->length_constraints[cloth_sim->tot_length_constraints].length = len_v3v3( @@ -133,12 +135,11 @@ static void do_cloth_brush_build_constraints_task_cb_ex( SculptSession *ss = data->ob->sculpt; PBVHVertexIter vd; - const float radius = ss->cache->initial_radius; - const float limit = radius + (radius * data->brush->cloth_sim_limit); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (len_squared_v3v3(vd.co, ss->cache->initial_location) < limit * limit) { + if (len_squared_v3v3(vd.co, data->cloth_sim_initial_location) < + data->cloth_sim_radius * data->cloth_sim_radius) { SculptVertexNeighborIter ni; int build_indices[CLOTH_MAX_CONSTRAINTS_PER_VERTEX]; @@ -159,7 +160,8 @@ static void do_cloth_brush_build_constraints_task_cb_ex( for (int c_i = 0; c_i < tot_indices; c_i++) { for (int c_j = 0; c_j < tot_indices; c_j++) { if (c_i != c_j) { - cloth_brush_add_length_constraint(ss, build_indices[c_i], build_indices[c_j]); + cloth_brush_add_length_constraint( + ss, data->cloth_sim, build_indices[c_i], build_indices[c_j]); } } } @@ -192,11 +194,11 @@ static float cloth_brush_simulation_falloff_get(const Brush *brush, } } -static void cloth_brush_apply_force_to_vertex(SculptSession *ss, +static void cloth_brush_apply_force_to_vertex(SculptSession *UNUSED(ss), + SculptClothSimulation *cloth_sim, const float force[3], const int vertex_index) { - SculptClothSimulation *cloth_sim = ss->cache->cloth_sim; madd_v3_v3fl(cloth_sim->acceleration[vertex_index], force, 1.0f / cloth_sim->mass); } @@ -212,8 +214,9 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, const float *grab_delta = data->grab_delta; float(*imat)[4] = data->mat; - const bool use_falloff_plane = brush->cloth_force_falloff_type == - BRUSH_CLOTH_FORCE_FALLOFF_PLANE; + const bool use_falloff_plane = !SCULPT_is_cloth_deform_brush(brush) && + brush->cloth_force_falloff_type == + BRUSH_CLOTH_FORCE_FALLOFF_PLANE; PBVHVertexIter vd; const float bstrength = ss->cache->bstrength; @@ -246,14 +249,29 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, gravity, ss->cache->gravity_direction, -ss->cache->radius * data->sd->gravity_factor); } + /* Original data for deform brushes. */ + SculptOrigVertData orig_data; + if (SCULPT_is_cloth_deform_brush(brush)) { + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + } + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float force[3]; const float sim_factor = cloth_brush_simulation_falloff_get( brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[vd.index]); + float current_vertex_location[3]; + if (SCULPT_is_cloth_deform_brush(brush)) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + copy_v3_v3(current_vertex_location, orig_data.co); + } + else { + copy_v3_v3(current_vertex_location, vd.co); + } + /* When using the plane falloff mode the falloff is not constrained by the brush radius. */ - if (sculpt_brush_test_sq_fn(&test, vd.co) || use_falloff_plane) { + if (sculpt_brush_test_sq_fn(&test, current_vertex_location) || use_falloff_plane) { float dist = sqrtf(test.dist); @@ -264,7 +282,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, const float fade = sim_factor * bstrength * SCULPT_brush_strength_factor(ss, brush, - vd.co, + current_vertex_location, dist, vd.no, vd.fno, @@ -274,7 +292,6 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, float brush_disp[3]; float normal[3]; - if (vd.no) { normal_short_to_float_v3(normal, vd.no); } @@ -293,7 +310,10 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(force, offset, -fade); break; case BRUSH_CLOTH_DEFORM_GRAB: - mul_v3_v3fl(force, grab_delta, fade); + /* Grab writes the positions in the simulation directly without applying forces. */ + madd_v3_v3v3fl( + cloth_sim->pos[vd.index], orig_data.co, ss->cache->grab_delta_symmetry, fade); + zero_v3(force); break; case BRUSH_CLOTH_DEFORM_PINCH_POINT: if (use_falloff_plane) { @@ -329,13 +349,15 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, madd_v3_v3fl(force, gravity, fade); - cloth_brush_apply_force_to_vertex(ss, force, vd.index); + cloth_brush_apply_force_to_vertex(ss, ss->cache->cloth_sim, force, vd.index); } } BKE_pbvh_vertex_iter_end; } -static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss, Brush *brush) +static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss, + const float cloth_mass, + const float cloth_damping) { const int totverts = SCULPT_vertex_count_get(ss); SculptClothSimulation *cloth_sim; @@ -354,8 +376,8 @@ static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss, B cloth_sim->length_constraint_tweak = MEM_callocN(sizeof(float) * totverts, "cloth sim length tweak"); - cloth_sim->mass = brush->cloth_mass; - cloth_sim->damping = brush->cloth_damping; + cloth_sim->mass = cloth_mass; + cloth_sim->damping = cloth_damping; return cloth_sim; } @@ -367,12 +389,16 @@ static void do_cloth_brush_solve_simulation_task_cb_ex( SculptSession *ss = data->ob->sculpt; const Brush *brush = data->brush; PBVHVertexIter vd; - SculptClothSimulation *cloth_sim = ss->cache->cloth_sim; + SculptClothSimulation *cloth_sim = data->cloth_sim; const float time_step = data->cloth_time_step; BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - const float sim_factor = cloth_brush_simulation_falloff_get( - brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[vd.index]); + const float sim_factor = ss->cache ? cloth_brush_simulation_falloff_get( + brush, + ss->cache->radius, + ss->cache->initial_location, + cloth_sim->init_pos[vd.index]) : + 1.0f; if (sim_factor > 0.0f) { int i = vd.index; float temp[3]; @@ -393,7 +419,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex( copy_v3_fl(cloth_sim->acceleration[i], 0.0f); - copy_v3_v3(vd.co, ss->cache->cloth_sim->pos[vd.index]); + copy_v3_v3(vd.co, cloth_sim->pos[vd.index]); if (vd.mvert) { vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } @@ -405,7 +431,10 @@ static void do_cloth_brush_solve_simulation_task_cb_ex( static void cloth_brush_build_nodes_constraints(Sculpt *sd, Object *ob, PBVHNode **nodes, - int totnode) + int totnode, + SculptClothSimulation *cloth_sim, + float initial_location[3], + const float radius) { Brush *brush = BKE_paint_brush(&sd->paint); @@ -421,6 +450,9 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd, .ob = ob, .brush = brush, .nodes = nodes, + .cloth_sim = cloth_sim, + .cloth_sim_initial_location = initial_location, + .cloth_sim_radius = radius, }; BLI_task_parallel_range( 0, totnode, &build_constraints_data, do_cloth_brush_build_constraints_task_cb_ex, &settings); @@ -461,10 +493,18 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss, const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2)) * SCULPT_automasking_factor_get(ss, v2); - const float sim_factor_v1 = cloth_brush_simulation_falloff_get( - brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[v1]); - const float sim_factor_v2 = cloth_brush_simulation_falloff_get( - brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[v2]); + const float sim_factor_v1 = ss->cache ? cloth_brush_simulation_falloff_get( + brush, + ss->cache->radius, + ss->cache->initial_location, + cloth_sim->init_pos[v1]) : + 1.0f; + const float sim_factor_v2 = ss->cache ? cloth_brush_simulation_falloff_get( + brush, + ss->cache->radius, + ss->cache->initial_location, + cloth_sim->init_pos[v2]) : + 1.0f; madd_v3_v3fl(cloth_sim->pos[v1], correction_vector_half, 1.0f * mask_v1 * sim_factor_v1); madd_v3_v3fl(cloth_sim->pos[v2], correction_vector_half, -1.0f * mask_v2 * sim_factor_v2); @@ -472,13 +512,12 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss, } } -static void cloth_brush_do_simulation_step(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +static void cloth_brush_do_simulation_step( + Sculpt *sd, Object *ob, SculptClothSimulation *cloth_sim, PBVHNode **nodes, int totnode) { SculptSession *ss = ob->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); - SculptClothSimulation *cloth_sim = ss->cache->cloth_sim; - /* Update the constraints. */ cloth_brush_satisfy_constraints(ss, brush, cloth_sim); @@ -489,6 +528,7 @@ static void cloth_brush_do_simulation_step(Sculpt *sd, Object *ob, PBVHNode **no .brush = brush, .nodes = nodes, .cloth_time_step = CLOTH_SIMULATION_TIME_STEP, + .cloth_sim = cloth_sim, }; TaskParallelSettings settings; @@ -589,7 +629,8 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode /* The simulation structure only needs to be created on the first symmetry pass. */ if (ss->cache->mirror_symmetry_pass == 0) { - ss->cache->cloth_sim = cloth_brush_simulation_create(ss, brush); + ss->cache->cloth_sim = cloth_brush_simulation_create( + ss, brush->cloth_mass, brush->cloth_damping); for (int i = 0; i < totverts; i++) { copy_v3_v3(ss->cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i)); copy_v3_v3(ss->cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i)); @@ -597,7 +638,10 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode } /* Build the constraints. */ - cloth_brush_build_nodes_constraints(sd, ob, nodes, totnode); + const float radius = ss->cache->initial_radius; + const float limit = radius + (radius * brush->cloth_sim_limit); + cloth_brush_build_nodes_constraints( + sd, ob, nodes, totnode, ss->cache->cloth_sim, ss->cache->location, limit); return; } @@ -611,7 +655,7 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode cloth_brush_apply_brush_foces(sd, ob, nodes, totnode); /* Update and write the simulation to the nodes. */ - cloth_brush_do_simulation_step(sd, ob, nodes, totnode); + cloth_brush_do_simulation_step(sd, ob, ss->cache->cloth_sim, nodes, totnode); return; } @@ -687,3 +731,246 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr, immEnd(); } + +/* Cloth Filter. */ + +typedef enum eSculpClothFilterType { + CLOTH_FILTER_GRAVITY, + CLOTH_FILTER_INFLATE, + CLOTH_FILTER_EXPAND, + CLOTH_FILTER_PINCH, +} eSculptClothFilterType; + +static EnumPropertyItem prop_cloth_filter_type[] = { + {CLOTH_FILTER_GRAVITY, "GRAVITY", 0, "Gravity", "Applies gravity to the simulation"}, + {CLOTH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflates the cloth"}, + {CLOTH_FILTER_EXPAND, "EXPAND", 0, "Expand", "Expands the cloth's dimensions"}, + {CLOTH_FILTER_PINCH, + "PINCH", + 0, + "Pinch", + "Pinches the cloth to the point were the cursor was when the filter started"}, + {0, NULL, 0, NULL, NULL}, +}; + +static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + Sculpt *sd = data->sd; + SculptSession *ss = data->ob->sculpt; + PBVHNode *node = data->nodes[i]; + + SculptClothSimulation *cloth_sim = ss->filter_cache->cloth_sim; + const int filter_type = data->filter_type; + + float sculpt_gravity[3] = {0.0f}; + if (sd->gravity_object) { + copy_v3_v3(sculpt_gravity, sd->gravity_object->obmat[2]); + } + else { + sculpt_gravity[2] = -1.0f; + } + mul_v3_fl(sculpt_gravity, sd->gravity_factor * data->filter_strength); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + { + float fade = vd.mask ? *vd.mask : 0.0f; + fade = 1.0f - fade; + float force[3] = {0.0f, 0.0f, 0.0f}; + + if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) { + if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) { + continue; + } + } + + switch (filter_type) { + case CLOTH_FILTER_GRAVITY: + force[2] = -data->filter_strength * fade; + break; + case CLOTH_FILTER_INFLATE: { + float normal[3]; + SCULPT_vertex_normal_get(ss, vd.index, normal); + mul_v3_v3fl(force, normal, fade * data->filter_strength); + } break; + case CLOTH_FILTER_EXPAND: + cloth_sim->length_constraint_tweak[vd.index] += fade * data->filter_strength * 0.01f; + zero_v3(force); + break; + case CLOTH_FILTER_PINCH: + sub_v3_v3v3(force, ss->filter_cache->cloth_sim_pinch_point, vd.co); + normalize_v3(force); + mul_v3_fl(force, fade * data->filter_strength); + break; + } + + add_v3_v3(force, sculpt_gravity); + + cloth_brush_apply_force_to_vertex(ss, cloth_sim, force, vd.index); + } + BKE_pbvh_vertex_iter_end; + + BKE_pbvh_node_mark_update(node); +} + +static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + Object *ob = CTX_data_active_object(C); + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + SculptSession *ss = ob->sculpt; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + int filter_type = RNA_enum_get(op->ptr, "type"); + float filter_strength = RNA_float_get(op->ptr, "strength"); + + if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { + SCULPT_filter_cache_free(ss); + SCULPT_undo_push_end(); + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); + return OPERATOR_FINISHED; + } + + if (event->type != MOUSEMOVE) { + return OPERATOR_RUNNING_MODAL; + } + + float len = event->prevclickx - event->mval[0]; + filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC; + + SCULPT_vertex_random_access_init(ss); + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); + + const int totverts = SCULPT_vertex_count_get(ss); + for (int i = 0; i < totverts; i++) { + copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i)); + } + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .nodes = ss->filter_cache->nodes, + .filter_type = filter_type, + .filter_strength = filter_strength, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings( + &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BLI_task_parallel_range( + 0, ss->filter_cache->totnode, &data, cloth_filter_apply_forces_task_cb, &settings); + + /* Update and write the simulation to the nodes. */ + cloth_brush_do_simulation_step( + sd, ob, ss->filter_cache->cloth_sim, ss->filter_cache->nodes, ss->filter_cache->totnode); + + if (ss->deform_modifiers_active || ss->shapekey_active) { + SCULPT_flush_stroke_deform(sd, ob, true); + } + SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS); + return OPERATOR_RUNNING_MODAL; +} + +static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Object *ob = CTX_data_active_object(C); + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + + /* Update the active vertex */ + float mouse[2]; + SculptCursorGeometryInfo sgi; + mouse[0] = event->mval[0]; + mouse[1] = event->mval[1]; + SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + + SCULPT_vertex_random_access_init(ss); + + /* Needs mask data to be available as it is used when solving the constraints. */ + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); + + SCULPT_undo_push_begin("Cloth filter"); + SCULPT_filter_cache_init(ob, sd); + + const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass"); + const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping"); + ss->filter_cache->cloth_sim = cloth_brush_simulation_create(ss, cloth_mass, cloth_damping); + copy_v3_v3(ss->filter_cache->cloth_sim_pinch_point, SCULPT_active_vertex_co_get(ss)); + + const int totverts = SCULPT_vertex_count_get(ss); + for (int i = 0; i < totverts; i++) { + copy_v3_v3(ss->filter_cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i)); + copy_v3_v3(ss->filter_cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i)); + } + + float origin[3] = {0.0f, 0.0f, 0.0f}; + cloth_brush_build_nodes_constraints(sd, + ob, + ss->filter_cache->nodes, + ss->filter_cache->totnode, + ss->filter_cache->cloth_sim, + origin, + FLT_MAX); + + const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets"); + if (use_face_sets) { + ss->filter_cache->active_face_set = SCULPT_active_face_set_get(ss); + } + else { + ss->filter_cache->active_face_set = SCULPT_FACE_SET_NONE; + } + + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; +} + +void SCULPT_OT_cloth_filter(struct wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Filter cloth"; + ot->idname = "SCULPT_OT_cloth_filter"; + ot->description = "Applies a cloth simulation deformation to the entire mesh"; + + /* API callbacks. */ + ot->invoke = sculpt_cloth_filter_invoke; + ot->modal = sculpt_cloth_filter_modal; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* RNA. */ + RNA_def_enum(ot->srna, + "type", + prop_cloth_filter_type, + CLOTH_FILTER_GRAVITY, + "Filter type", + "Operation that is going to be applied to the mesh"); + RNA_def_float( + ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f); + RNA_def_float(ot->srna, + "cloth_mass", + 1.0f, + 0.0f, + 2.0f, + "Cloth Mass", + "Mass of each simulation particle", + 0.0f, + 1.0f); + RNA_def_float(ot->srna, + "cloth_damping", + 0.0f, + 0.0f, + 1.0f, + "Cloth Damping", + "How much the applied forces are propagated through the cloth", + 0.0f, + 1.0f); + ot->prop = RNA_def_boolean(ot->srna, + "use_face_sets", + false, + "Use Face Sets", + "Apply the filter only to the Face Set under the cursor"); +} diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index f96f08e3244..cbdbab14690 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -297,6 +297,25 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } if (mode == SCULPT_FACE_SET_VISIBLE) { + + /* If all vertices in the sculpt are visible, create the new face set and update the default + * color. This way the new face set will be white, which is a quick way of disabling all face + * sets and the performance hit of rendering the overlay. */ + bool all_visible = true; + for (int i = 0; i < tot_vert; i++) { + if (!SCULPT_vertex_visible_get(ss, i)) { + all_visible = false; + break; + } + } + + if (all_visible) { + Mesh *mesh = ob->data; + mesh->face_sets_color_default = next_face_set; + BKE_pbvh_face_sets_color_set( + ss->pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default); + } + for (int i = 0; i < tot_vert; i++) { if (SCULPT_vertex_visible_get(ss, i)) { SCULPT_vertex_face_set_set(ss, i, next_face_set); @@ -504,7 +523,7 @@ static void sculpt_face_sets_init_flood_fill(Object *ob, .calc_face_normal = true, })); - bool *visited_faces = MEM_callocN(sizeof(bool) * mesh->totpoly, "visited faces"); + BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces"); const int totfaces = mesh->totpoly; int *face_sets = ss->face_sets; @@ -515,12 +534,12 @@ static void sculpt_face_sets_init_flood_fill(Object *ob, int next_face_set = 1; for (int i = 0; i < totfaces; i++) { - if (!visited_faces[i]) { + if (!BLI_BITMAP_TEST(visited_faces, i)) { GSQueue *queue; queue = BLI_gsqueue_new(sizeof(int)); face_sets[i] = next_face_set; - visited_faces[i] = true; + BLI_BITMAP_ENABLE(visited_faces, i); BLI_gsqueue_push(queue, &i); while (!BLI_gsqueue_is_empty(queue)) { @@ -537,10 +556,10 @@ static void sculpt_face_sets_init_flood_fill(Object *ob, BM_ITER_ELEM (f_neighbor, &iter_b, ed, BM_FACES_OF_EDGE) { if (f_neighbor != f) { int neighbor_face_index = BM_elem_index_get(f_neighbor); - if (!visited_faces[neighbor_face_index]) { + if (!BLI_BITMAP_TEST(visited_faces, neighbor_face_index)) { if (test(bm, f, ed, f_neighbor, threshold)) { face_sets[neighbor_face_index] = next_face_set; - visited_faces[neighbor_face_index] = true; + BLI_BITMAP_ENABLE(visited_faces, neighbor_face_index); BLI_gsqueue_push(queue, &neighbor_face_index); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 7c438e9245b..fd0f67f040a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -121,6 +121,9 @@ void SCULPT_filter_cache_init(Object *ob, Sculpt *sd) void SCULPT_filter_cache_free(SculptSession *ss) { + if (ss->filter_cache->cloth_sim) { + SCULPT_cloth_simulation_free(ss->filter_cache->cloth_sim); + } MEM_SAFE_FREE(ss->filter_cache->nodes); MEM_SAFE_FREE(ss->filter_cache->mask_update_it); MEM_SAFE_FREE(ss->filter_cache->prev_mask); @@ -129,7 +132,6 @@ void SCULPT_filter_cache_free(SculptSession *ss) MEM_SAFE_FREE(ss->filter_cache->automask); MEM_SAFE_FREE(ss->filter_cache->surface_smooth_laplacian_disp); MEM_SAFE_FREE(ss->filter_cache->sharpen_factor); - MEM_SAFE_FREE(ss->filter_cache->accum_disp); MEM_SAFE_FREE(ss->filter_cache); } @@ -344,9 +346,18 @@ static void mesh_filter_task_cb(void *__restrict userdata, /* This filter can't work at full strength as it needs multiple iterations to reach a * stable state. */ fade = clamp_f(fade, 0.0f, 0.5f); + float disp_sharpen[3] = {0.0f, 0.0f, 0.0f}; + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + float disp_n[3]; + sub_v3_v3v3( + disp_n, SCULPT_vertex_co_get(ss, ni.index), SCULPT_vertex_co_get(ss, vd.index)); + mul_v3_fl(disp_n, ss->filter_cache->sharpen_factor[ni.index]); + add_v3_v3(disp_sharpen, disp_n); + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - float disp_sharpen[3]; - copy_v3_v3(disp_sharpen, ss->filter_cache->accum_disp[vd.index]); mul_v3_fl(disp_sharpen, 1.0f - ss->filter_cache->sharpen_factor[vd.index]); float disp_avg[3]; @@ -404,24 +415,6 @@ static void mesh_filter_sharpen_init_factors(SculptSession *ss) } } -static void mesh_filter_sharpen_accumulate_displacement(SculptSession *ss) -{ - const int totvert = SCULPT_vertex_count_get(ss); - for (int i = 0; i < totvert; i++) { - zero_v3(ss->filter_cache->accum_disp[i]); - } - for (int i = 0; i < totvert; i++) { - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { - float disp_n[3]; - sub_v3_v3v3(disp_n, SCULPT_vertex_co_get(ss, i), SCULPT_vertex_co_get(ss, ni.index)); - mul_v3_fl(disp_n, ss->filter_cache->sharpen_factor[i]); - add_v3_v3(ss->filter_cache->accum_disp[ni.index], disp_n); - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - } -} - static void mesh_filter_surface_smooth_displace_task_cb( void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls)) { @@ -484,10 +477,6 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets); BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false); - if (filter_type == MESH_FILTER_SHARPEN) { - mesh_filter_sharpen_accumulate_displacement(ss); - } - SculptThreadedTaskData data = { .sd = sd, .ob = ob, @@ -565,8 +554,7 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent SCULPT_filter_cache_init(ob, sd); if (use_face_sets) { - ss->filter_cache->active_face_set = SCULPT_vertex_face_set_get(ss, - SCULPT_active_vertex_get(ss)); + ss->filter_cache->active_face_set = SCULPT_active_face_set_get(ss); } else { ss->filter_cache->active_face_set = SCULPT_FACE_SET_NONE; @@ -584,7 +572,6 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SHARPEN) { ss->filter_cache->sharpen_smooth_ratio = RNA_float_get(op->ptr, "sharpen_smooth_ratio"); ss->filter_cache->sharpen_factor = MEM_mallocN(sizeof(float) * totvert, "sharpen factor"); - ss->filter_cache->accum_disp = MEM_mallocN(3 * sizeof(float) * totvert, "orco"); mesh_filter_sharpen_init_factors(ss); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 9b13f6e6c24..50808b04276 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -120,7 +120,7 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \ neighbor_iterator.i++) { \ - neighbor_iterator.index = ni.neighbors[ni.i]; + neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; /* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come * first since they are nearest for floodfill. */ @@ -128,8 +128,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \ for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \ neighbor_iterator.i--) { \ - neighbor_iterator.index = ni.neighbors[ni.i]; \ - neighbor_iterator.is_duplicate = (ni.i >= \ + neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \ + neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \ neighbor_iterator.size - neighbor_iterator.num_duplicates); #define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \ @@ -233,7 +233,7 @@ void SCULPT_flip_quat_by_symm_area(float quat[3], /* Flood Fill. */ typedef struct { GSQueue *queue; - char *visited_vertices; + BLI_bitmap *visited_vertices; } SculptFloodFill; void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood); @@ -333,6 +333,13 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr, struct SculptSession *ss, const float outline_col[3], float outline_alpha); + +BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) +{ + return brush->sculpt_tool == SCULPT_TOOL_CLOTH && + brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB; +} + /* Pose Brush. */ void SCULPT_do_pose_brush(struct Sculpt *sd, struct Object *ob, @@ -585,6 +592,9 @@ typedef struct SculptThreadedTaskData { float transform_mats[8][4][4]; float cloth_time_step; + SculptClothSimulation *cloth_sim; + float *cloth_sim_initial_location; + float cloth_sim_radius; float dirty_mask_min; float dirty_mask_max; @@ -824,12 +834,15 @@ typedef struct FilterCache { /* Sharpen mesh filter. */ float sharpen_smooth_ratio; float *sharpen_factor; - float (*accum_disp)[3]; /* unmasked nodes */ PBVHNode **nodes; int totnode; + /* Cloth filter. */ + SculptClothSimulation *cloth_sim; + float cloth_sim_pinch_point[3]; + /* mask expand iteration caches */ int mask_update_current_it; int mask_update_last_it; @@ -884,6 +897,9 @@ void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot); /* Mesh Filter. */ void SCULPT_OT_mesh_filter(struct wmOperatorType *ot); +/* Cloth Filter. */ +void SCULPT_OT_cloth_filter(struct wmOperatorType *ot); + /* Mask filter and Dirty Mask. */ void SCULPT_OT_mask_filter(struct wmOperatorType *ot); void SCULPT_OT_dirty_mask(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index c7511dfc80f..56ba15bef70 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -131,6 +131,32 @@ static void pose_solve_roll_chain(SculptPoseIKChain *ik_chain, } } +static void pose_solve_translate_chain(SculptPoseIKChain *ik_chain, const float delta[3]) +{ + SculptPoseIKChainSegment *segments = ik_chain->segments; + const int tot_segments = ik_chain->tot_segments; + + for (int i = 0; i < tot_segments; i++) { + /* Move the origin and head of each segment by delta. */ + add_v3_v3v3(segments[i].head, segments[i].initial_head, delta); + add_v3_v3v3(segments[i].orig, segments[i].initial_orig, delta); + + /* Reset the segment rotation. */ + unit_qt(segments[i].rot); + } +} + +static void pose_solve_scale_chain(SculptPoseIKChain *ik_chain, const float scale) +{ + SculptPoseIKChainSegment *segments = ik_chain->segments; + const int tot_segments = ik_chain->tot_segments; + + for (int i = 0; i < tot_segments; i++) { + /* Assign the scale to each segment. */ + segments[i].scale = scale; + } +} + static void do_pose_brush_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) @@ -363,26 +389,43 @@ typedef struct PoseFloodFillData { GSet *visited_face_sets; /* In face sets origin mode, each vertex can only be assigned to one face set. */ - bool *is_weighted; + BLI_bitmap *is_weighted; bool is_first_iteration; + /* In topology mode this stores the furthest point from the stroke origin for cases when a pose + * origin based on the brush radius can't be set. */ + float fallback_floodfill_origin[3]; + /* Fallback origin. If we can't find any face set to continue, use the position of all vertices * that have the current face set. */ float fallback_origin[3]; int fallback_count; + + /* Face Set FK mode. */ + int *floodfill_it; + float *fk_weights; + int initial_face_set; + int masked_face_set_it; + int masked_face_set; + int target_face_set; } PoseFloodFillData; static bool pose_topology_floodfill_cb( SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) { PoseFloodFillData *data = userdata; + const float *co = SCULPT_vertex_co_get(ss, to_v); if (data->pose_factor) { data->pose_factor[to_v] = 1.0f; } - const float *co = SCULPT_vertex_co_get(ss, to_v); + if (len_squared_v3v3(data->pose_initial_co, data->fallback_floodfill_origin) < + len_squared_v3v3(data->pose_initial_co, co)) { + copy_v3_v3(data->fallback_floodfill_origin, co); + } + if (sculpt_pose_brush_is_vertex_inside_brush_radius( co, data->pose_initial_co, data->radius, data->symm)) { return true; @@ -415,7 +458,7 @@ static bool pose_face_sets_floodfill_cb( if (data->current_face_set == SCULPT_FACE_SET_NONE) { data->pose_factor[index] = 1.0f; - data->is_weighted[index] = true; + BLI_BITMAP_ENABLE(data->is_weighted, index); if (sculpt_pose_brush_is_vertex_inside_brush_radius( co, data->pose_initial_co, data->radius, data->symm)) { @@ -446,9 +489,9 @@ static bool pose_face_sets_floodfill_cb( if (is_vertex_valid) { - if (!data->is_weighted[index]) { + if (!BLI_BITMAP_TEST(data->is_weighted, index)) { data->pose_factor[index] = 1.0f; - data->is_weighted[index] = true; + BLI_BITMAP_ENABLE(data->is_weighted, index); visit_next = true; } @@ -521,12 +564,16 @@ void SCULPT_pose_calc_pose_data(Sculpt *sd, }; zero_v3(fdata.pose_origin); copy_v3_v3(fdata.pose_initial_co, initial_location); + copy_v3_v3(fdata.fallback_floodfill_origin, initial_location); SCULPT_floodfill_execute(ss, &flood, pose_topology_floodfill_cb, &fdata); SCULPT_floodfill_free(&flood); if (fdata.tot_co > 0) { mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co); } + else { + copy_v3_v3(fdata.pose_origin, fdata.fallback_floodfill_origin); + } /* Offset the pose origin. */ float pose_d[3]; @@ -600,7 +647,19 @@ static void pose_ik_chain_origin_heads_init(SculptPoseIKChain *ik_chain, copy_v3_v3(ik_chain->segments[i].initial_orig, origin); copy_v3_v3(ik_chain->segments[i].initial_head, head); ik_chain->segments[i].len = len_v3v3(head, origin); + ik_chain->segments[i].scale = 1.0f; + } +} + +static int pose_brush_num_effective_segments(const Brush *brush) +{ + /* Scaling multiple segments at the same time is not supported as the IK solver can't handle + * changes in the segment's length. It will also required a better weight distribution to avoid + * artifacts in the areas affected by multiple segments. */ + if (brush->pose_deform_type == BRUSH_POSE_DEFORM_SCALE_TRASLATE) { + return 1; } + return brush->pose_ik_segments; } static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd, @@ -629,7 +688,8 @@ static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd, pose_factor_grow[nearest_vertex_index] = 1.0f; - SculptPoseIKChain *ik_chain = pose_ik_chain_new(br->pose_ik_segments, totvert); + const int tot_segments = pose_brush_num_effective_segments(br); + SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert); /* Calculate the first segment in the chain using the brush radius and the pose origin offset. */ copy_v3_v3(next_chain_segment_target, initial_location); @@ -688,11 +748,13 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets( int totvert = SCULPT_vertex_count_get(ss); - SculptPoseIKChain *ik_chain = pose_ik_chain_new(br->pose_ik_segments, totvert); + const int tot_segments = pose_brush_num_effective_segments(br); + + SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert); GSet *visited_face_sets = BLI_gset_int_new_ex("visited_face_sets", ik_chain->tot_segments); - bool *is_weighted = MEM_callocN(sizeof(bool) * totvert, "weighted"); + BLI_bitmap *is_weighted = BLI_BITMAP_NEW(totvert, "weighted"); int current_face_set = SCULPT_FACE_SET_NONE; int prev_face_set = SCULPT_FACE_SET_NONE; @@ -752,6 +814,119 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets( return ik_chain; } +static bool pose_face_sets_fk_find_masked_floodfill_cb( + SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) +{ + PoseFloodFillData *data = userdata; + + if (!is_duplicate) { + data->floodfill_it[to_v] = data->floodfill_it[from_v] + 1; + } + else { + data->floodfill_it[to_v] = data->floodfill_it[from_v]; + } + + const int to_face_set = SCULPT_vertex_face_set_get(ss, to_v); + if (SCULPT_vertex_has_unique_face_set(ss, to_v) && + !SCULPT_vertex_has_unique_face_set(ss, from_v) && + SCULPT_vertex_has_face_set(ss, from_v, to_face_set)) { + + if (data->floodfill_it[to_v] > data->masked_face_set_it) { + data->masked_face_set = to_face_set; + data->masked_face_set_it = data->floodfill_it[to_v]; + } + + if (data->target_face_set == SCULPT_FACE_SET_NONE) { + data->target_face_set = to_face_set; + } + } + + return SCULPT_vertex_has_face_set(ss, to_v, data->initial_face_set); +} + +static bool pose_face_sets_fk_set_weights_floodfill_cb( + SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata) +{ + PoseFloodFillData *data = userdata; + data->fk_weights[to_v] = 1.0f; + return !SCULPT_vertex_has_face_set(ss, to_v, data->masked_face_set); +} + +static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk( + Sculpt *sd, Object *ob, SculptSession *ss, const float radius, const float *initial_location) +{ + const int totvert = SCULPT_vertex_count_get(ss); + + SculptPoseIKChain *ik_chain = pose_ik_chain_new(1, totvert); + + const int active_vertex = SCULPT_active_vertex_get(ss); + const int active_face_set = SCULPT_active_face_set_get(ss); + + SculptFloodFill flood; + SCULPT_floodfill_init(ss, &flood); + SCULPT_floodfill_add_initial(&flood, active_vertex); + PoseFloodFillData fdata; + fdata.floodfill_it = MEM_calloc_arrayN(totvert, sizeof(int), "floodfill iteration"); + fdata.floodfill_it[active_vertex] = 1; + fdata.initial_face_set = active_face_set; + fdata.masked_face_set = SCULPT_FACE_SET_NONE; + fdata.target_face_set = SCULPT_FACE_SET_NONE; + fdata.masked_face_set_it = 0; + SCULPT_floodfill_execute(ss, &flood, pose_face_sets_fk_find_masked_floodfill_cb, &fdata); + SCULPT_floodfill_free(&flood); + + int origin_count = 0; + float origin_acc[3] = {0.0f}; + for (int i = 0; i < totvert; i++) { + if (fdata.floodfill_it[i] != 0 && SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) && + SCULPT_vertex_has_face_set(ss, i, fdata.masked_face_set)) { + add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, i)); + origin_count++; + } + } + + int target_count = 0; + float target_acc[3] = {0.0f}; + if (fdata.target_face_set != fdata.masked_face_set) { + for (int i = 0; i < totvert; i++) { + if (fdata.floodfill_it[i] != 0 && + SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) && + SCULPT_vertex_has_face_set(ss, i, fdata.target_face_set)) { + add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, i)); + target_count++; + } + } + } + + MEM_freeN(fdata.floodfill_it); + + if (origin_count > 0) { + copy_v3_v3(ik_chain->segments[0].orig, origin_acc); + mul_v3_fl(ik_chain->segments[0].orig, 1.0f / origin_count); + } + else { + zero_v3(ik_chain->segments[0].orig); + } + + if (target_count > 0) { + copy_v3_v3(ik_chain->segments[0].head, target_acc); + mul_v3_fl(ik_chain->segments[0].head, 1.0f / target_count); + sub_v3_v3v3(ik_chain->grab_delta_offset, ik_chain->segments[0].head, initial_location); + } + else { + copy_v3_v3(ik_chain->segments[0].head, initial_location); + } + + SCULPT_floodfill_init(ss, &flood); + SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius); + fdata.fk_weights = ik_chain->segments[0].weights; + SCULPT_floodfill_execute(ss, &flood, pose_face_sets_fk_set_weights_floodfill_cb, &fdata); + SCULPT_floodfill_free(&flood); + + pose_ik_chain_origin_heads_init(ik_chain, ik_chain->segments[0].head); + return ik_chain; +} + SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd, Object *ob, SculptSession *ss, @@ -766,6 +941,9 @@ SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd, case BRUSH_POSE_ORIGIN_FACE_SETS: return pose_ik_chain_init_face_sets(sd, ob, ss, br, radius); break; + case BRUSH_POSE_ORIGIN_FACE_SETS_FK: + return pose_ik_chain_init_face_sets_fk(sd, ob, ss, radius, initial_location); + break; } return NULL; } @@ -802,13 +980,86 @@ void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br MEM_SAFE_FREE(nodes); } +static void sculpt_pose_do_translate_deform(SculptSession *ss, Brush *brush) +{ + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + BKE_curvemapping_initialize(brush->curve); + pose_solve_translate_chain(ik_chain, ss->cache->grab_delta); +} + +static void sculpt_pose_do_scale_deform(SculptSession *ss, Brush *brush) +{ + float ik_target[3]; + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + + copy_v3_v3(ik_target, ss->cache->true_location); + add_v3_v3(ik_target, ss->cache->grab_delta); + + /* Solve the IK for the first segment to include rotation as part of scale. */ + pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED); + + /* Calculate a scale factor based on the grab delta. */ + float plane[4]; + float segment_dir[3]; + sub_v3_v3v3(segment_dir, ik_chain->segments[0].initial_head, ik_chain->segments[0].initial_orig); + normalize_v3(segment_dir); + plane_from_point_normal_v3(plane, ik_chain->segments[0].initial_head, segment_dir); + const float segment_len = ik_chain->segments[0].len; + const float scale = segment_len / (segment_len - dist_signed_to_plane_v3(ik_target, plane)); + + /* Write the scale into the segments. */ + pose_solve_scale_chain(ik_chain, scale); +} + +static void sculpt_pose_do_twist_deform(SculptSession *ss, Brush *brush) +{ + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + + /* Calculate the maximum roll. 0.02 radians per pixel works fine. */ + float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength * 0.02f; + BKE_curvemapping_initialize(brush->curve); + pose_solve_roll_chain(ik_chain, brush, roll); +} + +static void sculpt_pose_do_rotate_deform(SculptSession *ss, Brush *brush) +{ + float ik_target[3]; + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + + /* Calculate the IK target. */ + copy_v3_v3(ik_target, ss->cache->true_location); + add_v3_v3(ik_target, ss->cache->grab_delta); + add_v3_v3(ik_target, ik_chain->grab_delta_offset); + + /* Solve the IK positions. */ + pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED); +} + +static void sculpt_pose_do_rotate_twist_deform(SculptSession *ss, Brush *brush) +{ + if (ss->cache->invert) { + sculpt_pose_do_twist_deform(ss, brush); + } + else { + sculpt_pose_do_rotate_deform(ss, brush); + } +} + +static void sculpt_pose_do_scale_translate_deform(SculptSession *ss, Brush *brush) +{ + if (ss->cache->invert) { + sculpt_pose_do_translate_deform(ss, brush); + } + else { + sculpt_pose_do_scale_deform(ss, brush); + } +} + /* Main Brush Function. */ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { SculptSession *ss = ob->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); - float grab_delta[3]; - float ik_target[3]; const ePaintSymmetryFlags symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; /* The pose brush applies all enabled symmetry axis in a single iteration, so the rest can be @@ -819,25 +1070,13 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; - /* Solve the positions and rotations of the IK chain. */ - if (ss->cache->invert) { - /* Roll Mode. */ - /* Calculate the maximum roll. 0.02 radians per pixel works fine. */ - float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength * - 0.02f; - BKE_curvemapping_initialize(brush->curve); - pose_solve_roll_chain(ik_chain, brush, roll); - } - else { - /* IK follow target mode. */ - /* Calculate the IK target. */ - - copy_v3_v3(grab_delta, ss->cache->grab_delta); - copy_v3_v3(ik_target, ss->cache->true_location); - add_v3_v3(ik_target, ss->cache->grab_delta); - - /* Solve the IK positions. */ - pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED); + switch (brush->pose_deform_type) { + case BRUSH_POSE_DEFORM_ROTATE_TWIST: + sculpt_pose_do_rotate_twist_deform(ss, brush); + break; + case BRUSH_POSE_DEFORM_SCALE_TRASLATE: + sculpt_pose_do_scale_translate_deform(ss, brush); + break; } /* Flip the segment chain in all symmetry axis and calculate the transform matrices for each @@ -845,7 +1084,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) /* This can be optimized by skipping the calculation of matrices where the symmetry is not * enabled. */ for (int symm_it = 0; symm_it < PAINT_SYMM_AREAS; symm_it++) { - for (int i = 0; i < brush->pose_ik_segments; i++) { + for (int i = 0; i < ik_chain->tot_segments; i++) { float symm_rot[4]; float symm_orig[3]; float symm_initial_orig[3]; @@ -865,6 +1104,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) /* Create the transform matrix and store it in the segment. */ unit_m4(ik_chain->segments[i].pivot_mat[symm_it]); quat_to_mat4(ik_chain->segments[i].trans_mat[symm_it], symm_rot); + mul_m4_fl(ik_chain->segments[i].trans_mat[symm_it], ik_chain->segments[i].scale); translate_m4(ik_chain->segments[i].trans_mat[symm_it], symm_orig[0] - symm_initial_orig[0], @@ -882,7 +1122,6 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .ob = ob, .brush = brush, .nodes = nodes, - .grab_delta = grab_delta, }; TaskParallelSettings settings; diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 4a449e529d5..d21552efafe 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -1570,7 +1570,7 @@ static void sculpt_undo_push_all_grids(Object *object) /* It is possible that undo push is done from an object state where there is no PBVH. This * happens, for example, when an operation which tagged for geometry update was performed prior - * to the current operation without making any stroke inbetween. + * to the current operation without making any stroke in between. * * Skip pushing nodes based on the following logic: on redo SCULPT_UNDO_COORDS will ensure * PBVH for the new base geometry, which will have same coordinates as if we create PBVH here. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index a1094dde749..d6b259c9ac0 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -548,8 +548,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm if (do_island_optimization) { UvElement *element; UvNearestHit hit = UV_NEAREST_HIT_INIT; - Image *ima = CTX_data_edit_image(C); - uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit); + uv_find_nearest_vert(scene, obedit, co, 0.0f, &hit); element = BM_uv_element_get(data->elementMap, hit.efa, hit.l); island_index = element->island; diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index e90122f2585..b390e4b56d6 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -218,7 +218,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const float tmin, tmax; /* get range and apply necessary scaling before processing */ - if (calc_fcurve_range(fcu, &tmin, &tmax, onlySel, false)) { + if (BKE_fcurve_calc_range(fcu, &tmin, &tmax, onlySel, false)) { if (adt) { tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP); @@ -490,7 +490,7 @@ void ACTION_OT_view_frame(wmOperatorType *ot) /* identifiers */ ot->name = "Go to Current Frame"; ot->idname = "ACTION_OT_view_frame"; - ot->description = "Move the view to the playhead"; + ot->description = "Move the view to the current frame"; /* api callbacks */ ot->exec = actkeys_view_frame_exec; diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index f81aaeb0ee4..e084d5fcdf2 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -135,6 +135,7 @@ void ED_spacetypes_init(void) ED_gizmotypes_blank_3d(); ED_gizmotypes_cage_2d(); ED_gizmotypes_cage_3d(); + ED_gizmotypes_snap_3d(); /* register types for operators and gizmos */ spacetypes = BKE_spacetypes_list(); diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 6b7f86a9143..3dc5eca8a8b 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -373,7 +373,7 @@ static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg) /* set user as active */ if (user->node) { - ED_node_set_active(CTX_data_main(C), user->ntree, user->node); + ED_node_set_active(CTX_data_main(C), user->ntree, user->node, NULL); ct->texture = NULL; } else { @@ -545,7 +545,7 @@ static void template_texture_show(bContext *C, void *data_p, void *prop_p) } } -void uiTemplateTextureShow(uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop) +void uiTemplateTextureShow(uiLayout *layout, const bContext *C, PointerRNA *ptr, PropertyRNA *prop) { /* button to quickly show texture in texture tab */ SpaceProperties *sbuts = CTX_wm_space_properties(C); diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index e3f7cffc8ed..5ab3304c0e6 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -30,7 +30,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" -#include "BKE_gpencil_modifier.h" /* Types for regiestering panels. */ +#include "BKE_gpencil_modifier.h" /* Types for registering panels. */ #include "BKE_modifier.h" #include "BKE_screen.h" #include "BKE_shader_fx.h" @@ -39,6 +39,8 @@ #include "DNA_modifier_types.h" #include "DNA_shader_fx_types.h" +#include "DNA_modifier_types.h" + #include "ED_screen.h" #include "ED_space_api.h" #include "ED_view3d.h" /* To draw toolbar UI. */ diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index 6b741363d42..805e9608fec 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -142,10 +142,7 @@ static void console_cursor_wrap_offset( return; } -static void console_textview_draw_cursor(TextViewContext *tvc, - int cwidth, - int columns, - int descender) +static void console_textview_draw_cursor(TextViewContext *tvc, int cwidth, int columns) { int pen[2]; { @@ -171,8 +168,7 @@ static void console_textview_draw_cursor(TextViewContext *tvc, immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immUniformThemeColor(TH_CONSOLE_CURSOR); - immRectf( - pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight + descender); + immRectf(pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight); immUnbindProgram(); } diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 226e7ae6b22..8d14664c0fa 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -220,7 +220,8 @@ static void file_draw_preview(uiBlock *block, const bool is_icon, const int typeflags, const bool drag, - const bool dimmed) + const bool dimmed, + const bool is_link) { uiBut *but; float fx, fy; @@ -312,37 +313,57 @@ static void file_draw_preview(uiBlock *block, GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - if (icon && !(typeflags & FILE_TYPE_FTFONT)) { - /* size of center icon is scaled to fit container and UI scale */ + if (icon && is_icon) { + /* Small icon in the middle of large image, scaled to fit container and UI scale */ float icon_x, icon_y; - - if (is_icon) { - const float icon_size = 16.0f / icon_aspect * U.dpi_fac; - float icon_opacity = 0.3f; - uchar icon_color[4] = {0, 0, 0, 255}; - float bgcolor[4]; - UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor); - if (rgb_to_grayscale(bgcolor) < 0.5f) { - icon_color[0] = 255; - icon_color[1] = 255; - icon_color[2] = 255; - } - icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); - icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f)); - UI_icon_draw_ex( - icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); + const float icon_size = 16.0f / icon_aspect * U.dpi_fac; + float icon_opacity = 0.3f; + uchar icon_color[4] = {0, 0, 0, 255}; + float bgcolor[4]; + UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor); + if (rgb_to_grayscale(bgcolor) < 0.5f) { + icon_color[0] = 255; + icon_color[1] = 255; + icon_color[2] = 255; } - else { + icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); + icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f)); + UI_icon_draw_ex( + icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); + } + + if (is_link) { + /* Arrow icon to indicate it is a shortcut, link, or alias. */ + float icon_x, icon_y; + icon_x = xco + (2.0f * UI_DPI_FAC); + icon_y = yco + (2.0f * UI_DPI_FAC); + const int arrow = ICON_LOOP_FORWARDS; + if (!is_icon) { + /* Arrow at very bottom-left if preview style. */ const uchar dark[4] = {0, 0, 0, 255}; const uchar light[4] = {255, 255, 255, 255}; - - /* Smaller, fainter icon for preview image thumbnail. */ - icon_x = xco + (2.0f * UI_DPI_FAC); - icon_y = yco + (2.0f * UI_DPI_FAC); - - UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); - UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); + UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); } + else { + /* Link to folder or non-previewed file. */ + uchar icon_color[4]; + UI_GetThemeColor4ubv(TH_BACK, icon_color); + icon_x = xco + ((typeflags & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx; + icon_y = yco + ((typeflags & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy; + UI_icon_draw_ex( + icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false); + } + } + else if (icon && !is_icon && !(typeflags & FILE_TYPE_FTFONT)) { + /* Smaller, fainter icon at bottom-left for preview image thumbnail, but not for fonts. */ + float icon_x, icon_y; + const uchar dark[4] = {0, 0, 0, 255}; + const uchar light[4] = {255, 255, 255, 255}; + icon_x = xco + (2.0f * UI_DPI_FAC); + icon_y = yco + (2.0f * UI_DPI_FAC); + UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); + UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); } /* Contrasting outline around some preview types. */ @@ -788,6 +809,7 @@ void file_draw_list(const bContext *C, ARegion *region) /* don't drag parent or refresh items */ do_drag = !(FILENAME_IS_CURRPAR(file->relpath)); const bool is_hidden = (file->attributes & FILE_ATTR_HIDDEN); + const bool is_link = (file->attributes & FILE_ATTR_ANY_LINK); if (FILE_IMGDISPLAY == params->display) { const int icon = filelist_geticon(files, i, false); @@ -809,7 +831,8 @@ void file_draw_list(const bContext *C, ARegion *region) is_icon, file->typeflag, do_drag, - is_hidden); + is_hidden, + is_link); } else { file_draw_icon(block, diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index a5263378850..41d32fda088 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1469,9 +1469,12 @@ void file_sfile_to_operator_ex(bContext *C, wmOperator *op, SpaceFile *sfile, ch for (i = 0; i < numfiles; i++) { if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { FileDirEntry *file = filelist_file(sfile->files, i); - RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", file->relpath); - num_files++; + /* Cannot (currently) mix regular items and alias/shortcuts in multiple selection. */ + if (!file->redirection_path) { + RNA_property_collection_add(op->ptr, prop, &itemptr); + RNA_string_set(&itemptr, "name", file->relpath); + num_files++; + } } } /* make sure the file specified in the filename button is added even if no @@ -1617,9 +1620,23 @@ static int file_exec(bContext *C, wmOperator *exec_op) Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); - const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); + struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); char filepath[FILE_MAX]; + if (file && file->redirection_path) { + /* redirection_path is an absolute path that takes precedence + * over using sfile->params->dir + sfile->params->file. */ + BLI_split_dirfile(file->redirection_path, + sfile->params->dir, + sfile->params->file, + sizeof(sfile->params->dir), + sizeof(sfile->params->file)); + /* Update relpath with redirected filename as well so that the alternative + * combination of sfile->params->dir + relpath remains valid as well. */ + MEM_freeN(file->relpath); + file->relpath = BLI_strdup(sfile->params->file); + } + /* directory change */ if (file && (file->typeflag & FILE_TYPE_DIR)) { if (!file->relpath) { @@ -1634,9 +1651,6 @@ static int file_exec(bContext *C, wmOperator *exec_op) BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath); BLI_path_slash_ensure(sfile->params->dir); } - if (file->redirection_path) { - STRNCPY(sfile->params->dir, file->redirection_path); - } ED_file_change_dir(C); } /* opening file - sends events now, so things get handled on windowqueue level */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 7f6d0658ec8..d8d7ef01a2e 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1015,6 +1015,7 @@ static int filelist_geticon_ex(FileDirEntry *file, /* If this path is in System list or path cache then use that icon. */ struct FSMenu *fsmenu = ED_fsmenu_get(); FSMenuCategory categories[] = { + FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_OTHER, }; @@ -1022,10 +1023,16 @@ static int filelist_geticon_ex(FileDirEntry *file, for (int i = 0; i < ARRAY_SIZE(categories); i++) { FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, categories[i]); char fullpath[FILE_MAX_LIBEXTRA]; - BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); - BLI_path_slash_ensure(fullpath); + char *target = fullpath; + if (file->redirection_path) { + target = file->redirection_path; + } + else { + BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); + BLI_path_slash_ensure(fullpath); + } for (; tfsm; tfsm = tfsm->next) { - if (STREQ(tfsm->path, fullpath)) { + if (STREQ(tfsm->path, target)) { /* Never want a little folder inside a large one. */ return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon; } @@ -1033,10 +1040,7 @@ static int filelist_geticon_ex(FileDirEntry *file, } } - if (file->attributes & FILE_ATTR_ANY_LINK) { - return ICON_LOOP_FORWARDS; - } - else if (file->attributes & FILE_ATTR_OFFLINE) { + if (file->attributes & FILE_ATTR_OFFLINE) { return ICON_ERROR; } else if (file->attributes & FILE_ATTR_TEMPORARY) { @@ -1375,8 +1379,15 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); - BLI_join_dirfile( - preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); + + if (entry->redirection_path) { + BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR); + } + else { + BLI_join_dirfile( + preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); + } + preview->index = index; preview->flags = entry->typeflag; preview->img = NULL; @@ -2270,13 +2281,6 @@ int ED_path_extension_type(const char *path) return 0; } -static int file_extension_type(const char *dir, const char *relpath) -{ - char path[FILE_MAX]; - BLI_join_dirfile(path, sizeof(path), dir, relpath); - return ED_path_extension_type(path); -} - int ED_file_extension_icon(const char *path) { const int type = ED_path_extension_type(path); @@ -2475,7 +2479,8 @@ static int filelist_readjob_list_dir(const char *root, { struct direntry *files; int nbr_files, nbr_entries = 0; - char path[FILE_MAX]; + /* Full path of the item. */ + char full_path[FILE_MAX]; nbr_files = BLI_filelist_dir_contents(root, &files); if (files) { @@ -2491,38 +2496,53 @@ static int filelist_readjob_list_dir(const char *root, entry->relpath = MEM_dupallocN(files[i].relname); entry->st = files[i].s; - BLI_join_dirfile(path, sizeof(path), root, entry->relpath); + BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath); + char *target = full_path; - /* Set file type. */ + /* Set initial file type and attributes. */ + entry->attributes = BLI_file_attributes(full_path); if (S_ISDIR(files[i].s.st_mode)) { entry->typeflag = FILE_TYPE_DIR; } - else if (do_lib && BLO_has_bfile_extension(entry->relpath)) { - /* If we are considering .blend files as libs, promote them to directory status. */ - entry->typeflag = FILE_TYPE_BLENDER; - /* prevent current file being used as acceptable dir */ - if (BLI_path_cmp(main_name, path) != 0) { - entry->typeflag |= FILE_TYPE_DIR; - } - } - /* Otherwise, do not check extensions for directories! */ - else if (!(entry->typeflag & FILE_TYPE_DIR)) { - entry->typeflag = file_extension_type(root, entry->relpath); - if (filter_glob[0] && BLI_path_extension_check_glob(entry->relpath, filter_glob)) { - entry->typeflag |= FILE_TYPE_OPERATOR; - } - } - /* Set file attributes. */ - entry->attributes = BLI_file_attributes(path); + /* Is this a file that points to another file? */ if (entry->attributes & FILE_ATTR_ALIAS) { entry->redirection_path = MEM_callocN(FILE_MAXDIR, __func__); - if (BLI_file_alias_target(entry->redirection_path, path)) { + if (BLI_file_alias_target(entry->redirection_path, full_path)) { if (BLI_is_dir(entry->redirection_path)) { entry->typeflag = FILE_TYPE_DIR; + BLI_path_slash_ensure(entry->redirection_path); } - else + else { entry->typeflag = ED_path_extension_type(entry->redirection_path); + } + target = entry->redirection_path; +#ifdef WIN32 + /* On Windows don't show ".lnk" extension for valid shortcuts. */ + BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, ""); +#endif + } + else { + MEM_freeN(entry->redirection_path); + entry->redirection_path = NULL; + entry->attributes |= FILE_ATTR_HIDDEN; + } + } + + if (!(entry->typeflag & FILE_TYPE_DIR)) { + if (do_lib && BLO_has_bfile_extension(target)) { + /* If we are considering .blend files as libs, promote them to directory status. */ + entry->typeflag = FILE_TYPE_BLENDER; + /* prevent current file being used as acceptable dir */ + if (BLI_path_cmp(main_name, target) != 0) { + entry->typeflag |= FILE_TYPE_DIR; + } + } + else { + entry->typeflag = ED_path_extension_type(target); + if (filter_glob[0] && BLI_path_extension_check_glob(target, filter_glob)) { + entry->typeflag |= FILE_TYPE_OPERATOR; + } } } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 66157296064..b03df01a02b 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -418,7 +418,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, else { /* if we're bookmarking this, file should come * before the last separator, only automatically added - * current dir go after the last sep. */ + * current dir go after the last separator. */ if (flag & FS_INSERT_SAVE) { break; } @@ -848,6 +848,10 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) CFRelease(volEnum); + /* kLSSharedFileListFavoriteItems is deprecated, but available till macOS 10.15. + * Will have to find a new method to sync the Finder Favorites with File Browser. */ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" /* Finally get user favorite places */ if (read_bookmarks) { UInt32 seed; @@ -891,6 +895,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) CFRelease(pathesArray); CFRelease(list); } +# pragma GCC diagnostic pop } # else /* unix */ diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 185bf029f1a..179d73a38ba 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -1284,7 +1284,7 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *panel) FCurve *fcu; bool driven, special; - fcu = rna_get_fcurve_context_ui( + fcu = BKE_fcurve_find_by_rna_context_ui( (bContext *)C, &ptr, prop, index, NULL, NULL, &driven, &special); /* Hack: Force all buttons in this panel to be able to know the driver button diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 68fef5e921f..f2071d292ca 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -1159,7 +1159,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor * we must obey this. */ if (!(sipo->flag & SIPO_SELCUVERTSONLY) || (fcu->flag & FCURVE_SELECTED)) { - if (!fcurve_are_keyframes_usable(fcu) && !(fcu->fpt && fcu->totvert)) { + if (!BKE_fcurve_are_keyframes_usable(fcu) && !(fcu->fpt && fcu->totvert)) { /* only draw controls if this is the active modifier */ if ((fcu->flag & FCURVE_ACTIVE) && (fcm)) { switch (fcm->type) { diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 8ffd2844f1a..03151da8d4d 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -126,7 +126,8 @@ void get_graph_keyframe_extents(bAnimContext *ac, float unitFac, offset; /* get range */ - if (calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) { + if (BKE_fcurve_calc_bounds( + fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) { short mapping_flag = ANIM_get_normalization_flags(ac); /* apply NLA scaling */ @@ -385,7 +386,7 @@ void GRAPH_OT_view_frame(wmOperatorType *ot) /* identifiers */ ot->name = "Go to Current Frame"; ot->idname = "GRAPH_OT_view_frame"; - ot->description = "Move the view to the playhead"; + ot->description = "Move the view to the current frame"; /* api callbacks */ ot->exec = graphkeys_view_frame_exec; @@ -409,7 +410,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end) int filter; /* free existing ghost curves */ - free_fcurves(&sipo->runtime.ghost_curves); + BKE_fcurves_free(&sipo->runtime.ghost_curves); /* sanity check */ if (start >= end) { @@ -425,7 +426,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end) /* loop through filtered data and add keys between selected keyframes on every frame */ for (ale = anim_data.first; ale; ale = ale->next) { FCurve *fcu = (FCurve *)ale->key_data; - FCurve *gcu = MEM_callocN(sizeof(FCurve), "Ghost FCurve"); + FCurve *gcu = BKE_fcurve_create(); AnimData *adt = ANIM_nla_mapping_get(ac, ale); ChannelDriver *driver = fcu->driver; FPoint *fpt; @@ -536,7 +537,7 @@ static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } /* free ghost curves */ - free_fcurves(&sipo->runtime.ghost_curves); + BKE_fcurves_free(&sipo->runtime.ghost_curves); /* update this editor only */ ED_area_tag_redraw(CTX_wm_area(C)); @@ -806,7 +807,7 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op) /* when there are F-Modifiers on the curve, only allow adding * keyframes if these will be visible after doing so... */ - if (fcurve_is_keyframable(fcu)) { + if (BKE_fcurve_is_keyframable(fcu)) { ListBase anim_data; ToolSettings *ts = ac.scene->toolsettings; diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c index 575cba07f04..03ed8870d67 100644 --- a/source/blender/editors/space_graph/graph_utils.c +++ b/source/blender/editors/space_graph/graph_utils.c @@ -171,7 +171,7 @@ bool graphop_visible_keyframes_poll(bContext *C) if (fcu->bezt == NULL) { continue; } - if (fcurve_are_keyframes_usable(fcu)) { + if (BKE_fcurve_are_keyframes_usable(fcu)) { found = 1; break; } @@ -225,7 +225,7 @@ bool graphop_editable_keyframes_poll(bContext *C) if (fcu->bezt == NULL) { continue; } - if (fcurve_is_keyframable(fcu)) { + if (BKE_fcurve_is_keyframable(fcu)) { found = 1; break; } diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index bd82b8ecf2e..b9c7c529620 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -145,7 +145,7 @@ static void graph_free(SpaceLink *sl) } if (si->runtime.ghost_curves.first) { - free_fcurves(&si->runtime.ghost_curves); + BKE_fcurves_free(&si->runtime.ghost_curves); } } diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 6037c1d2ec8..9040ca5e79c 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -476,7 +476,7 @@ static void sima_draw_zbuf_pixels( IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_uniform_vector( - state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red); + state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); immDrawPixelsTex( &state, x1, y1, rectx, recty, GL_RED, GL_INT, GL_NEAREST, recti, zoomx, zoomy, NULL); @@ -524,7 +524,7 @@ static void sima_draw_zbuffloat_pixels(Scene *scene, IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_uniform_vector( - state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red); + state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); immDrawPixelsTex( &state, x1, y1, rectx, recty, GL_RED, GL_FLOAT, GL_NEAREST, rectf, zoomx, zoomy, NULL); @@ -637,7 +637,7 @@ static void draw_image_buffer(const bContext *C, IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_uniform_vector( - state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, shuffle); + state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, shuffle); IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings); display_buffer = IMB_display_buffer_acquire( diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index eb97077f77a..8cb85ce9800 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -885,7 +885,6 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene; ViewLayer *view_layer; Object *obedit; - Image *ima; /* retrieve state */ sima = CTX_wm_space_image(C); @@ -894,15 +893,13 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) view_layer = CTX_data_view_layer(C); obedit = CTX_data_edit_object(C); - ima = ED_space_image(sima); - /* get bounds */ float min[2], max[2]; if (ED_space_image_show_uvedit(sima, obedit)) { uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - bool success = ED_uvedit_minmax_multi(scene, ima, objects, objects_len, min, max); + bool success = ED_uvedit_minmax_multi(scene, objects, objects_len, min, max); MEM_freeN(objects); if (!success) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c index 5668b88826e..e0c44c3a0ba 100644 --- a/source/blender/editors/space_image/image_undo.c +++ b/source/blender/editors/space_image/image_undo.c @@ -958,7 +958,7 @@ static void image_undosys_step_decode( } if (us->paint_mode == PAINT_MODE_TEXTURE_3D) { - ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT); + ED_object_mode_set_ex(C, OB_MODE_TEXTURE_PAINT, false, NULL); } /* Refresh texture slots. */ diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index dbd3b65857a..e1937dffb37 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -438,7 +438,7 @@ static const char *footer_string(ViewLayer *view_layer) "%s%s | %s", memstr, gpumemstr, - versionstr); + BKE_blender_version_string()); return view_layer->footer_str; diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index 5d5c41597b4..8076d3d7eaf 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -408,7 +408,7 @@ int textview_draw(TextViewContext *tvc, if (do_draw) { /* We always want the cursor to draw. */ if (tvc->draw_cursor && iter_index == 0) { - tvc->draw_cursor(tvc, tds.cwidth, tds.columns, tds.lofs); + tvc->draw_cursor(tvc, tds.cwidth, tds.columns); } /* When drawing, if we pass v2d->cur.ymax, then quit. */ diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h index 8eef4ef5d56..41f8baf634e 100644 --- a/source/blender/editors/space_info/textview.h +++ b/source/blender/editors/space_info/textview.h @@ -60,7 +60,7 @@ typedef struct TextViewContext { int *r_icon, uchar r_icon_fg[4], uchar r_icon_bg[4]); - void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns, int descender); + void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns); /* constant theme colors */ void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]); const void *iter; diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 5c4ccd96534..a56b7f8422e 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -325,7 +325,7 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uin /* influence -------------------------- */ if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) { - FCurve *fcu = list_find_fcurve(&strip->fcurves, "influence", 0); + FCurve *fcu = BKE_fcurve_find(&strip->fcurves, "influence", 0); float cfra; /* plot the curve (over the strip's main region) */ diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index f68896e21d6..dec7a0fd93c 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -567,7 +567,7 @@ void NLA_OT_view_frame(wmOperatorType *ot) /* identifiers */ ot->name = "Go to Current Frame"; ot->idname = "NLA_OT_view_frame"; - ot->description = "Move the view to the playhead"; + ot->description = "Move the view to the current frame"; /* api callbacks */ ot->exec = nlaedit_viewframe_exec; diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 44003a5b9bc..01ac3a80871 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3638,7 +3638,7 @@ void draw_nodespace_back_pix(const bContext *C, IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_uniform_vector( - state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, shuffle); + state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, shuffle); immDrawPixelsTex(&state, x, diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index 1d73937d762..95a37f85828 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -82,7 +82,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx nodeSetSelected(node, true); ntreeUpdateTree(bmain, snode->edittree); - ED_node_set_active(bmain, snode->edittree, node); + ED_node_set_active(bmain, snode->edittree, node, NULL); snode_update(snode, node); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index bd5ce135f82..ac58ec1e636 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -648,9 +648,12 @@ void snode_update(SpaceNode *snode, bNode *node) } } -void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) +void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed) { const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0; + if (r_active_texture_changed) { + *r_active_texture_changed = false; + } nodeSetActive(ntree, node); @@ -719,6 +722,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) } } + if (r_active_texture_changed) { + *r_active_texture_changed = true; + } ED_node_tag_update_nodetree(bmain, ntree, node); WM_main_add_notifier(NC_IMAGE, NULL); } @@ -1290,7 +1296,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) newnode = node->new_node; nodeSetSelected(node, false); - node->flag &= ~NODE_ACTIVE; + node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE); nodeSetSelected(newnode, true); do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode)); diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 9eabcc44d80..06f568c80f3 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include "DNA_node_types.h" +#include "DNA_windowmanager_types.h" #include "BLI_lasso_2d.h" #include "BLI_listbase.h" @@ -36,10 +37,12 @@ #include "BKE_context.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_workspace.h" #include "ED_node.h" /* own include */ #include "ED_screen.h" #include "ED_select_utils.h" +#include "ED_view3d.h" #include "RNA_access.h" #include "RNA_define.h" @@ -57,6 +60,36 @@ #include "node_intern.h" /* own include */ +/* Function to detect if there is a visible view3d that uses workbench in texture mode. + * This function is for fixing T76970 for Blender 2.83. The actual fix should add a mechanism in + * the depsgraph that can be used by the draw engines to check if they need to be redrawn. + * + * We don't want to add these risky changes this close before releasing 2.83 without good testing + * hence this workaround. There are still cases were too many updates happen. For example when you + * have both a Cycles and workbench with textures viewport. + * */ +static bool has_workbench_in_texture_color(const wmWindowManager *wm, + const Scene *scene, + const Object *ob) +{ + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + if (win->scene != scene) { + continue; + } + const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + if (area->spacetype == SPACE_VIEW3D) { + const View3D *v3d = area->spacedata.first; + + if (ED_view3d_has_workbench_in_texture_color(scene, ob, v3d)) { + return true; + } + } + } + } + return false; +} + /* -------------------------------------------------------------------- */ /** \name Public Node Selection API * \{ */ @@ -415,6 +448,10 @@ void node_select_single(bContext *C, bNode *node) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); + const Object *ob = CTX_data_active_object(C); + const Scene *scene = CTX_data_scene(C); + const wmWindowManager *wm = CTX_wm_manager(C); + bool active_texture_changed = false; bNode *tnode; for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { @@ -424,10 +461,13 @@ void node_select_single(bContext *C, bNode *node) } nodeSetSelected(node, true); - ED_node_set_active(bmain, snode->edittree, node); + ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed); ED_node_set_active_viewer_key(snode); ED_node_sort(snode->edittree); + if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) { + DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE); + } WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); } @@ -440,6 +480,9 @@ static int node_mouse_select(bContext *C, Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); ARegion *region = CTX_wm_region(C); + const Object *ob = CTX_data_active_object(C); + const Scene *scene = CTX_data_scene(C); + const wmWindowManager *wm = CTX_wm_manager(C); bNode *node, *tnode; bNodeSocket *sock = NULL; bNodeSocket *tsock; @@ -546,12 +589,15 @@ static int node_mouse_select(bContext *C, /* update node order */ if (ret_value != OPERATOR_CANCELLED) { + bool active_texture_changed = false; if (node != NULL && ret_value != OPERATOR_RUNNING_MODAL) { - ED_node_set_active(bmain, snode->edittree, node); + ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed); } ED_node_set_active_viewer_key(snode); ED_node_sort(snode->edittree); - DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE); + if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) { + DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE); + } WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 13cbda5aad7..7d3b95721c6 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -178,20 +178,13 @@ static void restrictbutton_r_lay_cb(bContext *C, void *poin, void *UNUSED(poin2) WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin); } -static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2) +static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *UNUSED(poin2)) { - bArmature *arm = (bArmature *)poin; - Bone *bone = (Bone *)poin2; - if (bone->flag & BONE_HIDDEN_P) { - bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } + Bone *bone = (Bone *)poin; if (CTX_wm_window(C)->eventstate->ctrl) { restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0); } - - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); - DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE); } static void restrictbutton_bone_select_cb(bContext *C, void *UNUSED(poin), void *poin2) @@ -859,6 +852,7 @@ typedef struct RestrictProperties { *layer_collection_hide_viewport; PropertyRNA *modifier_show_viewport, *modifier_show_render; PropertyRNA *constraint_enable; + PropertyRNA *bone_hide_viewport; } RestrictProperties; /* We don't care about the value of the property @@ -877,6 +871,7 @@ typedef struct RestrictPropertiesActive { bool modifier_show_viewport; bool modifier_show_render; bool constraint_enable; + bool bone_hide_viewport; } RestrictPropertiesActive; static void outliner_restrict_properties_enable_collection_set( @@ -1011,6 +1006,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute"); + props.bone_hide_viewport = RNA_struct_type_find_property(&RNA_Bone, "hide"); + props.initialized = true; } @@ -1279,27 +1276,32 @@ static void outliner_draw_restrictbuts(uiBlock *block, } } else if (tselem->type == TSE_POSE_CHANNEL) { + PointerRNA ptr; bPoseChannel *pchan = (bPoseChannel *)te->directdata; Bone *bone = pchan->bone; Object *ob = (Object *)tselem->id; + bArmature *arm = ob->data; + + RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr); if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { - bt = uiDefIconButBitI(block, - UI_BTYPE_ICON_TOGGLE, - BONE_HIDDEN_P, - 0, - ICON_RESTRICT_VIEW_OFF, - (int)(region->v2d.cur.xmax - restrict_offsets.viewport), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &(bone->flag), - 0, - 0, - 0, - 0, - TIP_("Restrict visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone); + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(region->v2d.cur.xmax - restrict_offsets.viewport), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.bone_hide_viewport, + -1, + 0, + 0, + -1, + -1, + TIP_("Restrict visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_bone_visibility_cb, bone, NULL); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 53f2c6a90d4..80a63af3f42 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -931,7 +931,7 @@ static void cleardrivers_animdata_cb(int UNUSED(event), IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id; /* just free drivers - stored as a list of F-Curves */ - free_fcurves(&iat->adt->drivers); + BKE_fcurves_free(&iat->adt->drivers); DEG_id_tag_update(tselem->id, ID_RECALC_ANIMATION); } @@ -2488,6 +2488,7 @@ static int do_outliner_operation_event( /* Only redraw, don't rebuild here because TreeElement pointers will * become invalid and operations will crash. */ ED_region_tag_redraw_no_rebuild(region); + ED_outliner_select_sync_from_outliner(C, soops); } set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 7bb62b0d1e2..d6efe683673 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1427,9 +1427,9 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops, ten->name = id->name + 2; ten->directdata = lc; - /* Open by default. */ + /* Open by default, except linked collections, which may contain many elements. */ TreeStoreElem *tselem = TREESTORE(ten); - if (!tselem->used) { + if (!(tselem->used || ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY(id))) { tselem->flag &= ~TSE_CLOSED; } diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 80172c5462f..6202a3556a4 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -655,7 +655,7 @@ static int sequencer_add_movie_strip_invoke(bContext *C, Scene *scene = CTX_data_scene(C); Editing *ed = BKE_sequencer_editing_get(scene, false); - /* Only enable "use_framerate" if there aren't any existing strips, unless overriden by user. */ + /* Only enable "use_framerate" if there aren't any existing strips, unless overridden by user. */ if (ed && ed->seqbasep && ed->seqbasep->first) { RNA_boolean_set(op->ptr, "use_framerate", false); } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 5d8851d5e3d..1f06ab68516 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2299,10 +2299,10 @@ void draw_timeline_seq(const bContext *C, ARegion *region) cfra_flag |= DRAWCFRA_UNIT_SECONDS; } - /* Draw playhead. */ + /* Draw the current frame indicator. */ ANIM_draw_cfra(C, v2d, cfra_flag); - /* Draw overlap playhead. */ + /* Draw overlap frame frame indicator. */ if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) { int cfra_over = (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) ? scene->ed->over_cfra : diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index c910f1d2382..28ded81eeae 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -71,7 +71,10 @@ /* Own include. */ #include "sequencer_intern.h" -/* XXX */ +/* -------------------------------------------------------------------- */ +/** \name Structs & Enums + * \{ */ + /* RNA Enums, used in multiple files. */ EnumPropertyItem sequencer_prop_effect_types[] = { {SEQ_TYPE_CROSS, "CROSS", 0, "Crossfade", "Crossfade effect strip type"}, @@ -122,9 +125,11 @@ typedef struct TransSeq { int len; } TransSeq; -/* ********************************************************************** */ +/** \} */ -/* ***************** proxy job manager ********************** */ +/* -------------------------------------------------------------------- */ +/** \name Proxy Job Manager + * \{ */ typedef struct ProxyBuildJob { struct Main *main; @@ -214,20 +219,41 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports) } file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list"); + bool selected = false; /* Check for no selected strips */ + SEQP_BEGIN (ed, seq) { - if ((seq->flag & SELECT)) { - bool success = BKE_sequencer_proxy_rebuild_context( - pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue); - if (!success) { - BKE_reportf(reports, RPT_ERROR, "Could not build proxy for strip %s", seq->name); - } + if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META) || + (seq->flag & SELECT) == 0) { + continue; + } + + selected = true; + if (!(seq->flag & SEQ_USE_PROXY)) { + BKE_reportf(reports, RPT_WARNING, "Proxy is not enabled for %s, skipping.", seq->name); + continue; + } + else if (seq->strip->proxy->build_size_flags == 0) { + BKE_reportf(reports, RPT_WARNING, "Resolution is not selected for %s, skipping.", seq->name); + continue; + } + + bool success = BKE_sequencer_proxy_rebuild_context( + pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue); + + if (!success && (seq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) != 0) { + BKE_reportf(reports, RPT_WARNING, "Overwrite is not checked for %s, skipping.", seq->name); } } SEQ_END; + if (!selected) { + BKE_reportf(reports, RPT_WARNING, "Select movie or image strips."); + return; + } + BLI_gset_free(file_list, MEM_freeN); - if (!WM_jobs_is_running(wm_job)) { + if (selected && !WM_jobs_is_running(wm_job)) { G.is_break = false; WM_jobs_start(CTX_wm_manager(C), wm_job); } @@ -235,7 +261,11 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports) ED_area_tag_redraw(area); } -/* ********************************************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sequence Query Utilities + * \{ */ void seq_rectf(Sequence *seq, rctf *rect) { @@ -290,7 +320,7 @@ static int mouse_frame_side(View2D *v2d, short mouse_x, int frame) mval[0] = mouse_x; mval[1] = 0; - /* Choose the side based on which side of the playhead the mouse is on. */ + /* Choose the side based on which side of the current frame the mouse is on. */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseloc[0], &mouseloc[1]); return mouseloc[0] > frame ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT; @@ -466,6 +496,12 @@ static bool seq_is_predecessor(Sequence *pred, Sequence *seq) return 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Selection Utilities + * \{ */ + void ED_sequencer_deselect_all(Scene *scene) { Sequence *seq; @@ -506,6 +542,12 @@ void recurs_sel_seq(Sequence *seqm) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public Context Checks + * \{ */ + bool ED_space_sequencer_maskedit_mask_poll(bContext *C) { return ED_space_sequencer_maskedit_poll(C); @@ -545,6 +587,12 @@ bool ED_space_sequencer_check_show_strip(SpaceSeq *sseq) ELEM(sseq->mainb, SEQ_DRAW_SEQUENCE, SEQ_DRAW_IMG_IMBUF)); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Find Selected Strips as Inputs to an Effects Strip + * \{ */ + int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, @@ -633,6 +681,12 @@ int seq_effect_find_selected(Scene *scene, return 1; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Utilities + * \{ */ + static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq) { Sequence *seq1, *seq2, *seq3; @@ -727,6 +781,12 @@ static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short de } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Split (Hard) Utility + * \{ */ + static Sequence *split_seq_hard( Main *bmain, Scene *scene, Sequence *seq, ListBase *new_seq_list, int split_frame) { @@ -844,6 +904,12 @@ static Sequence *split_seq_hard( return seqn; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Split (Soft) Utility + * \{ */ + static Sequence *split_seq_soft( Main *UNUSED(bmain), Scene *scene, Sequence *seq, ListBase *new_seq_list, int split_frame) { @@ -1109,6 +1175,12 @@ static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene) SEQ_END; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Remove Gaps Operator + * \{ */ + static int sequencer_gap_remove_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -1177,6 +1249,12 @@ void SEQUENCER_OT_gap_remove(struct wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", 0, "All Gaps", "Do all gaps to right of current frame"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Insert Gaps Operator + * \{ */ + static int sequencer_gap_insert_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -1217,6 +1295,12 @@ void SEQUENCER_OT_gap_insert(struct wmOperatorType *ot) 1000); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Shared Poll Functions + * \{ */ + #if 0 static int seq_get_snaplimit(View2D *v2d) { @@ -1277,7 +1361,12 @@ bool sequencer_view_strips_poll(bContext *C) return 0; } -/* Snap operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Snap Strips to the Current Frame Operator + * \{ */ + static int sequencer_snap_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -1355,7 +1444,7 @@ static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNU void SEQUENCER_OT_snap(struct wmOperatorType *ot) { /* Identifiers. */ - ot->name = "Snap Strips to Playhead"; + ot->name = "Snap Strips to the Current Frame"; ot->idname = "SEQUENCER_OT_snap"; ot->description = "Frame where selected strips will be snapped"; @@ -1378,6 +1467,12 @@ void SEQUENCER_OT_snap(struct wmOperatorType *ot) INT_MAX); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Trim Strips Operator + * \{ */ + typedef struct SlipData { int init_mouse[2]; float init_mouseloc[2]; @@ -1652,10 +1747,10 @@ static void sequencer_slip_update_header(Scene *scene, ScrArea *area, SlipData * if (hasNumInput(&data->num_input)) { char num_str[NUM_STR_REP_LEN]; outputNumInput(&data->num_input, num_str, &scene->unit); - BLI_snprintf(msg, sizeof(msg), TIP_("Trim offset: %s"), num_str); + BLI_snprintf(msg, sizeof(msg), TIP_("Slip offset: %s"), num_str); } else { - BLI_snprintf(msg, sizeof(msg), TIP_("Trim offset: %d"), offset); + BLI_snprintf(msg, sizeof(msg), TIP_("Slip offset: %d"), offset); } } @@ -1706,7 +1801,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even mouse_x = event->mval[0]; } - /* Choose the side based on which side of the playhead the mouse is. */ + /* Choose the side based on which side of the current frame the mouse is. */ UI_view2d_region_to_view(v2d, mouse_x, 0, &mouseloc[0], &mouseloc[1]); offset = mouseloc[0] - data->init_mouseloc[0]; @@ -1834,7 +1929,12 @@ void SEQUENCER_OT_slip(struct wmOperatorType *ot) INT32_MAX); } -/* Mute operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mute Strips Operator + * \{ */ + static int sequencer_mute_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -1885,7 +1985,12 @@ void SEQUENCER_OT_mute(struct wmOperatorType *ot) ot->srna, "unselected", 0, "Unselected", "Mute unselected rather than selected strips"); } -/* Unmute operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Unmute Strips Operator + * \{ */ + static int sequencer_unmute_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -1936,7 +2041,12 @@ void SEQUENCER_OT_unmute(struct wmOperatorType *ot) ot->srna, "unselected", 0, "Unselected", "Unmute unselected rather than selected strips"); } -/* Lock operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Lock Strips Operator + * \{ */ + static int sequencer_lock_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -1969,7 +2079,12 @@ void SEQUENCER_OT_lock(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Unlock operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Unlock Strips Operator + * \{ */ + static int sequencer_unlock_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -2002,7 +2117,12 @@ void SEQUENCER_OT_unlock(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Reload operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reload Strips Operator + * \{ */ + static int sequencer_reload_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -2053,7 +2173,12 @@ void SEQUENCER_OT_reload(struct wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* Reload operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Refresh Sequencer Operator + * \{ */ + static bool sequencer_refresh_all_poll(bContext *C) { if (G.is_rendering) { @@ -2086,6 +2211,12 @@ void SEQUENCER_OT_refresh_all(struct wmOperatorType *ot) ot->poll = sequencer_refresh_all_poll; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reassign Inputs Operator + * \{ */ + static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -2145,6 +2276,12 @@ void SEQUENCER_OT_reassign_inputs(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Swap Inputs Operator + * \{ */ + static int sequencer_swap_inputs_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -2180,7 +2317,12 @@ void SEQUENCER_OT_swap_inputs(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Split operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Split Strips Operator + * \{ */ + static const EnumPropertyItem prop_split_types[] = { {SEQ_SPLIT_SOFT, "SOFT", 0, "Soft", ""}, {SEQ_SPLIT_HARD, "HARD", 0, "Hard", ""}, @@ -2353,7 +2495,7 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot) "use_cursor_position", 0, "Use Cursor Position", - "Split at position of the cursor instead of playhead"); + "Split at position of the cursor instead of current frame"); prop = RNA_def_enum(ot->srna, "side", @@ -2376,7 +2518,12 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot) #undef SEQ_SIDE_MOUSE -/* Duplicate operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Duplicate Strips Operator + * \{ */ + static int apply_unique_name_fn(Sequence *seq, void *arg_pt) { Scene *scene = (Scene *)arg_pt; @@ -2432,7 +2579,12 @@ void SEQUENCER_OT_duplicate(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Delete operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Erase Strips Operator + * \{ */ + static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); @@ -2508,7 +2660,7 @@ static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *e } } - return WM_operator_confirm(C, op, event); + return sequencer_delete_exec(C, op); } void SEQUENCER_OT_delete(wmOperatorType *ot) @@ -2528,7 +2680,12 @@ void SEQUENCER_OT_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Offset clear operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Strip Offset Operator + * \{ */ + static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -2578,7 +2735,12 @@ void SEQUENCER_OT_offset_clear(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Separate_images operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Separate Images Operator + * \{ */ + static int sequencer_separate_images_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -2677,9 +2839,12 @@ void SEQUENCER_OT_images_separate(wmOperatorType *ot) RNA_def_int(ot->srna, "length", 1, 1, INT_MAX, "Length", "Length of each frame", 1, 1000); } -/* META Operators. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Meta Strip Operator + * \{ */ -/* Separate_meta_toggle operator. */ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -2765,7 +2930,12 @@ void SEQUENCER_OT_meta_toggle(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Separate_meta_make operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Make Meta Strip Operator + * \{ */ + static int sequencer_meta_make_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -2829,6 +2999,12 @@ void SEQUENCER_OT_meta_make(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name UnMeta Strip Operator + * \{ */ + static int seq_depends_on_meta(Sequence *seq, Sequence *seqm) { if (seq == seqm) { @@ -2848,7 +3024,6 @@ static int seq_depends_on_meta(Sequence *seq, Sequence *seqm) } } -/* Separate_meta_make operator. */ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -2914,7 +3089,12 @@ void SEQUENCER_OT_meta_separate(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* View_all operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sequencer Frame All Operator + * \{ */ + static int sequencer_view_all_exec(bContext *C, wmOperator *op) { ARegion *region = CTX_wm_region(C); @@ -2942,6 +3122,12 @@ void SEQUENCER_OT_view_all(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Go to Current Frame Operator + * \{ */ + static int sequencer_view_frame_exec(bContext *C, wmOperator *op) { const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); @@ -2955,7 +3141,7 @@ void SEQUENCER_OT_view_frame(wmOperatorType *ot) /* Identifiers. */ ot->name = "Go to Current Frame"; ot->idname = "SEQUENCER_OT_view_frame"; - ot->description = "Move the view to the playhead"; + ot->description = "Move the view to the current frame"; /* Api callbacks. */ ot->exec = sequencer_view_frame_exec; @@ -2965,7 +3151,12 @@ void SEQUENCER_OT_view_frame(wmOperatorType *ot) ot->flag = 0; } -/* View_all operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Preview Frame All Operator + * \{ */ + static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op)) { bScreen *screen = CTX_wm_screen(C); @@ -3029,6 +3220,12 @@ void SEQUENCER_OT_view_all_preview(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sequencer View Zoom Ratio Operator + * \{ */ + static int sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op) { RenderData *rd = &CTX_data_scene(C)->r; @@ -3072,6 +3269,12 @@ void SEQUENCER_OT_view_zoom_ratio(wmOperatorType *ot) FLT_MAX); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Toggle Operator + * \{ */ + #if 0 static const EnumPropertyItem view_type_items[] = { {SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""}, @@ -3085,7 +3288,6 @@ static const EnumPropertyItem view_type_items[] = { }; #endif -/* View_all operator. */ static int sequencer_view_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C); @@ -3115,7 +3317,12 @@ void SEQUENCER_OT_view_toggle(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } -/* View_selected operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Frame Selected Operator + * \{ */ + static int sequencer_view_selected_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -3197,6 +3404,12 @@ void SEQUENCER_OT_view_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Jump to Strip Operator + * \{ */ + static bool strip_jump_internal(Scene *scene, const short side, const bool do_skip_mute, @@ -3224,7 +3437,6 @@ static bool sequencer_strip_jump_poll(bContext *C) return sequencer_edit_poll(C); } -/* Jump frame to edit point operator. */ static int sequencer_strip_jump_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -3260,6 +3472,12 @@ void SEQUENCER_OT_strip_jump(wmOperatorType *ot) RNA_def_boolean(ot->srna, "center", true, "Use strip center", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Swap Strip Operator + * \{ */ + static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb) { int gap = seqb->startdisp - seqa->enddisp; @@ -3380,6 +3598,12 @@ void SEQUENCER_OT_swap(wmOperatorType *ot) ot->srna, "side", prop_side_lr_types, SEQ_SIDE_RIGHT, "Side", "Side of the strip to swap"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Render Size Operator + * \{ */ + static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op)) { int retval = OPERATOR_CANCELLED; @@ -3436,6 +3660,12 @@ void SEQUENCER_OT_rendersize(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Copy Operator + * \{ */ + static void seq_copy_del_sound(Scene *scene, Sequence *seq) { if (seq->type == SEQ_TYPE_META) { @@ -3495,6 +3725,12 @@ void SEQUENCER_OT_copy(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Paste Operator + * \{ */ + static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); @@ -3551,6 +3787,12 @@ void SEQUENCER_OT_paste(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sequencer Swap Data Operator + * \{ */ + static int sequencer_swap_data_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -3612,7 +3854,12 @@ void SEQUENCER_OT_swap_data(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Box select operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Border Offset View Operator + * \{ */ + static int view_ghost_border_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -3668,7 +3915,12 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot) WM_operator_properties_gesture_box(ot); } -/* Rebuild_proxy operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Rebuild Proxy and Timecode Indices Operator + * \{ */ + static int sequencer_rebuild_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) @@ -3732,6 +3984,12 @@ void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Selected Strip Proxies Operator + * \{ */ + static int sequencer_enable_proxies_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) @@ -3757,12 +4015,7 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op) SEQP_BEGIN (ed, seq) { if ((seq->flag & SELECT)) { - if (ELEM(seq->type, - SEQ_TYPE_MOVIE, - SEQ_TYPE_IMAGE, - SEQ_TYPE_META, - SEQ_TYPE_SCENE, - SEQ_TYPE_MULTICAM)) { + if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META)) { BKE_sequencer_proxy_set(seq, turnon); if (seq->strip->proxy == NULL) { continue; @@ -3833,7 +4086,12 @@ void SEQUENCER_OT_enable_proxies(wmOperatorType *ot) RNA_def_boolean(ot->srna, "overwrite", false, "Overwrite", ""); } -/* Change effect inputs operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Change Effect Input Operator + * \{ */ + static const EnumPropertyItem prop_change_effect_input_types[] = { {0, "A_B", 0, "A -> B", ""}, {1, "B_C", 0, "B -> C", ""}, @@ -3898,7 +4156,12 @@ void SEQUENCER_OT_change_effect_input(struct wmOperatorType *ot) ot->srna, "swap", prop_change_effect_input_types, 0, "Swap", "The effect inputs to swap"); } -/* Change effect type operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Change Effect Type Operator + * \{ */ + static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -3960,7 +4223,12 @@ void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot) "Sequencer effect type"); } -/* Change path operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Change Data/Files Operator + * \{ */ + static int sequencer_change_path_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -4108,7 +4376,12 @@ void SEQUENCER_OT_change_path(struct wmOperatorType *ot) "Use placeholders for missing frames of the strip"); } -/* Export subtitles operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Export Subtitles Operator + * \{ */ + static int sequencer_export_subtitles_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) @@ -4243,7 +4516,12 @@ void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot) FILE_SORT_ALPHA); } -/* Set range to strips operator. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Range to Strips Operator + * \{ */ + static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -4307,3 +4585,5 @@ void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "preview", false, "Preview", "Set the preview range instead"); RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } + +/** \} */ diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 708682cd04f..eec8d604b64 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -158,6 +158,7 @@ void SEQUENCER_OT_view_all_preview(struct wmOperatorType *ot); /* sequencer_select.c */ void SEQUENCER_OT_select_all(struct wmOperatorType *ot); void SEQUENCER_OT_select(struct wmOperatorType *ot); +void SEQUENCER_OT_select_side_of_frame(struct wmOperatorType *ot); void SEQUENCER_OT_select_more(struct wmOperatorType *ot); void SEQUENCER_OT_select_less(struct wmOperatorType *ot); void SEQUENCER_OT_select_linked(struct wmOperatorType *ot); @@ -181,20 +182,6 @@ enum { SEQ_SPLIT_SOFT, SEQ_SPLIT_HARD, }; -enum { - SEQ_SELECTED, - SEQ_UNSELECTED, -}; - -enum { - SEQ_SELECT_LR_NONE = 0, - SEQ_SELECT_LR_MOUSE, - SEQ_SELECT_LR_LEFT, - SEQ_SELECT_LR_RIGHT, -}; - -/* Defines used internally. */ -#define SCE_MARKERS 0 /* XXX - dummy */ /* sequencer_ops.c */ void sequencer_operatortypes(void); diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index ac00838a079..4fe1c953c74 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -99,6 +99,7 @@ void sequencer_operatortypes(void) WM_operatortype_append(SEQUENCER_OT_select_linked); WM_operatortype_append(SEQUENCER_OT_select_handles); WM_operatortype_append(SEQUENCER_OT_select_side); + WM_operatortype_append(SEQUENCER_OT_select_side_of_frame); WM_operatortype_append(SEQUENCER_OT_select_box); WM_operatortype_append(SEQUENCER_OT_select_grouped); diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index c5472ed88e5..f2b7e138c3e 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -52,10 +52,9 @@ /* Own include. */ #include "sequencer_intern.h" -static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2)) -{ - return NULL; -} +/* -------------------------------------------------------------------- */ +/** \name Selection Utilities + * \{ */ static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */ { @@ -253,6 +252,12 @@ static void select_neighbor_from_last(Scene *scene, int lr) } #endif +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name (De)select All Operator + * \{ */ + static int sequencer_de_select_all_exec(bContext *C, wmOperator *op) { int action = RNA_enum_get(op->ptr, "action"); @@ -316,6 +321,12 @@ void SEQUENCER_OT_select_all(struct wmOperatorType *ot) WM_operator_properties_select_all(ot); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Inverse Operator + * \{ */ + static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -354,6 +365,12 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot) ot->flag = OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Operator + * \{ */ + static int sequencer_select_exec(bContext *C, wmOperator *op) { View2D *v2d = UI_view2d_fromcontext(C); @@ -363,8 +380,8 @@ static int sequencer_select_exec(bContext *C, wmOperator *op) const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle"); const bool linked_time = RNA_boolean_get(op->ptr, "linked_time"); + bool side_of_frame = RNA_boolean_get(op->ptr, "side_of_frame"); bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); - int left_right = RNA_enum_get(op->ptr, "left_right"); int mval[2]; int ret_value = OPERATOR_CANCELLED; @@ -373,7 +390,6 @@ static int sequencer_select_exec(bContext *C, wmOperator *op) Sequence *seq, *neighbor, *act_orig; int hand, sel_side; - TimeMarker *marker; if (ed == NULL) { return OPERATOR_CANCELLED; @@ -383,57 +399,31 @@ static int sequencer_select_exec(bContext *C, wmOperator *op) wait_to_deselect_others = false; } - marker = find_nearest_marker(SCE_MARKERS, 1); /* XXX - dummy function for now */ - seq = find_nearest_seq(scene, v2d, &hand, mval); - /* XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip */ - if (seq && linked_time && (left_right == SEQ_SELECT_LR_MOUSE)) { - left_right = SEQ_SELECT_LR_NONE; + /* XXX - not nice, Ctrl+RMB needs to do side_of_frame only when not over a strip */ + if (seq && linked_time) { + side_of_frame = false; } - if (marker) { - int oldflag; - /* Select timeline marker. */ - if (extend) { - oldflag = marker->flag; - if (oldflag & SELECT) { - marker->flag &= ~SELECT; - } - else { - marker->flag |= SELECT; - } - } - else { - /* XXX, in 2.4x, seq selection used to deselect all, need to re-thnik this for 2.5 */ - /* deselect_markers(0, 0); */ - marker->flag |= SELECT; - } - - ret_value = OPERATOR_FINISHED; - } - else if (left_right != SEQ_SELECT_LR_NONE) { + /* Select left, right or overlapping the current frame. */ + if (side_of_frame) { /* Use different logic for this. */ float x; if (extend == false) { ED_sequencer_deselect_all(scene); } - switch (left_right) { - case SEQ_SELECT_LR_MOUSE: - x = UI_view2d_region_to_view_x(v2d, mval[0]); - break; - case SEQ_SELECT_LR_LEFT: - x = CFRA - 1.0f; - break; - case SEQ_SELECT_LR_RIGHT: - default: - x = CFRA; - break; + /* 10px margin around current frame to select under the current frame with mouse. */ + float margin = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask) * 10; + x = UI_view2d_region_to_view_x(v2d, mval[0]); + if (x >= CFRA - margin && x <= CFRA + margin) { + x = CFRA; } SEQP_BEGIN (ed, seq) { - if (((x < CFRA) && (seq->enddisp <= CFRA)) || ((x >= CFRA) && (seq->startdisp >= CFRA))) { + /* Select left or right. */ + if ((x < CFRA && seq->enddisp <= CFRA) || (x > CFRA && seq->startdisp >= CFRA)) { seq->flag |= SELECT; recurs_sel_seq(seq); } @@ -624,13 +614,6 @@ static int sequencer_select_exec(bContext *C, wmOperator *op) void SEQUENCER_OT_select(wmOperatorType *ot) { - static const EnumPropertyItem sequencer_select_left_right_types[] = { - {SEQ_SELECT_LR_NONE, "NONE", 0, "None", "Don't do left-right selection"}, - {SEQ_SELECT_LR_MOUSE, "MOUSE", 0, "Mouse", "Use mouse position for selection"}, - {SEQ_SELECT_LR_LEFT, "LEFT", 0, "Left", "Select left"}, - {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select right"}, - {0, NULL, 0, NULL, NULL}, - }; PropertyRNA *prop; /* Identifiers. */ @@ -649,26 +632,43 @@ void SEQUENCER_OT_select(wmOperatorType *ot) /* Properties. */ WM_operator_properties_generic_select(ot); - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); + + prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "deselect_all", false, "Deselect On Nothing", "Deselect all when nothing under the cursor"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); - RNA_def_boolean( - ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip"); - /* For animation this is enum but atm having an enum isn't useful for us. */ - RNA_def_enum(ot->srna, - "left_right", - sequencer_select_left_right_types, - 0, - "Left/Right", - "Select based on the current frame side the cursor is on"); - RNA_def_boolean( - ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time"); + + prop = RNA_def_boolean(ot->srna, + "linked_handle", + false, + "Linked Handle", + "Select handles next to the active strip"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_boolean( + ot->srna, "linked_time", false, "Linked Time", "Select other strips at the same time"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_boolean( + ot->srna, + "side_of_frame", + false, + "Side of Frame", + "Select all strips on same side of the current frame as the mouse cursor"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More Operator + * \{ */ + /* Run recursively to select linked. */ static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool linked) { @@ -766,6 +766,12 @@ void SEQUENCER_OT_select_more(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Less Operator + * \{ */ + static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -796,6 +802,12 @@ void SEQUENCER_OT_select_less(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Pick Linked Operator + * \{ */ + static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); @@ -849,6 +861,12 @@ void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked Operator + * \{ */ + static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -881,6 +899,12 @@ void SEQUENCER_OT_select_linked(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Handles Operator + * \{ */ + static int sequencer_select_handles_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -936,6 +960,87 @@ void SEQUENCER_OT_select_handles(wmOperatorType *ot) "The side of the handle that is selected"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Side of Frame Operator + * \{ */ + +static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Editing *ed = BKE_sequencer_editing_get(scene, false); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const int side = RNA_enum_get(op->ptr, "side"); + Sequence *seq; + + if (ed == NULL) { + return OPERATOR_CANCELLED; + } + if (extend == false) { + ED_sequencer_deselect_all(scene); + } + const int cfra = CFRA; + SEQP_BEGIN (ed, seq) { + bool test = false; + switch (side) { + case -1: + test = (cfra >= seq->startdisp); + break; + case 1: + test = (cfra <= seq->enddisp); + break; + case 0: + test = (cfra <= seq->enddisp) && (cfra >= seq->startdisp); + break; + } + + if (test) { + seq->flag |= SELECT; + recurs_sel_seq(seq); + } + } + SEQ_END; + + ED_outliner_select_sync_from_sequence_tag(C); + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_select_side_of_frame(wmOperatorType *ot) +{ + static const EnumPropertyItem sequencer_select_left_right_types[] = { + {0, "OVERLAP", 0, "Overlap", "Select overlapping the current frame"}, + {-1, "LEFT", 0, "Left", "Select to the left of the current frame"}, + {1, "RIGHT", 0, "Right", "Select to the right of the current frame"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* Identifiers. */ + ot->name = "Select Side of Frame"; + ot->idname = "SEQUENCER_OT_select_side_of_frame"; + ot->description = "Select strips relative to the current frame"; + + /* Api callbacks. */ + ot->exec = sequencer_select_side_of_frame_exec; + ot->poll = ED_operator_sequencer_active; + + /* Flags. */ + ot->flag = OPTYPE_UNDO; + + /* Properties. */ + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); + ot->prop = RNA_def_enum(ot->srna, "side", sequencer_select_left_right_types, 0, "Side", ""); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Side Operator + * \{ */ + static int sequencer_select_side_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -1000,6 +1105,12 @@ void SEQUENCER_OT_select_side(wmOperatorType *ot) "The side to which the selection is applied"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Box Select Operator + * \{ */ + static int sequencer_box_select_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -1124,6 +1235,12 @@ void SEQUENCER_OT_select_box(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Grouped Operator + * \{ */ + enum { SEQ_SELECT_GROUP_TYPE, SEQ_SELECT_GROUP_TYPE_BASIC, @@ -1460,8 +1577,8 @@ void SEQUENCER_OT_select_grouped(wmOperatorType *ot) { /* Identifiers. */ ot->name = "Select Grouped"; - ot->description = "Select all strips grouped by various properties"; ot->idname = "SEQUENCER_OT_select_grouped"; + ot->description = "Select all strips grouped by various properties"; /* Api callbacks. */ ot->invoke = WM_menu_invoke; @@ -1484,3 +1601,5 @@ void SEQUENCER_OT_select_grouped(wmOperatorType *ot) "Same Channel", "Only consider strips on the same channel as the active one"); } + +/** \} */ diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c index 1ec459ccfca..d823530fd89 100644 --- a/source/blender/editors/space_userpref/userpref_ops.c +++ b/source/blender/editors/space_userpref/userpref_ops.c @@ -25,11 +25,15 @@ #include "DNA_screen_types.h" +#include "BLI_listbase.h" + #include "BKE_context.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_report.h" +#include "RNA_access.h" +#include "RNA_define.h" #include "RNA_types.h" #include "UI_interface.h" @@ -41,11 +45,13 @@ #include "ED_userpref.h" +#include "MEM_guardedalloc.h" + /* -------------------------------------------------------------------- */ -/** \name Reset Default Theme +/** \name Reset Default Theme Operator * \{ */ -static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op)) +static int preferences_reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); UI_theme_init_default(); @@ -64,7 +70,7 @@ static void PREFERENCES_OT_reset_default_theme(wmOperatorType *ot) ot->description = "Reset to the default theme colors"; /* callbacks */ - ot->exec = reset_default_theme_exec; + ot->exec = preferences_reset_default_theme_exec; /* flags */ ot->flag = OPTYPE_REGISTER; @@ -72,7 +78,64 @@ static void PREFERENCES_OT_reset_default_theme(wmOperatorType *ot) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Add Auto-Execution Path Operator + * \{ */ + +static int preferences_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) +{ + bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare"); + BLI_addtail(&U.autoexec_paths, path_cmp); + U.runtime.is_dirty = true; + return OPERATOR_FINISHED; +} + +static void PREFERENCES_OT_autoexec_path_add(wmOperatorType *ot) +{ + ot->name = "Add Autoexec Path"; + ot->idname = "PREFERENCES_OT_autoexec_path_add"; + ot->description = "Add path to exclude from auto-execution"; + + ot->exec = preferences_autoexec_add_exec; + + ot->flag = OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Remove Auto-Execution Path Operator + * \{ */ + +static int preferences_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op) +{ + const int index = RNA_int_get(op->ptr, "index"); + bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index); + if (path_cmp) { + BLI_freelinkN(&U.autoexec_paths, path_cmp); + U.runtime.is_dirty = true; + } + return OPERATOR_FINISHED; +} + +static void PREFERENCES_OT_autoexec_path_remove(wmOperatorType *ot) +{ + ot->name = "Remove Autoexec Path"; + ot->idname = "PREFERENCES_OT_autoexec_path_remove"; + ot->description = "Remove path to exclude from auto-execution"; + + ot->exec = preferences_autoexec_remove_exec; + + ot->flag = OPTYPE_INTERNAL; + + RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); +} + +/** \} */ + void ED_operatortypes_userpref(void) { WM_operatortype_append(PREFERENCES_OT_reset_default_theme); + WM_operatortype_append(PREFERENCES_OT_autoexec_path_add); + WM_operatortype_append(PREFERENCES_OT_autoexec_path_remove); } diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index c7fe82e0cbb..f2536cfac62 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -64,6 +64,7 @@ set(SRC view3d_header.c view3d_iterators.c view3d_ops.c + view3d_placement.c view3d_project.c view3d_select.c view3d_snap.c diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index a5c99016434..4fc98789c18 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -675,6 +675,8 @@ static void view3d_widgets(void) WM_gizmogrouptype_append(VIEW3D_GGT_ruler); WM_gizmotype_append(VIEW3D_GT_ruler_item); + WM_gizmogrouptype_append(VIEW3D_GGT_placement); + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_navigate); WM_gizmotype_append(VIEW3D_GT_navigate_rotate); } @@ -1082,9 +1084,19 @@ static void view3d_main_region_message_subscribe(const struct bContext *C, } } +/* concept is to retrieve cursor type context-less */ static void view3d_main_region_cursor(wmWindow *win, ScrArea *area, ARegion *region) { - if (!WM_cursor_set_from_tool(win, area, region)) { + if (WM_cursor_set_from_tool(win, area, region)) { + return; + } + + ViewLayer *view_layer = WM_window_get_active_view_layer(win); + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); + if (obedit) { + WM_cursor_set(win, WM_CURSOR_EDIT); + } + else { WM_cursor_set(win, WM_CURSOR_DEFAULT); } } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index f81b4bb09e2..cb87ddafea1 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1642,7 +1642,7 @@ static int view3d_object_mode_menu(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } else if (((ob->mode & OB_MODE_EDIT) == 0) && (ELEM(ob->type, OB_ARMATURE))) { - ED_object_mode_toggle(C, OB_MODE_POSE); + ED_object_mode_set(C, (ob->mode == OB_MODE_OBJECT) ? OB_MODE_POSE : OB_MODE_OBJECT); return OPERATOR_CANCELLED; } else { diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 5cdf6ce28cb..edd75d8e561 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3349,7 +3349,7 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name View Camera Center Operator +/** \name Frame Camera Bounds Operator * \{ */ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) @@ -3386,8 +3386,8 @@ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) void VIEW3D_OT_view_center_camera(wmOperatorType *ot) { /* identifiers */ - ot->name = "View Camera Center"; - ot->description = "Center the camera view"; + ot->name = "Frame Camera Bounds"; + ot->description = "Center the camera view, resizing the view to fit its bounds"; ot->idname = "VIEW3D_OT_view_center_camera"; /* api callbacks */ @@ -5018,7 +5018,6 @@ void ED_view3d_cursor3d_position_rotation(bContext *C, float cursor_co[3], float cursor_quat[4]) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); ARegion *region = CTX_wm_region(C); @@ -5052,7 +5051,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C, float ray_co[3]; struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - bmain, scene, 0, region, v3d); + scene, 0, region, v3d); float obmat[4][4]; Object *ob_dummy = NULL; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c index 3301e28c90c..3ce4c8dc9a8 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c @@ -536,9 +536,12 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv return -1; } -static int gizmo_axis_cursor_get(wmGizmo *UNUSED(gz)) +static int gizmo_axis_cursor_get(wmGizmo *gz) { - return WM_CURSOR_DEFAULT; + if (gz->highlight_part > 0) { + return WM_CURSOR_EDIT; + } + return WM_CURSOR_NSEW_SCROLL; } void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt) diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index e4863c0cdeb..f3bc0a8a15b 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -40,6 +40,7 @@ #include "DNA_object_types.h" #include "DNA_view3d_types.h" +#include "ED_gizmo_library.h" #include "ED_gizmo_utils.h" #include "ED_gpencil.h" #include "ED_screen.h" @@ -57,10 +58,13 @@ #include "WM_toolsystem.h" #include "WM_types.h" +#include "DEG_depsgraph_query.h" + #include "view3d_intern.h" /* own include */ #include "GPU_immediate.h" #include "GPU_immediate_util.h" +#include "GPU_matrix.h" #include "GPU_state.h" #include "BLF_api.h" @@ -94,10 +98,6 @@ enum { RULER_STATE_DRAG, }; -enum { - RULER_SNAP_OK = (1 << 0), -}; - struct RulerItem; typedef struct RulerInfo { @@ -106,19 +106,25 @@ typedef struct RulerInfo { int snap_flag; int state; - struct SnapObjectContext *snap_context; - /* wm state */ + wmWindowManager *wm; wmWindow *win; ScrArea *area; ARegion *region; /* re-assigned every modal update */ /* Track changes in state. */ struct { +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK bool do_snap; +#endif bool do_thickness; } drag_state_prev; + struct { + wmGizmo *gizmo; + PropertyRNA *prop_prevpoint; + } snap_data; + } RulerInfo; /* -------------------------------------------------------------------- */ @@ -269,26 +275,17 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, * Ensure the 'snap_context' is only cached while dragging, * needed since the user may toggle modes between tool use. */ -static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) +static void ruler_state_set(RulerInfo *ruler_info, int state) { - Main *bmain = CTX_data_main(C); if (state == ruler_info->state) { return; } - /* always remove */ - if (ruler_info->snap_context) { - ED_transform_snap_object_context_destroy(ruler_info->snap_context); - ruler_info->snap_context = NULL; - } - if (state == RULER_STATE_NORMAL) { /* pass */ } else if (state == RULER_STATE_DRAG) { memset(&ruler_info->drag_state_prev, 0x0, sizeof(ruler_info->drag_state_prev)); - ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - bmain, CTX_data_scene(C), 0, ruler_info->region, CTX_wm_view3d(C)); } else { BLI_assert(0); @@ -307,13 +304,18 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, RulerInfo *ruler_info, RulerItem *ruler_item, const int mval[2], - const bool do_thickness, - const bool do_snap) + const bool do_thickness +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + , + const bool do_snap +#endif +) { + wmGizmo *snap_gizmo = ruler_info->snap_data.gizmo; const float eps_bias = 0.0002f; float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */ - ruler_info->snap_flag &= ~RULER_SNAP_OK; + WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, true); if (ruler_item) { RulerInteraction *inter = ruler_item->gz.interaction_data; @@ -322,8 +324,10 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, copy_v3_v3(co, inter->drag_start_co); view3d_ruler_item_project(ruler_info, co, mval); if (do_thickness && inter->co_index != 1) { - // Scene *scene = CTX_data_scene(C); - // View3D *v3d = ruler_info->area->spacedata.first; + Scene *scene = DEG_get_input_scene(depsgraph); + View3D *v3d = ruler_info->area->spacedata.first; + SnapObjectContext *snap_context = ED_gizmotypes_snap_3d_context_ensure( + scene, ruler_info->region, v3d, snap_gizmo); const float mval_fl[2] = {UNPACK2(mval)}; float ray_normal[3]; float ray_start[3]; @@ -331,7 +335,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0]; - if (ED_transform_snap_object_project_view3d(ruler_info->snap_context, + if (ED_transform_snap_object_project_view3d(snap_context, depsgraph, SCE_SNAP_MODE_FACE, &(const struct SnapObjectParams){ @@ -346,7 +350,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, negate_v3(ray_normal); /* add some bias */ madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias); - ED_transform_snap_object_project_ray(ruler_info->snap_context, + ED_transform_snap_object_project_ray(snap_context, depsgraph, &(const struct SnapObjectParams){ .snap_select = SNAP_ALL, @@ -359,7 +363,12 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, NULL); } } - else if (do_snap) { + else +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + if (do_snap) +#endif + { + View3D *v3d = ruler_info->area->spacedata.first; const float mval_fl[2] = {UNPACK2(mval)}; float *prev_point = NULL; @@ -374,23 +383,16 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, prev_point = ruler_item->co[0]; } } + if (prev_point != NULL) { + RNA_property_float_set_array( + snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); + } - if (ED_transform_snap_object_project_view3d( - ruler_info->snap_context, - depsgraph, - (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR), - &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, - .use_object_edit_cage = true, - .use_occlusion_test = true, - }, - mval_fl, - prev_point, - &dist_px, - co, - NULL)) { - ruler_info->snap_flag |= RULER_SNAP_OK; + short snap_elem = ED_gizmotypes_snap_3d_update( + snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl, co, NULL); + + if (snap_elem) { + WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, false); } } return true; @@ -417,6 +419,15 @@ static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd) return NULL; } +static RulerItem *gzgroup_ruler_item_first_get(wmGizmoGroup *gzgroup) +{ +#ifndef NDEBUG + RulerInfo *ruler_info = gzgroup->customdata; + BLI_assert(gzgroup->gizmos.first == ruler_info->snap_data.gizmo); +#endif + return (RulerItem *)((wmGizmo *)gzgroup->gizmos.first)->next; +} + #define RULER_ID "RulerData3D" static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) { @@ -448,7 +459,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW); BKE_gpencil_free_strokes(gpf); - for (ruler_item = gzgroup->gizmos.first; ruler_item; + for (ruler_item = gzgroup_ruler_item_first_get(gzgroup); ruler_item; ruler_item = (RulerItem *)ruler_item->gz.next) { bGPDspoint *pt; int j; @@ -556,6 +567,12 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) uchar color_wire[3]; float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f}; + /* Pixel Space. */ + GPU_matrix_push_projection(); + GPU_matrix_push(); + GPU_matrix_identity_set(); + wmOrtho2_region_pixelspace(region); + /* anti-aliased lines for more consistent appearance */ GPU_line_smooth(true); GPU_line_width(1.0f); @@ -575,20 +592,30 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) const bool is_act = (ruler_info->item_active == ruler_item); float dir_ruler[2]; float co_ss[3][2]; + bool proj_ok[3]; int j; - /* should these be checked? - ok for now not to */ + /* Check if each corner is behind the near plane. If it is, we do not draw certain lines. */ for (j = 0; j < 3; j++) { - ED_view3d_project_float_global(region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); + eV3DProjStatus status = ED_view3d_project_float_global( + region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_CLIP_NEAR); + proj_ok[j] = (status == V3D_PROJ_RET_OK); } + /* 3d drawing. */ + + GPU_matrix_push_projection(); + GPU_matrix_push(); + GPU_matrix_projection_set(rv3d->winmat); + GPU_matrix_set(rv3d->viewmat); + GPU_blend(true); - const uint shdr_pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + const uint shdr_pos_3d = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); if (ruler_item->flag & RULERITEM_USE_ANGLE) { - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); @@ -605,21 +632,20 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immBegin(GPU_PRIM_LINE_STRIP, 3); - immVertex2fv(shdr_pos, co_ss[0]); - immVertex2fv(shdr_pos, co_ss[1]); - immVertex2fv(shdr_pos, co_ss[2]); + immVertex3fv(shdr_pos_3d, ruler_item->co[0]); + immVertex3fv(shdr_pos_3d, ruler_item->co[1]); + immVertex3fv(shdr_pos_3d, ruler_item->co[2]); immEnd(); immUnbindProgram(); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); /* arc */ { float dir_tmp[3]; - float co_tmp[3]; - float arc_ss_coord[2]; + float ar_coord[3]; float dir_a[3]; float dir_b[3]; @@ -648,16 +674,53 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1); for (j = 0; j <= arc_steps; j++) { - madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale); - ED_view3d_project_float_global(region, co_tmp, arc_ss_coord, V3D_PROJ_TEST_NOP); + madd_v3_v3v3fl(ar_coord, ruler_item->co[1], dir_tmp, px_scale); mul_qt_v3(quat, dir_tmp); - immVertex2fv(shdr_pos, arc_ss_coord); + immVertex3fv(shdr_pos_3d, ar_coord); } immEnd(); } + immUnbindProgram(); + } + else { + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniform1i("colors_len", 2); /* "advanced" mode */ + const float *col = is_act ? color_act : color_base; + immUniformArray4fv( + "colors", + (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, + 2); + immUniform1f("dash_width", 6.0f); + immUniform1f("dash_factor", 0.5f); + + immBegin(GPU_PRIM_LINES, 2); + + immVertex3fv(shdr_pos_3d, ruler_item->co[0]); + immVertex3fv(shdr_pos_3d, ruler_item->co[2]); + + immEnd(); + + immUnbindProgram(); + } + + /* 2d drawing. */ + + GPU_matrix_pop(); + GPU_matrix_pop_projection(); + + const uint shdr_pos_2d = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); /* capping */ { float rot_90_vec_a[2]; @@ -676,15 +739,15 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) GPU_blend(true); - if (is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) { + if (proj_ok[1] && is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) { GPU_line_width(3.0f); immUniformColor3fv(color_act); immBegin(GPU_PRIM_LINES, 4); /* angle vertex */ - immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); - immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); - immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); - immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); immEnd(); GPU_line_width(1.0f); @@ -692,25 +755,33 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immUniformColor3ubv(color_wire); - immBegin(GPU_PRIM_LINES, 8); + if (proj_ok[0] || proj_ok[2] || proj_ok[1]) { + immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2 + proj_ok[1] * 4); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); - immVertex2fv(shdr_pos, cap); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); - immVertex2fv(shdr_pos, cap); + if (proj_ok[0]) { + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); + immVertex2fv(shdr_pos_2d, cap); + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); + immVertex2fv(shdr_pos_2d, cap); + } - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); - immVertex2fv(shdr_pos, cap); - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); - immVertex2fv(shdr_pos, cap); + if (proj_ok[2]) { + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); + immVertex2fv(shdr_pos_2d, cap); + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); + immVertex2fv(shdr_pos_2d, cap); + } - /* angle vertex */ - immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); - immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); - immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); - immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); + /* angle vertex */ + if (proj_ok[1]) { + immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); + } - immEnd(); + immEnd(); + } GPU_blend(false); } @@ -729,10 +800,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); /* draw text (bg) */ - { + if (proj_ok[1]) { immUniformColor4fv(color_back); GPU_blend(true); - immRectf(shdr_pos, + immRectf(shdr_pos_2d, posit[0] - bg_margin, posit[1] - bg_margin, posit[0] + bg_margin + numstr_size[0], @@ -743,7 +814,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immUnbindProgram(); /* draw text */ - { + if (proj_ok[1]) { BLF_color3ubv(blf_mono_font, color_text); BLF_position(blf_mono_font, posit[0], posit[1], 0.0f); BLF_rotation(blf_mono_font, 0.0f); @@ -751,30 +822,6 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) } } else { - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); - - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); - - immUniform1i("colors_len", 2); /* "advanced" mode */ - const float *col = is_act ? color_act : color_base; - immUniformArray4fv( - "colors", - (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, - 2); - immUniform1f("dash_width", 6.0f); - immUniform1f("dash_factor", 0.5f); - - immBegin(GPU_PRIM_LINES, 2); - - immVertex2fv(shdr_pos, co_ss[0]); - immVertex2fv(shdr_pos, co_ss[2]); - - immEnd(); - - immUnbindProgram(); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); @@ -790,19 +837,25 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immUniformColor3ubv(color_wire); - immBegin(GPU_PRIM_LINES, 4); + if (proj_ok[0] || proj_ok[2]) { + immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); - immVertex2fv(shdr_pos, cap); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); - immVertex2fv(shdr_pos, cap); + if (proj_ok[0]) { + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); + immVertex2fv(shdr_pos_2d, cap); + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); + immVertex2fv(shdr_pos_2d, cap); + } - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); - immVertex2fv(shdr_pos, cap); - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); - immVertex2fv(shdr_pos, cap); + if (proj_ok[2]) { + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); + immVertex2fv(shdr_pos_2d, cap); + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); + immVertex2fv(shdr_pos_2d, cap); + } - immEnd(); + immEnd(); + } GPU_blend(false); } @@ -824,10 +877,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) posit[1] -= numstr_size[1] / 2.0f; /* draw text (bg) */ - { + if (proj_ok[0] && proj_ok[2]) { immUniformColor4fv(color_back); GPU_blend(true); - immRectf(shdr_pos, + immRectf(shdr_pos_2d, posit[0] - bg_margin, posit[1] - bg_margin, posit[0] + bg_margin + numstr_size[0], @@ -838,7 +891,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immUnbindProgram(); /* draw text */ - { + if (proj_ok[0] && proj_ok[2]) { BLF_color3ubv(blf_mono_font, color_text); BLF_position(blf_mono_font, posit[0], posit[1], 0.0f); BLF_draw(blf_mono_font, numstr, sizeof(numstr)); @@ -849,27 +902,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) BLF_disable(blf_mono_font, BLF_ROTATION); -#undef ARC_STEPS - - /* draw snap */ - if ((ruler_info->snap_flag & RULER_SNAP_OK) && (ruler_info->state == RULER_STATE_DRAG) && - (ruler_item->gz.interaction_data != NULL)) { - RulerInteraction *inter = ruler_item->gz.interaction_data; - /* size from drawSnapping */ - const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); - float co_ss_snap[3]; - ED_view3d_project_float_global( - region, ruler_item->co[inter->co_index], co_ss_snap, V3D_PROJ_TEST_NOP); - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPU_matrix_pop(); + GPU_matrix_pop_projection(); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColor3(TH_GIZMO_VIEW_ALIGN); - - imm_draw_circle_wire_2d(pos, co_ss_snap[0], co_ss_snap[1], size * U.pixelsize, 32); - - immUnbindProgram(); - } +#undef ARC_STEPS } static int gizmo_ruler_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2]) @@ -902,35 +938,36 @@ static int gizmo_ruler_modal(bContext *C, RulerInfo *ruler_info = gz->parent_gzgroup->customdata; RulerItem *ruler_item = (RulerItem *)gz; ARegion *region = CTX_wm_region(C); - bool do_cursor_update = false; + bool do_cursor_update = (event->val == KM_RELEASE) || (event->type == MOUSEMOVE); ruler_info->region = region; - switch (event->type) { - case MOUSEMOVE: { - do_cursor_update = true; - break; - } - } - - const bool do_snap = tweak_flag & WM_GIZMO_TWEAK_SNAP; +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP); +#endif const bool do_thickness = tweak_flag & WM_GIZMO_TWEAK_PRECISE; - if ((ruler_info->drag_state_prev.do_snap != do_snap) || - (ruler_info->drag_state_prev.do_thickness != do_thickness)) { + if ((ruler_info->drag_state_prev.do_thickness != do_thickness)) { do_cursor_update = true; } if (do_cursor_update) { if (ruler_info->state == RULER_STATE_DRAG) { struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - if (view3d_ruler_item_mousemove( - depsgraph, ruler_info, ruler_item, event->mval, do_thickness, do_snap)) { + if (view3d_ruler_item_mousemove(depsgraph, + ruler_info, + ruler_item, + event->mval, + do_thickness +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + , + do_snap +#endif + )) { do_draw = true; } } } - ruler_info->drag_state_prev.do_snap = do_snap; ruler_info->drag_state_prev.do_thickness = do_thickness; if (do_draw) { @@ -957,7 +994,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) /* Add Center Point */ ruler_item_pick->flag |= RULERITEM_USE_ANGLE; inter->co_index = 1; - ruler_state_set(C, ruler_info, RULER_STATE_DRAG); + ruler_state_set(ruler_info, RULER_STATE_DRAG); /* find the factor */ { @@ -978,13 +1015,21 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) /* update the new location */ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - view3d_ruler_item_mousemove( - depsgraph, ruler_info, ruler_item_pick, event->mval, false, false); + view3d_ruler_item_mousemove(depsgraph, + ruler_info, + ruler_item_pick, + event->mval, + false +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + , + false +#endif + ); } } else { inter->co_index = gz->highlight_part; - ruler_state_set(C, ruler_info, RULER_STATE_DRAG); + ruler_state_set(ruler_info, RULER_STATE_DRAG); /* store the initial depth */ copy_v3_v3(inter->drag_start_co, ruler_item_pick->co[inter->co_index]); @@ -997,6 +1042,28 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) ruler_item_pick->flag &= ~RULERITEM_USE_ANGLE_ACTIVE; } + { + /* Set Snap prev point. */ + float *prev_point; + if (ruler_item_pick->flag & RULERITEM_USE_ANGLE) { + prev_point = (inter->co_index != 1) ? ruler_item_pick->co[1] : NULL; + } + else if (inter->co_index == 0) { + prev_point = ruler_item_pick->co[2]; + } + else { + prev_point = ruler_item_pick->co[0]; + } + + if (prev_point) { + RNA_property_float_set_array( + ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); + } + else { + RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint); + } + } + ruler_info->item_active = ruler_item_pick; return OPERATOR_RUNNING_MODAL; @@ -1009,10 +1076,9 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel) if (!cancel) { if (ruler_info->state == RULER_STATE_DRAG) { - if (ruler_info->snap_flag & RULER_SNAP_OK) { - ruler_info->snap_flag &= ~RULER_SNAP_OK; - } - ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); + WM_gizmo_set_flag(ruler_info->snap_data.gizmo, WM_GIZMO_HIDDEN, false); + RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint); + ruler_state_set(ruler_info, RULER_STATE_NORMAL); } /* We could convert only the current gizmo, for now just re-generate. */ view3d_ruler_to_gpencil(C, gzgroup); @@ -1022,7 +1088,7 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel) MEM_SAFE_FREE(gz->interaction_data); } - ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); + ruler_state_set(ruler_info, RULER_STATE_NORMAL); } static int gizmo_ruler_cursor_get(wmGizmo *gz) @@ -1059,16 +1125,39 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup) { RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__); + wmGizmo *gizmo; + { + /* The gizmo snap has to be the first gizmo. */ + const wmGizmoType *gzt_snap; + gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true); + gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL); + RNA_enum_set(gizmo->ptr, + "snap_elements_force", + (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */ + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT)); + + WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); + + wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true); + WM_gizmo_operator_set(gizmo, 0, ot, NULL); + } + if (view3d_ruler_from_gpencil(C, gzgroup)) { /* nop */ } + wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); + + ruler_info->wm = wm; ruler_info->win = win; ruler_info->area = area; ruler_info->region = region; + ruler_info->snap_data.gizmo = gizmo; + ruler_info->snap_data.prop_prevpoint = RNA_struct_find_property(gizmo->ptr, "prev_point"); gzgroup->customdata = ruler_info; } @@ -1078,7 +1167,7 @@ void VIEW3D_GGT_ruler(wmGizmoGroupType *gzgt) gzgt->name = "Ruler Widgets"; gzgt->idname = view3d_gzgt_ruler_id; - gzgt->flag |= WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL; + gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL; gzgt->gzmap_params.spaceid = SPACE_VIEW3D; gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; @@ -1132,8 +1221,20 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); /* snap the first point added, not essential but handy */ inter->co_index = 0; - view3d_ruler_item_mousemove(depsgraph, ruler_info, ruler_item, event->mval, false, true); + view3d_ruler_item_mousemove(depsgraph, + ruler_info, + ruler_item, + event->mval, + false +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + , + true +#endif + ); copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]); + RNA_property_float_set_array(ruler_info->snap_data.gizmo->ptr, + ruler_info->snap_data.prop_prevpoint, + inter->drag_start_co); } else { negate_v3_v3(inter->drag_start_co, rv3d->ofs); @@ -1152,6 +1253,7 @@ void VIEW3D_OT_ruler_add(wmOperatorType *ot) /* identifiers */ ot->name = "Ruler Add"; ot->idname = "VIEW3D_OT_ruler_add"; + ot->description = "Add ruler"; ot->invoke = view3d_ruler_add_invoke; ot->poll = view3d_ruler_poll; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index c16131c8317..50cd71d7edc 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -213,6 +213,7 @@ void viewrotate_modal_keymap(struct wmKeyConfig *keyconf); void viewmove_modal_keymap(struct wmKeyConfig *keyconf); void viewzoom_modal_keymap(struct wmKeyConfig *keyconf); void viewdolly_modal_keymap(struct wmKeyConfig *keyconf); +void viewplace_modal_keymap(struct wmKeyConfig *keyconf); /* view3d_buttons.c */ void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot); @@ -243,6 +244,9 @@ void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot); +/* view3d_placement.c */ +void VIEW3D_OT_interactive_add(struct wmOperatorType *ot); + /* space_view3d.c */ extern const char *view3d_context_dir[]; /* doc access */ @@ -268,6 +272,8 @@ void VIEW3D_OT_ruler_remove(struct wmOperatorType *ot); void VIEW3D_GT_navigate_rotate(struct wmGizmoType *gzt); +void VIEW3D_GGT_placement(struct wmGizmoGroupType *gzgt); + /* workaround for trivial but noticeable camera bug caused by imprecision * between view border calculation in 2D/3D space, workaround for bug [#28037]. * without this define we get the old behavior which is to try and align them diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index 2ad7797f6c8..91e629147f4 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -406,6 +406,7 @@ void nurbs_foreachScreenVert(ViewContext *vc, BPoint *bp, BezTriple *bezt, int beztindex, + bool handles_visible, const float screen_co_b[2]), void *userData, const eV3DProjTest clip_flag) @@ -414,6 +415,8 @@ void nurbs_foreachScreenVert(ViewContext *vc, Nurb *nu; int i; ListBase *nurbs = BKE_curve_editNurbs_get(cu); + /* If no point in the triple is selected, the handles are invisible. */ + const bool only_selected = (vc->v3d->overlay.handle_display == CURVE_HANDLE_SELECTED); ED_view3d_check_mats_rv3d(vc->rv3d); @@ -427,15 +430,17 @@ void nurbs_foreachScreenVert(ViewContext *vc, BezTriple *bezt = &nu->bezt[i]; if (bezt->hide == 0) { + const bool handles_visible = (vc->v3d->overlay.handle_display != CURVE_HANDLE_NONE) && + (!only_selected || BEZT_ISSEL_ANY(bezt)); float screen_co[2]; - if ((vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { + if (!handles_visible) { if (ED_view3d_project_float_object(vc->region, bezt->vec[1], screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 1, screen_co); + func(userData, nu, NULL, bezt, 1, false, screen_co); } } else { @@ -444,21 +449,21 @@ void nurbs_foreachScreenVert(ViewContext *vc, screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 0, screen_co); + func(userData, nu, NULL, bezt, 0, true, screen_co); } if (ED_view3d_project_float_object(vc->region, bezt->vec[1], screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 1, screen_co); + func(userData, nu, NULL, bezt, 1, true, screen_co); } if (ED_view3d_project_float_object(vc->region, bezt->vec[2], screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 2, screen_co); + func(userData, nu, NULL, bezt, 2, true, screen_co); } } } @@ -473,7 +478,7 @@ void nurbs_foreachScreenVert(ViewContext *vc, if (ED_view3d_project_float_object( vc->region, bp->vec, screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { - func(userData, nu, bp, NULL, -1, screen_co); + func(userData, nu, bp, NULL, -1, false, screen_co); } } } diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 1ad3f8bb1f5..0770bac1313 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -211,6 +211,8 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active); + WM_operatortype_append(VIEW3D_OT_interactive_add); + WM_operatortype_append(VIEW3D_OT_toggle_shading); WM_operatortype_append(VIEW3D_OT_toggle_xray); WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip); @@ -234,4 +236,5 @@ void view3d_keymap(wmKeyConfig *keyconf) viewmove_modal_keymap(keyconf); viewzoom_modal_keymap(keyconf); viewdolly_modal_keymap(keyconf); + viewplace_modal_keymap(keyconf); } diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c new file mode 100644 index 00000000000..f2b78bc2aaf --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -0,0 +1,1153 @@ +/* + * 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 spview3d + * + * Operator to interactively place data. + * + * Currently only adds meshes, but could add other kinds of data + * including library assets & non-mesh types. + */ + +#include "BLI_math_vector.h" +#include "MEM_guardedalloc.h" + +#include "DNA_collection_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_vfont_types.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_main.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_toolsystem.h" +#include "WM_types.h" + +#include "ED_gizmo_library.h" +#include "ED_gizmo_utils.h" +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_transform.h" +#include "ED_transform_snap_object_context.h" +#include "ED_view3d.h" + +#include "UI_resources.h" + +#include "GPU_batch.h" +#include "GPU_immediate.h" +#include "GPU_state.h" + +#include "view3d_intern.h" + +static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement"; + +/* -------------------------------------------------------------------- */ +/** \name Local Types + * \{ */ + +enum ePlace_PrimType { + PLACE_PRIMITIVE_TYPE_CUBE = 1, + PLACE_PRIMITIVE_TYPE_CYLINDER = 2, + PLACE_PRIMITIVE_TYPE_CONE = 3, + PLACE_PRIMITIVE_TYPE_SPHERE_UV = 4, + PLACE_PRIMITIVE_TYPE_SPHERE_ICO = 5, +}; + +enum ePlace_Origin { + PLACE_ORIGIN_BASE = 1, + PLACE_ORIGIN_CENTER = 2, +}; + +enum ePlace_Depth { + PLACE_DEPTH_SURFACE = 1, + PLACE_DEPTH_CURSOR_PLANE = 2, + PLACE_DEPTH_CURSOR_VIEW = 3, +}; + +struct InteractivePlaceData { + /* Window manager variables (set these even when waiting for input). */ + Scene *scene; + ScrArea *area; + View3D *v3d; + ARegion *region; + + /** Draw object preview region draw callback. */ + void *draw_handle_view; + + float co_src[3]; + + /** Primary & secondary steps. */ + struct { + bool is_centered; + bool is_fixed_aspect; + float plane[4]; + float co_dst[3]; + } step[2]; + + float matrix_orient[3][3]; + int orient_axis; + + /** The tool option, if we start centered, invert toggling behavior. */ + bool is_centered_init; + + bool use_snap, is_snap_found, is_snap_invert; + float snap_co[3]; + + /** Can index into #InteractivePlaceData.step. */ + enum { + STEP_BASE = 0, + STEP_DEPTH = 1, + } step_index; + + enum ePlace_PrimType primitive_type; + + /** Activated from the tool-system. */ + bool use_tool; + + /** Event used to start the operator. */ + short launch_event; + + /** When activated without a tool. */ + bool wait_for_input; + + /** Optional snap gizmo, needed for snapping. */ + wmGizmo *snap_gizmo; +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Utilities + * \{ */ + +/* On-screen snap distance. */ +#define MVAL_MAX_PX_DIST 12.0f + +static bool idp_snap_point_from_gizmo(wmGizmo *gz, float r_location[3]) +{ + if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) { + PropertyRNA *prop_location = RNA_struct_find_property(gz->ptr, "location"); + RNA_property_float_get_array(gz->ptr, prop_location, r_location); + return true; + } + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Primitive Drawing (Cube, Cone, Cylinder...) + * \{ */ + +static void draw_line_loop(float coords[][3], int coords_len, const float color[4]) +{ + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(vert, coords_len); + + for (int i = 0; i < coords_len; i++) { + GPU_vertbuf_attr_set(vert, pos, i, coords[i]); + } + + GPU_blend(true); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vert, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + + GPU_batch_bind(batch); + + GPU_batch_uniform_4fv(batch, "color", color); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); + GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize); + + GPU_batch_draw(batch); + + GPU_batch_program_use_end(batch); + + GPU_batch_discard(batch); + GPU_blend(false); +} + +static void draw_line_pairs(float coords_a[][3], + float coords_b[][3], + int coords_len, + const float color[4]) +{ + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(vert, coords_len * 2); + + for (int i = 0; i < coords_len; i++) { + GPU_vertbuf_attr_set(vert, pos, i * 2, coords_a[i]); + GPU_vertbuf_attr_set(vert, pos, (i * 2) + 1, coords_b[i]); + } + + GPU_blend(true); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + + GPU_batch_bind(batch); + + GPU_batch_uniform_4fv(batch, "color", color); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); + GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize); + + GPU_batch_draw(batch); + + GPU_batch_program_use_end(batch); + + GPU_batch_discard(batch); + GPU_blend(false); +} + +static void draw_line_bounds(const BoundBox *bounds, const float color[4]) +{ + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + int edges[12][2] = { + /* First side. */ + {0, 1}, + {1, 2}, + {2, 3}, + {3, 0}, + /* Second side. */ + {4, 5}, + {5, 6}, + {6, 7}, + {7, 4}, + /* Edges between. */ + {0, 4}, + {1, 5}, + {2, 6}, + {3, 7}, + }; + + GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(vert, ARRAY_SIZE(edges) * 2); + + for (int i = 0, j = 0; i < ARRAY_SIZE(edges); i++) { + GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][0]]); + GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][1]]); + } + + GPU_blend(true); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + + GPU_batch_bind(batch); + + GPU_batch_uniform_4fv(batch, "color", color); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); + GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize); + + GPU_batch_draw(batch); + + GPU_batch_program_use_end(batch); + + GPU_batch_discard(batch); + GPU_blend(false); +} + +static bool calc_bbox(struct InteractivePlaceData *ipd, BoundBox *bounds) +{ + memset(bounds, 0x0, sizeof(*bounds)); + + if (compare_v3v3(ipd->co_src, ipd->step[0].co_dst, FLT_EPSILON)) { + return false; + } + + float matrix_orient_inv[3][3]; + invert_m3_m3(matrix_orient_inv, ipd->matrix_orient); + + const int x_axis = (ipd->orient_axis + 1) % 3; + const int y_axis = (ipd->orient_axis + 2) % 3; + + float quad_base[4][3]; + float quad_secondary[4][3]; + + copy_v3_v3(quad_base[0], ipd->co_src); + copy_v3_v3(quad_base[2], ipd->step[0].co_dst); + + /* Only set when we have a fixed aspect. */ + float fixed_aspect_dimension; + + /* *** Primary *** */ + + { + float delta_local[3]; + float delta_a[3]; + float delta_b[3]; + + sub_v3_v3v3(delta_local, ipd->step[0].co_dst, ipd->co_src); + mul_m3_v3(matrix_orient_inv, delta_local); + + copy_v3_v3(delta_a, delta_local); + copy_v3_v3(delta_b, delta_local); + delta_a[ipd->orient_axis] = 0.0f; + delta_b[ipd->orient_axis] = 0.0f; + + delta_a[x_axis] = 0.0f; + delta_b[y_axis] = 0.0f; + + /* Assign here in case secondary */ + fixed_aspect_dimension = max_ff(fabsf(delta_a[y_axis]), fabsf(delta_b[x_axis])); + + if (ipd->step[0].is_fixed_aspect) { + delta_a[y_axis] = copysignf(fixed_aspect_dimension, delta_a[y_axis]); + delta_b[x_axis] = copysignf(fixed_aspect_dimension, delta_b[x_axis]); + } + + mul_m3_v3(ipd->matrix_orient, delta_a); + mul_m3_v3(ipd->matrix_orient, delta_b); + + if (ipd->step[0].is_fixed_aspect) { + /* Recalculate the destination point. */ + copy_v3_v3(quad_base[2], ipd->co_src); + add_v3_v3(quad_base[2], delta_a); + add_v3_v3(quad_base[2], delta_b); + } + + add_v3_v3v3(quad_base[1], ipd->co_src, delta_a); + add_v3_v3v3(quad_base[3], ipd->co_src, delta_b); + } + + if (ipd->step[0].is_centered) { + /* Use a copy in case aspect was applied to the quad. */ + float base_co_dst[3]; + copy_v3_v3(base_co_dst, quad_base[2]); + for (int i = 0; i < 4; i++) { + sub_v3_v3(quad_base[i], base_co_dst); + mul_v3_fl(quad_base[i], 2.0f); + add_v3_v3(quad_base[i], base_co_dst); + } + } + + /* *** Secondary *** */ + + float delta_local[3]; + if (ipd->step_index == STEP_DEPTH) { + sub_v3_v3v3(delta_local, ipd->step[1].co_dst, ipd->step[0].co_dst); + } + else { + zero_v3(delta_local); + } + + if (ipd->step[1].is_fixed_aspect) { + if (!is_zero_v3(delta_local)) { + normalize_v3_length(delta_local, fixed_aspect_dimension); + } + } + + if (ipd->step[1].is_centered) { + for (int i = 0; i < ARRAY_SIZE(quad_base); i++) { + sub_v3_v3(quad_base[i], delta_local); + } + mul_v3_fl(delta_local, 2.0f); + } + + if ((ipd->step_index == STEP_DEPTH) && + (compare_v3v3(ipd->step[0].co_dst, ipd->step[1].co_dst, FLT_EPSILON) == false)) { + + for (int i = 0; i < ARRAY_SIZE(quad_base); i++) { + add_v3_v3v3(quad_secondary[i], quad_base[i], delta_local); + } + } + else { + copy_v3_v3(quad_secondary[0], quad_base[0]); + copy_v3_v3(quad_secondary[1], quad_base[1]); + copy_v3_v3(quad_secondary[2], quad_base[2]); + copy_v3_v3(quad_secondary[3], quad_base[3]); + } + + for (int i = 0; i < 4; i++) { + copy_v3_v3(bounds->vec[i], quad_base[i]); + copy_v3_v3(bounds->vec[i + 4], quad_secondary[i]); + } + + return true; +} + +static void draw_circle_in_quad(const float v1[2], + const float v2[2], + const float v3[2], + const float v4[2], + const int resolution, + const float color[4]) +{ + /* This isn't so efficient. */ + const float quad[4][2] = { + {-1, -1}, + {+1, -1}, + {+1, +1}, + {-1, +1}, + }; + + float(*coords)[3] = MEM_mallocN(sizeof(float[3]) * (resolution + 1), __func__); + for (int i = 0; i <= resolution; i++) { + float theta = ((2.0f * M_PI) * ((float)i / (float)resolution)) + 0.01f; + float x = cosf(theta); + float y = sinf(theta); + float pt[2] = {x, y}; + float w[4]; + barycentric_weights_v2_quad(UNPACK4(quad), pt, w); + + float *co = coords[i]; + zero_v3(co); + madd_v3_v3fl(co, v1, w[0]); + madd_v3_v3fl(co, v2, w[1]); + madd_v3_v3fl(co, v3, w[2]); + madd_v3_v3fl(co, v4, w[3]); + } + draw_line_loop(coords, resolution + 1, color); + MEM_freeN(coords); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Drawing Callbacks + * \{ */ + +static void draw_primitive_view_impl(const struct bContext *C, + struct InteractivePlaceData *ipd, + const float color[4]) +{ + UNUSED_VARS(C); + + BoundBox bounds; + calc_bbox(ipd, &bounds); + draw_line_bounds(&bounds, color); + + if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) { + /* pass */ + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) { + draw_circle_in_quad(UNPACK4(bounds.vec), 32, color); + draw_circle_in_quad(UNPACK4((&bounds.vec[4])), 32, color); + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) { + draw_circle_in_quad(UNPACK4(bounds.vec), 32, color); + + float center[3]; + mid_v3_v3v3v3v3(center, UNPACK4((&bounds.vec[4]))); + + float coords_a[4][3]; + float coords_b[4][3]; + + for (int i = 0; i < 4; i++) { + copy_v3_v3(coords_a[i], center); + mid_v3_v3v3(coords_b[i], bounds.vec[i], bounds.vec[(i + 1) % 4]); + } + + draw_line_pairs(coords_a, coords_b, 4, color); + } + else if (ELEM(ipd->primitive_type, + PLACE_PRIMITIVE_TYPE_SPHERE_UV, + PLACE_PRIMITIVE_TYPE_SPHERE_ICO)) { + /* See bound-box diagram for reference. */ + + /* Primary Side. */ + float v01[3], v12[3], v23[3], v30[3]; + mid_v3_v3v3(v01, bounds.vec[0], bounds.vec[1]); + mid_v3_v3v3(v12, bounds.vec[1], bounds.vec[2]); + mid_v3_v3v3(v23, bounds.vec[2], bounds.vec[3]); + mid_v3_v3v3(v30, bounds.vec[3], bounds.vec[0]); + /* Secondary Side. */ + float v45[3], v56[3], v67[3], v74[3]; + mid_v3_v3v3(v45, bounds.vec[4], bounds.vec[5]); + mid_v3_v3v3(v56, bounds.vec[5], bounds.vec[6]); + mid_v3_v3v3(v67, bounds.vec[6], bounds.vec[7]); + mid_v3_v3v3(v74, bounds.vec[7], bounds.vec[4]); + /* Edges between. */ + float v04[3], v15[3], v26[3], v37[3]; + mid_v3_v3v3(v04, bounds.vec[0], bounds.vec[4]); + mid_v3_v3v3(v15, bounds.vec[1], bounds.vec[5]); + mid_v3_v3v3(v26, bounds.vec[2], bounds.vec[6]); + mid_v3_v3v3(v37, bounds.vec[3], bounds.vec[7]); + + draw_circle_in_quad(v01, v45, v67, v23, 32, color); + draw_circle_in_quad(v30, v12, v56, v74, 32, color); + draw_circle_in_quad(v04, v15, v26, v37, 32, color); + } +} + +static void draw_primitive_view(const struct bContext *C, ARegion *UNUSED(region), void *arg) +{ + struct InteractivePlaceData *ipd = arg; + float color[4]; + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, color); + + const bool use_depth = !XRAY_ENABLED(ipd->v3d); + const bool depth_test_enabled = GPU_depth_test_enabled(); + + if (use_depth) { + GPU_depth_test(false); + color[3] = 0.15f; + draw_primitive_view_impl(C, ipd, color); + } + + if (use_depth) { + GPU_depth_test(true); + } + color[3] = 1.0f; + draw_primitive_view_impl(C, ipd, color); + + if (use_depth) { + if (depth_test_enabled == false) { + GPU_depth_test(false); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Object Modal Operator + * \{ */ + +/** + * + * */ +static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event) +{ + + const int plane_axis = RNA_enum_get(op->ptr, "plane_axis"); + const enum ePlace_Depth plane_depth = RNA_enum_get(op->ptr, "plane_depth"); + const enum ePlace_Origin plane_origin = RNA_enum_get(op->ptr, "plane_origin"); + + struct InteractivePlaceData *ipd = op->customdata; + + RegionView3D *rv3d = ipd->region->regiondata; + + ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type); + + ED_transform_calc_orientation_from_type(C, ipd->matrix_orient); + + ipd->orient_axis = plane_axis; + ipd->is_centered_init = (plane_origin == PLACE_ORIGIN_CENTER); + ipd->step[0].is_centered = ipd->is_centered_init; + ipd->step[1].is_centered = ipd->is_centered_init; + ipd->step_index = STEP_BASE; + + /* Assign snap gizmo which is may be used as part of the tool. */ + { + wmGizmoMap *gzmap = ipd->region->gizmo_map; + wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL; + if ((gzgroup != NULL) && gzgroup->gizmos.first) { + ipd->snap_gizmo = gzgroup->gizmos.first; + } + } + + { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "primitive_type"); + if (RNA_property_is_set(op->ptr, prop)) { + ipd->primitive_type = RNA_property_enum_get(op->ptr, prop); + ipd->use_tool = false; + } + else { + ipd->use_tool = true; + + /* Get from the tool, a bit of a non-standard way of operating. */ + const bToolRef *tref = ipd->area->runtime.tool; + if (tref && STREQ(tref->idname, "builtin.primitive_cube_add")) { + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE; + } + else if (tref && STREQ(tref->idname, "builtin.primitive_cylinder_add")) { + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CYLINDER; + } + else if (tref && STREQ(tref->idname, "builtin.primitive_cone_add")) { + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CONE; + } + else if (tref && STREQ(tref->idname, "builtin.primitive_uv_sphere_add")) { + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_UV; + } + else if (tref && STREQ(tref->idname, "builtin.primitive_ico_sphere_add")) { + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_ICO; + } + else { + /* If the user runs this as an operator they should set the 'primitive_type', + * however running from operator search will end up at this point. */ + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE; + ipd->use_tool = false; + } + } + } + + UNUSED_VARS(C, event); + + ipd->draw_handle_view = ED_region_draw_cb_activate( + ipd->region->type, draw_primitive_view, ipd, REGION_DRAW_POST_VIEW); + + ED_region_tag_redraw(ipd->region); + + plane_from_point_normal_v3( + ipd->step[0].plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]); + + const float mval_fl[2] = {UNPACK2(event->mval)}; + + const bool is_snap_found = ipd->snap_gizmo ? + idp_snap_point_from_gizmo(ipd->snap_gizmo, ipd->co_src) : + false; + ipd->is_snap_invert = ipd->snap_gizmo ? ED_gizmotypes_snap_3d_invert_snap_get(ipd->snap_gizmo) : + false; + { + const ToolSettings *ts = ipd->scene->toolsettings; + ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP)); + } + + if (is_snap_found) { + /* pass */ + } + else { + bool use_depth_fallback = true; + if (plane_depth == PLACE_DEPTH_CURSOR_VIEW) { + /* View plane. */ + ED_view3d_win_to_3d( + ipd->v3d, ipd->region, ipd->scene->cursor.location, mval_fl, ipd->co_src); + use_depth_fallback = false; + } + else if (plane_depth == PLACE_DEPTH_SURFACE) { + SnapObjectContext *snap_context = + (ipd->snap_gizmo ? ED_gizmotypes_snap_3d_context_ensure( + ipd->scene, ipd->region, ipd->v3d, ipd->snap_gizmo) : + NULL); + if ((snap_context != NULL) && + ED_transform_snap_object_project_view3d(snap_context, + CTX_data_ensure_evaluated_depsgraph(C), + SCE_SNAP_MODE_FACE, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .use_object_edit_cage = true, + }, + mval_fl, + NULL, + NULL, + ipd->co_src, + NULL)) { + use_depth_fallback = false; + } + } + + /* Use as fallback to surface. */ + if (use_depth_fallback || (plane_depth == PLACE_DEPTH_CURSOR_PLANE)) { + /* Cursor plane. */ + float plane[4]; + plane_from_point_normal_v3( + plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]); + if (ED_view3d_win_to_3d_on_plane(ipd->region, plane, mval_fl, false, ipd->co_src)) { + use_depth_fallback = false; + } + /* Even if the calculation works, it's possible the point found is behind the view. */ + if (rv3d->is_persp) { + float dir[3]; + sub_v3_v3v3(dir, rv3d->viewinv[3], ipd->co_src); + if (dot_v3v3(dir, rv3d->viewinv[2]) < ipd->v3d->clip_start) { + use_depth_fallback = true; + } + } + } + + if (use_depth_fallback) { + float co_depth[3]; + /* Fallback to view center. */ + negate_v3_v3(co_depth, rv3d->ofs); + ED_view3d_win_to_3d(ipd->v3d, ipd->region, co_depth, mval_fl, ipd->co_src); + } + } + + plane_from_point_normal_v3( + ipd->step[0].plane, ipd->co_src, ipd->matrix_orient[ipd->orient_axis]); + + copy_v3_v3(ipd->step[0].co_dst, ipd->co_src); +} + +static int view3d_interactive_add_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input"); + + struct InteractivePlaceData *ipd = MEM_callocN(sizeof(*ipd), __func__); + op->customdata = ipd; + + ipd->scene = CTX_data_scene(C); + ipd->area = CTX_wm_area(C); + ipd->region = CTX_wm_region(C); + ipd->v3d = CTX_wm_view3d(C); + + if (wait_for_input) { + ipd->wait_for_input = true; + /* TODO: support snapping when not using with tool. */ +#if 0 + WM_gizmo_group_type_ensure(view3d_gzgt_placement_id); +#endif + } + else { + view3d_interactive_add_begin(C, op, event); + } + + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static void view3d_interactive_add_exit(bContext *C, wmOperator *op) +{ + UNUSED_VARS(C); + + struct InteractivePlaceData *ipd = op->customdata; + + ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view); + + ED_region_tag_redraw(ipd->region); + + MEM_freeN(ipd); +} + +static void view3d_interactive_add_cancel(bContext *C, wmOperator *op) +{ + view3d_interactive_add_exit(C, op); +} + +enum { + PLACE_MODAL_SNAP_ON, + PLACE_MODAL_SNAP_OFF, + PLACE_MODAL_FIXED_ASPECT_ON, + PLACE_MODAL_FIXED_ASPECT_OFF, + PLACE_MODAL_PIVOT_CENTER_ON, + PLACE_MODAL_PIVOT_CENTER_OFF, +}; + +void viewplace_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {PLACE_MODAL_SNAP_ON, "SNAP_ON", 0, "Snap On", ""}, + {PLACE_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""}, + {PLACE_MODAL_FIXED_ASPECT_ON, "FIXED_ASPECT_ON", 0, "Fixed Aspect On", ""}, + {PLACE_MODAL_FIXED_ASPECT_OFF, "FIXED_ASPECT_OFF", 0, "Fixed Aspect Off", ""}, + {PLACE_MODAL_PIVOT_CENTER_ON, "PIVOT_CENTER_ON", 0, "Center Pivot On", ""}, + {PLACE_MODAL_PIVOT_CENTER_OFF, "PIVOT_CENTER_OFF", 0, "Center Pivot Off", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + const char *keymap_name = "View3D Placement Modal Map"; + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name); + + /* This function is called for each space-type, only needs to add map once. */ + if (keymap && keymap->modal_items) { + return; + } + + keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items); + + WM_modalkeymap_assign(keymap, "VIEW3D_OT_interactive_add"); +} + +static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + UNUSED_VARS(C, op); + + struct InteractivePlaceData *ipd = op->customdata; + + ARegion *region = ipd->region; + bool do_redraw = false; + bool do_cursor_update = false; + + /* Handle modal key-map. */ + if (event->type == EVT_MODAL_MAP) { + bool is_fallthrough = false; + switch (event->val) { + case PLACE_MODAL_FIXED_ASPECT_ON: { + is_fallthrough = true; + ATTR_FALLTHROUGH; + } + case PLACE_MODAL_FIXED_ASPECT_OFF: { + ipd->step[ipd->step_index].is_fixed_aspect = is_fallthrough; + do_redraw = true; + break; + } + case PLACE_MODAL_PIVOT_CENTER_ON: { + is_fallthrough = true; + ATTR_FALLTHROUGH; + } + case PLACE_MODAL_PIVOT_CENTER_OFF: { + ipd->step[ipd->step_index].is_centered = is_fallthrough; + do_redraw = true; + break; + } + case PLACE_MODAL_SNAP_ON: { + is_fallthrough = true; + ATTR_FALLTHROUGH; + } + case PLACE_MODAL_SNAP_OFF: { + const ToolSettings *ts = ipd->scene->toolsettings; + ipd->is_snap_invert = is_fallthrough; + ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP)); + do_cursor_update = true; + break; + } + } + } + + if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) { + view3d_interactive_add_exit(C, op); + return OPERATOR_CANCELLED; + } + else if (event->type == MOUSEMOVE) { + do_cursor_update = true; + } + + if (ipd->wait_for_input) { + if (ELEM(event->type, LEFTMOUSE)) { + if (event->val == KM_PRESS) { + view3d_interactive_add_begin(C, op, event); + ipd->wait_for_input = false; + return OPERATOR_RUNNING_MODAL; + } + } + return OPERATOR_RUNNING_MODAL; + } + + if (ipd->step_index == STEP_BASE) { + if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) { + if (event->val == KM_RELEASE) { + /* Set secondary plane. */ + + /* Create normal. */ + { + RegionView3D *rv3d = region->regiondata; + float no_temp[3]; + float no[3]; + cross_v3_v3v3(no_temp, ipd->step[0].plane, rv3d->viewinv[2]); + cross_v3_v3v3(no, no_temp, ipd->step[0].plane); + normalize_v3(no); + + plane_from_point_normal_v3(ipd->step[1].plane, ipd->step[0].co_dst, no); + } + + copy_v3_v3(ipd->step[1].co_dst, ipd->step[0].co_dst); + ipd->step_index = STEP_DEPTH; + + /* Keep these values from the previous step. */ + ipd->step[1].is_centered = ipd->step[0].is_centered; + ipd->step[1].is_fixed_aspect = ipd->step[0].is_fixed_aspect; + } + } + } + else if (ipd->step_index == STEP_DEPTH) { + if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) { + if (event->val == KM_PRESS) { + + BoundBox bounds; + calc_bbox(ipd, &bounds); + + float location[3]; + float rotation[3]; + float scale[3]; + + float matrix_orient_axis[3][3]; + copy_m3_m3(matrix_orient_axis, ipd->matrix_orient); + if (ipd->orient_axis != 2) { + swap_v3_v3(matrix_orient_axis[2], matrix_orient_axis[ipd->orient_axis]); + swap_v3_v3(matrix_orient_axis[0], matrix_orient_axis[1]); + } + /* Needed for shapes where the sign matters (cone for eg). */ + { + float delta[3]; + sub_v3_v3v3(delta, bounds.vec[0], bounds.vec[4]); + if (dot_v3v3(ipd->matrix_orient[ipd->orient_axis], delta) > 0.0f) { + negate_v3(matrix_orient_axis[2]); + + /* Only flip Y so we don't flip a single axis which causes problems. */ + negate_v3(matrix_orient_axis[1]); + } + } + + mat3_to_eul(rotation, matrix_orient_axis); + + mid_v3_v3v3(location, bounds.vec[0], bounds.vec[6]); + const int cube_verts[3] = {3, 1, 4}; + for (int i = 0; i < 3; i++) { + scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]); + } + + wmOperatorType *ot = NULL; + PointerRNA op_props; + if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) { + ot = WM_operatortype_find("MESH_OT_primitive_cube_add", false); + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) { + ot = WM_operatortype_find("MESH_OT_primitive_cylinder_add", false); + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) { + ot = WM_operatortype_find("MESH_OT_primitive_cone_add", false); + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_UV) { + ot = WM_operatortype_find("MESH_OT_primitive_uv_sphere_add", false); + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_ICO) { + ot = WM_operatortype_find("MESH_OT_primitive_ico_sphere_add", false); + } + + if (ot != NULL) { + WM_operator_properties_create_ptr(&op_props, ot); + + if (ipd->use_tool) { + bToolRef *tref = ipd->area->runtime.tool; + PointerRNA temp_props; + WM_toolsystem_ref_properties_init_for_keymap(tref, &temp_props, &op_props, ot); + SWAP(PointerRNA, temp_props, op_props); + WM_operator_properties_free(&temp_props); + } + + RNA_float_set_array(&op_props, "rotation", rotation); + RNA_float_set_array(&op_props, "location", location); + RNA_float_set_array(&op_props, "scale", scale); + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props); + WM_operator_properties_free(&op_props); + } + else { + BLI_assert(0); + } + + view3d_interactive_add_exit(C, op); + return OPERATOR_FINISHED; + } + } + } + else { + BLI_assert(0); + } + + if (do_cursor_update) { + const float mval_fl[2] = {UNPACK2(event->mval)}; + + /* Calculate the snap location on mouse-move or when toggling snap. */ + bool is_snap_found_prev = ipd->is_snap_found; + ipd->is_snap_found = false; + if (ipd->use_snap) { + if (ipd->snap_gizmo != NULL) { + ED_gizmotypes_snap_3d_toggle_set(ipd->snap_gizmo, ipd->use_snap); + if (ED_gizmotypes_snap_3d_update(ipd->snap_gizmo, + CTX_data_ensure_evaluated_depsgraph(C), + ipd->region, + ipd->v3d, + NULL, + mval_fl, + ipd->snap_co, + NULL)) { + ipd->is_snap_found = true; + } + ED_gizmotypes_snap_3d_toggle_clear(ipd->snap_gizmo); + } + } + + /* Workaround because test_select doesn't run at the same time as the modal operator. */ + if (is_snap_found_prev != ipd->is_snap_found) { + wmGizmoMap *gzmap = ipd->region->gizmo_map; + WM_gizmo_highlight_set(gzmap, ipd->is_snap_found ? ipd->snap_gizmo : NULL); + } + + if (ipd->step_index == STEP_BASE) { + if (ipd->is_snap_found) { + closest_to_plane_normalized_v3(ipd->step[0].co_dst, ipd->step[0].plane, ipd->snap_co); + } + else { + if (ED_view3d_win_to_3d_on_plane( + region, ipd->step[0].plane, mval_fl, false, ipd->step[0].co_dst)) { + /* pass */ + } + } + } + else if (ipd->step_index == STEP_DEPTH) { + if (ipd->is_snap_found) { + closest_to_plane_normalized_v3(ipd->step[1].co_dst, ipd->step[1].plane, ipd->snap_co); + } + else { + if (ED_view3d_win_to_3d_on_plane( + region, ipd->step[1].plane, mval_fl, false, ipd->step[1].co_dst)) { + /* pass */ + } + } + + /* Correct the point so it's aligned with the 'ipd->step[0].co_dst'. */ + float close[3], delta[3]; + closest_to_plane_normalized_v3(close, ipd->step[0].plane, ipd->step[1].co_dst); + sub_v3_v3v3(delta, close, ipd->step[0].co_dst); + sub_v3_v3(ipd->step[1].co_dst, delta); + } + do_redraw = true; + } + + if (do_redraw) { + ED_region_tag_redraw(region); + } + + return OPERATOR_RUNNING_MODAL; +} + +static bool view3d_interactive_add_poll(bContext *C) +{ + const enum eContextObjectMode mode = CTX_data_mode_enum(C); + return ELEM(mode, CTX_MODE_OBJECT, CTX_MODE_EDIT_MESH); +} + +void VIEW3D_OT_interactive_add(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Primitive Object"; + ot->description = "Interactively add an object"; + ot->idname = "VIEW3D_OT_interactive_add"; + + /* api callbacks */ + ot->invoke = view3d_interactive_add_invoke; + ot->modal = view3d_interactive_add_modal; + ot->cancel = view3d_interactive_add_cancel; + ot->poll = view3d_interactive_add_poll; + + /* Note, let the operator we call handle undo and registering it's self. */ + /* flags */ + ot->flag = 0; + + /* properties */ + PropertyRNA *prop; + + /* Normally not accessed directly, leave unset and check the active tool. */ + static const EnumPropertyItem primitive_type[] = { + {PLACE_PRIMITIVE_TYPE_CUBE, "CUBE", 0, "Cube", ""}, + {PLACE_PRIMITIVE_TYPE_CYLINDER, "CYLINDER", 0, "Cylinder", ""}, + {PLACE_PRIMITIVE_TYPE_CONE, "CONE", 0, "Cone", ""}, + {PLACE_PRIMITIVE_TYPE_SPHERE_UV, "SPHERE_UV", 0, "UV Sphere", ""}, + {PLACE_PRIMITIVE_TYPE_SPHERE_ICO, "SPHERE_ICO", 0, "ICO Sphere", ""}, + {0, NULL, 0, NULL, NULL}, + }; + prop = RNA_def_property(ot->srna, "primitive_type", PROP_ENUM, PROP_NONE); + RNA_def_property_ui_text(prop, "Primitive", ""); + RNA_def_property_enum_items(prop, primitive_type); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_property(ot->srna, "plane_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_ui_text(prop, "Plane Axis", "The axis used for placing the base region"); + RNA_def_property_enum_default(prop, 2); + RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + static const EnumPropertyItem plane_depth_items[] = { + {PLACE_DEPTH_SURFACE, + "SURFACE", + 0, + "Surface", + "Start placing on the surface, using the 3D cursor position as a fallback"}, + {PLACE_DEPTH_CURSOR_PLANE, + "CURSOR_PLANE", + 0, + "3D Cursor Plane", + "Start placement using a point projected onto the selected axis at the 3D cursor position"}, + {PLACE_DEPTH_CURSOR_VIEW, + "CURSOR_VIEW", + 0, + "3D Cursor View", + "Start placement using the mouse cursor projected onto the view plane"}, + {0, NULL, 0, NULL, NULL}, + }; + prop = RNA_def_property(ot->srna, "plane_depth", PROP_ENUM, PROP_NONE); + RNA_def_property_ui_text(prop, "Position", "The initial depth used when placing the cursor"); + RNA_def_property_enum_default(prop, PLACE_DEPTH_SURFACE); + RNA_def_property_enum_items(prop, plane_depth_items); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + static const EnumPropertyItem origin_items[] = { + {PLACE_ORIGIN_BASE, "BASE", 0, "Base", "Start placing the corner position"}, + {PLACE_ORIGIN_CENTER, "CENTER", 0, "Center", "Start placing the center position"}, + {0, NULL, 0, NULL, NULL}, + }; + prop = RNA_def_property(ot->srna, "plane_origin", PROP_ENUM, PROP_NONE); + RNA_def_property_ui_text(prop, "Origin", "The initial position for placement"); + RNA_def_property_enum_default(prop, PLACE_ORIGIN_BASE); + RNA_def_property_enum_items(prop, origin_items); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + /* When not accessed via a tool. */ + prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Placement Gizmo Group + * + * This is currently only used for snapping before the tool is initialized, + * we could show a placement plane here. + * \{ */ + +static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + wmGizmo *gizmo; + + { + /* The gizmo snap has to be the first gizmo. */ + const wmGizmoType *gzt_snap; + gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true); + gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL); + RNA_enum_set(gizmo->ptr, + "snap_elements_force", + (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */ + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT)); + + WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); + + /* Don't handle any events, this is for display only. */ + gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP; + } +} + +void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Placement Widget"; + gzgt->idname = view3d_gzgt_placement_id; + + gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL; + + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + + gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool; + gzgt->setup = WIDGETGROUP_placement_setup; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 2ce2edb98fe..8c60e36a141 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -411,6 +411,7 @@ typedef struct LassoSelectUserData { const int (*mcoords)[2]; int mcoords_len; eSelectOp sel_op; + eBezTriple_Flag select_flag; /* runtime */ int pass; @@ -434,6 +435,8 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, r_data->mcoords = mcoords; r_data->mcoords_len = mcoords_len; r_data->sel_op = sel_op; + /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ + r_data->select_flag = SELECT; /* runtime */ r_data->pass = 0; @@ -903,6 +906,7 @@ static void do_lasso_select_curve__doSelect(void *userData, BPoint *bp, BezTriple *bezt, int beztindex, + bool handles_visible, const float screen_co[2]) { LassoSelectUserData *data = userData; @@ -913,17 +917,17 @@ static void do_lasso_select_curve__doSelect(void *userData, const bool is_select = bp->f1 & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag); data->is_changed = true; } } else { - if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { - /* can only be (beztindex == 0) here since handles are hidden */ + if (!handles_visible) { + /* can only be (beztindex == 1) here since handles are hidden */ const bool is_select = bezt->f2 & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag); } bezt->f1 = bezt->f3 = bezt->f2; data->is_changed = true; @@ -933,7 +937,7 @@ static void do_lasso_select_curve__doSelect(void *userData, const bool is_select = *flag_p & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag); data->is_changed = true; } } @@ -945,6 +949,7 @@ static bool do_lasso_select_curve(ViewContext *vc, const int mcoords_len, const eSelectOp sel_op) { + const bool deselect_all = (sel_op == SEL_OP_SET); LassoSelectUserData data; rcti rect; @@ -952,13 +957,23 @@ static bool do_lasso_select_curve(ViewContext *vc, view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - Curve *curve = (Curve *)vc->obedit->data; - data.is_changed |= ED_curve_deselect_all(curve->editnurb); + Curve *curve = (Curve *)vc->obedit->data; + ListBase *nurbs = BKE_curve_editNurbs_get(curve); + + /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */ + if (deselect_all) { + BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false); + data.select_flag = BEZT_FLAG_TEMP_TAG; } ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + + /* Deselect items that were not added to selection (indicated by temp flag). */ + if (deselect_all) { + BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT); + } + if (data.is_changed) { BKE_curve_nurb_vert_active_validate(vc->obedit->data); } @@ -2559,6 +2574,7 @@ typedef struct BoxSelectUserData { const rctf *rect_fl; rctf _rect_fl; eSelectOp sel_op; + eBezTriple_Flag select_flag; /* runtime */ bool is_done; @@ -2577,6 +2593,8 @@ static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, BLI_rctf_rcti_copy(&r_data->_rect_fl, rect); r_data->sel_op = sel_op; + /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ + r_data->select_flag = SELECT; /* runtime */ r_data->is_done = false; @@ -2707,6 +2725,7 @@ static void do_nurbs_box_select__doSelect(void *userData, BPoint *bp, BezTriple *bezt, int beztindex, + bool handles_visible, const float screen_co[2]) { BoxSelectUserData *data = userData; @@ -2716,17 +2735,17 @@ static void do_nurbs_box_select__doSelect(void *userData, const bool is_select = bp->f1 & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag); data->is_changed = true; } } else { - if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { - /* can only be (beztindex == 0) here since handles are hidden */ + if (!handles_visible) { + /* can only be (beztindex == 1) here since handles are hidden */ const bool is_select = bezt->f2 & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag); data->is_changed = true; } bezt->f1 = bezt->f3 = bezt->f2; @@ -2736,7 +2755,7 @@ static void do_nurbs_box_select__doSelect(void *userData, const bool is_select = *flag_p & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag); data->is_changed = true; } } @@ -2744,17 +2763,28 @@ static void do_nurbs_box_select__doSelect(void *userData, } static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op) { + const bool deselect_all = (sel_op == SEL_OP_SET); BoxSelectUserData data; view3d_userdata_boxselect_init(&data, vc, rect, sel_op); - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - Curve *curve = (Curve *)vc->obedit->data; - data.is_changed |= ED_curve_deselect_all(curve->editnurb); + Curve *curve = (Curve *)vc->obedit->data; + ListBase *nurbs = BKE_curve_editNurbs_get(curve); + + /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */ + if (deselect_all) { + BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false); + data.select_flag = BEZT_FLAG_TEMP_TAG; } ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + + /* Deselect items that were not added to selection (indicated by temp flag). */ + if (deselect_all) { + BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT); + } + BKE_curve_nurb_vert_active_validate(vc->obedit->data); return data.is_changed; @@ -3393,6 +3423,7 @@ typedef struct CircleSelectUserData { float mval_fl[2]; float radius; float radius_squared; + eBezTriple_Flag select_flag; /* runtime */ bool is_changed; @@ -3413,6 +3444,9 @@ static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, r_data->radius = rad; r_data->radius_squared = rad * rad; + /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ + r_data->select_flag = SELECT; + /* runtime */ r_data->is_changed = false; } @@ -3650,29 +3684,24 @@ static void nurbscurve_circle_doSelect(void *userData, BPoint *bp, BezTriple *bezt, int beztindex, + bool UNUSED(handles_visible), const float screen_co[2]) { CircleSelectUserData *data = userData; if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { if (bp) { - bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); + SET_FLAG_FROM_TEST(bp->f1, data->select, data->select_flag); } else { - if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { - /* can only be (beztindex == 0) here since handles are hidden */ - bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); + if (beztindex == 0) { + SET_FLAG_FROM_TEST(bezt->f1, data->select, data->select_flag); + } + else if (beztindex == 1) { + SET_FLAG_FROM_TEST(bezt->f2, data->select, data->select_flag); } else { - if (beztindex == 0) { - bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT); - } - else if (beztindex == 1) { - bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); - } - else { - bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT); - } + SET_FLAG_FROM_TEST(bezt->f3, data->select, data->select_flag); } } data->is_changed = true; @@ -3683,18 +3712,30 @@ static bool nurbscurve_circle_select(ViewContext *vc, const int mval[2], float rad) { + const bool select = (sel_op != SEL_OP_SUB); + const bool deselect_all = (sel_op == SEL_OP_SET); CircleSelectUserData data; bool changed = false; - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - Curve *curve = vc->obedit->data; - changed |= ED_curve_deselect_all(curve->editnurb); - } - const bool select = (sel_op != SEL_OP_SUB); view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + Curve *curve = (Curve *)vc->obedit->data; + ListBase *nurbs = BKE_curve_editNurbs_get(curve); + + /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */ + if (deselect_all) { + BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false); + data.select_flag = BEZT_FLAG_TEMP_TAG; + } + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + + /* Deselect items that were not added to selection (indicated by temp flag). */ + if (deselect_all) { + BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT); + } + BKE_curve_nurb_vert_active_validate(vc->obedit->data); return changed || data.is_changed; diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 09e1dca3152..377e8c58ba3 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -86,6 +86,26 @@ void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float UI_GetThemeColor3fv(TH_BACK, r_color); } +bool ED_view3d_has_workbench_in_texture_color(const Scene *scene, + const Object *ob, + const View3D *v3d) +{ + if (v3d->shading.type == OB_SOLID) { + if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) { + return true; + } + if (ob->mode == OB_MODE_TEXTURE_PAINT) { + return true; + } + } + else if (v3d->shading.type == OB_RENDER) { + if (STREQ(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH)) { + return scene->display.shading.color_type == V3D_SHADING_TEXTURE_COLOR; + } + } + return false; +} + Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) { /* establish the camera object, diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 8ee52756f27..7aefd173953 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -374,16 +374,19 @@ static bool walk_floor_distance_get(RegionView3D *rv3d, mul_v3_v3fl(dvec_tmp, dvec, walk->grid); add_v3_v3(ray_start, dvec_tmp); - ret = ED_transform_snap_object_project_ray(walk->snap_context, - walk->depsgraph, - &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, - }, - ray_start, - ray_normal, - r_distance, - r_location, - r_normal_dummy); + ret = ED_transform_snap_object_project_ray( + walk->snap_context, + walk->depsgraph, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + /* Avoid having to convert the edit-mesh to a regular mesh. */ + .use_object_edit_cage = true, + }, + ray_start, + ray_normal, + r_distance, + r_location, + r_normal_dummy); /* artificially scale the distance to the scene size */ *r_distance /= walk->grid; @@ -449,7 +452,6 @@ static float userdef_speed = -1.f; static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); - Main *bmain = CTX_data_main(C); wmWindow *win = CTX_wm_window(C); walk->rv3d = CTX_wm_region_view3d(C); @@ -553,7 +555,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->rv3d->rflag |= RV3D_NAVIGATING; walk->snap_context = ED_transform_snap_object_context_create_view3d( - bmain, walk->scene, 0, walk->region, walk->v3d); + walk->scene, 0, walk->region, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( walk->depsgraph, diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index bb4291555d0..79090bd633e 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -49,6 +49,7 @@ #include "ED_space_api.h" #include "WM_api.h" +#include "WM_message.h" #include "WM_types.h" #include "UI_interface_icons.h" @@ -825,17 +826,17 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is } } else if (!edit_2d) { - if (t->orientation.index == 0 || ELEM(cmode, '\0', axis)) { + if (t->orient_curr == 0 || ELEM(cmode, '\0', axis)) { /* Successive presses on existing axis, cycle orientation modes. */ - t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types); - initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); + t->orient_curr = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient)); + transform_orientations_current_set(t, t->orient_curr); } - if (t->orientation.index == 0) { + if (t->orient_curr == 0) { stopConstraint(t); } else { - const short orientation = t->orientation.types[t->orientation.index]; + const short orientation = t->orient[t->orient_curr].type; if (is_plane == false) { setUserConstraint(t, orientation, constraint_axis, msg2); } @@ -983,7 +984,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) } else if (transform_mode_is_changeable(t->mode)) { /* Scale isn't normally very useful after extrude along normals, see T39756 */ - if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_ORIENT_NORMAL)) { + if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) { stopConstraint(t); } @@ -1195,7 +1196,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) stopConstraint(t); } else { - initSelectConstraint(t, event->shift); + initSelectConstraint(t); postSelectConstraint(t); } } @@ -1601,8 +1602,8 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) mul_m3_v3(t->spacemtx, t->values_final); unit_m3(t->spacemtx); - BLI_assert(t->orientation.index == 0); - t->orientation.types[0] = V3D_ORIENT_GLOBAL; + BLI_assert(t->orient_curr == 0); + t->orient[0].type = V3D_ORIENT_GLOBAL; } // Save back mode in case we're in the generic operator @@ -1672,11 +1673,14 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if (t->flag & T_MODAL) { /* do we check for parameter? */ if (transformModeUseSnap(t)) { - if (t->modifiers & MOD_SNAP) { - ts->snap_flag |= SCE_SNAP; - } - else { - ts->snap_flag &= ~SCE_SNAP; + if (!(t->modifiers & MOD_SNAP) != !(ts->snap_flag & SCE_SNAP)) { + if (t->modifiers & MOD_SNAP) { + ts->snap_flag |= SCE_SNAP; + } + else { + ts->snap_flag &= ~SCE_SNAP; + } + WM_msg_publish_rna_prop(t->mbus, &t->scene->id, ts, ToolSettings, use_snap); } } } @@ -1713,19 +1717,20 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) { - short orient_set, orient_cur; - orient_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : -1; - orient_cur = t->orientation.types[t->orientation.index]; + short orient_type_set, orient_type_curr; + orient_type_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : + -1; + orient_type_curr = t->orient[t->orient_curr].type; - if (!ELEM(orient_cur, orient_set, V3D_ORIENT_CUSTOM_MATRIX)) { - RNA_property_enum_set(op->ptr, prop, orient_cur); - orient_set = orient_cur; + if (!ELEM(orient_type_curr, orient_type_set, V3D_ORIENT_CUSTOM_MATRIX)) { + RNA_property_enum_set(op->ptr, prop, orient_type_curr); + orient_type_set = orient_type_curr; } if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && !RNA_property_is_set(op->ptr, prop))) { /* Set the first time to register on redo. */ - RNA_property_enum_set(op->ptr, prop, orient_set); + RNA_property_enum_set(op->ptr, prop, orient_type_set); RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]); } } @@ -1873,11 +1878,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve initTransInfo(C, t, op, event); /* Use the custom orientation when it is set. */ - short orientation = t->orientation.types[0] == V3D_ORIENT_CUSTOM_MATRIX ? - V3D_ORIENT_CUSTOM_MATRIX : - t->orientation.types[t->orientation.index]; - - initTransformOrientation(C, t, orientation); + short orient_index = t->orient[0].type == V3D_ORIENT_CUSTOM_MATRIX ? 0 : t->orient_curr; + transform_orientations_current_set(t, orient_index); if (t->spacetype == SPACE_VIEW3D) { t->draw_handle_apply = ED_region_draw_cb_activate( @@ -1886,62 +1888,38 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); t->draw_handle_pixel = ED_region_draw_cb_activate( t->region->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL); - t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, - RGN_TYPE_ANY, - transform_draw_cursor_poll, - transform_draw_cursor_draw, - t); + t->draw_handle_cursor = WM_paint_cursor_activate( + SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t); } else if (t->spacetype == SPACE_IMAGE) { t->draw_handle_view = ED_region_draw_cb_activate( t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); - t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, - RGN_TYPE_ANY, - transform_draw_cursor_poll, - transform_draw_cursor_draw, - t); + t->draw_handle_cursor = WM_paint_cursor_activate( + SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t); } else if (t->spacetype == SPACE_CLIP) { t->draw_handle_view = ED_region_draw_cb_activate( t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); - t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, - RGN_TYPE_ANY, - transform_draw_cursor_poll, - transform_draw_cursor_draw, - t); + t->draw_handle_cursor = WM_paint_cursor_activate( + SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t); } else if (t->spacetype == SPACE_NODE) { t->draw_handle_view = ED_region_draw_cb_activate( t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); - t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, - RGN_TYPE_ANY, - transform_draw_cursor_poll, - transform_draw_cursor_draw, - t); + t->draw_handle_cursor = WM_paint_cursor_activate( + SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t); } else if (t->spacetype == SPACE_GRAPH) { t->draw_handle_view = ED_region_draw_cb_activate( t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); - t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, - RGN_TYPE_ANY, - transform_draw_cursor_poll, - transform_draw_cursor_draw, - t); + t->draw_handle_cursor = WM_paint_cursor_activate( + SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t); } else if (t->spacetype == SPACE_ACTION) { t->draw_handle_view = ED_region_draw_cb_activate( t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); - t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), - SPACE_TYPE_ANY, - RGN_TYPE_ANY, - transform_draw_cursor_poll, - transform_draw_cursor_draw, - t); + t->draw_handle_cursor = WM_paint_cursor_activate( + SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t); } createTransData(C, t); // make TransData structs from selection @@ -2033,7 +2011,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve /* Constraint init from operator */ if (t->con.mode & CON_APPLY) { - setUserConstraint(t, t->orientation.types[t->orientation.index], t->con.mode, "%s"); + setUserConstraint(t, t->orient[t->orient_curr].type, t->con.mode, "%s"); } /* Don't write into the values when non-modal because they are already set from operator redo diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 9f4b3773fd8..192728f63d2 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -113,13 +113,8 @@ typedef struct TransSnap { } TransSnap; typedef struct TransCon { - short orientation; /** Description of the constraint for header_print. */ char text[50]; - /** Matrix of the constraint space. */ - float mtx[3][3]; - /** Inverse matrix of the constraint space. */ - float imtx[3][3]; /** Projection constraint matrix (same as #imtx with some axis == 0). */ float pmtx[3][3]; /** Initial mouse value for visual calculation @@ -531,13 +526,11 @@ typedef struct TransInfo { bool is_launch_event_tweak; struct { - short index; - short types[3]; - /* this gets used when orientation.type[x] is V3D_ORIENT_CUSTOM */ - struct TransformOrientation *custom; - /* this gets used when orientation.type[0] is V3D_ORIENT_CUSTOM_MATRIX */ - float custom_matrix[3][3]; - } orientation; + short type; + float matrix[3][3]; + } orient[3]; + short orient_curr; + /** backup from view3d, to restore on end. */ short gizmo_flag; @@ -567,6 +560,7 @@ typedef struct TransInfo { void *view; /** Only valid (non null) during an operator called function. */ struct bContext *context; + struct wmMsgBus *mbus; struct ScrArea *area; struct ARegion *region; struct Depsgraph *depsgraph; @@ -617,56 +611,53 @@ enum { T_CURSOR = 1 << 5, /** Transform points, having no rotation/scale. */ T_POINTS = 1 << 6, - - /* empty slot - (1 << 7) */ - /** restrictions flags */ - T_NO_CONSTRAINT = 1 << 8, - T_NULL_ONE = 1 << 9, - T_NO_ZERO = 1 << 10, + T_NO_CONSTRAINT = 1 << 7, + T_NULL_ONE = 1 << 8, + T_NO_ZERO = 1 << 9, T_ALL_RESTRICTIONS = T_NO_CONSTRAINT | T_NULL_ONE | T_NO_ZERO, - T_PROP_EDIT = 1 << 11, - T_PROP_CONNECTED = 1 << 12, - T_PROP_PROJECTED = 1 << 13, + T_PROP_EDIT = 1 << 10, + T_PROP_CONNECTED = 1 << 11, + T_PROP_PROJECTED = 1 << 12, T_PROP_EDIT_ALL = T_PROP_EDIT | T_PROP_CONNECTED | T_PROP_PROJECTED, - T_V3D_ALIGN = 1 << 14, + T_V3D_ALIGN = 1 << 13, /** For 2d views like uv or fcurve. */ - T_2D_EDIT = 1 << 15, - T_CLIP_UV = 1 << 16, + T_2D_EDIT = 1 << 14, + T_CLIP_UV = 1 << 15, /** Auto-ik is on. */ - T_AUTOIK = 1 << 18, + T_AUTOIK = 1 << 16, /** Don't use mirror even if the data-block option is set. */ - T_NO_MIRROR = 1 << 19, + T_NO_MIRROR = 1 << 17, /** To indicate that the value set in the `value` parameter is the final * value of the transformation, modified only by the constrain. */ - T_INPUT_IS_VALUES_FINAL = 1 << 20, + T_INPUT_IS_VALUES_FINAL = 1 << 18, /** To specify if we save back settings at the end. */ - T_MODAL = 1 << 21, + T_MODAL = 1 << 19, /** No retopo. */ - T_NO_PROJECT = 1 << 22, + T_NO_PROJECT = 1 << 20, - T_RELEASE_CONFIRM = 1 << 23, + T_RELEASE_CONFIRM = 1 << 21, /** Alternative transformation. used to add offset to tracking markers. */ - T_ALT_TRANSFORM = 1 << 24, + T_ALT_TRANSFORM = 1 << 22, /** #TransInfo.center has been set, don't change it. */ - T_OVERRIDE_CENTER = 1 << 25, + T_OVERRIDE_CENTER = 1 << 23, - T_MODAL_CURSOR_SET = 1 << 26, + T_MODAL_CURSOR_SET = 1 << 24, - T_CLNOR_REBUILD = 1 << 27, + T_CLNOR_REBUILD = 1 << 25, /* Special Aftertrans. */ - T_AUTOMERGE = 1 << 28, - T_AUTOSPLIT = 1 << 29, + T_AUTOMERGE = 1 << 26, + T_AUTOSPLIT = 1 << 27, }; /** #TransInfo.modifiers */ @@ -713,40 +704,39 @@ enum { /** #TransData.flag */ enum { TD_SELECTED = 1 << 0, - TD_NOACTION = 1 << 2, - TD_USEQUAT = 1 << 3, - TD_NOTCONNECTED = 1 << 4, + TD_USEQUAT = 1 << 1, + TD_NOTCONNECTED = 1 << 2, /** Used for scaling of #MetaElem.rad */ - TD_SINGLESIZE = 1 << 5, + TD_SINGLESIZE = 1 << 3, /** Scale relative to individual element center */ - TD_INDIVIDUAL_SCALE = 1 << 8, - TD_NOCENTER = 1 << 9, + TD_INDIVIDUAL_SCALE = 1 << 4, + TD_NOCENTER = 1 << 5, /** #TransData.ext abused for particle key timing. */ - TD_NO_EXT = 1 << 10, + TD_NO_EXT = 1 << 6, /** don't transform this data */ - TD_SKIP = 1 << 11, + TD_SKIP = 1 << 7, /** if this is a bez triple, we need to restore the handles, * if this is set #TransData.hdata needs freeing */ - TD_BEZTRIPLE = 1 << 12, + TD_BEZTRIPLE = 1 << 8, /** when this is set, don't apply translation changes to this element */ - TD_NO_LOC = 1 << 13, + TD_NO_LOC = 1 << 9, /** For Graph Editor autosnap, indicates that point should not undergo autosnapping */ - TD_NOTIMESNAP = 1 << 14, + TD_NOTIMESNAP = 1 << 10, /** For Graph Editor - curves that can only have int-values * need their keyframes tagged with this. */ - TD_INTVALUES = 1 << 15, + TD_INTVALUES = 1 << 11, /** For editmode mirror, clamp axis to 0 */ - TD_MIRROR_EDGE_X = 1 << 16, - TD_MIRROR_EDGE_Y = 1 << 17, - TD_MIRROR_EDGE_Z = 1 << 18, + TD_MIRROR_EDGE_X = 1 << 12, + TD_MIRROR_EDGE_Y = 1 << 13, + TD_MIRROR_EDGE_Z = 1 << 14, /** For fcurve handles, move them along with their keyframes */ - TD_MOVEHANDLE1 = 1 << 19, - TD_MOVEHANDLE2 = 1 << 20, + TD_MOVEHANDLE1 = 1 << 15, + TD_MOVEHANDLE2 = 1 << 16, /** Exceptional case with pose bone rotating when a parent bone has 'Local Location' * option enabled and rotating also transforms it. */ - TD_PBONE_LOCAL_MTX_P = 1 << 21, + TD_PBONE_LOCAL_MTX_P = 1 << 17, /** Same as above but for a child bone. */ - TD_PBONE_LOCAL_MTX_C = 1 << 22, + TD_PBONE_LOCAL_MTX_C = 1 << 18, }; /** #TransSnap.status */ @@ -911,8 +901,13 @@ void getViewVector(const TransInfo *t, const float coord[3], float vec[3]); void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot); /*********************** Transform Orientations ******************************/ - -void initTransformOrientation(struct bContext *C, TransInfo *t, short orientation); +short transform_orientation_matrix_get(struct bContext *C, + TransInfo *t, + const short orientation, + const float custom[3][3], + float r_spacemtx[3][3]); +const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type); +void transform_orientations_current_set(struct TransInfo *t, const short orient_index); /* Those two fill in mat and return non-zero on success */ bool createSpaceNormal(float mat[3][3], const float normal[3]); @@ -922,7 +917,7 @@ struct TransformOrientation *addMatrixSpace(struct bContext *C, float mat[3][3], const char *name, const bool overwrite); -bool applyTransformOrientation(const struct TransformOrientation *ts, +void applyTransformOrientation(const struct TransformOrientation *ts, float r_mat[3][3], char r_name[64]); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index b05b99d9601..0347522b8e8 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -42,6 +42,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_scene.h" #include "ED_view3d.h" @@ -57,6 +58,27 @@ static void drawObjectConstraint(TransInfo *t); +static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3]) +{ + unit_m3(r_pmtx); + + if (!(t->con.mode & CON_AXIS0)) { + zero_v3(r_pmtx[0]); + } + + if (!(t->con.mode & CON_AXIS1)) { + zero_v3(r_pmtx[1]); + } + + if (!(t->con.mode & CON_AXIS2)) { + zero_v3(r_pmtx[2]); + } + + float mat[3][3]; + mul_m3_m3m3(mat, r_pmtx, t->spacemtx_inv); + mul_m3_m3m3(r_pmtx, t->spacemtx, mat); +} + /* ************************** CONSTRAINTS ************************* */ static void constraintValuesFinal(TransInfo *t, float vec[3]) { @@ -123,7 +145,7 @@ void constraintNumInput(TransInfo *t, float vec[3]) static void postConstraintChecks(TransInfo *t, float vec[3]) { - mul_m3_v3(t->con.imtx, vec); + mul_m3_v3(t->spacemtx_inv, vec); snapGridIncrement(t, vec); @@ -153,7 +175,7 @@ static void postConstraintChecks(TransInfo *t, float vec[3]) /* inverse transformation at the end */ } - mul_m3_v3(t->con.mtx, vec); + mul_m3_v3(t->spacemtx, vec); } static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3]) @@ -286,7 +308,7 @@ static bool isPlaneProjectionViewAligned(const TransInfo *t) int n = 0; for (int i = 0; i < 3; i++) { if (t->con.mode & (CON_AXIS0 << i)) { - constraint_vector[n++] = t->con.mtx[i]; + constraint_vector[n++] = t->spacemtx[i]; if (n == 2) { break; } @@ -355,13 +377,13 @@ static void applyAxisConstraintVec( float c[3]; if (t->con.mode & CON_AXIS0) { - copy_v3_v3(c, t->con.mtx[0]); + copy_v3_v3(c, t->spacemtx[0]); } else if (t->con.mode & CON_AXIS1) { - copy_v3_v3(c, t->con.mtx[1]); + copy_v3_v3(c, t->spacemtx[1]); } else if (t->con.mode & CON_AXIS2) { - copy_v3_v3(c, t->con.mtx[2]); + copy_v3_v3(c, t->spacemtx[2]); } axisProjection(t, c, in, out); } @@ -373,7 +395,7 @@ static void applyAxisConstraintVec( /* * Generic callback for object based spatial constraints applied to linear motion * - * At first, the following is applied to the first data in the array + * At first, the following is applied without orientation * The IN vector in projected into the constrained space and then further * projected along the view vector. * (in perspective mode, the view vector is relative to the position on screen) @@ -384,40 +406,16 @@ static void applyAxisConstraintVec( static void applyObjectConstraintVec( TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3]) { - copy_v3_v3(out, in); - if (t->con.mode & CON_APPLY) { - if (!td) { - mul_m3_v3(t->con.pmtx, out); - - const int dims = getConstraintSpaceDimension(t); - if (dims == 2) { - if (!is_zero_v3(out)) { - if (!isPlaneProjectionViewAligned(t)) { - planeProjection(t, in, out); - } - } - } - else if (dims == 1) { - float c[3]; - - if (t->con.mode & CON_AXIS0) { - copy_v3_v3(c, t->con.mtx[0]); - } - else if (t->con.mode & CON_AXIS1) { - copy_v3_v3(c, t->con.mtx[1]); - } - else if (t->con.mode & CON_AXIS2) { - copy_v3_v3(c, t->con.mtx[2]); - } - axisProjection(t, c, in, out); - } - postConstraintChecks(t, out); - } - else { - mul_m3_v3(td->axismtx, out); - if (t->flag & T_EDIT) { - mul_m3_v3(tc->mat3_unit, out); - } + if (!td) { + applyAxisConstraintVec(t, tc, td, in, out); + } + else { + /* Specific TransData's space. */ + copy_v3_v3(out, in); + mul_m3_v3(t->spacemtx_inv, out); + mul_m3_v3(td->axismtx, out); + if (t->flag & T_EDIT) { + mul_m3_v3(tc->mat3_unit, out); } } } @@ -444,8 +442,8 @@ static void applyAxisConstraintSize(TransInfo *t, smat[2][2] = 1.0f; } - mul_m3_m3m3(tmat, smat, t->con.imtx); - mul_m3_m3m3(smat, t->con.mtx, tmat); + mul_m3_m3m3(tmat, smat, t->spacemtx_inv); + mul_m3_m3m3(smat, t->spacemtx, tmat); } } @@ -505,15 +503,15 @@ static void applyAxisConstraintRot( switch (mode) { case CON_AXIS0: case (CON_AXIS1 | CON_AXIS2): - copy_v3_v3(vec, t->con.mtx[0]); + copy_v3_v3(vec, t->spacemtx[0]); break; case CON_AXIS1: case (CON_AXIS0 | CON_AXIS2): - copy_v3_v3(vec, t->con.mtx[1]); + copy_v3_v3(vec, t->spacemtx[1]); break; case CON_AXIS2: case (CON_AXIS0 | CON_AXIS1): - copy_v3_v3(vec, t->con.mtx[2]); + copy_v3_v3(vec, t->spacemtx[2]); break; } /* don't flip axis if asked to or if num input */ @@ -586,12 +584,11 @@ static void applyObjectConstraintRot( /*--------------------- INTERNAL SETUP CALLS ------------------*/ -void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) +void setConstraint(TransInfo *t, int mode, const char text[]) { BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); - copy_m3_m3(t->con.mtx, space); t->con.mode = mode; - getConstraintMatrix(t); + projection_matrix_calc(t, t->con.pmtx); startConstraint(t); @@ -605,41 +602,25 @@ void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) /* applies individual td->axismtx constraints */ void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]) { - TransDataContainer *tc = t->data_container; - if (t->data_len_all == 1) { - float axismtx[3][3]; - if (t->flag & T_EDIT) { - mul_m3_m3m3(axismtx, tc->mat3_unit, tc->data->axismtx); - } - else { - copy_m3_m3(axismtx, tc->data->axismtx); - } - - setConstraint(t, axismtx, mode, text); - } - else { - BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); - unit_m3(t->con.mtx); - t->con.mode = mode; - getConstraintMatrix(t); + BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); + t->con.mode = mode; + projection_matrix_calc(t, t->con.pmtx); - startConstraint(t); + startConstraint(t); - t->con.drawExtra = drawObjectConstraint; - t->con.applyVec = applyObjectConstraintVec; - t->con.applySize = applyObjectConstraintSize; - t->con.applyRot = applyObjectConstraintRot; - t->redraw = TREDRAW_HARD; - } + t->con.drawExtra = drawObjectConstraint; + t->con.applyVec = applyObjectConstraintVec; + t->con.applySize = applyObjectConstraintSize; + t->con.applyRot = applyObjectConstraintRot; + t->redraw = TREDRAW_HARD; } void setLocalConstraint(TransInfo *t, int mode, const char text[]) { - /* edit-mode now allows local transforms too */ if (t->flag & T_EDIT) { - /* Use the active (first) edit object. */ - TransDataContainer *tc = t->data_container; - setConstraint(t, tc->mat3_unit, mode, text); + /* Although in edit-mode each object has its local space, use the + * orientation of the active object. */ + setConstraint(t, mode, text); } else { setAxisMatrixConstraint(t, mode, text); @@ -655,61 +636,30 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]) void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[]) { char text[256]; + const char *spacename = transform_orientations_spacename_get(t, orientation); + BLI_snprintf(text, sizeof(text), ftext, spacename); switch (orientation) { - case V3D_ORIENT_GLOBAL: { - float mtx[3][3]; - BLI_snprintf(text, sizeof(text), ftext, TIP_("global")); - unit_m3(mtx); - setConstraint(t, mtx, mode, text); - break; - } case V3D_ORIENT_LOCAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("local")); setLocalConstraint(t, mode, text); break; case V3D_ORIENT_NORMAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("normal")); if (checkUseAxisMatrix(t)) { setAxisMatrixConstraint(t, mode, text); + break; } - else { - setConstraint(t, t->spacemtx, mode, text); - } - break; + ATTR_FALLTHROUGH; + case V3D_ORIENT_GLOBAL: case V3D_ORIENT_VIEW: - BLI_snprintf(text, sizeof(text), ftext, TIP_("view")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_CURSOR: - BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_GIMBAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("gimbal")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_CUSTOM_MATRIX: - BLI_snprintf(text, sizeof(text), ftext, TIP_("custom matrix")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_CUSTOM: default: { - BLI_assert(orientation >= V3D_ORIENT_CUSTOM); - char orientation_str[128]; - BLI_snprintf(orientation_str, - sizeof(orientation_str), - "%s \"%s\"", - TIP_("custom orientation"), - t->orientation.custom->name); - BLI_snprintf(text, sizeof(text), ftext, orientation_str); - setConstraint(t, t->spacemtx, mode, text); + setConstraint(t, mode, text); break; } } - - t->con.orientation = orientation; - t->con.mode |= CON_USER; } @@ -740,9 +690,9 @@ void drawConstraint(TransInfo *t) convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1])); add_v3_v3(vec, t->center_global); - drawLine(t, t->center_global, tc->mtx[0], 'X', 0); - drawLine(t, t->center_global, tc->mtx[1], 'Y', 0); - drawLine(t, t->center_global, tc->mtx[2], 'Z', 0); + drawLine(t, t->center_global, t->spacemtx[0], 'X', 0); + drawLine(t, t->center_global, t->spacemtx[1], 'Y', 0); + drawLine(t, t->center_global, t->spacemtx[2], 'Z', 0); depth_test_enabled = GPU_depth_test_enabled(); if (depth_test_enabled) { @@ -776,13 +726,13 @@ void drawConstraint(TransInfo *t) } if (tc->mode & CON_AXIS0) { - drawLine(t, t->center_global, tc->mtx[0], 'X', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx[0], 'X', DRAWLIGHT); } if (tc->mode & CON_AXIS1) { - drawLine(t, t->center_global, tc->mtx[1], 'Y', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx[1], 'Y', DRAWLIGHT); } if (tc->mode & CON_AXIS2) { - drawLine(t, t->center_global, tc->mtx[2], 'Z', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx[2], 'Z', DRAWLIGHT); } } } @@ -879,11 +829,7 @@ static void drawObjectConstraint(TransInfo *t) } } - if (t->flag & T_OBJECT) { - copy_v3_v3(co, td->ob->obmat[3]); - axismtx = td->axismtx; - } - else if (t->flag & T_EDIT) { + if (t->flag & T_EDIT) { mul_v3_m4v3(co, tc->mat, td->center); mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx); @@ -928,45 +874,17 @@ void stopConstraint(TransInfo *t) t->num.idx_max = t->idx_max; } -void getConstraintMatrix(TransInfo *t) -{ - float mat[3][3]; - invert_m3_m3(t->con.imtx, t->con.mtx); - unit_m3(t->con.pmtx); - - if (!(t->con.mode & CON_AXIS0)) { - zero_v3(t->con.pmtx[0]); - } - - if (!(t->con.mode & CON_AXIS1)) { - zero_v3(t->con.pmtx[1]); - } - - if (!(t->con.mode & CON_AXIS2)) { - zero_v3(t->con.pmtx[2]); - } - - mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx); - mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat); -} - /*------------------------- MMB Select -------------------------------*/ -void initSelectConstraint(TransInfo *t, bool force_global) +void initSelectConstraint(TransInfo *t) { - short orientation; - if (force_global) { - orientation = V3D_ORIENT_GLOBAL; - } - else { - if (t->orientation.index == 0) { - t->orientation.index = 1; - initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); - } - orientation = t->orientation.types[t->orientation.index]; + if (t->orient_curr == 0) { + t->orient_curr = 1; + transform_orientations_current_set(t, t->orient_curr); } - setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, ""); + short orientation = t->orient[t->orient_curr].type; + setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, "%s"); setNearestAxis(t); } @@ -1033,7 +951,7 @@ static void setNearestAxis3d(TransInfo *t) for (i = 0; i < 3; i++) { float axis[3], axis_2d[2]; - copy_v3_v3(axis, t->con.mtx[i]); + copy_v3_v3(axis, t->spacemtx[i]); mul_v3_fl(axis, zfac); /* now we can project to get window coordinate */ @@ -1102,7 +1020,7 @@ void setNearestAxis(TransInfo *t) setNearestAxis2d(t); } - getConstraintMatrix(t); + projection_matrix_calc(t, t->con.pmtx); } /*-------------- HELPER FUNCTIONS ----------------*/ diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h index c98234c83da..c41b9361ca4 100644 --- a/source/blender/editors/transform/transform_constraints.h +++ b/source/blender/editors/transform/transform_constraints.h @@ -27,7 +27,7 @@ struct TransInfo; void constraintNumInput(TransInfo *t, float vec[3]); -void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]); +void setConstraint(TransInfo *t, int mode, const char text[]); void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]); void setLocalConstraint(TransInfo *t, int mode, const char text[]); void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]); @@ -35,8 +35,7 @@ void drawConstraint(TransInfo *t); void drawPropCircle(const struct bContext *C, TransInfo *t); void startConstraint(TransInfo *t); void stopConstraint(TransInfo *t); -void getConstraintMatrix(TransInfo *t); -void initSelectConstraint(TransInfo *t, bool force_global); +void initSelectConstraint(TransInfo *t); void selectConstraint(TransInfo *t); void postSelectConstraint(TransInfo *t); void setNearestAxis(TransInfo *t); diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 7295a8623d9..cf60990d09c 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -111,8 +111,10 @@ void transform_around_single_fallback(TransInfo *t) } if (tc->data_len == 3) { const TransData *td = tc->data; - if ((td[0].loc == td[1].loc) && (td[1].loc == td[2].loc)) { - is_data_single = true; + if ((td[0].flag | td[1].flag | td[2].flag) & TD_BEZTRIPLE) { + if ((td[0].loc == td[1].loc) && (td[1].loc == td[2].loc)) { + is_data_single = true; + } } } break; @@ -827,10 +829,6 @@ void clipUVData(TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (int a = 0; a < tc->data_len; a++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if ((td->flag & TD_SKIP) || (!td->loc)) { continue; } @@ -1848,7 +1846,10 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t) if (IS_AUTOKEY_ON(t->scene)) { Scene *scene = t->scene; - ED_mask_layer_shape_auto_key_select(mask, CFRA); + if (ED_mask_layer_shape_auto_key_select(mask, CFRA)) { + WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id); + DEG_id_tag_update(&mask->id, 0); + } } } @@ -2387,10 +2388,6 @@ void special_aftertrans_update(bContext *C, TransInfo *t) PTCacheID *pid; ob = td->ob; - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index 42ffe675dc5..1f113a36a89 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -93,9 +93,8 @@ void createTransCurveVerts(TransInfo *t) int count = 0, countsel = 0; const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; View3D *v3d = t->view; - short hide_handles = (v3d != NULL) ? - ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) : - false; + short hide_handles = (v3d != NULL) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) : + false; /* count total of vertices, check identical as in 2nd loop for making transdata! */ ListBase *nurbs = BKE_curve_editNurbs_get(cu); @@ -163,9 +162,8 @@ void createTransCurveVerts(TransInfo *t) int a; const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; View3D *v3d = t->view; - short hide_handles = (v3d != NULL) ? - ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) : - false; + short hide_handles = (v3d != NULL) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) : + false; bool use_around_origins_for_handles_test = ((t->around == V3D_AROUND_LOCAL_ORIGINS) && transform_mode_use_local_origins(t)); diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 24dda8c8464..07b2f07bf2c 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1450,7 +1450,6 @@ static void UVsToTransData(const float aspect[2], void createTransUVs(bContext *C, TransInfo *t) { SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); Scene *scene = t->scene; ToolSettings *ts = CTX_data_tool_settings(C); @@ -1500,7 +1499,7 @@ void createTransUVs(bContext *C, TransInfo *t) BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BMLoop *l; - if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { BM_elem_flag_disable(efa, BM_ELEM_TAG); continue; } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 2f3b50a7c1a..6de962a3ed1 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -174,9 +174,6 @@ static void clipMirrorModifier(TransInfo *t) int clip; float loc[3], iloc[3]; - if (td->flag & TD_NOACTION) { - break; - } if (td->loc == NULL) { break; } @@ -1068,11 +1065,6 @@ static void recalcData_objects(TransInfo *t) for (int i = 0; i < tc->data_len; i++, td++) { Object *ob = td->ob; - - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } @@ -1379,6 +1371,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve bGPdata *gpd = CTX_data_gpencil_data(C); PropertyRNA *prop; + t->mbus = CTX_wm_message_bus(C); t->depsgraph = CTX_data_depsgraph_pointer(C); t->scene = sce; t->view_layer = view_layer; @@ -1626,7 +1619,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } if (t_values_set_is_array && t->flag & T_INPUT_IS_VALUES_FINAL) { - /* For operators whose `t->values` is array, set contrain so that the + /* For operators whose `t->values` is array, set constraint so that the * orientation is more intuitive in the Redo Panel. */ for (int i = 3; i--;) { constraint_axis[i] |= t->values[i] != 0.0f; @@ -1649,29 +1642,26 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } { - TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; - TransformOrientation *custom_orientation = NULL; short orient_type_set = -1; short orient_type_matrix_set = -1; - short orient_type_scene = orient_slot->type; - if (orient_type_scene == V3D_ORIENT_CUSTOM) { - const int index_custom = orient_slot->index_custom; - custom_orientation = BKE_scene_transform_orientation_find(t->scene, index_custom); - orient_type_scene += index_custom; - } + short orient_type_scene = V3D_ORIENT_GLOBAL; - short orient_type_default; - short orient_type_constraint[2]; - if ((t->flag & T_MODAL) && transform_mode_is_changeable(t->mode)) { - /* During modal, rotation starts with the View orientation. */ - orient_type_default = V3D_ORIENT_VIEW; - } - else { - orient_type_default = orient_type_scene; + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; + orient_type_scene = orient_slot->type; + if (orient_type_scene == V3D_ORIENT_CUSTOM) { + const int index_custom = orient_slot->index_custom; + orient_type_scene += index_custom; + } } + short orient_types[3]; + float custom_matrix[3][3]; + bool use_orient_axis = false; + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { t->orient_axis = RNA_property_enum_get(op->ptr, prop); + use_orient_axis = true; } if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); @@ -1684,26 +1674,28 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { orient_type_set = V3D_ORIENT_GLOBAL; } - else { - custom_orientation = BKE_scene_transform_orientation_find( - t->scene, orient_type_set - V3D_ORIENT_CUSTOM); - } } /* Change the default orientation to be used when redoing. */ - orient_type_default = orient_type_set; - orient_type_constraint[0] = orient_type_set; - orient_type_constraint[1] = orient_type_scene; + orient_types[0] = orient_type_set; + orient_types[1] = orient_type_set; + orient_types[2] = orient_type_scene; } else { - orient_type_constraint[0] = orient_type_scene; - orient_type_constraint[1] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL : - V3D_ORIENT_LOCAL; + if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode))) { + orient_types[0] = V3D_ORIENT_VIEW; + } + else { + orient_types[0] = orient_type_scene; + } + orient_types[1] = orient_type_scene; + orient_types[2] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL : + V3D_ORIENT_LOCAL; } if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && RNA_property_is_set(op->ptr, prop))) { - RNA_property_float_get_array(op->ptr, prop, &t->orientation.custom_matrix[0][0]); + RNA_property_float_get_array(op->ptr, prop, &custom_matrix[0][0]); if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && RNA_property_is_set(op->ptr, prop)) { @@ -1718,18 +1710,30 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve if (orient_type_matrix_set == orient_type_set) { /* Constraints are forced to use the custom matrix when redoing. */ - orient_type_default = V3D_ORIENT_CUSTOM_MATRIX; + orient_types[0] = V3D_ORIENT_CUSTOM_MATRIX; } } - t->orientation.types[0] = orient_type_default; - t->orientation.types[1] = orient_type_constraint[0]; - t->orientation.types[2] = orient_type_constraint[1]; - t->orientation.custom = custom_orientation; - if (t->con.mode & CON_APPLY) { - t->orientation.index = 1; + t->orient_curr = 1; + } + + /* For efficiency, avoid calculating the same orientation twice. */ + for (int i = 1; i < 3; i++) { + t->orient[i].type = transform_orientation_matrix_get( + C, t, orient_types[i], custom_matrix, t->orient[i].matrix); + } + + if (orient_types[0] != orient_types[1]) { + t->orient[0].type = transform_orientation_matrix_get( + C, t, orient_types[0], custom_matrix, t->orient[0].matrix); } + else { + memcpy(&t->orient[0], &t->orient[1], sizeof(t->orient[0])); + } + + const char *spacename = transform_orientations_spacename_get(t, orient_types[0]); + BLI_strncpy(t->spacename, spacename, sizeof(t->spacename)); } if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && @@ -1922,7 +1926,7 @@ void postTrans(bContext *C, TransInfo *t) ED_region_draw_cb_exit(t->region->type, t->draw_handle_pixel); } if (t->draw_handle_cursor) { - WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor); + WM_paint_cursor_end(t->draw_handle_cursor); } if (t->flag & T_MODAL_CURSOR_SET) { @@ -2401,19 +2405,11 @@ void calculatePropRatio(TransInfo *t) } else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) || (connected == 0 && td->rdist > t->prop_size)) { - /* - * The elements are sorted according to their dist member in the array, - * that means we can stop when it finds one element outside of the propsize. - * do not set 'td->flag |= TD_NOACTION', the prop circle is being changed. - */ - td->factor = 0.0f; restoreElement(td); } else { /* Use rdist for falloff calculations, it is the real distance */ - td->flag &= ~TD_NOACTION; - if (connected) { dist = (t->prop_size - td->dist) / t->prop_size; } diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c index 50317d8b395..c63e90ac2b7 100644 --- a/source/blender/editors/transform/transform_gizmo_2d.c +++ b/source/blender/editors/transform/transform_gizmo_2d.c @@ -217,14 +217,12 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min ScrArea *area = CTX_wm_area(C); bool changed = false; if (area->spacetype == SPACE_IMAGE) { - SpaceImage *sima = area->spacedata.first; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = ED_space_image(sima); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, NULL, &objects_len); - if (ED_uvedit_minmax_multi(scene, ima, objects, objects_len, r_min, r_max)) { + if (ED_uvedit_minmax_multi(scene, objects, objects_len, r_min, r_max)) { changed = true; } MEM_freeN(objects); diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index f143d4c2993..ebc021cd983 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -635,101 +635,6 @@ bool gimbal_axis(Object *ob, float gmat[3][3]) return 0; } -void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3]) -{ - ARegion *region = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = CTX_data_edit_object(C); - RegionView3D *rv3d = region->regiondata; - Object *ob = OBACT(view_layer); - const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type; - const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; - const int pivot_point = scene->toolsettings->transform_pivot_point; - - ED_transform_calc_orientation_from_type_ex( - C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point); -} - -void ED_transform_calc_orientation_from_type_ex(const bContext *C, - float r_mat[3][3], - /* extra args (can be accessed from context) */ - Scene *scene, - RegionView3D *rv3d, - Object *ob, - Object *obedit, - const short orientation_type, - int orientation_index_custom, - const int pivot_point) -{ - bool ok = false; - - switch (orientation_type) { - case V3D_ORIENT_GLOBAL: { - break; /* nothing to do */ - } - case V3D_ORIENT_GIMBAL: { - if (gimbal_axis(ob, r_mat)) { - ok = true; - break; - } - /* if not gimbal, fall through to normal */ - ATTR_FALLTHROUGH; - } - case V3D_ORIENT_NORMAL: { - if (obedit || ob->mode & OB_MODE_POSE) { - ED_getTransformOrientationMatrix(C, r_mat, pivot_point); - ok = true; - break; - } - /* no break we define 'normal' as 'local' in Object mode */ - ATTR_FALLTHROUGH; - } - case V3D_ORIENT_LOCAL: { - if (ob->mode & OB_MODE_POSE) { - /* each bone moves on its own local axis, but to avoid confusion, - * use the active pones axis for display [#33575], this works as expected on a single bone - * and users who select many bones will understand what's going on and what local means - * when they start transforming */ - ED_getTransformOrientationMatrix(C, r_mat, pivot_point); - ok = true; - break; - } - copy_m3_m4(r_mat, ob->obmat); - normalize_m3(r_mat); - ok = true; - break; - } - case V3D_ORIENT_VIEW: { - if (rv3d != NULL) { - copy_m3_m4(r_mat, rv3d->viewinv); - normalize_m3(r_mat); - ok = true; - } - break; - } - case V3D_ORIENT_CURSOR: { - BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat); - ok = true; - break; - } - case V3D_ORIENT_CUSTOM: - default: { - BLI_assert(orientation_type >= V3D_ORIENT_CUSTOM); - TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find( - scene, orientation_index_custom); - if (applyTransformOrientation(custom_orientation, r_mat, NULL)) { - ok = true; - } - break; - } - } - - if (!ok) { - unit_m3(r_mat); - } -} - /* centroid, boundbox, of selection */ /* returns total items selected */ int ED_transform_calc_gizmo_stats(const bContext *C, @@ -929,7 +834,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, * if handles are hidden then only check the center points. * If the center knot is selected then only use this as the center point. */ - if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { + if (v3d->overlay.handle_display == CURVE_HANDLE_NONE) { if (bezt->f2 & SELECT) { calc_tw_center_with_matrix(tbounds, bezt->vec[1], use_mat_local, mat_local); totsel++; @@ -1390,16 +1295,16 @@ void drawDial3d(const TransInfo *t) if (tc->mode & CON_APPLY) { if (tc->mode & CON_AXIS0) { axis_idx = MAN_AXIS_ROT_X; - negate_v3_v3(mat_basis[2], tc->mtx[0]); + negate_v3_v3(mat_basis[2], t->spacemtx[0]); } else if (tc->mode & CON_AXIS1) { axis_idx = MAN_AXIS_ROT_Y; - negate_v3_v3(mat_basis[2], tc->mtx[1]); + negate_v3_v3(mat_basis[2], t->spacemtx[1]); } else { BLI_assert((tc->mode & CON_AXIS2) != 0); axis_idx = MAN_AXIS_ROT_Z; - negate_v3_v3(mat_basis[2], tc->mtx[2]); + negate_v3_v3(mat_basis[2], t->spacemtx[2]); } } else { diff --git a/source/blender/editors/transform/transform_mode_align.c b/source/blender/editors/transform/transform_mode_align.c index 9bce793809b..4fd4599b940 100644 --- a/source/blender/editors/transform/transform_mode_align.c +++ b/source/blender/editors/transform/transform_mode_align.c @@ -52,10 +52,6 @@ static void applyAlign(TransInfo *t, const int UNUSED(mval[2])) for (i = 0; i < tc->data_len; i++, td++) { float mat[3][3], invmat[3][3]; - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_baketime.c b/source/blender/editors/transform/transform_mode_baketime.c index bb8fd0df13d..4e7fc3578ce 100644 --- a/source/blender/editors/transform/transform_mode_baketime.c +++ b/source/blender/editors/transform/transform_mode_baketime.c @@ -97,10 +97,6 @@ static void applyBakeTime(TransInfo *t, const int mval[2]) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c index c81049ac379..77850e74785 100644 --- a/source/blender/editors/transform/transform_mode_bbone_resize.c +++ b/source/blender/editors/transform/transform_mode_bbone_resize.c @@ -141,10 +141,6 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c index 721d226050a..3b51626b170 100644 --- a/source/blender/editors/transform/transform_mode_bend.c +++ b/source/blender/editors/transform/transform_mode_bend.c @@ -186,10 +186,6 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2])) float delta[3]; float fac, fac_scaled; - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c index aa20a5ade95..7045d190478 100644 --- a/source/blender/editors/transform/transform_mode_boneenvelope.c +++ b/source/blender/editors/transform/transform_mode_boneenvelope.c @@ -73,10 +73,6 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_boneroll.c b/source/blender/editors/transform/transform_mode_boneroll.c index 0564a946148..1503519c519 100644 --- a/source/blender/editors/transform/transform_mode_boneroll.c +++ b/source/blender/editors/transform/transform_mode_boneroll.c @@ -75,10 +75,6 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c index 057f13ac068..84e4e950804 100644 --- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c @@ -73,10 +73,6 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c index 5db7895232c..399cec2d62c 100644 --- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c +++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c @@ -87,10 +87,6 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->val) { *td->val = td->ival + weight * td->factor; if (*td->val < 0.0f) { diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c index 4a92a57fef6..53c948c742b 100644 --- a/source/blender/editors/transform/transform_mode_edge_crease.c +++ b/source/blender/editors/transform/transform_mode_edge_crease.c @@ -87,10 +87,6 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c index 8690cd54a3b..c1cb4325c09 100644 --- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c @@ -81,10 +81,6 @@ static void applySeqSlideValue(TransInfo *t, const float val[2]) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c index 267d297a31c..4712fb7ba01 100644 --- a/source/blender/editors/transform/transform_mode_gpopacity.c +++ b/source/blender/editors/transform/transform_mode_gpopacity.c @@ -73,10 +73,6 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c index 7c49d107703..ab9a0aa79ed 100644 --- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c @@ -73,10 +73,6 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c index e42439920db..68f3abda85b 100644 --- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c @@ -78,10 +78,6 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } @@ -97,10 +93,6 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (td = tc->data, i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c index dae17374481..8d953610eb8 100644 --- a/source/blender/editors/transform/transform_mode_mirror.c +++ b/source/blender/editors/transform/transform_mode_mirror.c @@ -69,10 +69,6 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } @@ -93,10 +89,6 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c index 6eb038ea9b0..4a2f979ec38 100644 --- a/source/blender/editors/transform/transform_mode_push_pull.c +++ b/source/blender/editors/transform/transform_mode_push_pull.c @@ -82,10 +82,6 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c index 00644b9bfdc..d919d5c889d 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -93,10 +93,6 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 55c97630487..6480cb6c30e 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -82,10 +82,6 @@ static void applyRotationValue(TransInfo *t, FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index dc0479f4e60..fa33c1550e7 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -56,7 +56,7 @@ static void initShear_mouseInputMode(TransInfo *t) copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]); /* Needed for axis aligned view gizmo. */ - if (t->orientation.types[t->orientation.index] == V3D_ORIENT_VIEW) { + if (t->orient[t->orient_curr].type == V3D_ORIENT_VIEW) { if (t->orient_axis_ortho == 0) { if (t->center2d[1] > t->mouse.imval[1]) { dir_flip = !dir_flip; @@ -165,11 +165,6 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { const float *center, *co; - - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c index ed082e86b6d..78d3efa0d69 100644 --- a/source/blender/editors/transform/transform_mode_shrink_fatten.c +++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c @@ -95,10 +95,6 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { float tdistance; /* temp dist */ - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c index b53dbb55c62..23d83050613 100644 --- a/source/blender/editors/transform/transform_mode_skin_resize.c +++ b/source/blender/editors/transform/transform_mode_skin_resize.c @@ -73,11 +73,6 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2])) for (i = 0; i < tc->data_len; i++, td++) { float tmat[3][3], smat[3][3]; float fsize[3]; - - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_tilt.c b/source/blender/editors/transform/transform_mode_tilt.c index 2f56f4bd162..ca0a8818477 100644 --- a/source/blender/editors/transform/transform_mode_tilt.c +++ b/source/blender/editors/transform/transform_mode_tilt.c @@ -77,10 +77,6 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2])) FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c index 841ccf41365..f6c5448a906 100644 --- a/source/blender/editors/transform/transform_mode_tosphere.c +++ b/source/blender/editors/transform/transform_mode_tosphere.c @@ -79,10 +79,6 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2])) TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { float tratio; - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c index c6e0b205204..ca5a749b275 100644 --- a/source/blender/editors/transform/transform_mode_trackball.c +++ b/source/blender/editors/transform/transform_mode_trackball.c @@ -63,10 +63,6 @@ static void applyTrackballValue(TransInfo *t, FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 69552eda5bf..96820ca6385 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -236,10 +236,6 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) TransData *td = tc->data; for (int i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index ff15bbfb5d6..cd170b144d8 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -397,14 +397,12 @@ int BIF_countTransformOrientation(const bContext *C) return BLI_listbase_count(transform_orientations); } -bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char *r_name) +void applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char *r_name) { if (r_name) { BLI_strncpy(r_name, ts->name, MAX_NAME); } copy_m3_m3(r_mat, ts->mat); - - return true; } /* Updates all `BONE_TRANSFORM` flags. @@ -438,79 +436,176 @@ static int armature_bone_transflags_update_recursive(bArmature *arm, return total; } -void initTransformOrientation(bContext *C, TransInfo *t, short orientation) +void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3]) { - Object *ob = CTX_data_active_object(C); - Object *obedit = CTX_data_active_object(C); + ARegion *region = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obedit = CTX_data_edit_object(C); + RegionView3D *rv3d = region->regiondata; + Object *ob = OBACT(view_layer); + const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type; + const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; + const int pivot_point = scene->toolsettings->transform_pivot_point; - switch (orientation) { - case V3D_ORIENT_GLOBAL: - unit_m3(t->spacemtx); - BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename)); - break; + ED_transform_calc_orientation_from_type_ex( + C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point); +} - case V3D_ORIENT_GIMBAL: - unit_m3(t->spacemtx); - if (ob && gimbal_axis(ob, t->spacemtx)) { - BLI_strncpy(t->spacename, TIP_("gimbal"), sizeof(t->spacename)); - break; +short ED_transform_calc_orientation_from_type_ex(const bContext *C, + float r_mat[3][3], + /* extra args (can be accessed from context) */ + Scene *scene, + RegionView3D *rv3d, + Object *ob, + Object *obedit, + const short orientation_type, + int orientation_index_custom, + const int pivot_point) +{ + switch (orientation_type) { + case V3D_ORIENT_GLOBAL: { + unit_m3(r_mat); + return V3D_ORIENT_GLOBAL; + } + case V3D_ORIENT_GIMBAL: { + if (gimbal_axis(ob, r_mat)) { + return V3D_ORIENT_GIMBAL; } - ATTR_FALLTHROUGH; /* no gimbal fallthrough to normal */ - case V3D_ORIENT_NORMAL: - if (obedit || (ob && ob->mode & OB_MODE_POSE)) { - BLI_strncpy(t->spacename, TIP_("normal"), sizeof(t->spacename)); - ED_getTransformOrientationMatrix(C, t->spacemtx, t->around); - break; + /* if not gimbal, fall through to normal */ + ATTR_FALLTHROUGH; + } + case V3D_ORIENT_NORMAL: { + if (obedit || ob->mode & OB_MODE_POSE) { + ED_getTransformOrientationMatrix(C, r_mat, pivot_point); + return V3D_ORIENT_NORMAL; } - ATTR_FALLTHROUGH; /* we define 'normal' as 'local' in Object mode */ - case V3D_ORIENT_LOCAL: - BLI_strncpy(t->spacename, TIP_("local"), sizeof(t->spacename)); - + /* no break we define 'normal' as 'local' in Object mode */ + ATTR_FALLTHROUGH; + } + case V3D_ORIENT_LOCAL: { if (ob) { - copy_m3_m4(t->spacemtx, ob->obmat); - normalize_m3(t->spacemtx); - } - else { - unit_m3(t->spacemtx); + if (ob->mode & OB_MODE_POSE) { + /* each bone moves on its own local axis, but to avoid confusion, + * use the active pones axis for display [#33575], this works as expected on a single + * bone and users who select many bones will understand what's going on and what local + * means when they start transforming */ + ED_getTransformOrientationMatrix(C, r_mat, pivot_point); + } + else { + copy_m3_m4(r_mat, ob->obmat); + normalize_m3(r_mat); + } + return V3D_ORIENT_LOCAL; } - - break; - + unit_m3(r_mat); + return V3D_ORIENT_GLOBAL; + } case V3D_ORIENT_VIEW: { - float mat[3][3]; - if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { - BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename)); - copy_m3_m4(mat, t->viewinv); - normalize_m3(mat); + if (rv3d != NULL) { + copy_m3_m4(r_mat, rv3d->viewinv); + normalize_m3(r_mat); } else { - unit_m3(mat); + unit_m3(r_mat); } - copy_m3_m3(t->spacemtx, mat); - break; + return V3D_ORIENT_VIEW; } case V3D_ORIENT_CURSOR: { - BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename)); - BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx); + BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat); + return V3D_ORIENT_CURSOR; + } + case V3D_ORIENT_CUSTOM_MATRIX: { + /* Do nothing. */; break; } - case V3D_ORIENT_CUSTOM_MATRIX: - BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename)); - copy_m3_m3(t->spacemtx, t->orientation.custom_matrix); + case V3D_ORIENT_CUSTOM: + default: { + BLI_assert(orientation_type >= V3D_ORIENT_CUSTOM); + TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find( + scene, orientation_index_custom); + applyTransformOrientation(custom_orientation, r_mat, NULL); break; + } + } + + return orientation_type; +} + +/* Sets the matrix of the specified space orientation. + * If the matrix cannot be obtained, an orientation different from the one + * informed is returned */ +short transform_orientation_matrix_get(bContext *C, + TransInfo *t, + const short orientation, + const float custom[3][3], + float r_spacemtx[3][3]) +{ + if (orientation == V3D_ORIENT_CUSTOM_MATRIX) { + copy_m3_m3(r_spacemtx, custom); + return V3D_ORIENT_CUSTOM_MATRIX; + } + + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + Object *ob = CTX_data_active_object(C); + Object *obedit = CTX_data_active_object(C); + RegionView3D *rv3d = t->region->regiondata; + int orientation_index_custom = 0; + + if (orientation >= V3D_ORIENT_CUSTOM) { + orientation_index_custom = orientation - V3D_ORIENT_CUSTOM; + } + + return ED_transform_calc_orientation_from_type_ex( + C, + r_spacemtx, + /* extra args (can be accessed from context) */ + t->scene, + rv3d, + ob, + obedit, + orientation, + orientation_index_custom, + t->around); + } + + unit_m3(r_spacemtx); + return V3D_ORIENT_GLOBAL; +} + +const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type) +{ + switch (orient_type) { + case V3D_ORIENT_GLOBAL: + return TIP_("global"); + case V3D_ORIENT_GIMBAL: + return TIP_("gimbal"); + case V3D_ORIENT_NORMAL: + return TIP_("normal"); + case V3D_ORIENT_LOCAL: + return TIP_("local"); + case V3D_ORIENT_VIEW: + return TIP_("view"); + case V3D_ORIENT_CURSOR: + return TIP_("cursor"); + case V3D_ORIENT_CUSTOM_MATRIX: + return TIP_("custom"); case V3D_ORIENT_CUSTOM: default: - BLI_assert(orientation >= V3D_ORIENT_CUSTOM); - BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename)); - if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) { - /* pass */ - } - else { - unit_m3(t->spacemtx); - } - break; + BLI_assert(orient_type >= V3D_ORIENT_CUSTOM); + TransformOrientation *ts = BKE_scene_transform_orientation_find( + t->scene, orient_type - V3D_ORIENT_CUSTOM); + return ts->name; } +} + +void transform_orientations_current_set(TransInfo *t, const short orient_index) +{ + const short orientation = t->orient[orient_index].type; + const char *spacename = transform_orientations_spacename_get(t, orientation); + BLI_strncpy(t->spacename, spacename, sizeof(t->spacename)); + copy_m3_m3(t->spacemtx, t->orient[orient_index].matrix); invert_m3_m3(t->spacemtx_inv, t->spacemtx); } @@ -853,7 +948,7 @@ int getTransformOrientation_ex(const bContext *C, } } else { - const bool use_handle = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0; + const bool use_handle = v3d->overlay.handle_display != CURVE_HANDLE_NONE; for (nu = nurbs->first; nu; nu = nu->next) { /* only bezier has a normal */ diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index cb4446deb99..82602e7d828 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -56,6 +56,7 @@ #include "WM_types.h" +#include "ED_gizmo_library.h" #include "ED_image.h" #include "ED_markers.h" #include "ED_node.h" @@ -178,99 +179,53 @@ void drawSnapping(const struct bContext *C, TransInfo *t) (t->scene->toolsettings->snap_mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); if (draw_target || validSnap(t)) { - TransSnapPoint *p; - RegionView3D *rv3d = CTX_wm_region_view3d(C); - float imat[4][4]; - float size; + const float *loc_cur = NULL; + const float *loc_prev = NULL; + const float *normal = NULL; GPU_depth_test(false); - size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (!BLI_listbase_is_empty(&t->tsnap.points)) { + /* Draw snap points. */ - invert_m4_m4(imat, rv3d->viewmat); + float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE); + float view_inv[4][4]; + copy_m4_m4(view_inv, rv3d->viewinv); - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - for (p = t->tsnap.points.first; p; p = p->next) { - if (p == t->tsnap.selectedPoint) { - immUniformColor4ubv(selectedCol); - } - else { - immUniformColor4ubv(col); + LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) { + if (p == t->tsnap.selectedPoint) { + immUniformColor4ubv(selectedCol); + } + else { + immUniformColor4ubv(col); + } + imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos); } - imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat, pos); - } - - if (t->tsnap.status & POINT_INIT) { - immUniformColor4ubv(activeCol); - - imm_drawcircball( - t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat, pos); + immUnbindProgram(); } /* draw normal if needed */ if (usingSnappingNormal(t) && validSnappingNormal(t)) { - immUniformColor4ubv(activeCol); - - immBegin(GPU_PRIM_LINES, 2); - immVertex3f(pos, t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]); - immVertex3f(pos, - t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0], - t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1], - t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]); - immEnd(); + normal = t->tsnap.snapNormal; } if (draw_target) { - /* Draw snapTarget */ - float targ_co[3], vx[3], vy[3], v1[3], v2[3], v3[3], v4[4]; - copy_v3_v3(targ_co, t->tsnap.snapTarget); - float px_size = 0.75f * size * ED_view3d_pixel_size(rv3d, targ_co); - - mul_v3_v3fl(vx, imat[0], px_size); - mul_v3_v3fl(vy, imat[1], px_size); - - add_v3_v3v3(v1, vx, vy); - sub_v3_v3v3(v2, vx, vy); - negate_v3_v3(v3, v1); - negate_v3_v3(v4, v2); - - add_v3_v3(v1, targ_co); - add_v3_v3(v2, targ_co); - add_v3_v3(v3, targ_co); - add_v3_v3(v4, targ_co); - - immUniformColor4ubv(col); - immBegin(GPU_PRIM_LINES, 4); - immVertex3fv(pos, v3); - immVertex3fv(pos, v1); - immVertex3fv(pos, v4); - immVertex3fv(pos, v2); - immEnd(); - - if (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) { - immUnbindProgram(); - - immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); - immUniform1f("dash_width", 6.0f * U.pixelsize); - immUniform1f("dash_factor", 1.0f / 4.0f); - immUniformColor4ubv(col); + loc_prev = t->tsnap.snapTarget; + } - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, targ_co); - immVertex3fv(pos, t->tsnap.snapPoint); - immEnd(); - } + if (validSnap(t)) { + loc_cur = t->tsnap.snapPoint; } - immUnbindProgram(); + ED_gizmotypes_snap_3d_draw_util( + rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem); GPU_depth_test(true); } @@ -351,11 +306,6 @@ void applyProject(TransInfo *t) for (i = 0; i < tc->data_len; i++, td++) { float iloc[3], loc[3], no[3]; float mval_fl[2]; - - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } @@ -462,11 +412,6 @@ void applyGridAbsolute(TransInfo *t) for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { float iloc[3], loc[3], tvec[3]; - - if (td->flag & TD_NOACTION) { - break; - } - if (td->flag & TD_SKIP) { continue; } @@ -590,7 +535,6 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data)) static void initSnappingMode(TransInfo *t) { - Main *bmain = CTX_data_main(t->context); ToolSettings *ts = t->settings; /* All obedit types will match. */ const int obedit_type = t->data_container->obedit ? t->data_container->obedit->type : -1; @@ -687,7 +631,7 @@ static void initSnappingMode(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( - bmain, t->scene, 0, t->region, t->view); + t->scene, 0, t->region, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( t->tsnap.object_context, @@ -1106,7 +1050,6 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) } else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) { if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) { - Image *ima = ED_space_image(t->area->spacedata.first); float co[2]; UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]); @@ -1117,7 +1060,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) float dist_sq = FLT_MAX; if (ED_uvedit_nearest_uv_multi( - t->scene, ima, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) { + t->scene, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) { t->tsnap.snapPoint[0] *= t->aspect[0]; t->tsnap.snapPoint[1] *= t->aspect[1]; @@ -1750,8 +1693,8 @@ static void applyGridIncrement( float local_axis[3]; float pos_on_axis[3]; - copy_v3_v3(local_axis, t->con.mtx[i]); - copy_v3_v3(pos_on_axis, t->con.mtx[i]); + copy_v3_v3(local_axis, t->spacemtx[i]); + copy_v3_v3(pos_on_axis, t->spacemtx[i]); /* amount of movement on axis from initial pos */ mul_v3_fl(pos_on_axis, val[i]); diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index acd76a2e3f5..c30b8d59dc0 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -104,13 +104,12 @@ typedef struct SnapObjectData { /* SNAP_EDIT_MESH */ BVHTreeFromEditMesh treedata_editmesh; float min[3], max[3]; - struct LinkNode **bvh_cache_p; + struct Mesh_Runtime *mesh_runtime; }; }; } SnapObjectData; struct SnapObjectContext { - Main *bmain; Scene *scene; int flag; @@ -145,6 +144,17 @@ struct SnapObjectContext { /** \} */ /* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +static bool editmesh_eval_final_is_bmesh(const BMEditMesh *em) +{ + return (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Snap Object Data * \{ */ @@ -245,17 +255,17 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object return sod; } -static struct LinkNode **snap_object_data_editmesh_bvh_cache_get(Object *ob) +static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob) { BMEditMesh *em = BKE_editmesh_from_object(ob); if (em->mesh_eval_final) { - return &em->mesh_eval_final->runtime.bvh_cache; + return &em->mesh_eval_final->runtime; } if (em->mesh_eval_cage) { - return &em->mesh_eval_cage->runtime.bvh_cache; + return &em->mesh_eval_cage->runtime; } - return &((Mesh *)ob->data)->runtime.bvh_cache; + return &((Mesh *)ob->data)->runtime; } static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, @@ -292,23 +302,23 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, clear_cache = true; init = true; } - else if (sod->bvh_cache_p) { - if (sod->bvh_cache_p != snap_object_data_editmesh_bvh_cache_get(ob)) { + else if (sod->mesh_runtime) { + if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob)) { clear_cache = true; init = true; } else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached && - !bvhcache_has_tree(*sod->bvh_cache_p, sod->treedata_editmesh.tree)) { + !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree)) { /* The tree is owned by the EditMesh and may have been freed since we last used! */ clear = true; } else if (sod->bvhtree[0] && sod->cached[0] && - !bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[0])) { + !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0])) { /* The tree is owned by the EditMesh and may have been freed since we last used! */ clear = true; } else if (sod->bvhtree[1] && sod->cached[1] && - !bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[1])) { + !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1])) { /* The tree is owned by the EditMesh and may have been freed since we last used! */ clear = true; } @@ -347,7 +357,7 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, bm_mesh_minmax(em->bm, sod->min, sod->max); } - sod->bvh_cache_p = snap_object_data_editmesh_bvh_cache_get(ob); + sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob); } return sod; @@ -360,7 +370,7 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, * \{ */ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, - bool is_obedit, + bool use_obedit, bool use_backface_culling, Object *ob, float obmat[4][4], @@ -836,14 +846,19 @@ static bool raycastEditMesh(SnapObjectContext *sctx, sctx->callbacks.edit_mesh.user_data); bvhtree_from_editmesh_looptri_ex( - treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL); + treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL, NULL); MEM_freeN(elem_mask); } else { /* Only cache if bvhtree is created without a mask. * This helps keep a standardized bvhtree in cache. */ - BKE_bvhtree_from_editmesh_get(treedata, em, 4, BVHTREE_FROM_EM_LOOPTRI, sod->bvh_cache_p); + BKE_bvhtree_from_editmesh_get(treedata, + em, + 4, + BVHTREE_FROM_EM_LOOPTRI, + &sod->mesh_runtime->bvh_cache, + sod->mesh_runtime->eval_mutex); } if (treedata->tree == NULL) { @@ -921,41 +936,52 @@ static bool raycastEditMesh(SnapObjectContext *sctx, return retval; } +struct RaycastObjUserData { + const float *ray_start; + const float *ray_dir; + uint ob_index; + /* read/write args */ + float *ray_depth; + /* return args */ + float *r_loc; + float *r_no; + int *r_index; + Object **r_ob; + float (*r_obmat)[4]; + ListBase *r_hit_list; + bool use_occlusion_test; + bool ret; +}; + /** * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; * * \note Duplicate args here are documented at #snapObjectsRay */ -static bool raycastObj(SnapObjectContext *sctx, - const float ray_start[3], - const float ray_dir[3], - Object *ob, - const float obmat[4][4], - const uint ob_index, - bool use_obedit, - bool use_occlusion_test, - bool use_backface_culling, - /* read/write args */ - float *ray_depth, - /* return args */ - float r_loc[3], - float r_no[3], - int *r_index, - Object **r_ob, - float r_obmat[4][4], - ListBase *r_hit_list) +static void raycast_obj_fn(SnapObjectContext *sctx, + bool use_obedit, + bool use_backface_culling, + Object *ob, + float obmat[4][4], + void *data) { + struct RaycastObjUserData *dt = data; + const uint ob_index = dt->ob_index++; + bool use_occlusion_test = dt->use_occlusion_test; + /* read/write args */ + float *ray_depth = dt->ray_depth; + bool retval = false; if (use_occlusion_test) { if (use_obedit && sctx->use_v3d && XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) { /* Use of occlude geometry in editing mode disabled. */ - return false; + return; } if (ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE)) { /* Do not hit objects that are in wire or bounding box * display mode. */ - return false; + return; } } @@ -964,22 +990,22 @@ static bool raycastObj(SnapObjectContext *sctx, Mesh *me = ob->data; bool use_hide = false; if (BKE_object_is_in_editmode(ob)) { - if (use_obedit) { + if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) { /* Operators only update the editmesh looptris of the original mesh. */ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob)); retval = raycastEditMesh(sctx, - ray_start, - ray_dir, + dt->ray_start, + dt->ray_dir, ob, em_orig, obmat, ob_index, use_backface_culling, ray_depth, - r_loc, - r_no, - r_index, - r_hit_list); + dt->r_loc, + dt->r_no, + dt->r_index, + dt->r_hit_list); break; } else { @@ -991,8 +1017,8 @@ static bool raycastObj(SnapObjectContext *sctx, } } retval = raycastMesh(sctx, - ray_start, - ray_dir, + dt->ray_start, + dt->ray_dir, ob, me, obmat, @@ -1000,10 +1026,10 @@ static bool raycastObj(SnapObjectContext *sctx, use_hide, use_backface_culling, ray_depth, - r_loc, - r_no, - r_index, - r_hit_list); + dt->r_loc, + dt->r_no, + dt->r_index, + dt->r_hit_list); break; } case OB_CURVE: @@ -1012,8 +1038,8 @@ static bool raycastObj(SnapObjectContext *sctx, Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); if (mesh_eval) { retval = raycastMesh(sctx, - ray_start, - ray_dir, + dt->ray_start, + dt->ray_dir, ob, mesh_eval, obmat, @@ -1021,70 +1047,24 @@ static bool raycastObj(SnapObjectContext *sctx, false, use_backface_culling, ray_depth, - r_loc, - r_no, - r_index, - r_hit_list); + dt->r_loc, + dt->r_no, + dt->r_index, + dt->r_hit_list); break; } } } if (retval) { - if (r_ob) { - *r_ob = ob; + if (dt->r_ob) { + *dt->r_ob = ob; } - if (r_obmat) { - copy_m4_m4(r_obmat, obmat); + if (dt->r_obmat) { + copy_m4_m4(dt->r_obmat, obmat); } - return true; + dt->ret = true; } - - return false; -} - -struct RaycastObjUserData { - const float *ray_start; - const float *ray_dir; - uint ob_index; - /* read/write args */ - float *ray_depth; - /* return args */ - float *r_loc; - float *r_no; - int *r_index; - Object **r_ob; - float (*r_obmat)[4]; - ListBase *r_hit_list; - bool use_occlusion_test; - bool ret; -}; - -static void raycast_obj_cb(SnapObjectContext *sctx, - bool use_obedit, - bool use_backface_culling, - Object *ob, - float obmat[4][4], - void *data) -{ - struct RaycastObjUserData *dt = data; - - dt->ret |= raycastObj(sctx, - dt->ray_start, - dt->ray_dir, - ob, - obmat, - dt->ob_index++, - use_obedit, - dt->use_occlusion_test, - use_backface_culling, - dt->ray_depth, - dt->r_loc, - dt->r_no, - dt->r_index, - dt->r_ob, - dt->r_obmat, - dt->r_hit_list); } /** @@ -1145,7 +1125,7 @@ static bool raycastObjects(SnapObjectContext *sctx, .ret = false, }; - iter_snap_objects(sctx, depsgraph, params, raycast_obj_cb, &data); + iter_snap_objects(sctx, depsgraph, params, raycast_obj_fn, &data); return data.ret; } @@ -2525,11 +2505,16 @@ static short snapEditMesh(SnapObjectContext *sctx, sctx->callbacks.edit_mesh.user_data); bvhtree_from_editmesh_verts_ex( - &treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL); + &treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL, NULL); MEM_freeN(verts_mask); } else { - BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_VERTS, sod->bvh_cache_p); + BKE_bvhtree_from_editmesh_get(&treedata, + em, + 2, + BVHTREE_FROM_EM_VERTS, + &sod->mesh_runtime->bvh_cache, + (ThreadMutex *)sod->mesh_runtime->eval_mutex); } sod->bvhtree[0] = treedata.tree; sod->cached[0] = treedata.cached; @@ -2552,11 +2537,16 @@ static short snapEditMesh(SnapObjectContext *sctx, sctx->callbacks.edit_mesh.user_data); bvhtree_from_editmesh_edges_ex( - &treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL); + &treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL, NULL); MEM_freeN(edges_mask); } else { - BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_EDGES, sod->bvh_cache_p); + BKE_bvhtree_from_editmesh_get(&treedata, + em, + 2, + BVHTREE_FROM_EM_EDGES, + &sod->mesh_runtime->bvh_cache, + sod->mesh_runtime->eval_mutex); } sod->bvhtree[1] = treedata.tree; sod->cached[1] = treedata.cached; @@ -2645,45 +2635,51 @@ static short snapEditMesh(SnapObjectContext *sctx, return 0; } +struct SnapObjUserData { + SnapData *snapdata; + /* read/write args */ + float *dist_px; + /* return args */ + float *r_loc; + float *r_no; + int *r_index; + Object **r_ob; + float (*r_obmat)[4]; + short ret; +}; + /** * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; * * \note Duplicate args here are documented at #snapObjectsRay */ -static short snapObject(SnapObjectContext *sctx, - SnapData *snapdata, - Object *ob, - float obmat[4][4], +static void sanp_obj_fn(SnapObjectContext *sctx, bool use_obedit, bool use_backface_culling, - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float r_no[3], - int *r_index, - Object **r_ob, - float r_obmat[4][4]) + Object *ob, + float obmat[4][4], + void *data) { + struct SnapObjUserData *dt = data; short retval = 0; switch (ob->type) { case OB_MESH: { Mesh *me = ob->data; if (BKE_object_is_in_editmode(ob)) { - if (use_obedit) { + if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) { /* Operators only update the editmesh looptris of the original mesh. */ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob)); retval = snapEditMesh(sctx, - snapdata, + dt->snapdata, ob, em_orig, obmat, use_backface_culling, - dist_px, - r_loc, - r_no, - r_index); + dt->dist_px, + dt->r_loc, + dt->r_no, + dt->r_index); break; } else { @@ -2695,99 +2691,66 @@ static short snapObject(SnapObjectContext *sctx, } else if (ob->dt == OB_BOUNDBOX) { /* Do not snap to objects that are in bounding box display mode */ - return 0; + return; } - retval = snapMesh( - sctx, snapdata, ob, me, obmat, use_backface_culling, dist_px, r_loc, r_no, r_index); + retval = snapMesh(sctx, + dt->snapdata, + ob, + me, + obmat, + use_backface_culling, + dt->dist_px, + dt->r_loc, + dt->r_no, + dt->r_index); break; } case OB_ARMATURE: - retval = snapArmature(snapdata, ob, obmat, use_obedit, dist_px, r_loc, r_no, r_index); + retval = snapArmature( + dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; case OB_CURVE: - retval = snapCurve(snapdata, ob, obmat, use_obedit, dist_px, r_loc, r_no, r_index); + retval = snapCurve( + dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */ case OB_SURF: case OB_FONT: { Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); if (mesh_eval) { retval |= snapMesh(sctx, - snapdata, + dt->snapdata, ob, mesh_eval, obmat, use_backface_culling, - dist_px, - r_loc, - r_no, - r_index); + dt->dist_px, + dt->r_loc, + dt->r_no, + dt->r_index); } break; } case OB_EMPTY: - retval = snapEmpty(snapdata, ob, obmat, dist_px, r_loc, r_no, r_index); + retval = snapEmpty(dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; case OB_GPENCIL: - retval = snapEmpty(snapdata, ob, obmat, dist_px, r_loc, r_no, r_index); + retval = snapEmpty(dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; case OB_CAMERA: - retval = snapCamera(sctx, snapdata, ob, obmat, dist_px, r_loc, r_no, r_index); + retval = snapCamera( + sctx, dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; } if (retval) { - if (r_ob) { - *r_ob = ob; + if (dt->r_ob) { + *dt->r_ob = ob; } - if (r_obmat) { - copy_m4_m4(r_obmat, obmat); + if (dt->r_obmat) { + copy_m4_m4(dt->r_obmat, obmat); } - return retval; - } - - return 0; -} - -struct SnapObjUserData { - SnapData *snapdata; - /* read/write args */ - float *dist_px; - /* return args */ - float *r_loc; - float *r_no; - int *r_index; - Object **r_ob; - float (*r_obmat)[4]; - short ret; -}; - -static void sanp_obj_cb(SnapObjectContext *sctx, - bool is_obedit, - bool use_backface_culling, - Object *ob, - float obmat[4][4], - void *data) -{ - struct SnapObjUserData *dt = data; - - short elem = snapObject(sctx, - dt->snapdata, - ob, - obmat, - is_obedit, - use_backface_culling, - /* read/write args */ - dt->dist_px, - /* return args */ - dt->r_loc, - dt->r_no, - dt->r_index, - dt->r_ob, - dt->r_obmat); - - if (elem) { - dt->ret = elem; + dt->ret = retval; } } @@ -2840,7 +2803,7 @@ static short snapObjectsRay(SnapObjectContext *sctx, .ret = 0, }; - iter_snap_objects(sctx, depsgraph, params, sanp_obj_cb, &data); + iter_snap_objects(sctx, depsgraph, params, sanp_obj_fn, &data); return data.ret; } @@ -2851,13 +2814,12 @@ static short snapObjectsRay(SnapObjectContext *sctx, /** \name Public Object Snapping API * \{ */ -SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *scene, int flag) +SnapObjectContext *ED_transform_snap_object_context_create(Scene *scene, int flag) { SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__); sctx->flag = flag; - sctx->bmain = bmain; sctx->scene = scene; sctx->cache.object_map = BLI_ghash_ptr_new(__func__); @@ -2868,14 +2830,13 @@ SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *s return sctx; } -SnapObjectContext *ED_transform_snap_object_context_create_view3d(Main *bmain, - Scene *scene, +SnapObjectContext *ED_transform_snap_object_context_create_view3d(Scene *scene, int flag, /* extra args for view3d */ const ARegion *region, const View3D *v3d) { - SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, flag); sctx->use_v3d = true; sctx->v3d_data.region = region; diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index f22e18de7a1..2df26abe8b3 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -216,7 +216,7 @@ static void memfile_undosys_step_decode(struct bContext *C, FOREACH_MAIN_ID_BEGIN (bmain, id) { if (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) { BKE_library_foreach_ID_link( - bmain, id, memfile_undosys_step_id_reused_cb, bmain, IDWALK_READONLY); + bmain, id, memfile_undosys_step_id_reused_cb, NULL, IDWALK_READONLY); } /* Tag depsgraph to update data-block for changes that happened between the diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index f8e19b742e4..af387e4f7c2 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -153,10 +153,10 @@ void ED_editors_init(bContext *C) ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, true, reports); } else if (mode == OB_MODE_VERTEX_PAINT) { - ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob); + ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob); } else if (mode == OB_MODE_WEIGHT_PAINT) { - ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob); + ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob); } else { BLI_assert(0); @@ -174,7 +174,7 @@ void ED_editors_init(bContext *C) else { /* TODO(campbell): avoid operator calls. */ if (obact == ob) { - ED_object_mode_toggle(C, mode); + ED_object_mode_set(C, mode); } } } diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c index c072220842e..edfbfd0cdc3 100644 --- a/source/blender/editors/uvedit/uvedit_buttons.c +++ b/source/blender/editors/uvedit/uvedit_buttons.c @@ -58,8 +58,7 @@ /* UV Utilities */ -static int uvedit_center( - Scene *scene, Object **objects, uint objects_len, Image *ima, float center[2]) +static int uvedit_center(Scene *scene, Object **objects, uint objects_len, float center[2]) { BMFace *f; BMLoop *l; @@ -75,7 +74,7 @@ static int uvedit_center( const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, f)) { + if (!uvedit_face_visible_test(scene, f)) { continue; } @@ -97,8 +96,10 @@ static int uvedit_center( return tot; } -static void uvedit_translate( - Scene *scene, Object **objects, uint objects_len, Image *ima, const float delta[2]) +static void uvedit_translate(Scene *scene, + Object **objects, + uint objects_len, + const float delta[2]) { BMFace *f; BMLoop *l; @@ -112,7 +113,7 @@ static void uvedit_translate( const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, f)) { + if (!uvedit_face_visible_test(scene, f)) { continue; } @@ -134,7 +135,6 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block) { SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); - Image *ima = sima->image; float center[2]; int imx, imy, step, digits; float width = 8 * UI_UNIT_X; @@ -144,7 +144,7 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block) ED_space_image_get_size(sima, &imx, &imy); - if (uvedit_center(scene, objects, objects_len, ima, center)) { + if (uvedit_center(scene, objects, objects_len, center)) { float range_xy[2][2] = { {-10.0f, 10.0f}, {-10.0f, 10.0f}, @@ -212,7 +212,6 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) { SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); - Image *ima = sima->image; float center[2], delta[2]; int imx, imy; @@ -225,7 +224,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) CTX_data_view_layer(C), CTX_wm_view3d(C), &objects_len); ED_space_image_get_size(sima, &imx, &imy); - uvedit_center(scene, objects, objects_len, ima, center); + uvedit_center(scene, objects, objects_len, center); if (sima->flag & SI_COORDFLOATS) { delta[0] = uvedit_old_center[0] - center[0]; @@ -236,7 +235,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) delta[1] = uvedit_old_center[1] / imy - center[1]; } - uvedit_translate(scene, objects, objects_len, ima, delta); + uvedit_translate(scene, objects, objects_len, delta); WM_event_add_notifier(C, NC_IMAGE, sima->image); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index f8cef95c776..897e2f13774 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -39,6 +39,7 @@ #include "../../draw/intern/draw_cache_impl.h" #include "BLI_math.h" +#include "BLI_task.h" #include "BLI_utildefines.h" #include "BKE_deform.h" @@ -206,8 +207,10 @@ static void uvedit_get_batches(Object *ob, else { batches->faces = NULL; } - - DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false); + struct TaskGraph *task_graph = BLI_task_graph_create(); + DRW_mesh_batch_cache_create_requested(task_graph, ob, ob->data, scene, false, false); + BLI_task_graph_work_and_wait(task_graph); + BLI_task_graph_free(task_graph); if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) { /* after create_requested we can load the actual areas */ @@ -229,7 +232,11 @@ static void draw_uvs_shadow(SpaceImage *sima, DRW_mesh_batch_cache_validate(me); GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me); - DRW_mesh_batch_cache_create_requested(ob_eval, me, scene, false, false); + + struct TaskGraph *task_graph = BLI_task_graph_create(); + DRW_mesh_batch_cache_create_requested(task_graph, ob_eval, me, scene, false, false); + BLI_task_graph_work_and_wait(task_graph); + BLI_task_graph_free(task_graph); if (edges) { if (sima->flag & SI_SMOOTH_UV) { @@ -269,7 +276,10 @@ static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgra DRW_mesh_batch_cache_validate(me); GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me); - DRW_mesh_batch_cache_create_requested(ob_eval, me, scene, false, false); + struct TaskGraph *task_graph = BLI_task_graph_create(); + DRW_mesh_batch_cache_create_requested(task_graph, ob_eval, me, scene, false, false); + BLI_task_graph_work_and_wait(task_graph); + BLI_task_graph_free(task_graph); GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UV_UNIFORM_COLOR); GPU_batch_uniform_4fv(geom, "color", col); diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index ffab5bd094f..31384d6df17 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -57,13 +57,11 @@ typedef struct UvNearestHit { } bool uv_find_nearest_vert(struct Scene *scene, - struct Image *ima, struct Object *obedit, const float co[2], const float penalty_dist, struct UvNearestHit *hit_final); bool uv_find_nearest_vert_multi(struct Scene *scene, - struct Image *ima, struct Object **objects, const uint objects_len, const float co[2], @@ -71,24 +69,20 @@ bool uv_find_nearest_vert_multi(struct Scene *scene, struct UvNearestHit *hit_final); bool uv_find_nearest_edge(struct Scene *scene, - struct Image *ima, struct Object *obedit, const float co[2], struct UvNearestHit *hit_final); bool uv_find_nearest_edge_multi(struct Scene *scene, - struct Image *ima, struct Object **objects, const uint objects_len, const float co[2], struct UvNearestHit *hit_final); bool uv_find_nearest_face(struct Scene *scene, - struct Image *ima, struct Object *obedit, const float co[2], struct UvNearestHit *hit_final); bool uv_find_nearest_face_multi(struct Scene *scene, - struct Image *ima, struct Object **objects, const uint objects_len, const float co[2], @@ -116,14 +110,11 @@ void UV_OT_stitch(struct wmOperatorType *ot); /* uvedit_select.c */ -bool uvedit_select_is_any_selected(struct Scene *scene, struct Image *ima, struct Object *obedit); +bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit); bool uvedit_select_is_any_selected_multi(struct Scene *scene, - struct Image *ima, struct Object **objects, const uint objects_len); const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene, - struct Object *obedit, - struct Image *ima, struct BMVert *eve, const int cd_loop_uv_offset); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index a99e05cb52b..652d07f02db 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -252,12 +252,8 @@ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float as } } -bool ED_uvedit_minmax_multi(const Scene *scene, - Image *ima, - Object **objects_edit, - uint objects_len, - float r_min[2], - float r_max[2]) +bool ED_uvedit_minmax_multi( + const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2]) { bool changed = false; INIT_MINMAX2(r_min, r_max); @@ -274,7 +270,7 @@ bool ED_uvedit_minmax_multi(const Scene *scene, const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -290,10 +286,9 @@ bool ED_uvedit_minmax_multi(const Scene *scene, return changed; } -bool ED_uvedit_minmax( - const Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2]) +bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2]) { - return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max); + return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max); } /* Be careful when using this, it bypasses all synchronization options */ @@ -314,8 +309,10 @@ void ED_uvedit_select_all(BMesh *bm) } } -static bool ED_uvedit_median_multi( - const Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2]) +static bool ED_uvedit_median_multi(const Scene *scene, + Object **objects_edit, + uint objects_len, + float co[2]) { uint sel = 0; zero_v2(co); @@ -332,7 +329,7 @@ static bool ED_uvedit_median_multi( const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -351,24 +348,20 @@ static bool ED_uvedit_median_multi( return (sel != 0); } -bool ED_uvedit_center_multi(const Scene *scene, - Image *ima, - Object **objects_edit, - uint objects_len, - float cent[2], - char mode) +bool ED_uvedit_center_multi( + const Scene *scene, Object **objects_edit, uint objects_len, float cent[2], char mode) { bool changed = false; if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */ float min[2], max[2]; - if (ED_uvedit_minmax_multi(scene, ima, objects_edit, objects_len, min, max)) { + if (ED_uvedit_minmax_multi(scene, objects_edit, objects_len, min, max)) { mid_v2_v2v2(cent, min, max); changed = true; } } else { - if (ED_uvedit_median_multi(scene, ima, objects_edit, objects_len, cent)) { + if (ED_uvedit_median_multi(scene, objects_edit, objects_len, cent)) { changed = true; } } @@ -392,8 +385,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima, uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - *r_has_select = uvedit_select_is_any_selected_multi( - scene, sima->image, objects, objects_len); + *r_has_select = uvedit_select_is_any_selected_multi(scene, objects, objects_len); MEM_freeN(objects); } break; @@ -402,7 +394,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima, uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - changed = ED_uvedit_center_multi(scene, sima->image, objects, objects_len, r_center, mode); + changed = ED_uvedit_center_multi(scene, objects, objects_len, r_center, mode); MEM_freeN(objects); if (r_has_select != NULL) { *r_has_select = changed; @@ -440,7 +432,6 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); const ToolSettings *ts = scene->toolsettings; const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; float cent[2], min[2], max[2]; @@ -467,7 +458,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -482,7 +473,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X; } - ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0); + ED_uvedit_center_multi(scene, objects, objects_len, cent, 0); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; @@ -501,7 +492,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -521,7 +512,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -548,7 +539,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) /* tag verts with a selected UV */ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { + if (!uvedit_face_visible_test(scene, l->f)) { continue; } @@ -619,9 +610,9 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) /* we know the returns from these must be valid */ const float *uv_start = uvedit_first_selected_uv_from_vertex( - scene, obedit, ima, eve_line[0], cd_loop_uv_offset); + scene, eve_line[0], cd_loop_uv_offset); const float *uv_end = uvedit_first_selected_uv_from_vertex( - scene, obedit, ima, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset); + scene, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset); /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */ float a = 0.0f; eUVWeldAlign tool_local = tool; @@ -646,7 +637,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) /* go over all verts except for endpoints */ for (i = 0; i < BLI_array_len(eve_line); i++) { BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { + if (!uvedit_face_visible_test(scene, l->f)) { continue; } @@ -754,7 +745,6 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); const ToolSettings *ts = scene->toolsettings; const float threshold = RNA_float_get(op->ptr, "threshold"); @@ -808,7 +798,7 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -899,7 +889,6 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); const ToolSettings *ts = scene->toolsettings; const float threshold = RNA_float_get(op->ptr, "threshold"); @@ -939,7 +928,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -972,7 +961,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1086,10 +1075,12 @@ static void uv_snap_cursor_to_pixels(SpaceImage *sima) uv_snap_to_pixel(sima->cursor, width, height); } -static bool uv_snap_cursor_to_selection( - Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima) +static bool uv_snap_cursor_to_selection(Scene *scene, + Object **objects_edit, + uint objects_len, + SpaceImage *sima) { - return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, sima->cursor, sima->around); + return ED_uvedit_center_multi(scene, objects_edit, objects_len, sima->cursor, sima->around); } static int uv_snap_cursor_exec(bContext *C, wmOperator *op) @@ -1105,13 +1096,12 @@ static int uv_snap_cursor_exec(bContext *C, wmOperator *op) break; case 1: { Scene *scene = CTX_data_scene(C); - Image *ima = CTX_data_edit_image(C); ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima); + changed = uv_snap_cursor_to_selection(scene, objects, objects_len, sima); MEM_freeN(objects); break; } @@ -1155,7 +1145,7 @@ static void UV_OT_snap_cursor(wmOperatorType *ot) /** \name Snap Selection Operator * \{ */ -static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2]) +static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2]) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; @@ -1167,7 +1157,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1183,7 +1173,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons return changed; } -static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const float offset[2]) +static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2]) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; @@ -1195,7 +1185,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1211,7 +1201,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f return changed; } -static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit) +static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Object *obedit) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; @@ -1225,7 +1215,7 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object /* index every vert that has a selected UV using it, but only once so as to * get unique indices and to count how much to malloc */ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, f)) { + if (uvedit_face_visible_test(scene, f)) { BM_elem_flag_enable(f, BM_ELEM_TAG); BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset)); @@ -1269,7 +1259,6 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit) { BMEditMesh *em = BKE_editmesh_from_object(obedit); - Image *ima = sima->image; BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -1285,7 +1274,7 @@ static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit h = (float)height; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1307,7 +1296,6 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); const ToolSettings *ts = scene->toolsettings; const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; const int target = RNA_enum_get(op->ptr, "target"); @@ -1319,7 +1307,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op) if (target == 2) { float center[2]; - if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) { + if (!ED_uvedit_center_multi(scene, objects, objects_len, center, sima->around)) { MEM_freeN(objects); return OPERATOR_CANCELLED; } @@ -1341,13 +1329,13 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op) changed = uv_snap_uvs_to_pixels(sima, scene, obedit); break; case 1: - changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor); + changed = uv_snap_uvs_to_cursor(scene, obedit, sima->cursor); break; case 2: - changed = uv_snap_uvs_offset(scene, ima, obedit, offset); + changed = uv_snap_uvs_offset(scene, obedit, offset); break; case 3: - changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit); + changed = uv_snap_uvs_to_adjacent_unselected(scene, obedit); break; } @@ -1398,7 +1386,6 @@ static int uv_pin_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -1423,7 +1410,7 @@ static int uv_pin_exec(bContext *C, wmOperator *op) } BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1501,11 +1488,9 @@ static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop static int uv_hide_exec(bContext *C, wmOperator *op) { ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; const bool swap = RNA_boolean_get(op->ptr, "unselected"); - Image *ima = sima ? sima->image : NULL; const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE); uint objects_len = 0; @@ -1532,7 +1517,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op) BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { int hide = 0; - if (!uvedit_face_visible_test(scene, ob, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1858,11 +1843,12 @@ static void UV_OT_cursor_set(wmOperatorType *ot) static int uv_seams_from_islands_exec(bContext *C, wmOperator *op) { + Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - int ret = OPERATOR_CANCELLED; const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT}; const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams"); const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); + bool changed_multi = false; uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( @@ -1873,111 +1859,76 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op) Mesh *me = (Mesh *)ob->data; BMEditMesh *em = me->edit_mesh; BMesh *bm = em->bm; - - UvVertMap *vmap; - BMEdge *editedge; BMIter iter; if (!EDBM_uv_check(em)) { continue; } - ret = OPERATOR_FINISHED; - - /* This code sets editvert->tmp.l to the index. This will be useful later on. */ - BM_mesh_elem_table_ensure(bm, BM_FACE); - vmap = BM_uv_vert_map_create(bm, limit, false, false); - - BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) { - /* flags to determine if we uv is separated from first editface match */ - char separated1 = 0, separated2; - /* set to denote edge must be flagged as seam */ - char faces_separated = 0; - /* flag to keep track if uv1 is disconnected from first editface match */ - char v1coincident = 1; - /* For use with v1coincident. v1coincident will change only if we've had commonFaces */ - int commonFaces = 0; - - BMFace *efa1, *efa2; - - UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter; - /* mv2cache stores the first of the list of coincident uv's for later comparison - * mv2sep holds the last separator and is copied to mv2cache - * when a hit is first found */ - UvMapVert *mv2cache = NULL, *mv2sep = NULL; - - mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)]; - if (mark_seams) { - BM_elem_flag_disable(editedge, BM_ELEM_SEAM); + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + bool changed = false; + + BMFace *f; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, f)) { + continue; } - for (mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) { - if (mv1->separate && commonFaces) { - v1coincident = 0; + BMLoop *l_iter; + BMLoop *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (l_iter == l_iter->radial_next) { + continue; + } + if (!uvedit_edge_select_test(scene, l_iter, cd_loop_uv_offset)) { + continue; } - separated2 = 0; - efa1 = BM_face_at_index(bm, mv1->poly_index); - mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)]; + const MLoopUV *luv_curr = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); + const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l_iter->next, cd_loop_uv_offset); - for (mv2 = mvinit2; mv2; mv2 = mv2->next) { - if (mv2->separate) { - mv2sep = mv2; + bool mark = false; + BMLoop *l_other = l_iter->radial_next; + do { + const MLoopUV *luv_other_curr = BM_ELEM_CD_GET_VOID_P(l_other, cd_loop_uv_offset); + const MLoopUV *luv_other_next = BM_ELEM_CD_GET_VOID_P(l_other->next, cd_loop_uv_offset); + if (l_iter->v != l_other->v) { + SWAP(const MLoopUV *, luv_other_curr, luv_other_next); } - efa2 = BM_face_at_index(bm, mv2->poly_index); - if (efa1 == efa2) { - /* if v1 is not coincident no point in comparing */ - if (v1coincident) { - /* have we found previously anything? */ - if (mv2cache) { - /* flag seam unless proved to be coincident with previous hit */ - separated2 = 1; - for (mviter = mv2cache; mviter; mviter = mviter->next) { - if (mviter->separate && mviter != mv2cache) { - break; - } - /* coincident with previous hit, do not flag seam */ - if (mviter == mv2) { - separated2 = 0; - } - } - } - /* First hit case, store the hit in the cache */ - else { - mv2cache = mv2sep; - commonFaces = 1; - } - } - else { - separated1 = 1; - } + if (!compare_ff(luv_curr->uv[0], luv_other_curr->uv[0], limit[0]) || + !compare_ff(luv_curr->uv[1], luv_other_curr->uv[1], limit[1]) || - if (separated1 || separated2) { - faces_separated = 1; - break; - } + !compare_ff(luv_next->uv[0], luv_other_next->uv[0], limit[0]) || + !compare_ff(luv_next->uv[1], luv_other_next->uv[1], limit[1])) { + mark = true; + break; } - } - } + } while ((l_other = l_other->radial_next) != l_iter); - if (faces_separated) { - if (mark_seams) { - BM_elem_flag_enable(editedge, BM_ELEM_SEAM); - } - if (mark_sharp) { - BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH); + if (mark) { + if (mark_seams) { + BM_elem_flag_enable(l_iter->e, BM_ELEM_SEAM); + } + if (mark_sharp) { + BM_elem_flag_disable(l_iter->e, BM_ELEM_SMOOTH); + } + changed = true; } - } + } while ((l_iter = l_iter->next) != l_first); } - BM_uv_vert_map_free(vmap); - - DEG_id_tag_update(&me->id, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + if (changed) { + changed_multi = true; + DEG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + } } MEM_freeN(objects); - return ret; + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } static void UV_OT_seams_from_islands(wmOperatorType *ot) @@ -2006,8 +1957,6 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot) static int uv_mark_seam_exec(bContext *C, wmOperator *op) { - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = sima ? sima->image : NULL; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); const ToolSettings *ts = scene->toolsettings; @@ -2038,7 +1987,7 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ob, ima, efa)) { + if (uvedit_face_visible_test(scene, efa)) { BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) { if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) { BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set); diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 6e931b56a85..cc9be9d48c1 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -70,9 +70,11 @@ #include "uvedit_intern.h" -static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action); -static void uv_select_all_perform_multi( - Scene *scene, Image *ima, Object **objects, const uint objects_len, int action); +static void uv_select_all_perform(Scene *scene, Object *obedit, int action); +static void uv_select_all_perform_multi(Scene *scene, + Object **objects, + const uint objects_len, + int action); static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, @@ -112,7 +114,7 @@ static void uvedit_vertex_select_tagged(BMEditMesh *em, } } -bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa) +bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa) { if (ts->uv_flag & UV_SYNC_SELECTION) { return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); @@ -121,25 +123,9 @@ bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa) return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); } } -bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa) +bool uvedit_face_visible_test(const Scene *scene, BMFace *efa) { - return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa); -} - -bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa) -{ - if (ts->uv_flag & UV_SHOW_SAME_IMAGE) { - Image *face_image; - ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL); - return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false; - } - else { - return uvedit_face_visible_nolocal_ex(ts, efa); - } -} -bool uvedit_face_visible_test(const Scene *scene, Object *obedit, Image *ima, BMFace *efa) -{ - return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa); + return uvedit_face_visible_test_ex(scene->toolsettings, efa); } bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset) @@ -437,8 +423,7 @@ void uvedit_uv_select_disable(BMEditMesh *em, /** \name Find Nearest Elements * \{ */ -bool uv_find_nearest_edge( - Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit) +bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; @@ -453,7 +438,7 @@ bool uv_find_nearest_edge( BM_mesh_elem_index_ensure(em->bm, BM_VERT); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { @@ -479,7 +464,6 @@ bool uv_find_nearest_edge( } bool uv_find_nearest_edge_multi(Scene *scene, - Image *ima, Object **objects, const uint objects_len, const float co[2], @@ -488,7 +472,7 @@ bool uv_find_nearest_edge_multi(Scene *scene, bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) { + if (uv_find_nearest_edge(scene, obedit, co, hit_final)) { hit_final->ob = obedit; found = true; } @@ -496,8 +480,7 @@ bool uv_find_nearest_edge_multi(Scene *scene, return found; } -bool uv_find_nearest_face( - Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final) +bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit_final) { BMEditMesh *em = BKE_editmesh_from_object(obedit); bool found = false; @@ -507,7 +490,7 @@ bool uv_find_nearest_face( /* this will fill in hit.vert1 and hit.vert2 */ float dist_sq_init = hit_final->dist_sq; UvNearestHit hit = *hit_final; - if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + if (uv_find_nearest_edge(scene, obedit, co, &hit)) { hit.dist_sq = dist_sq_init; hit.l = NULL; hit.luv = hit.luv_next = NULL; @@ -516,7 +499,7 @@ bool uv_find_nearest_face( BMFace *efa; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -539,7 +522,6 @@ bool uv_find_nearest_face( } bool uv_find_nearest_face_multi(Scene *scene, - Image *ima, Object **objects, const uint objects_len, const float co[2], @@ -548,7 +530,7 @@ bool uv_find_nearest_face_multi(Scene *scene, bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) { + if (uv_find_nearest_face(scene, obedit, co, hit_final)) { hit_final->ob = obedit; found = true; } @@ -567,7 +549,6 @@ static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_ } bool uv_find_nearest_vert(Scene *scene, - Image *ima, Object *obedit, float const co[2], const float penalty_dist, @@ -578,7 +559,7 @@ bool uv_find_nearest_vert(Scene *scene, /* this will fill in hit.vert1 and hit.vert2 */ float dist_sq_init = hit_final->dist_sq; UvNearestHit hit = *hit_final; - if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + if (uv_find_nearest_edge(scene, obedit, co, &hit)) { hit.dist_sq = dist_sq_init; hit.l = NULL; @@ -593,7 +574,7 @@ bool uv_find_nearest_vert(Scene *scene, const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -639,7 +620,6 @@ bool uv_find_nearest_vert(Scene *scene, } bool uv_find_nearest_vert_multi(Scene *scene, - Image *ima, Object **objects, const uint objects_len, float const co[2], @@ -649,7 +629,7 @@ bool uv_find_nearest_vert_multi(Scene *scene, bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) { + if (uv_find_nearest_vert(scene, obedit, co, penalty_dist, hit_final)) { hit_final->ob = obedit; found = true; } @@ -657,12 +637,8 @@ bool uv_find_nearest_vert_multi(Scene *scene, return found; } -bool ED_uvedit_nearest_uv(const Scene *scene, - Object *obedit, - Image *ima, - const float co[2], - float *dist_sq, - float r_uv[2]) +bool ED_uvedit_nearest_uv( + const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2]) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMIter iter; @@ -671,7 +647,7 @@ bool ED_uvedit_nearest_uv(const Scene *scene, float dist_best = *dist_sq; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } BMLoop *l_iter, *l_first; @@ -697,7 +673,6 @@ bool ED_uvedit_nearest_uv(const Scene *scene, } bool ED_uvedit_nearest_uv_multi(const Scene *scene, - Image *ima, Object **objects, const uint objects_len, const float co[2], @@ -707,7 +682,7 @@ bool ED_uvedit_nearest_uv_multi(const Scene *scene, bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) { + if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) { found = true; } } @@ -817,12 +792,8 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, return true; } -static int uv_select_edgeloop(Scene *scene, - Image *ima, - Object *obedit, - UvNearestHit *hit, - const float limit[2], - const bool extend) +static int uv_select_edgeloop( + Scene *scene, Object *obedit, UvNearestHit *hit, const float limit[2], const bool extend) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; @@ -843,7 +814,7 @@ static int uv_select_edgeloop(Scene *scene, BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); if (!extend) { - uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); + uv_select_all_perform(scene, obedit, SEL_DESELECT); } BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); @@ -867,8 +838,7 @@ static int uv_select_edgeloop(Scene *scene, /* find correct valence edges which are not tagged yet, but connect to tagged one */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && - uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, efa)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { /* check face not hidden and not tagged */ if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) { @@ -930,7 +900,6 @@ static int uv_select_edgeloop(Scene *scene, * \{ */ static void uv_select_linked_multi(Scene *scene, - Image *ima, Object **objects, const uint objects_len, const float limit[2], @@ -980,7 +949,7 @@ static void uv_select_linked_multi(Scene *scene, if (hit_final == NULL) { /* Use existing selection */ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (uvedit_face_visible_test(scene, efa)) { if (select_faces) { if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { stack[stacksize] = a; @@ -1121,14 +1090,15 @@ static void uv_select_linked_multi(Scene *scene, * \warning This returns first selected UV, * not ideal in many cases since there could be multiple. */ -const float *uvedit_first_selected_uv_from_vertex( - Scene *scene, Object *obedit, Image *ima, BMVert *eve, const int cd_loop_uv_offset) +const float *uvedit_first_selected_uv_from_vertex(Scene *scene, + BMVert *eve, + const int cd_loop_uv_offset) { BMIter liter; BMLoop *l; BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { + if (!uvedit_face_visible_test(scene, l->f)) { continue; } @@ -1151,7 +1121,6 @@ static int uv_select_more_less(bContext *C, const bool select) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); SpaceImage *sima = CTX_wm_space_image(C); BMFace *efa; @@ -1193,7 +1162,7 @@ static int uv_select_more_less(bContext *C, const bool select) /* mark loops to be selected */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (uvedit_face_visible_test(scene, efa)) { #define IS_SEL 1 #define IS_UNSEL 2 @@ -1233,7 +1202,7 @@ static int uv_select_more_less(bContext *C, const bool select) /* mark loops to be selected */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (uvedit_face_visible_test(scene, efa)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); @@ -1308,7 +1277,7 @@ void UV_OT_select_less(wmOperatorType *ot) /** \name (De)Select All Operator * \{ */ -bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit) +bool uvedit_select_is_any_selected(Scene *scene, Object *obedit) { const ToolSettings *ts = scene->toolsettings; BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -1323,7 +1292,7 @@ bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit) else { const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1337,15 +1306,12 @@ bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit) return false; } -bool uvedit_select_is_any_selected_multi(Scene *scene, - Image *ima, - Object **objects, - const uint objects_len) +bool uvedit_select_is_any_selected_multi(Scene *scene, Object **objects, const uint objects_len) { bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (uvedit_select_is_any_selected(scene, ima, obedit)) { + if (uvedit_select_is_any_selected(scene, obedit)) { found = true; break; } @@ -1353,7 +1319,7 @@ bool uvedit_select_is_any_selected_multi(Scene *scene, return found; } -static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action) +static void uv_select_all_perform(Scene *scene, Object *obedit, int action) { const ToolSettings *ts = scene->toolsettings; BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -1365,7 +1331,7 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); if (action == SEL_TOGGLE) { - action = uvedit_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT; + action = uvedit_select_is_any_selected(scene, obedit) ? SEL_DESELECT : SEL_SELECT; } if (ts->uv_flag & UV_SYNC_SELECTION) { @@ -1387,7 +1353,7 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int } else { BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1410,17 +1376,19 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int } } -static void uv_select_all_perform_multi( - Scene *scene, Image *ima, Object **objects, const uint objects_len, int action) +static void uv_select_all_perform_multi(Scene *scene, + Object **objects, + const uint objects_len, + int action) { if (action == SEL_TOGGLE) { - action = uvedit_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT : - SEL_SELECT; + action = uvedit_select_is_any_selected_multi(scene, objects, objects_len) ? SEL_DESELECT : + SEL_SELECT; } for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - uv_select_all_perform(scene, ima, obedit, action); + uv_select_all_perform(scene, obedit, action); } } @@ -1429,7 +1397,6 @@ static int uv_select_all_exec(bContext *C, wmOperator *op) Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); ViewLayer *view_layer = CTX_data_view_layer(C); int action = RNA_enum_get(op->ptr, "action"); @@ -1438,7 +1405,7 @@ static int uv_select_all_exec(bContext *C, wmOperator *op) Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - uv_select_all_perform_multi(scene, ima, objects, objects_len, action); + uv_select_all_perform_multi(scene, objects, objects_len, action); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; @@ -1510,7 +1477,6 @@ static int uv_mouse_select_multi(bContext *C, SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -1563,12 +1529,11 @@ static int uv_mouse_select_multi(bContext *C, /* find nearest element */ if (loop) { /* find edge */ - found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); + found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); } else if (selectmode == UV_SELECT_VERTEX) { /* find vertex */ - found_item = uv_find_nearest_vert_multi( - scene, ima, objects, objects_len, co, penalty_dist, &hit); + found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit); found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); if (found_item) { @@ -1585,7 +1550,7 @@ static int uv_mouse_select_multi(bContext *C, } else if (selectmode == UV_SELECT_EDGE) { /* find edge */ - found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); + found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); if (found_item) { @@ -1604,7 +1569,7 @@ static int uv_mouse_select_multi(bContext *C, } else if (selectmode == UV_SELECT_FACE) { /* find face */ - found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit); + found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit); found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); if (found_item) { @@ -1628,13 +1593,13 @@ static int uv_mouse_select_multi(bContext *C, } } else if (selectmode == UV_SELECT_ISLAND) { - found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); + found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); } if (!found_item) { if (deselect_all) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; @@ -1654,19 +1619,18 @@ static int uv_mouse_select_multi(bContext *C, if (loop) { if (!extend) { /* TODO(MULTI_EDIT): We only need to de-select non-active */ - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } - flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend); + flush = uv_select_edgeloop(scene, obedit, &hit, limit, extend); } else if (selectmode == UV_SELECT_ISLAND) { if (!extend) { /* TODO(MULTI_EDIT): We only need to de-select non-active */ - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } /* Current behavior of 'extend' * is actually toggling, so pass extend flag as 'toggle' here */ - uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, false, false, extend, false); + uv_select_linked_multi(scene, objects, objects_len, limit, &hit, false, false, extend, false); } else if (extend) { if (selectmode == UV_SELECT_VERTEX) { @@ -1701,7 +1665,7 @@ static int uv_mouse_select_multi(bContext *C, BM_mesh_elem_index_ensure(em->bm, BM_VERT); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1719,7 +1683,7 @@ static int uv_mouse_select_multi(bContext *C, } else { /* deselect all */ - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); if (selectmode == UV_SELECT_VERTEX) { /* select vertex */ @@ -1739,7 +1703,7 @@ static int uv_mouse_select_multi(bContext *C, /* select sticky uvs */ if (sticky != SI_STICKY_DISABLE) { BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1946,7 +1910,6 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); float limit[2]; bool extend = true; bool deselect = false; @@ -1986,18 +1949,17 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent RNA_float_get_array(op->ptr, "location", co); } - if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { + if (!uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit)) { MEM_freeN(objects); return OPERATOR_CANCELLED; } } if (!extend) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } uv_select_linked_multi(scene, - ima, objects, objects_len, limit, @@ -2117,7 +2079,6 @@ static int uv_select_split_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); const ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); BMFace *efa; BMLoop *l; @@ -2147,7 +2108,7 @@ static int uv_select_split_exec(bContext *C, wmOperator *op) bool is_sel = false; bool is_unsel = false; - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -2483,7 +2444,6 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); const ARegion *region = CTX_wm_region(C); BMFace *efa; BMLoop *l; @@ -2518,7 +2478,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) view_layer, ((View3D *)NULL), &objects_len); if (use_pre_deselect) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } /* don't indent to avoid diff noise! */ @@ -2539,7 +2499,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) /* assume not touched */ BM_elem_flag_disable(efa, BM_ELEM_TAG); - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (uvedit_face_visible_test(scene, efa)) { uv_poly_center(efa, cent, cd_loop_uv_offset); if (BLI_rctf_isect_pt_v(&rectf, cent)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); @@ -2558,7 +2518,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -2594,7 +2554,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } bool has_selected = false; @@ -2623,7 +2583,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) .efa = efa, }; uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + scene, objects, objects_len, limit, &hit, true, !select, false, false); } } @@ -2708,7 +2668,6 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); const ToolSettings *ts = scene->toolsettings; @@ -2757,7 +2716,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); if (use_pre_deselect) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } for (uint ob_index = 0; ob_index < objects_len; ob_index++) { @@ -2792,7 +2751,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -2826,7 +2785,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } bool has_selected = false; @@ -2847,7 +2806,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) .efa = efa, }; uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + scene, objects, objects_len, limit, &hit, true, !select, false, false); } } @@ -2920,7 +2879,6 @@ static bool do_lasso_select_mesh_uv(bContext *C, { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); const ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; @@ -2952,7 +2910,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, view_layer, ((View3D *)NULL), &objects_len); if (use_pre_deselect) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } /* don't indent to avoid diff noise! */ @@ -2988,7 +2946,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -3025,7 +2983,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } bool has_selected = false; @@ -3047,7 +3005,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, .efa = efa, }; uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + scene, objects, objects_len, limit, &hit, true, !select, false, false); } } @@ -3116,7 +3074,6 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -3134,7 +3091,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) bool changed = false; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -3208,7 +3165,6 @@ static int uv_select_overlap(bContext *C, const bool extend) Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( @@ -3224,13 +3180,13 @@ static int uv_select_overlap(bContext *C, const bool extend) BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); if (!extend) { - uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); + uv_select_all_perform(scene, obedit, SEL_DESELECT); } BMIter iter; BMFace *efa; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) { + if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) { continue; } uv_tri_len += efa->len - 2; @@ -3261,7 +3217,7 @@ static int uv_select_overlap(bContext *C, const bool extend) int face_index; BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) { - if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) { + if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) { continue; } diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 3a4f12acf9c..594847b7249 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -2550,12 +2550,11 @@ static StitchState *stitch_select(bContext *C, float co[2]; UvNearestHit hit = UV_NEAREST_HIT_INIT; ARegion *region = CTX_wm_region(C); - Image *ima = CTX_data_edit_image(C); UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); if (ssc->mode == STITCH_VERT) { - if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) { + if (uv_find_nearest_vert_multi(scene, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) { /* Add vertex to selection, deselect all common uv's of vert other than selected and * update the preview. This behavior was decided so that you can do stuff like deselect * the opposite stitchable vertex and the initial still gets deselected */ @@ -2576,7 +2575,7 @@ static StitchState *stitch_select(bContext *C, return state; } } - else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) { + else if (uv_find_nearest_edge_multi(scene, ssc->objects, ssc->objects_len, co, &hit)) { /* find StitchState from hit->ob */ StitchState *state = NULL; for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h index 648eb4e453d..8503836e0ca 100644 --- a/source/blender/freestyle/intern/view_map/Silhouette.h +++ b/source/blender/freestyle/intern/view_map/Silhouette.h @@ -1592,15 +1592,15 @@ class SShape { /*! Splits an edge into several edges. * The edge's vertices are passed rather than the edge itself. This way, all feature edges - * (SILHOUETTE, CREASE, BORDER) are splitted in the same time. The processed edges are flagged as - * done (using the userdata flag).One single new vertex is created whereas several splitted edges + * (SILHOUETTE, CREASE, BORDER) are split in the same time. The processed edges are flagged as + * done (using the user-data flag).One single new vertex is created whereas several split edges * might created for the different kinds of edges. These new elements are added to the lists * maintained by the shape. * New chains are also created. * ioA - * The first vertex for the edge that gets splitted + * The first vertex for the edge that gets split. * ioB - * The second vertex for the edge that gets splitted + * The second vertex for the edge that gets split. * iParameters * A vector containing 2D real vectors indicating the parameters giving the intersections * coordinates in 3D and in 2D. These intersections points must be sorted from B to A. Each diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index 546032c64ac..cb88b1abf92 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -181,9 +181,12 @@ static void deformStroke(GpencilModifierData *md, float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ? noise_table(len, seed) : NULL; float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ? noise_table(len, seed + 4) : NULL; - /* calculate stroke normal*/ + /* Calculate stroke normal. */ if (gps->totpoints > 2) { BKE_gpencil_stroke_normal(gps, normal); + if (is_zero_v3(normal)) { + copy_v3_fl(normal, 1.0f); + } } else { copy_v3_fl(normal, 1.0f); diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 3fb48292000..ab507d852e8 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -50,7 +50,7 @@ void GPU_paint_set_mipmap(struct Main *bmain, bool mipmap); /* Anisotropic filtering settings * - these will free textures on changes */ -void GPU_set_anisotropic(struct Main *bmain, float value); +void GPU_set_anisotropic(float value); float GPU_get_anisotropic(void); /* Image updates and free diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 337c0b03308..eeb2d2caef2 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -29,6 +29,8 @@ #include "BLI_sys_types.h" /* for bool */ +#include "GPU_texture.h" /* for eGPUSamplerState */ + #ifdef __cplusplus extern "C" { #endif @@ -138,8 +140,14 @@ typedef enum eGPUMaterialStatus { GPUNodeLink *GPU_constant(const float *num); GPUNodeLink *GPU_uniform(const float *num); GPUNodeLink *GPU_attribute(GPUMaterial *mat, CustomDataType type, const char *name); -GPUNodeLink *GPU_image(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); -GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); +GPUNodeLink *GPU_image(GPUMaterial *mat, + struct Image *ima, + struct ImageUser *iuser, + eGPUSamplerState sampler_state); +GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, + struct Image *ima, + struct ImageUser *iuser, + eGPUSamplerState sampler_state); GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer); GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, const char *name); @@ -190,6 +198,7 @@ void GPU_materials_free(struct Main *bmain); struct Scene *GPU_material_scene(GPUMaterial *material); struct GPUPass *GPU_material_get_pass(GPUMaterial *material); +struct GPUShader *GPU_material_get_shader(GPUMaterial *material); struct Material *GPU_material_get_material(GPUMaterial *material); eGPUMaterialStatus GPU_material_status(GPUMaterial *mat); @@ -228,6 +237,7 @@ typedef struct GPUMaterialTexture { char sampler_name[32]; /* Name of sampler in GLSL. */ char tiled_mapping_name[32]; /* Name of tile mapping sampler in GLSL. */ int users; + int sampler_state; /* eGPUSamplerState */ } GPUMaterialTexture; typedef struct GPUMaterialVolumeGrid { diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 0e382f2225f..0ad472113c9 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -92,16 +92,18 @@ void *GPU_shader_get_interface(GPUShader *shader); void GPU_shader_set_srgb_uniform(const struct GPUShaderInterface *interface); int GPU_shader_get_uniform(GPUShader *shader, const char *name); -int GPU_shader_get_uniform_ensure(GPUShader *shader, const char *name); int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin); +int GPU_shader_get_builtin_block(GPUShader *shader, int builtin); int GPU_shader_get_uniform_block(GPUShader *shader, const char *name); + +int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name); +int GPU_shader_get_texture_binding(GPUShader *shader, const char *name); + void GPU_shader_uniform_vector( GPUShader *shader, int location, int length, int arraysize, const float *value); void GPU_shader_uniform_vector_int( GPUShader *shader, int location, int length, int arraysize, const int *value); -void GPU_shader_uniform_buffer(GPUShader *shader, int location, struct GPUUniformBuffer *ubo); -void GPU_shader_uniform_texture(GPUShader *shader, int location, struct GPUTexture *tex); void GPU_shader_uniform_float(GPUShader *shader, int location, float value); void GPU_shader_uniform_int(GPUShader *shader, int location, int value); diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h index 3e7bad409a3..28ee162bdbd 100644 --- a/source/blender/gpu/GPU_shader_interface.h +++ b/source/blender/gpu/GPU_shader_interface.h @@ -33,9 +33,7 @@ extern "C" { #endif typedef enum { - GPU_UNIFORM_NONE = 0, /* uninitialized/unknown */ - - GPU_UNIFORM_MODEL, /* mat4 ModelMatrix */ + GPU_UNIFORM_MODEL = 0, /* mat4 ModelMatrix */ GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */ GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */ GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */ @@ -58,49 +56,56 @@ typedef enum { GPU_UNIFORM_RESOURCE_ID, /* int resourceId */ GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */ - GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */ - GPU_NUM_UNIFORMS, /* Special value, denotes number of builtin uniforms. */ } GPUUniformBuiltin; +typedef enum { + GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */ + GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */ + GPU_UNIFORM_BLOCK_INFO, /* infoBlock */ + + GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */ +} GPUUniformBlockBuiltin; + typedef struct GPUShaderInput { - struct GPUShaderInput *next; uint32_t name_offset; - uint name_hash; - /** Only for uniform inputs. */ - GPUUniformBuiltin builtin_type; - /** Only for attribute inputs. */ - uint32_t gl_type; - /** Only for attribute inputs. */ - int32_t size; + uint32_t name_hash; int32_t location; + /** Defined at interface creation or in shader. Only for Samplers, UBOs and Vertex Attribs. */ + int32_t binding; } GPUShaderInput; -#define GPU_NUM_SHADERINTERFACE_BUCKETS 257 #define GPU_SHADERINTERFACE_REF_ALLOC_COUNT 16 typedef struct GPUShaderInterface { - int32_t program; - uint32_t name_buffer_offset; - GPUShaderInput *attr_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]; - GPUShaderInput *uniform_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]; - GPUShaderInput *ubo_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]; - GPUShaderInput *builtin_uniforms[GPU_NUM_UNIFORMS]; + /** Buffer containing all inputs names separated by '\0'. */ char *name_buffer; - struct GPUBatch **batches; /* references to batches using this interface */ + /** Reference to GPUBatches using this interface */ + struct GPUBatch **batches; uint batches_len; - /** All enabled attributes in this shader. Used to set default values for unbound attributes. */ + /** Input counts. */ + uint attribute_len; + uint ubo_len; + uint uniform_len; + /** Enabled bindpoints that needs to be fed with data. */ uint16_t enabled_attr_mask; + uint16_t enabled_ubo_mask; + uint64_t enabled_tex_mask; + /** Opengl Location of builtin uniforms. Fast access, no lookup needed. */ + int32_t builtins[GPU_NUM_UNIFORMS]; + int32_t builtin_blocks[GPU_NUM_UNIFORM_BLOCKS]; + /** Flat array. In this order: Attributes, Ubos, Uniforms. */ + GPUShaderInput inputs[0]; } GPUShaderInterface; GPUShaderInterface *GPU_shaderinterface_create(int32_t program_id); void GPU_shaderinterface_discard(GPUShaderInterface *); const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *, const char *name); -const GPUShaderInput *GPU_shaderinterface_uniform_ensure(const GPUShaderInterface *, - const char *name); -const GPUShaderInput *GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *, - GPUUniformBuiltin); +int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface, + GPUUniformBuiltin builtin); +int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface, + GPUUniformBlockBuiltin builtin); const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *, const char *name); const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *, const char *name); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 3d99a3c8a56..a13f61177e6 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -41,6 +41,31 @@ struct PreviewImage; struct GPUFrameBuffer; typedef struct GPUTexture GPUTexture; +/* GPU Samplers state + * - Specify the sampler state to bind a texture with. + * - Internally used by textures. + * - All states are created at startup to avoid runtime costs. + */ + +typedef enum eGPUSamplerState { + GPU_SAMPLER_FILTER = (1 << 0), + GPU_SAMPLER_MIPMAP = (1 << 1), + GPU_SAMPLER_REPEAT_S = (1 << 2), + GPU_SAMPLER_REPEAT_T = (1 << 3), + GPU_SAMPLER_REPEAT_R = (1 << 4), + GPU_SAMPLER_CLAMP_BORDER = (1 << 5), /* Clamp to border color instead of border texel. */ + GPU_SAMPLER_COMPARE = (1 << 6), + GPU_SAMPLER_ANISO = (1 << 7), + /* Don't use that. */ + GPU_SAMPLER_MAX = (1 << 8), +} eGPUSamplerState; + +#define GPU_SAMPLER_DEFAULT GPU_SAMPLER_FILTER +#define GPU_SAMPLER_REPEAT (GPU_SAMPLER_REPEAT_S | GPU_SAMPLER_REPEAT_T | GPU_SAMPLER_REPEAT_R) + +void GPU_samplers_init(void); +void GPU_samplers_free(void); + /* GPU Texture * - always returns unsigned char RGBA textures * - if texture with non square dimensions is created, depending on the @@ -236,8 +261,9 @@ void GPU_texture_free(GPUTexture *tex); void GPU_texture_ref(GPUTexture *tex); void GPU_texture_bind(GPUTexture *tex, int number); +void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, const bool set_number); void GPU_texture_unbind(GPUTexture *tex); -int GPU_texture_bound_number(GPUTexture *tex); +void GPU_texture_unbind_all(void); void GPU_texture_copy(GPUTexture *dst, GPUTexture *src); diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h index 7adad2ff831..61b14a4c5c0 100644 --- a/source/blender/gpu/GPU_vertex_format.h +++ b/source/blender/gpu/GPU_vertex_format.h @@ -101,12 +101,11 @@ typedef struct GPUVertFormat { char names[GPU_VERT_ATTR_NAMES_BUF_LEN]; } GPUVertFormat; -struct GPUShaderInterface; +struct GPUShader; void GPU_vertformat_clear(GPUVertFormat *); void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src); -void GPU_vertformat_from_interface(GPUVertFormat *format, - const struct GPUShaderInterface *shaderface); +void GPU_vertformat_from_shader(GPUVertFormat *format, const struct GPUShader *shader); uint GPU_vertformat_attr_add( GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode); diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index 3e0a1e57664..5f77f13c135 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -375,7 +375,7 @@ void GPU_batch_program_set_no_use(GPUBatch *batch, const GPUShaderInterface *shaderface) { #if TRUST_NO_ONE - assert(glIsProgram(shaderface->program)); + assert(glIsProgram(program)); assert(batch->program_in_use == 0); #endif batch->interface = shaderface; @@ -551,11 +551,11 @@ void GPU_batch_program_use_end(GPUBatch *batch) #if TRUST_NO_ONE # define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(batch->interface, name); \ + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->interface, name); \ assert(uniform); #else # define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(batch->interface, name); + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->interface, name); #endif void GPU_batch_uniform_1ui(GPUBatch *batch, const char *name, uint value) diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 8a46e24d459..c1e7933d7ba 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -1160,7 +1160,7 @@ static int count_active_texture_sampler(GPUShader *shader, char *source) if (*code != '\0') { char sampler_name[64]; code = gpu_str_skip_token(code, sampler_name, sizeof(sampler_name)); - int id = GPU_shader_get_uniform_ensure(shader, sampler_name); + int id = GPU_shader_get_uniform(shader, sampler_name); if (id == -1) { continue; diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 7871907a7d4..1c346217e9f 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -158,10 +158,10 @@ static GLenum gpu_get_mipmap_filter(bool mag) } /* Anisotropic filtering settings */ -void GPU_set_anisotropic(Main *bmain, float value) +void GPU_set_anisotropic(float value) { if (GTS.anisotropic != value) { - GPU_free_images(bmain); + GPU_samplers_free(); /* Clamp value to the maximum value the graphics card supports */ const float max = GPU_max_texture_anisotropy(); @@ -170,6 +170,8 @@ void GPU_set_anisotropic(Main *bmain, float value) } GTS.anisotropic = value; + + GPU_samplers_init(); } } @@ -449,22 +451,12 @@ static uint gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) BKE_image_release_ibuf(ima, ibuf, NULL); } - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - if (GPU_get_mipmap()) { glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); if (ima) { ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; } } - else { - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - - if (GLEW_EXT_texture_filter_anisotropic) { - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - } glBindTexture(GL_TEXTURE_2D_ARRAY, 0); @@ -1098,18 +1090,12 @@ void GPU_create_gl_tex(uint *bind, GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect); } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - if (GPU_get_mipmap() && mipmap) { glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); if (ima) { ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; } } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } } else if (textarget == GL_TEXTURE_CUBE_MAP) { int w = rectw / 3, h = recth / 2; @@ -1132,22 +1118,13 @@ void GPU_create_gl_tex(uint *bind, } } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - if (GPU_get_mipmap() && mipmap) { glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); if (ima) { ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; } } - else { - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); gpu_del_cube_map(cube_map); } @@ -1156,10 +1133,6 @@ void GPU_create_gl_tex(uint *bind, } } - if (GLEW_EXT_texture_filter_anisotropic) { - glTexParameterf(textarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - } - glBindTexture(textarget, 0); if (ibuf) { @@ -1211,10 +1184,6 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf, bool use_srgb) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - if (GLEW_EXT_texture_filter_anisotropic) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - } - blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16; for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); i++) { if (width == 0) { diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index ff745787630..8dd468b5414 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -304,8 +304,8 @@ void gpu_extensions_init(void) GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary; } - /* Special fix for theses specific GPUs. Without thoses workaround, blender crashes on strartup. - * (see T72098) */ + /* Special fix for theses specific GPUs. + * Without this workaround, blender crashes on startup. (see T72098) */ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && (strstr(renderer, "HD Graphics 620") || strstr(renderer, "HD Graphics 630"))) { GG.mip_render_workaround = true; @@ -355,11 +355,13 @@ void gpu_extensions_init(void) } GPU_invalid_tex_init(); + GPU_samplers_init(); } void gpu_extensions_exit(void) { GPU_invalid_tex_free(); + GPU_samplers_free(); } bool GPU_mem_stats_supported(void) diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c index d95904c0007..9ea273f33cf 100644 --- a/source/blender/gpu/intern/gpu_immediate.c +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -759,13 +759,11 @@ void immVertex2iv(uint attr_id, const int data[2]) #if 0 # if TRUST_NO_ONE # define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \ - name); \ + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); \ assert(uniform); # else # define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \ - name); + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); # endif #else /* NOTE: It is possible to have uniform fully optimized out from the shader. @@ -773,8 +771,7 @@ void immVertex2iv(uint attr_id, const int data[2]) * TODO(sergey): How can we detect existing-but-optimized-out uniform but still * catch typos in uniform names passed to immUniform*() functions? */ # define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \ - name); \ + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); \ if (uniform == NULL) \ return; #endif @@ -812,20 +809,9 @@ void immUniform3fv(const char *name, const float data[3]) /* can increase this limit or move to another file */ #define MAX_UNIFORM_NAME_LEN 60 -void immUniformArray3fv(const char *bare_name, const float *data, int count) +/* Note array index is not supported for name (i.e: "array[0]"). */ +void immUniformArray3fv(const char *name, const float *data, int count) { - /* look up "name[0]" when given "name" */ - const size_t len = strlen(bare_name); -#if TRUST_NO_ONE - assert(len <= MAX_UNIFORM_NAME_LEN); -#endif - char name[MAX_UNIFORM_NAME_LEN]; - strcpy(name, bare_name); - name[len + 0] = '['; - name[len + 1] = '0'; - name[len + 2] = ']'; - name[len + 3] = '\0'; - GET_UNIFORM glUniform3fv(uniform->location, count, data); } @@ -842,20 +828,9 @@ void immUniform4fv(const char *name, const float data[4]) glUniform4fv(uniform->location, 1, data); } -void immUniformArray4fv(const char *bare_name, const float *data, int count) +/* Note array index is not supported for name (i.e: "array[0]"). */ +void immUniformArray4fv(const char *name, const float *data, int count) { - /* look up "name[0]" when given "name" */ - const size_t len = strlen(bare_name); -#if TRUST_NO_ONE - assert(len <= MAX_UNIFORM_NAME_LEN); -#endif - char name[MAX_UNIFORM_NAME_LEN]; - strcpy(name, bare_name); - name[len + 0] = '['; - name[len + 1] = '0'; - name[len + 2] = ']'; - name[len + 3] = '\0'; - GET_UNIFORM glUniform4fv(uniform->location, count, data); } @@ -882,12 +857,10 @@ void immUniform4iv(const char *name, const int data[4]) void immUniformColor4f(float r, float g, float b, float a) { - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(imm.shader_interface, - GPU_UNIFORM_COLOR); -#if TRUST_NO_ONE - assert(uniform != NULL); -#endif - glUniform4f(uniform->location, r, g, b, a); + int32_t uniform_loc = GPU_shaderinterface_uniform_builtin(imm.shader_interface, + GPU_UNIFORM_COLOR); + BLI_assert(uniform_loc != -1); + glUniform4f(uniform_loc, r, g, b, a); } void immUniformColor4fv(const float rgba[4]) diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 97e4c880644..d2384b9c065 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -209,6 +209,11 @@ GPUPass *GPU_material_get_pass(GPUMaterial *material) return material->pass; } +GPUShader *GPU_material_get_shader(GPUMaterial *material) +{ + return material->pass ? GPU_pass_shader_get(material->pass) : NULL; +} + /* Return can be NULL if it's a world material. */ Material *GPU_material_get_material(GPUMaterial *material) { @@ -662,6 +667,9 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, /* Caller must re-use materials. */ BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL); + /* HACK: Eevee assume this to create Ghash keys. */ + BLI_assert(sizeof(GPUPass) > 16); + /* allocate material */ GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); mat->ma = ma; diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c index 8260e1496ff..2687f56ad27 100644 --- a/source/blender/gpu/intern/gpu_matrix.c +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -654,63 +654,59 @@ void GPU_matrix_bind(const GPUShaderInterface *shaderface) * call glUseProgram before this, as glUniform expects program to be bound */ - const GPUShaderInput *MV = GPU_shaderinterface_uniform_builtin(shaderface, - GPU_UNIFORM_MODELVIEW); - const GPUShaderInput *P = GPU_shaderinterface_uniform_builtin(shaderface, - GPU_UNIFORM_PROJECTION); - const GPUShaderInput *MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP); - - const GPUShaderInput *N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL); - const GPUShaderInput *MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, - GPU_UNIFORM_MODELVIEW_INV); - const GPUShaderInput *P_inv = GPU_shaderinterface_uniform_builtin(shaderface, - GPU_UNIFORM_PROJECTION_INV); - - if (MV) { + int32_t MV = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW); + int32_t P = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION); + int32_t MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP); + + int32_t N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL); + int32_t MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW_INV); + int32_t P_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION_INV); + + if (MV != -1) { #if DEBUG_MATRIX_BIND puts("setting MV matrix"); #endif - glUniformMatrix4fv(MV->location, 1, GL_FALSE, (const float *)GPU_matrix_model_view_get(NULL)); + glUniformMatrix4fv(MV, 1, GL_FALSE, (const float *)GPU_matrix_model_view_get(NULL)); } - if (P) { + if (P != -1) { #if DEBUG_MATRIX_BIND puts("setting P matrix"); #endif - glUniformMatrix4fv(P->location, 1, GL_FALSE, (const float *)GPU_matrix_projection_get(NULL)); + glUniformMatrix4fv(P, 1, GL_FALSE, (const float *)GPU_matrix_projection_get(NULL)); } - if (MVP) { + if (MVP != -1) { #if DEBUG_MATRIX_BIND puts("setting MVP matrix"); #endif glUniformMatrix4fv( - MVP->location, 1, GL_FALSE, (const float *)GPU_matrix_model_view_projection_get(NULL)); + MVP, 1, GL_FALSE, (const float *)GPU_matrix_model_view_projection_get(NULL)); } - if (N) { + if (N != -1) { #if DEBUG_MATRIX_BIND puts("setting normal matrix"); #endif - glUniformMatrix3fv(N->location, 1, GL_FALSE, (const float *)GPU_matrix_normal_get(NULL)); + glUniformMatrix3fv(N, 1, GL_FALSE, (const float *)GPU_matrix_normal_get(NULL)); } - if (MV_inv) { + if (MV_inv != -1) { Mat4 m; GPU_matrix_model_view_get(m); invert_m4(m); - glUniformMatrix4fv(MV_inv->location, 1, GL_FALSE, (const float *)m); + glUniformMatrix4fv(MV_inv, 1, GL_FALSE, (const float *)m); } - if (P_inv) { + if (P_inv != -1) { Mat4 m; GPU_matrix_projection_get(m); invert_m4(m); - glUniformMatrix4fv(P_inv->location, 1, GL_FALSE, (const float *)m); + glUniformMatrix4fv(P_inv, 1, GL_FALSE, (const float *)m); } gpu_matrix_state_active_set_dirty(false); diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 876a6bef670..17d97dc05e2 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -34,6 +34,8 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "GPU_texture.h" + #include "gpu_material_library.h" #include "gpu_node_graph.h" @@ -298,13 +300,14 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, Image *ima, ImageUser *iuser, struct GPUTexture **colorband, - GPUNodeLinkType link_type) + GPUNodeLinkType link_type, + eGPUSamplerState sampler_state) { /* Find existing texture. */ int num_textures = 0; GPUMaterialTexture *tex = graph->textures.first; for (; tex; tex = tex->next) { - if (tex->ima == ima && tex->colorband == colorband) { + if (tex->ima == ima && tex->colorband == colorband && tex->sampler_state == sampler_state) { break; } num_textures++; @@ -316,6 +319,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, tex->ima = ima; tex->iuser = iuser; tex->colorband = colorband; + tex->sampler_state = sampler_state; BLI_snprintf(tex->sampler_name, sizeof(tex->sampler_name), "samp%d", num_textures); if (ELEM(link_type, GPU_NODE_LINK_IMAGE_TILED, GPU_NODE_LINK_IMAGE_TILED_MAPPING)) { BLI_snprintf( @@ -389,21 +393,29 @@ GPUNodeLink *GPU_uniform(const float *num) return link; } -GPUNodeLink *GPU_image(GPUMaterial *mat, Image *ima, ImageUser *iuser) +GPUNodeLink *GPU_image(GPUMaterial *mat, + Image *ima, + ImageUser *iuser, + eGPUSamplerState sampler_state) { GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE; - link->texture = gpu_node_graph_add_texture(graph, ima, iuser, NULL, link->link_type); + link->texture = gpu_node_graph_add_texture( + graph, ima, iuser, NULL, link->link_type, sampler_state); return link; } -GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, Image *ima, ImageUser *iuser) +GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, + Image *ima, + ImageUser *iuser, + eGPUSamplerState sampler_state) { GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE_TILED; - link->texture = gpu_node_graph_add_texture(graph, ima, iuser, NULL, link->link_type); + link->texture = gpu_node_graph_add_texture( + graph, ima, iuser, NULL, link->link_type, sampler_state); return link; } @@ -412,7 +424,8 @@ GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, Image *ima, ImageUser *iu GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE_TILED_MAPPING; - link->texture = gpu_node_graph_add_texture(graph, ima, iuser, NULL, link->link_type); + link->texture = gpu_node_graph_add_texture( + graph, ima, iuser, NULL, link->link_type, GPU_SAMPLER_MAX); return link; } @@ -424,7 +437,8 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_COLORBAND; - link->texture = gpu_node_graph_add_texture(graph, NULL, NULL, colorband, link->link_type); + link->texture = gpu_node_graph_add_texture( + graph, NULL, NULL, colorband, link->link_type, GPU_SAMPLER_MAX); return link; } diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 8dfc992ae9f..8c03567b95f 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -331,6 +331,8 @@ GPUShader *GPU_shader_load_from_binary(const char *binary, glGetProgramiv(program, GL_LINK_STATUS, &success); if (success) { + glUseProgram(program); + GPUShader *shader = MEM_callocN(sizeof(*shader), __func__); shader->interface = GPU_shaderinterface_create(program); shader->program = program; @@ -572,6 +574,7 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, return NULL; } + glUseProgram(shader->program); shader->interface = GPU_shaderinterface_create(shader->program); return shader; @@ -726,21 +729,19 @@ int GPU_shader_get_uniform(GPUShader *shader, const char *name) { BLI_assert(shader && shader->program); const GPUShaderInput *uniform = GPU_shaderinterface_uniform(shader->interface, name); - return uniform ? uniform->location : -2; + return uniform ? uniform->location : -1; } -int GPU_shader_get_uniform_ensure(GPUShader *shader, const char *name) +int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin) { BLI_assert(shader && shader->program); - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(shader->interface, name); - return uniform ? uniform->location : -1; + return GPU_shaderinterface_uniform_builtin(shader->interface, builtin); } -int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin) +int GPU_shader_get_builtin_block(GPUShader *shader, int builtin) { BLI_assert(shader && shader->program); - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(shader->interface, builtin); - return uniform ? uniform->location : -1; + return GPU_shaderinterface_block_builtin(shader->interface, builtin); } int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) @@ -750,6 +751,20 @@ int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) return ubo ? ubo->location : -1; } +int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name) +{ + BLI_assert(shader && shader->program); + const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name); + return ubo ? ubo->binding : -1; +} + +int GPU_shader_get_texture_binding(GPUShader *shader, const char *name) +{ + BLI_assert(shader && shader->program); + const GPUShaderInput *tex = GPU_shaderinterface_uniform(shader->interface, name); + return tex ? tex->binding : -1; +} + void *GPU_shader_get_interface(GPUShader *shader) { return shader->interface; @@ -837,40 +852,11 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) glUniform1i(location, value); } -void GPU_shader_uniform_buffer(GPUShader *shader, int location, GPUUniformBuffer *ubo) -{ - int bindpoint = GPU_uniformbuffer_bindpoint(ubo); - - if (location == -1) { - return; - } - - glUniformBlockBinding(shader->program, location, bindpoint); -} - -void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) -{ - int number = GPU_texture_bound_number(tex); - - if (number == -1) { - fprintf(stderr, "Texture is not bound.\n"); - BLI_assert(0); - return; - } - - if (location == -1) { - return; - } - - glUniform1i(location, number); -} - void GPU_shader_set_srgb_uniform(const GPUShaderInterface *interface) { - const GPUShaderInput *srgb_uniform = GPU_shaderinterface_uniform_builtin( - interface, GPU_UNIFORM_SRGB_TRANSFORM); - if (srgb_uniform) { - glUniform1i(srgb_uniform->location, g_shader_builtin_srgb_transform); + int32_t loc = GPU_shaderinterface_uniform_builtin(interface, GPU_UNIFORM_SRGB_TRANSFORM); + if (loc != -1) { + glUniform1i(loc, g_shader_builtin_srgb_transform); } } diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c index 3218d12bc0d..9d9f98c6bb0 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.c +++ b/source/blender/gpu/intern/gpu_shader_interface.c @@ -24,6 +24,10 @@ */ #include "BKE_global.h" + +#include "BLI_bitmap.h" +#include "BLI_math_base.h" + #include "MEM_guardedalloc.h" #include "GPU_shader_interface.h" @@ -36,7 +40,6 @@ #include <string.h> #define DEBUG_SHADER_INTERFACE 0 -#define DEBUG_SHADER_UNIFORMS 0 #if DEBUG_SHADER_INTERFACE # include <stdio.h> @@ -45,8 +48,6 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u) { static const char *names[] = { - [GPU_UNIFORM_NONE] = NULL, - [GPU_UNIFORM_MODEL] = "ModelMatrix", [GPU_UNIFORM_VIEW] = "ViewMatrix", [GPU_UNIFORM_MODELVIEW] = "ModelViewMatrix", @@ -70,13 +71,25 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u) [GPU_UNIFORM_RESOURCE_ID] = "resourceId", [GPU_UNIFORM_SRGB_TRANSFORM] = "srgbTarget", - [GPU_UNIFORM_CUSTOM] = NULL, [GPU_NUM_UNIFORMS] = NULL, }; return names[u]; } +static const char *BuiltinUniformBlock_name(GPUUniformBlockBuiltin u) +{ + static const char *names[] = { + [GPU_UNIFORM_BLOCK_VIEW] = "viewBlock", + [GPU_UNIFORM_BLOCK_MODEL] = "modelBlock", + [GPU_UNIFORM_BLOCK_INFO] = "infoBlock", + + [GPU_NUM_UNIFORM_BLOCKS] = NULL, + }; + + return names[u]; +} + GPU_INLINE bool match(const char *a, const char *b) { return strcmp(a, b) == 0; @@ -91,129 +104,136 @@ GPU_INLINE uint hash_string(const char *str) return i; } -GPU_INLINE void set_input_name(GPUShaderInterface *shaderface, - GPUShaderInput *input, - const char *name, - uint32_t name_len) +GPU_INLINE uint32_t set_input_name(GPUShaderInterface *shaderface, + GPUShaderInput *input, + char *name, + uint32_t name_len) { - input->name_offset = shaderface->name_buffer_offset; - input->name_hash = hash_string(name); - shaderface->name_buffer_offset += name_len + 1; /* include NULL terminator */ -} + /* remove "[0]" from array name */ + if (name[name_len - 1] == ']') { + name[name_len - 3] = '\0'; + name_len -= 3; + } -GPU_INLINE void shader_input_to_bucket(GPUShaderInput *input, - GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]) -{ - const uint bucket_index = input->name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS; - input->next = buckets[bucket_index]; - buckets[bucket_index] = input; + input->name_offset = (uint32_t)(name - shaderface->name_buffer); + input->name_hash = hash_string(name); + return name_len + 1; /* include NULL terminator */ } -GPU_INLINE const GPUShaderInput *buckets_lookup( - GPUShaderInput *const buckets[GPU_NUM_SHADERINTERFACE_BUCKETS], - const char *name_buffer, - const char *name) +GPU_INLINE const GPUShaderInput *input_lookup(const GPUShaderInterface *shaderface, + const GPUShaderInput *const inputs, + const uint inputs_len, + const char *name) { const uint name_hash = hash_string(name); - const uint bucket_index = name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS; - const GPUShaderInput *input = buckets[bucket_index]; - if (input == NULL) { - /* Requested uniform is not found at all. */ - return NULL; - } - /* Optimization bit: if there is no hash collision detected when constructing shader interface - * it means we can only request the single possible uniform. Surely, it's possible we request - * uniform which causes hash collision, but that will be detected in debug builds. */ - if (input->next == NULL) { - if (name_hash == input->name_hash) { -#if TRUST_NO_ONE - assert(match(name_buffer + input->name_offset, name)); -#endif - return input; - } - return NULL; - } - /* Work through possible collisions. */ - const GPUShaderInput *next = input; - while (next != NULL) { - input = next; - next = input->next; - if (input->name_hash != name_hash) { - continue; - } - if (match(name_buffer + input->name_offset, name)) { - return input; + /* Simple linear search for now. */ + for (int i = inputs_len - 1; i >= 0; i--) { + if (inputs[i].name_hash == name_hash) { + if ((i > 0) && UNLIKELY(inputs[i - 1].name_hash == name_hash)) { + /* Hash colision resolve. */ + for (; i >= 0 && inputs[i].name_hash == name_hash; i--) { + if (match(name, shaderface->name_buffer + inputs[i].name_offset)) { + return inputs + i; /* not found */ + } + } + return NULL; /* not found */ + } + else { + /* This is a bit dangerous since we could have a hash collision. + * where the asked uniform that does not exist has the same hash + * as a real uniform. */ + BLI_assert(match(name, shaderface->name_buffer + inputs[i].name_offset)); + return inputs + i; + } } } return NULL; /* not found */ } -GPU_INLINE void buckets_free(GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]) +/* Note that this modify the src array. */ +GPU_INLINE void sort_input_list(GPUShaderInput *dst, GPUShaderInput *src, const uint input_len) { - for (uint bucket_index = 0; bucket_index < GPU_NUM_SHADERINTERFACE_BUCKETS; bucket_index++) { - GPUShaderInput *input = buckets[bucket_index]; - while (input != NULL) { - GPUShaderInput *input_next = input->next; - MEM_freeN(input); - input = input_next; + for (uint i = 0; i < input_len; i++) { + GPUShaderInput *input_src = &src[0]; + for (uint j = 1; j < input_len; j++) { + if (src[j].name_hash > input_src->name_hash) { + input_src = &src[j]; + } } + dst[i] = *input_src; + input_src->name_hash = 0; } } -static bool setup_builtin_uniform(GPUShaderInput *input, const char *name) +static int block_binding(int32_t program, uint32_t block_index) { - /* TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types */ - - /* detect built-in uniforms (name must match) */ - for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; u++) { - const char *builtin_name = BuiltinUniform_name(u); - if (match(name, builtin_name)) { - input->builtin_type = u; - return true; - } - } - input->builtin_type = GPU_UNIFORM_CUSTOM; - return false; + /* For now just assign a consecutive index. In the future, we should set it in + * the shader using layout(binding = i) and query its value. */ + glUniformBlockBinding(program, block_index, block_index); + return block_index; } -static const GPUShaderInput *add_uniform(GPUShaderInterface *shaderface, const char *name) +static int sampler_binding(int32_t program, + uint32_t uniform_index, + int32_t uniform_location, + int *sampler_len) { - GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Unif"); - - input->location = glGetUniformLocation(shaderface->program, name); - - const uint name_len = strlen(name); - /* Include NULL terminator. */ - shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer, - shaderface->name_buffer_offset + name_len + 1); - char *name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset; - strcpy(name_buffer, name); - - set_input_name(shaderface, input, name, name_len); - setup_builtin_uniform(input, name); - - shader_input_to_bucket(input, shaderface->uniform_buckets); - if (input->builtin_type != GPU_UNIFORM_NONE && input->builtin_type != GPU_UNIFORM_CUSTOM) { - shaderface->builtin_uniforms[input->builtin_type] = input; + /* Identify sampler uniforms and asign sampler units to them. */ + GLint type; + glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type); + + switch (type) { + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: /* OpenGL 4.0 */ + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_1D_ARRAY: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_1D_ARRAY_SHADOW: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_BUFFER: + case GL_INT_SAMPLER_1D: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_1D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_INT_SAMPLER_BUFFER: + case GL_UNSIGNED_INT_SAMPLER_1D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_BUFFER: { + /* For now just assign a consecutive index. In the future, we should set it in + * the shader using layout(binding = i) and query its value. */ + int binding = *sampler_len; + glUniform1i(uniform_location, binding); + (*sampler_len)++; + return binding; + } + default: + return -1; } -#if DEBUG_SHADER_INTERFACE - printf("GPUShaderInterface %p, program %d, uniform[] '%s' at location %d\n", - shaderface, - shaderface->program, - name, - input->location); -#endif - return input; } GPUShaderInterface *GPU_shaderinterface_create(int32_t program) { - GPUShaderInterface *shaderface = MEM_callocN(sizeof(GPUShaderInterface), "GPUShaderInterface"); - shaderface->program = program; - -#if DEBUG_SHADER_INTERFACE - printf("%s {\n", __func__); /* enter function */ - printf("GPUShaderInterface %p, program %d\n", shaderface, program); +#ifndef NDEBUG + GLint curr_program; + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_program); + BLI_assert(curr_program == program); #endif GLint max_attr_name_len = 0, attr_len = 0; @@ -224,6 +244,11 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program) glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len); glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len); + GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len); + glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len); + uniform_len = active_uniform_len; + /* Work around driver bug with Intel HD 4600 on Windows 7/8, where * GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */ if (attr_len > 0 && max_attr_name_len == 0) { @@ -232,87 +257,190 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program) if (ubo_len > 0 && max_ubo_name_len == 0) { max_ubo_name_len = 256; } + if (uniform_len > 0 && max_uniform_name_len == 0) { + max_uniform_name_len = 256; + } + + /* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before + * allocating the uniform array. */ + GLint max_ubo_uni_len = 0; + for (int i = 0; i < ubo_len; i++) { + GLint ubo_uni_len; + glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len); + max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len); + uniform_len -= ubo_uni_len; + } + /* Bit set to true if uniform comes from a uniform block. */ + BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__); + /* Set uniforms from block for exclusion. */ + GLint *ubo_uni_ids = MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__); + for (int i = 0; i < ubo_len; i++) { + GLint ubo_uni_len; + glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len); + glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids); + for (int u = 0; u < ubo_uni_len; u++) { + BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]); + } + } + MEM_freeN(ubo_uni_ids); - const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len; + uint32_t name_buffer_offset = 0; + const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len + + uniform_len * max_uniform_name_len; + + int input_tot_len = attr_len + ubo_len + uniform_len; + size_t interface_size = sizeof(GPUShaderInterface) + sizeof(GPUShaderInput) * input_tot_len; + + GPUShaderInterface *shaderface = MEM_callocN(interface_size, "GPUShaderInterface"); + shaderface->attribute_len = attr_len; + shaderface->ubo_len = ubo_len; + shaderface->uniform_len = uniform_len; shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer"); + GPUShaderInput *inputs = shaderface->inputs; + + /* Temp buffer. */ + int input_tmp_len = max_iii(attr_len, ubo_len, uniform_len); + GPUShaderInput *inputs_tmp = MEM_mallocN(sizeof(GPUShaderInput) * input_tmp_len, "name_buffer"); /* Attributes */ shaderface->enabled_attr_mask = 0; - for (uint32_t i = 0; i < attr_len; i++) { - GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Attr"); - GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; - char *name = shaderface->name_buffer + shaderface->name_buffer_offset; + for (int i = 0, idx = 0; i < attr_len; i++) { + char *name = shaderface->name_buffer + name_buffer_offset; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; GLsizei name_len = 0; + GLenum type; + GLint size; - glGetActiveAttrib( - program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name); - - /* remove "[0]" from array name */ - if (name[name_len - 1] == ']') { - name[name_len - 3] = '\0'; - name_len -= 3; - } - - /* TODO: reject DOUBLE gl_types */ - input->location = glGetAttribLocation(program, name); + glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name); + GLint location = glGetAttribLocation(program, name); /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */ - if (input->location == -1) { - MEM_freeN(input); + if (location == -1) { + shaderface->attribute_len--; continue; } - if (input->location != -1) { - shaderface->enabled_attr_mask |= (1 << input->location); - } - - set_input_name(shaderface, input, name, name_len); - - shader_input_to_bucket(input, shaderface->attr_buckets); + GPUShaderInput *input = &inputs_tmp[idx++]; + input->location = input->binding = location; -#if DEBUG_SHADER_INTERFACE - printf("attr[%u] '%s' at location %d\n", i, name, input->location); -#endif + name_buffer_offset += set_input_name(shaderface, input, name, name_len); + shaderface->enabled_attr_mask |= (1 << input->location); } + sort_input_list(inputs, inputs_tmp, shaderface->attribute_len); + inputs += shaderface->attribute_len; + /* Uniform Blocks */ - for (uint32_t i = 0; i < ubo_len; i++) { - GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput UBO"); - GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; - char *name = shaderface->name_buffer + shaderface->name_buffer_offset; + for (int i = 0, idx = 0; i < ubo_len; i++) { + char *name = shaderface->name_buffer + name_buffer_offset; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; GLsizei name_len = 0; glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name); - input->location = i; + GPUShaderInput *input = &inputs_tmp[idx++]; + input->binding = input->location = block_binding(program, i); - set_input_name(shaderface, input, name, name_len); + name_buffer_offset += set_input_name(shaderface, input, name, name_len); + shaderface->enabled_ubo_mask |= (1 << input->binding); + } + sort_input_list(inputs, inputs_tmp, shaderface->ubo_len); + inputs += shaderface->ubo_len; - shader_input_to_bucket(input, shaderface->ubo_buckets); + /* Uniforms */ + for (int i = 0, idx = 0, sampler = 0; i < active_uniform_len; i++) { + if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) { + continue; + } + char *name = shaderface->name_buffer + name_buffer_offset; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + GLsizei name_len = 0; -#if DEBUG_SHADER_INTERFACE - printf("ubo '%s' at location %d\n", name, input->location); -#endif + glGetActiveUniformName(program, i, remaining_buffer, &name_len, name); + + GPUShaderInput *input = &inputs_tmp[idx++]; + input->location = glGetUniformLocation(program, name); + input->binding = sampler_binding(program, i, input->location, &sampler); + + name_buffer_offset += set_input_name(shaderface, input, name, name_len); + shaderface->enabled_tex_mask |= (input->binding != -1) ? (1lu << input->binding) : 0lu; } + sort_input_list(inputs, inputs_tmp, shaderface->uniform_len); + /* Builtin Uniforms */ - for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; u++) { - const char *builtin_name = BuiltinUniform_name(u); - if (glGetUniformLocation(program, builtin_name) != -1) { - add_uniform((GPUShaderInterface *)shaderface, builtin_name); - } + for (GPUUniformBuiltin u = 0; u < GPU_NUM_UNIFORMS; u++) { + shaderface->builtins[u] = glGetUniformLocation(program, BuiltinUniform_name(u)); } + + /* Builtin Uniforms Blocks */ + for (GPUUniformBlockBuiltin u = 0; u < GPU_NUM_UNIFORM_BLOCKS; u++) { + const GPUShaderInput *block = GPU_shaderinterface_ubo(shaderface, BuiltinUniformBlock_name(u)); + shaderface->builtin_blocks[u] = (block != NULL) ? block->binding : -1; + } + /* Batches ref buffer */ shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT; shaderface->batches = MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *), "GPUShaderInterface batches"); + MEM_freeN(uniforms_from_blocks); + MEM_freeN(inputs_tmp); + + /* Resize name buffer to save some memory. */ + if (name_buffer_offset < name_buffer_len) { + shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer, name_buffer_offset); + } + +#if DEBUG_SHADER_INTERFACE + char *name_buf = shaderface->name_buffer; + printf("--- GPUShaderInterface %p, program %d ---\n", shaderface, program); + if (shaderface->attribute_len > 0) { + printf("Attributes {\n"); + for (int i = 0; i < shaderface->attribute_len; i++) { + GPUShaderInput *input = shaderface->inputs + i; + printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset); + } + printf("};\n"); + } + if (shaderface->ubo_len > 0) { + printf("Uniform Buffer Objects {\n"); + for (int i = 0; i < shaderface->ubo_len; i++) { + GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + i; + printf("\t(binding = %d) %s;\n", input->binding, name_buf + input->name_offset); + } + printf("};\n"); + } + if (shaderface->enabled_tex_mask > 0) { + printf("Samplers {\n"); + for (int i = 0; i < shaderface->uniform_len; i++) { + GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + + shaderface->ubo_len + i; + if (input->binding != -1) { + printf("\t(location = %d, binding = %d) %s;\n", + input->location, + input->binding, + name_buf + input->name_offset); + } + } + printf("};\n"); + } + if (shaderface->uniform_len > 0) { + printf("Uniforms {\n"); + for (int i = 0; i < shaderface->uniform_len; i++) { + GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + + shaderface->ubo_len + i; + if (input->binding == -1) { + printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset); + } + } + printf("};\n"); + } + printf("--- GPUShaderInterface end ---\n\n"); +#endif + return shaderface; } void GPU_shaderinterface_discard(GPUShaderInterface *shaderface) { - /* Free memory used by buckets and has entries. */ - buckets_free(shaderface->uniform_buckets); - buckets_free(shaderface->attr_buckets); - buckets_free(shaderface->ubo_buckets); /* Free memory used by name_buffer. */ MEM_freeN(shaderface->name_buffer); /* Remove this interface from all linked Batches vao cache. */ @@ -326,59 +454,39 @@ void GPU_shaderinterface_discard(GPUShaderInterface *shaderface) MEM_freeN(shaderface); } -const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface, - const char *name) +const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface, + const char *name) { - return buckets_lookup(shaderface->uniform_buckets, shaderface->name_buffer, name); + uint ofs = 0; + return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->attribute_len, name); } -const GPUShaderInput *GPU_shaderinterface_uniform_ensure(const GPUShaderInterface *shaderface, - const char *name) +const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface, + const char *name) { - const GPUShaderInput *input = GPU_shaderinterface_uniform(shaderface, name); - /* If input is not found add it so it's found next time. */ - if (input == NULL) { - input = add_uniform((GPUShaderInterface *)shaderface, name); - - if ((G.debug & G_DEBUG_GPU) && (input->location == -1)) { - fprintf(stderr, "GPUShaderInterface: Warning: Uniform '%s' not found!\n", name); - } - } - -#if DEBUG_SHADER_UNIFORMS - if ((G.debug & G_DEBUG_GPU) && input->builtin_type != GPU_UNIFORM_NONE && - input->builtin_type != GPU_UNIFORM_CUSTOM) { - /* Warn if we find a matching builtin, since these can be looked up much quicker. */ - fprintf(stderr, - "GPUShaderInterface: Warning: Uniform '%s' is a builtin uniform but not queried as " - "such!\n", - name); - } -#endif - return (input->location != -1) ? input : NULL; + uint ofs = shaderface->attribute_len; + return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->ubo_len, name); } -const GPUShaderInput *GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface, - GPUUniformBuiltin builtin) +const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface, + const char *name) { -#if TRUST_NO_ONE - assert(builtin != GPU_UNIFORM_NONE); - assert(builtin != GPU_UNIFORM_CUSTOM); - assert(builtin != GPU_NUM_UNIFORMS); -#endif - return shaderface->builtin_uniforms[builtin]; + uint ofs = shaderface->attribute_len + shaderface->ubo_len; + return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->uniform_len, name); } -const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface, - const char *name) +int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface, + GPUUniformBuiltin builtin) { - return buckets_lookup(shaderface->ubo_buckets, shaderface->name_buffer, name); + BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORMS); + return shaderface->builtins[builtin]; } -const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface, - const char *name) +int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface, + GPUUniformBlockBuiltin builtin) { - return buckets_lookup(shaderface->attr_buckets, shaderface->name_buffer, name); + BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORM_BLOCKS); + return shaderface->builtin_blocks[builtin]; } void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch) diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index fd01ddf8597..ca0d633aa9e 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -50,7 +50,9 @@ static struct GPUTextureGlobal { GPUTexture *invalid_tex_1D; GPUTexture *invalid_tex_2D; GPUTexture *invalid_tex_3D; -} GG = {NULL, NULL, NULL}; + /** Sampler objects used to replace internal texture parameters. */ + GLuint samplers[GPU_SAMPLER_MAX]; +} GG = {NULL}; /* Maximum number of FBOs a texture can be attached to. */ #define GPU_TEX_MAX_FBO_ATTACHED 12 @@ -72,7 +74,7 @@ typedef enum eGPUTextureFormatFlag { struct GPUTexture { int w, h, d; /* width/height/depth */ int orig_w, orig_h; /* width/height (of source data), optional. */ - int number; /* number for multitexture binding */ + int number; /* Texture unit to which this texture is bound. */ int refcount; /* reference count */ GLenum target; /* GL_TEXTURE_* */ GLenum target_base; /* same as target, (but no multisample) @@ -81,6 +83,7 @@ struct GPUTexture { eGPUTextureFormat format; eGPUTextureFormatFlag format_flag; + eGPUSamplerState sampler_state; /* Internal Sampler state. */ int mipmaps; /* number of mipmaps */ int components; /* number of color/alpha channels */ @@ -94,6 +97,7 @@ struct GPUTexture { }; static uint gpu_get_bytesize(eGPUTextureFormat data_type); +static void gpu_texture_framebuffer_ensure(GPUTexture *tex); /* ------ Memory Management ------- */ /* Records every texture allocation / free @@ -826,12 +830,12 @@ GPUTexture *GPU_texture_create_nD(int w, tex->h = h; tex->d = d; tex->samples = samples; - tex->number = -1; tex->refcount = 1; tex->format = tex_format; tex->components = gpu_get_component_count(tex_format); tex->mipmaps = 0; tex->format_flag = 0; + tex->number = -1; if (n == 2) { if (d == 0) { @@ -975,26 +979,13 @@ GPUTexture *GPU_texture_create_nD(int w, if (GPU_texture_stencil(tex) || /* Does not support filtering */ GPU_texture_integer(tex) || /* Does not support filtering */ GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + tex->sampler_state = GPU_SAMPLER_DEFAULT & ~GPU_SAMPLER_FILTER; } else { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - } - - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - if (n > 1) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - if (n > 2) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + tex->sampler_state = GPU_SAMPLER_DEFAULT; } + /* Avoid issue with incomplete textures. */ + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(tex->target, 0); @@ -1013,12 +1004,12 @@ GPUTexture *GPU_texture_cube_create(int w, tex->h = w; tex->d = d; tex->samples = 0; - tex->number = -1; tex->refcount = 1; tex->format = tex_format; tex->components = gpu_get_component_count(tex_format); tex->mipmaps = 0; tex->format_flag = GPU_FORMAT_CUBE; + tex->number = -1; if (d == 0) { tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; @@ -1116,22 +1107,13 @@ GPUTexture *GPU_texture_cube_create(int w, if (GPU_texture_stencil(tex) || /* Does not support filtering */ GPU_texture_integer(tex) || /* Does not support filtering */ GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + tex->sampler_state = GPU_SAMPLER_DEFAULT & ~GPU_SAMPLER_FILTER; } else { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + tex->sampler_state = GPU_SAMPLER_DEFAULT; } - - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + /* Avoid issue with incomplete textures. */ + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(tex->target, 0); @@ -1142,13 +1124,13 @@ GPUTexture *GPU_texture_cube_create(int w, GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint buffer) { GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->number = -1; tex->refcount = 1; tex->format = tex_format; tex->components = gpu_get_component_count(tex_format); tex->format_flag = 0; tex->target_base = tex->target = GL_TEXTURE_BUFFER; tex->mipmaps = 0; + tex->number = -1; GLenum internalformat = gpu_format_to_gl_internalformat(tex_format); @@ -1195,11 +1177,15 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode) { GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->bindcode = bindcode; - tex->number = -1; tex->refcount = 1; tex->target = textarget; tex->target_base = textarget; tex->samples = 0; + tex->sampler_state = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO; + if (GPU_get_mipmap()) { + tex->sampler_state |= (GPU_SAMPLER_MIPMAP | GPU_SAMPLER_FILTER); + } + tex->number = -1; if (!glIsTexture(tex->bindcode)) { GPU_print_error_debug("Blender Texture Not Loaded"); @@ -1570,25 +1556,117 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat gpu_data_format, const void *color) { - if (GLEW_ARB_clear_texture) { - GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag); + BLI_assert(color != NULL); /* Do not accept NULL as parameter. */ + gpu_validate_data_format(tex->format, gpu_data_format); + + if (false && GLEW_ARB_clear_texture) { GLenum data_type = gpu_get_gl_datatype(gpu_data_format); + GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag); glClearTexImage(tex->bindcode, 0, data_format, data_type, color); + + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) { + /* TODO(clem) implement in fallback. */ + BLI_assert(0); + } + else if (GPU_texture_depth(tex)) { + switch (gpu_data_format) { + case GPU_DATA_FLOAT: + case GPU_DATA_UNSIGNED_INT: + break; + default: + /* TODO(clem) implement in fallback. */ + BLI_assert(0); + break; + } + } + else { + switch (gpu_data_format) { + case GPU_DATA_FLOAT: + case GPU_DATA_UNSIGNED_INT: + case GPU_DATA_UNSIGNED_BYTE: + break; + default: + /* TODO(clem) implement in fallback. */ + BLI_assert(0); + break; + } + } } else { - size_t buffer_len = gpu_texture_memory_footprint_compute(tex); - unsigned char *pixels = MEM_mallocN(buffer_len, __func__); - if (color) { - const size_t bytesize = (size_t)gpu_get_bytesize(tex->format); - for (size_t byte = 0; byte < buffer_len; byte += bytesize) { - memcpy(&pixels[byte], color, bytesize); + /* Fallback for older GL. */ + GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get(); + + gpu_texture_framebuffer_ensure(tex); + /* This means that this function can only be used in one context for each texture. */ + BLI_assert(tex->copy_fb_ctx == GPU_context_active_get()); + + glBindFramebuffer(GL_FRAMEBUFFER, tex->copy_fb); + glViewport(0, 0, tex->w, tex->h); + + /* Watch: Write mask could prevent the clear. + * glClearTexImage does not change the state so we don't do it here either. */ + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) { + /* TODO(clem) implement. */ + BLI_assert(0); + } + else if (GPU_texture_depth(tex)) { + float depth; + switch (gpu_data_format) { + case GPU_DATA_FLOAT: { + depth = *(float *)color; + break; + } + case GPU_DATA_UNSIGNED_INT: { + depth = *(uint *)color / (float)UINT_MAX; + break; + } + default: + BLI_assert(!"Unhandled data format"); + depth = 0.0f; + break; } + glClearDepth(depth); + glClear(GL_DEPTH_BUFFER_BIT); } else { - memset(pixels, 0, buffer_len); + float r, g, b, a; + switch (gpu_data_format) { + case GPU_DATA_FLOAT: { + float *f_color = (float *)color; + r = f_color[0]; + g = (tex->components > 1) ? f_color[1] : 0.0f; + b = (tex->components > 2) ? f_color[2] : 0.0f; + a = (tex->components > 3) ? f_color[3] : 0.0f; + break; + } + case GPU_DATA_UNSIGNED_INT: { + uint *u_color = (uint *)color; + r = u_color[0] / (float)UINT_MAX; + g = (tex->components > 1) ? u_color[1] / (float)UINT_MAX : 0.0f; + b = (tex->components > 2) ? u_color[2] / (float)UINT_MAX : 0.0f; + a = (tex->components > 3) ? u_color[3] / (float)UINT_MAX : 0.0f; + break; + } + case GPU_DATA_UNSIGNED_BYTE: { + uchar *ub_color = (uchar *)color; + r = ub_color[0] / 255.0f; + g = (tex->components > 1) ? ub_color[1] / 255.0f : 0.0f; + b = (tex->components > 2) ? ub_color[2] / 255.0f : 0.0f; + a = (tex->components > 3) ? ub_color[3] / 255.0f : 0.0f; + break; + } + default: + BLI_assert(!"Unhandled data format"); + r = g = b = a = 0.0f; + break; + } + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT); + } + + if (prev_fb) { + GPU_framebuffer_bind(prev_fb); } - GPU_texture_update(tex, gpu_data_format, pixels); - MEM_freeN(pixels); } } @@ -1634,16 +1712,17 @@ void GPU_invalid_tex_free(void) } } -void GPU_texture_bind(GPUTexture *tex, int number) +/* set_number is to save the the texture unit for setting texture parameters. */ +void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, const bool set_number) { - BLI_assert(number >= 0); + BLI_assert(unit >= 0); - if (number >= GPU_max_textures()) { + if (unit >= GPU_max_textures()) { fprintf(stderr, "Not enough texture slots.\n"); return; } - if ((G.debug & G_DEBUG)) { + if (G.debug & G_DEBUG) { for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) { if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) { fprintf(stderr, @@ -1655,16 +1734,27 @@ void GPU_texture_bind(GPUTexture *tex, int number) } } - glActiveTexture(GL_TEXTURE0 + number); + if (set_number) { + tex->number = unit; + } + + glActiveTexture(GL_TEXTURE0 + unit); + + state = (state < GPU_SAMPLER_MAX) ? state : tex->sampler_state; if (tex->bindcode != 0) { glBindTexture(tex->target, tex->bindcode); + glBindSampler(unit, GG.samplers[state]); } else { GPU_invalid_tex_bind(tex->target_base); + glBindSampler(unit, 0); } +} - tex->number = number; +void GPU_texture_bind(GPUTexture *tex, int unit) +{ + GPU_texture_bind_ex(tex, GPU_SAMPLER_MAX, unit, true); } void GPU_texture_unbind(GPUTexture *tex) @@ -1675,13 +1765,34 @@ void GPU_texture_unbind(GPUTexture *tex) glActiveTexture(GL_TEXTURE0 + tex->number); glBindTexture(tex->target, 0); - + glBindSampler(tex->number, 0); tex->number = -1; } -int GPU_texture_bound_number(GPUTexture *tex) +void GPU_texture_unbind_all(void) { - return tex->number; + if (GLEW_ARB_multi_bind) { + glBindTextures(0, GPU_max_textures(), NULL); + glBindSamplers(0, GPU_max_textures(), NULL); + return; + } + + for (int i = 0; i < GPU_max_textures(); i++) { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + glBindTexture(GL_TEXTURE_1D, 0); + glBindTexture(GL_TEXTURE_1D_ARRAY, 0); + glBindTexture(GL_TEXTURE_3D, 0); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + glBindTexture(GL_TEXTURE_BUFFER, 0); + if (GPU_arb_texture_cube_map_array_is_supported()) { + glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY_ARB, 0); + } + glBindSampler(i, 0); + } + + glActiveTexture(GL_TEXTURE0); } #define WARN_NOT_BOUND(_tex) \ @@ -1705,8 +1816,8 @@ void GPU_texture_generate_mipmap(GPUTexture *tex) if (GPU_texture_depth(tex)) { /* Some drivers have bugs when using glGenerateMipmap with depth textures (see T56789). - * In this case we just create a complete texture with mipmaps manually without down-sampling. - * You must initialize the texture levels using other methods like + * In this case we just create a complete texture with mipmaps manually without + * down-sampling. You must initialize the texture levels using other methods like * GPU_framebuffer_recursive_downsample(). */ eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex->format); for (int i = 1; i < levels; i++) { @@ -1812,69 +1923,35 @@ void GPU_texture_copy(GPUTexture *dst, GPUTexture *src) void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) { - WARN_NOT_BOUND(tex); - /* Could become an assertion ? (fclem) */ if (!GPU_texture_depth(tex)) { return; } - - GLenum mode = (use_compare) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE; - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, mode); + SET_FLAG_FROM_TEST(tex->sampler_state, use_compare, GPU_SAMPLER_COMPARE); } void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter) { - WARN_NOT_BOUND(tex); - /* Stencil and integer format does not support filtering. */ BLI_assert(!use_filter || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST; - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter); + SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER); } void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter) { - WARN_NOT_BOUND(tex); - /* Stencil and integer format does not support filtering. */ - BLI_assert((!use_filter && !use_mipmap) || + BLI_assert(!(use_filter || use_mipmap) || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST; - GLenum mipmap = ((use_filter) ? (use_mipmap) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR : - (use_mipmap) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST); - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); + SET_FLAG_FROM_TEST(tex->sampler_state, use_mipmap, GPU_SAMPLER_MIPMAP); + SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER); } void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp) { - WARN_NOT_BOUND(tex); - - GLenum repeat = (use_repeat) ? GL_REPEAT : (use_clamp) ? GL_CLAMP_TO_EDGE : GL_CLAMP_TO_BORDER; - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, repeat); - if (tex->target_base != GL_TEXTURE_1D) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, repeat); - } - if (tex->target_base == GL_TEXTURE_3D) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat); - } - - if (repeat == GL_CLAMP_TO_BORDER) { - const float black[] = {0.0f, 0.0f, 0.0f, 0.0f}; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, black); - } + SET_FLAG_FROM_TEST(tex->sampler_state, use_repeat, GPU_SAMPLER_REPEAT); + SET_FLAG_FROM_TEST(tex->sampler_state, !use_clamp, GPU_SAMPLER_CLAMP_BORDER); } void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels) @@ -1888,34 +1965,6 @@ void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels) glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, (channels >= 4) ? GL_ALPHA : GL_ONE); } -static GLenum gpu_get_gl_filterfunction(eGPUFilterFunction filter) -{ - switch (filter) { - case GPU_NEAREST: - return GL_NEAREST; - case GPU_LINEAR: - return GL_LINEAR; - default: - BLI_assert(!"Unhandled filter mode"); - return GL_NEAREST; - } -} - -void GPU_texture_filters(GPUTexture *tex, - eGPUFilterFunction min_filter, - eGPUFilterFunction mag_filter) -{ - WARN_NOT_BOUND(tex); - - /* Stencil and integer format does not support filtering. */ - BLI_assert(!(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - BLI_assert(mag_filter == GPU_NEAREST || mag_filter == GPU_LINEAR); - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, gpu_get_gl_filterfunction(min_filter)); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, gpu_get_gl_filterfunction(mag_filter)); -} - void GPU_texture_free(GPUTexture *tex) { tex->refcount--; @@ -2076,3 +2125,55 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size) size[2] = max_ii(1, tex->d / div); } } + +/* -------------------------------------------------------------------- */ +/** \name GPU Sampler Objects + * + * Simple wrapper around opengl sampler objects. + * Override texture sampler state for one sampler unit only. + * \{ */ + +void GPU_samplers_init(void) +{ + glGenSamplers(GPU_SAMPLER_MAX, GG.samplers); + for (int i = 0; i < GPU_SAMPLER_MAX; i++) { + eGPUSamplerState state = i; + GLenum clamp_type = (state & GPU_SAMPLER_CLAMP_BORDER) ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE; + GLenum wrap_s = (state & GPU_SAMPLER_REPEAT_S) ? GL_REPEAT : clamp_type; + GLenum wrap_t = (state & GPU_SAMPLER_REPEAT_T) ? GL_REPEAT : clamp_type; + GLenum wrap_r = (state & GPU_SAMPLER_REPEAT_R) ? GL_REPEAT : clamp_type; + GLenum mag_filter = (state & GPU_SAMPLER_FILTER) ? GL_LINEAR : GL_NEAREST; + GLenum min_filter = (state & GPU_SAMPLER_FILTER) ? + ((state & GPU_SAMPLER_MIPMAP) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) : + ((state & GPU_SAMPLER_MIPMAP) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST); + GLenum compare_mode = (state & GPU_SAMPLER_COMPARE) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE; + float aniso_filter = ((state & GPU_SAMPLER_MIPMAP) && (state & GPU_SAMPLER_ANISO)) ? + GPU_get_anisotropic() : + 1.0f; + + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_S, wrap_s); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_T, wrap_t); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_R, wrap_r); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_MIN_FILTER, min_filter); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_MAG_FILTER, mag_filter); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_COMPARE_MODE, compare_mode); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + if (GLEW_EXT_texture_filter_anisotropic) { + glSamplerParameterf(GG.samplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso_filter); + } + + /** Other states are left to default: + * - GL_TEXTURE_BORDER_COLOR is {0, 0, 0, 0}. + * - GL_TEXTURE_MIN_LOD is -1000. + * - GL_TEXTURE_MAX_LOD is 1000. + * - GL_TEXTURE_LOD_BIAS is 0.0f. + **/ + } +} + +void GPU_samplers_free(void) +{ + glDeleteSamplers(GPU_SAMPLER_MAX, GG.samplers); +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c index e6a9cb8f2f2..b84a7e0f554 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.c +++ b/source/blender/gpu/intern/gpu_vertex_format.c @@ -23,8 +23,6 @@ * GPU vertex format */ -#include "GPU_shader_interface.h" - #include "GPU_vertex_format.h" #include "gpu_vertex_format_private.h" #include <stddef.h> @@ -34,6 +32,9 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "GPU_shader.h" +#include "gpu_shader_private.h" + #define PACK_DEBUG 0 #if PACK_DEBUG @@ -391,38 +392,37 @@ void VertexFormat_pack(GPUVertFormat *format) format->packed = true; } -static uint calc_input_component_size(const GPUShaderInput *input) +static uint calc_component_size(const GLenum gl_type) { - int size = input->size; - switch (input->gl_type) { + switch (gl_type) { case GL_FLOAT_VEC2: case GL_INT_VEC2: case GL_UNSIGNED_INT_VEC2: - return size * 2; + return 2; case GL_FLOAT_VEC3: case GL_INT_VEC3: case GL_UNSIGNED_INT_VEC3: - return size * 3; + return 3; case GL_FLOAT_VEC4: case GL_FLOAT_MAT2: case GL_INT_VEC4: case GL_UNSIGNED_INT_VEC4: - return size * 4; + return 4; case GL_FLOAT_MAT3: - return size * 9; + return 9; case GL_FLOAT_MAT4: - return size * 16; + return 16; case GL_FLOAT_MAT2x3: case GL_FLOAT_MAT3x2: - return size * 6; + return 6; case GL_FLOAT_MAT2x4: case GL_FLOAT_MAT4x2: - return size * 8; + return 8; case GL_FLOAT_MAT3x4: case GL_FLOAT_MAT4x3: - return size * 12; + return 12; default: - return size; + return 1; } } @@ -466,42 +466,39 @@ static void get_fetch_mode_and_comp_type(int gl_type, } } -void GPU_vertformat_from_interface(GPUVertFormat *format, const GPUShaderInterface *shaderface) +void GPU_vertformat_from_shader(GPUVertFormat *format, const GPUShader *shader) { - const char *name_buffer = shaderface->name_buffer; - - for (int i = 0; i < GPU_NUM_SHADERINTERFACE_BUCKETS; i++) { - const GPUShaderInput *input = shaderface->attr_buckets[i]; - if (input == NULL) { - continue; - } + GPU_vertformat_clear(format); + GPUVertAttr *attr = &format->attrs[0]; - const GPUShaderInput *next = input; - while (next != NULL) { - input = next; - next = input->next; + GLint attr_len; + glGetProgramiv(shader->program, GL_ACTIVE_ATTRIBUTES, &attr_len); - /* OpenGL attributes such as `gl_VertexID` have a location of -1. */ - if (input->location < 0) { - continue; - } - - format->name_len++; /* multiname support */ - format->attr_len++; - - GPUVertCompType comp_type; - GPUVertFetchMode fetch_mode; - get_fetch_mode_and_comp_type(input->gl_type, &comp_type, &fetch_mode); + for (int i = 0; i < attr_len; i++) { + char name[256]; + GLenum gl_type; + GLint size; + glGetActiveAttrib(shader->program, i, sizeof(name), NULL, &size, &gl_type, name); - GPUVertAttr *attr = &format->attrs[input->location]; - - attr->names[attr->name_len++] = copy_attr_name(format, name_buffer + input->name_offset); - attr->offset = 0; /* offsets & stride are calculated later (during pack) */ - attr->comp_len = calc_input_component_size(input); - attr->sz = attr->comp_len * 4; - attr->fetch_mode = fetch_mode; - attr->comp_type = comp_type; - attr->gl_comp_type = convert_comp_type_to_gl(comp_type); + /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */ + if (glGetAttribLocation(shader->program, name) == -1) { + continue; } + + format->name_len++; /* multiname support */ + format->attr_len++; + + GPUVertCompType comp_type; + GPUVertFetchMode fetch_mode; + get_fetch_mode_and_comp_type(gl_type, &comp_type, &fetch_mode); + + attr->names[attr->name_len++] = copy_attr_name(format, name); + attr->offset = 0; /* offsets & stride are calculated later (during pack) */ + attr->comp_len = calc_component_size(gl_type) * size; + attr->sz = attr->comp_len * 4; + attr->fetch_mode = fetch_mode; + attr->comp_type = comp_type; + attr->gl_comp_type = convert_comp_type_to_gl(comp_type); + attr += 1; } } diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index f30270b9eed..753da8544ea 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -382,12 +382,10 @@ GPUTexture *GPU_viewport_texture_pool_query( } tex = GPU_texture_create_2d(width, height, format, NULL, NULL); - GPU_texture_bind(tex, 0); /* Doing filtering for depth does not make sense when not doing shadow mapping, * and enabling texture filtering on integer texture make them unreadable. */ bool do_filter = !GPU_texture_depth(tex) && !GPU_texture_integer(tex); GPU_texture_filter_mode(tex, do_filter); - GPU_texture_unbind(tex); ViewportTempTexture *tmp_tex = MEM_callocN(sizeof(ViewportTempTexture), "ViewportTempTexture"); tmp_tex->texture = tex; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl index 62f76d46088..4cb00c15b78 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl @@ -1,8 +1,16 @@ -void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result) +void node_output_material( + Closure surface, Closure volume, vec3 displacement, float alpha_threshold, out Closure result) { #ifdef VOLUMETRICS result = volume; #else result = surface; +# if defined(USE_ALPHA_HASH) + /* Alpha clip emulation. */ + if (alpha_threshold >= 0.0) { + float alpha = saturate(1.0 - avg(result.transmittance)); + result.transmittance = vec3(step(alpha, alpha_threshold)); + } +# endif #endif } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl index 9bd36f8a757..20a65f23c05 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl @@ -15,16 +15,11 @@ void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec) #endif } -void node_tex_environment_equirectangular(vec3 co, float clamp_size, sampler2D ima, out vec3 uv) +void node_tex_environment_equirectangular(vec3 co, out vec3 uv) { vec3 nco = normalize(co); uv.x = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5; uv.y = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5; - - /* Fix pole bleeding */ - float half_height = clamp_size / float(textureSize(ima, 0).y); - uv.y = clamp(uv.y, half_height, 1.0 - half_height); - uv.z = 0.0; } void node_tex_environment_mirror_ball(vec3 co, out vec3 uv) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl index c39bec8ac64..df949f7358b 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl @@ -54,19 +54,6 @@ void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alp alpha = color.a; } -void node_tex_image_linear_no_mip(vec3 co, sampler2D ima, out vec4 color, out float alpha) -{ - color = safe_color(textureLod(ima, co.xy, 0.0)); - alpha = color.a; -} - -void node_tex_image_nearest(vec3 co, sampler2D ima, out vec4 color, out float alpha) -{ - ivec2 pix = ivec2(fract(co.xy) * textureSize(ima, 0).xy); - color = safe_color(texelFetch(ima, pix, 0)); - alpha = color.a; -} - /** \param f: Signed distance to texel center. */ void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3) { @@ -79,8 +66,7 @@ void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w2 = 1.0 - w0 - w1 - w3; } -void node_tex_image_cubic_ex( - vec3 co, sampler2D ima, float do_extend, out vec4 color, out float alpha) +void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha) { vec2 tex_size = vec2(textureSize(ima, 0).xy); @@ -101,9 +87,6 @@ void node_tex_image_cubic_ex( final_co.xy = tc - 1.0 + f0; final_co.zw = tc + 1.0 + f1; - if (do_extend == 1.0) { - final_co = clamp(final_co, vec4(0.5), tex_size.xyxy - 0.5); - } final_co /= tex_size.xyxy; color = safe_color(textureLod(ima, final_co.xy, 0.0)) * s0.x * s0.y; @@ -136,22 +119,6 @@ void node_tex_image_cubic_ex( alpha = color.a; } -void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha) -{ - node_tex_image_cubic_ex(co, ima, 0.0, color, alpha); -} - -void node_tex_image_cubic_extend(vec3 co, sampler2D ima, out vec4 color, out float alpha) -{ - node_tex_image_cubic_ex(co, ima, 1.0, color, alpha); -} - -void node_tex_image_smart(vec3 co, sampler2D ima, out vec4 color, out float alpha) -{ - /* use cubic for now */ - node_tex_image_cubic_ex(co, ima, 0.0, color, alpha); -} - void tex_box_sample_linear( vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3) { @@ -175,32 +142,6 @@ void tex_box_sample_linear( color3 = texture(ima, uv); } -void tex_box_sample_nearest( - vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3) -{ - /* X projection */ - vec2 uv = texco.yz; - if (N.x < 0.0) { - uv.x = 1.0 - uv.x; - } - ivec2 pix = ivec2(fract(uv.xy) * textureSize(ima, 0).xy); - color1 = texelFetch(ima, pix, 0); - /* Y projection */ - uv = texco.xz; - if (N.y > 0.0) { - uv.x = 1.0 - uv.x; - } - pix = ivec2(fract(uv.xy) * textureSize(ima, 0).xy); - color2 = texelFetch(ima, pix, 0); - /* Z projection */ - uv = texco.yx; - if (N.z > 0.0) { - uv.x = 1.0 - uv.x; - } - pix = ivec2(fract(uv.xy) * textureSize(ima, 0).xy); - color3 = texelFetch(ima, pix, 0); -} - void tex_box_sample_cubic( vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3) { @@ -210,36 +151,23 @@ void tex_box_sample_cubic( if (N.x < 0.0) { uv.x = 1.0 - uv.x; } - node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color1, alpha); + node_tex_image_cubic(uv.xyy, ima, color1, alpha); /* Y projection */ uv = texco.xz; if (N.y > 0.0) { uv.x = 1.0 - uv.x; } - node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color2, alpha); + node_tex_image_cubic(uv.xyy, ima, color2, alpha); /* Z projection */ uv = texco.yx; if (N.z > 0.0) { uv.x = 1.0 - uv.x; } - node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color3, alpha); + node_tex_image_cubic(uv.xyy, ima, color3, alpha); } -void tex_box_sample_smart( - vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3) -{ - tex_box_sample_cubic(texco, N, ima, color1, color2, color3); -} - -void node_tex_image_box(vec3 texco, - vec3 N, - vec4 color1, - vec4 color2, - vec4 color3, - sampler2D ima, - float blend, - out vec4 color, - out float alpha) +void tex_box_blend( + vec3 N, vec4 color1, vec4 color2, vec4 color3, float blend, out vec4 color, out float alpha) { /* project from direction vector to barycentric coordinates in triangles */ N = abs(N); @@ -284,70 +212,6 @@ void node_tex_image_box(vec3 texco, alpha = color.a; } -void tex_clip_linear(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha) -{ - vec2 tex_size = vec2(textureSize(ima, 0).xy); - vec2 minco = min(co.xy, 1.0 - co.xy); - minco = clamp(minco * tex_size + 0.5, 0.0, 1.0); - float fac = minco.x * minco.y; - - color = mix(vec4(0.0), icolor, fac); - alpha = color.a; -} - -void tex_clip_nearest(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha) -{ - vec4 minco = vec4(co.xy, 1.0 - co.xy); - color = (any(lessThan(minco, vec4(0.0)))) ? vec4(0.0) : icolor; - alpha = color.a; -} - -void tex_clip_cubic(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha) -{ - vec2 tex_size = vec2(textureSize(ima, 0).xy); - - co.xy *= tex_size; - /* texel center */ - vec2 tc = floor(co.xy - 0.5) + 0.5; - vec2 w0, w1, w2, w3; - cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3); - - /* TODO Optimize this part. I'm sure there is a smarter way to do that. - * Could do that when sampling? */ -#define CLIP_CUBIC_SAMPLE(samp, size) \ - (float(all(greaterThan(samp, vec2(-0.5)))) * float(all(lessThan(ivec2(samp), itex_size)))) - ivec2 itex_size = textureSize(ima, 0).xy; - float fac; - fac = CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, -1.0), itex_size) * w0.x * w0.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, -1.0), itex_size) * w1.x * w0.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, -1.0), itex_size) * w2.x * w0.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, -1.0), itex_size) * w3.x * w0.y; - - fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 0.0), itex_size) * w0.x * w1.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 0.0), itex_size) * w1.x * w1.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 0.0), itex_size) * w2.x * w1.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 0.0), itex_size) * w3.x * w1.y; - - fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 1.0), itex_size) * w0.x * w2.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 1.0), itex_size) * w1.x * w2.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 1.0), itex_size) * w2.x * w2.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 1.0), itex_size) * w3.x * w2.y; - - fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 2.0), itex_size) * w0.x * w3.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 2.0), itex_size) * w1.x * w3.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 2.0), itex_size) * w2.x * w3.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 2.0), itex_size) * w3.x * w3.y; -#undef CLIP_CUBIC_SAMPLE - - color = mix(vec4(0.0), icolor, fac); - alpha = color.a; -} - -void tex_clip_smart(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha) -{ - tex_clip_cubic(co, ima, icolor, color, alpha); -} - void node_tex_image_empty(vec3 co, out vec4 color, out float alpha) { color = vec4(0.0); @@ -389,20 +253,6 @@ void node_tex_tile_linear( alpha = color.a; } -void node_tex_tile_nearest( - vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha) -{ - if (node_tex_tile_lookup(co, ima, map)) { - ivec3 pix = ivec3(fract(co.xy) * textureSize(ima, 0).xy, co.z); - color = safe_color(texelFetch(ima, pix, 0)); - } - else { - color = vec4(1.0, 0.0, 1.0, 1.0); - } - - alpha = color.a; -} - void node_tex_tile_cubic( vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha) { @@ -437,9 +287,3 @@ void node_tex_tile_cubic( alpha = color.a; } - -void node_tex_tile_smart( - vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha) -{ - node_tex_tile_cubic(co, ima, map, color, alpha); -} diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 40a057f9a20..62f6a52f7cf 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -144,7 +144,7 @@ const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, Custom * - (optional due to its behavior) tag as UV using Alembic::AbcGeom::SetIsUV */ static void write_uv(const OCompoundProperty &prop, - const CDStreamConfig &config, + CDStreamConfig &config, void *data, const char *name) { @@ -157,13 +157,18 @@ static void write_uv(const OCompoundProperty &prop, return; } - OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1); + std::string uv_map_name(name); + OV2fGeomParam param = config.abc_uv_maps[uv_map_name]; + if (!param.valid()) { + param = OV2fGeomParam(prop, name, true, kFacevaryingScope, 1); + } OV2fGeomParam::Sample sample(V2fArraySample(&uvs.front(), uvs.size()), UInt32ArraySample(&indices.front(), indices.size()), kFacevaryingScope); - param.set(sample); + + config.abc_uv_maps[uv_map_name] = param; } /* Convention to write Vertex Colors: @@ -217,7 +222,7 @@ static void write_mcol(const OCompoundProperty &prop, } void write_custom_data(const OCompoundProperty &prop, - const CDStreamConfig &config, + CDStreamConfig &config, CustomData *data, int data_type) { diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h index 04572c736af..96b57b08681 100644 --- a/source/blender/io/alembic/intern/abc_customdata.h +++ b/source/blender/io/alembic/intern/abc_customdata.h @@ -27,6 +27,8 @@ #include <Alembic/Abc/All.h> #include <Alembic/AbcGeom/All.h> +#include <map> + struct CustomData; struct MLoop; struct MLoopUV; @@ -70,6 +72,12 @@ struct CDStreamConfig { const char **modifier_error_message; + /* Alembic needs Blender to keep references to C++ objects (the destructors + * finalize the writing to ABC). This map stores OV2fGeomParam objects for the + * 2nd and subsequent UV maps; the primary UV map is kept alive by the Alembic + * mesh sample itself. */ + std::map<std::string, Alembic::AbcGeom::OV2fGeomParam> abc_uv_maps; + CDStreamConfig() : mloop(NULL), totloop(0), @@ -95,7 +103,7 @@ struct CDStreamConfig { const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data); void write_custom_data(const OCompoundProperty &prop, - const CDStreamConfig &config, + CDStreamConfig &config, CustomData *data, int data_type); diff --git a/source/blender/io/alembic/intern/abc_writer_archive.cc b/source/blender/io/alembic/intern/abc_writer_archive.cc index 5aae1f05f4b..e7dee536cb9 100644 --- a/source/blender/io/alembic/intern/abc_writer_archive.cc +++ b/source/blender/io/alembic/intern/abc_writer_archive.cc @@ -52,7 +52,7 @@ static OArchive create_archive(std::ostream *ostream, abc_metadata.set(Alembic::Abc::kApplicationNameKey, "Blender"); abc_metadata.set(Alembic::Abc::kUserDescriptionKey, scene_name); - abc_metadata.set("blender_version", versionstr); + abc_metadata.set("blender_version", std::string("v") + BKE_blender_version_string()); abc_metadata.set("FramesPerTimeUnit", std::to_string(scene_fps)); time_t raw_time; diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index 987a3cacb3b..6ca9e82a26c 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -875,8 +875,7 @@ bool ABC_import(bContext *C, bool validate_meshes, bool as_background_job) { - /* Using new here since MEM_* funcs do not call ctor to properly initialize - * data. */ + /* Using new here since MEM_* functions do not call constructor to properly initialize data. */ ImportJobData *job = new ImportJobData(); job->bmain = CTX_data_main(C); job->scene = CTX_data_scene(C); diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index 2511d3c287d..edac84e2aaa 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -57,7 +57,7 @@ template<class T> static const char *bc_get_joint_name(T *node) FCurve *AnimationImporter::create_fcurve(int array_index, const char *rna_path) { - FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve"); + FCurve *fcu = BKE_fcurve_create(); fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED); fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); fcu->array_index = array_index; @@ -100,7 +100,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) case 16: /* matrix */ { for (i = 0; i < dim; i++) { - FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve"); + FCurve *fcu = BKE_fcurve_create(); fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED); fcu->array_index = 0; @@ -274,7 +274,7 @@ AnimationImporter::~AnimationImporter() /* free unused FCurves */ for (std::vector<FCurve *>::iterator it = unused_curves.begin(); it != unused_curves.end(); it++) { - free_fcurve(*it); + BKE_fcurve_free(*it); } if (unused_curves.size()) { @@ -442,7 +442,7 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act) } action_groups_remove_channel(act, eulcu[i]); - free_fcurve(eulcu[i]); + BKE_fcurve_free(eulcu[i]); } chan->rotmode = ROT_MODE_QUAT; diff --git a/source/blender/io/collada/BCAnimationCurve.cpp b/source/blender/io/collada/BCAnimationCurve.cpp index 98eb12f738e..61dded368b5 100644 --- a/source/blender/io/collada/BCAnimationCurve.cpp +++ b/source/blender/io/collada/BCAnimationCurve.cpp @@ -89,12 +89,12 @@ void BCAnimationCurve::init_pointer_rna(Object *ob) void BCAnimationCurve::delete_fcurve(FCurve *fcu) { - free_fcurve(fcu); + BKE_fcurve_free(fcu); } FCurve *BCAnimationCurve::create_fcurve(int array_index, const char *rna_path) { - FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve"); + FCurve *fcu = BKE_fcurve_create(); fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED); fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); fcu->array_index = array_index; diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp index fc23a58ccbc..4aea74cd82f 100644 --- a/source/blender/io/collada/BCAnimationSampler.cpp +++ b/source/blender/io/collada/BCAnimationSampler.cpp @@ -271,7 +271,7 @@ void BCAnimationSampler::find_depending_animated(std::set<Object *> &animated_ob std::set<Object *>::iterator it; for (it = candidates.begin(); it != candidates.end(); ++it) { Object *cob = *it; - ListBase *conlist = get_active_constraints(cob); + ListBase *conlist = ED_object_constraint_list_from_context(cob); if (is_animated_by_constraint(cob, conlist, animated_objects)) { animated_objects.insert(cob); candidates.erase(cob); diff --git a/source/blender/io/collada/DocumentExporter.cpp b/source/blender/io/collada/DocumentExporter.cpp index b890d4cf018..0578bf45f04 100644 --- a/source/blender/io/collada/DocumentExporter.cpp +++ b/source/blender/io/collada/DocumentExporter.cpp @@ -243,20 +243,13 @@ int DocumentExporter::exportCurrentScene() #ifdef WITH_BUILDINFO BLI_snprintf(version_buf, sizeof(version_buf), - "Blender %d.%02d.%d commit date:%s, commit time:%s, hash:%s", - BLENDER_VERSION / 100, - BLENDER_VERSION % 100, - BLENDER_SUBVERSION, + "Blender %s commit date:%s, commit time:%s, hash:%s", + BKE_blender_version_string(), build_commit_date, build_commit_time, build_hash); #else - BLI_snprintf(version_buf, - sizeof(version_buf), - "Blender %d.%02d.%d", - BLENDER_VERSION / 100, - BLENDER_VERSION % 100, - BLENDER_SUBVERSION); + BLI_snprintf(version_buf, sizeof(version_buf), "Blender %s", BKE_blender_version_string()); #endif asset.getContributor().mAuthoringTool = version_buf; asset.add(); diff --git a/source/blender/io/collada/ErrorHandler.h b/source/blender/io/collada/ErrorHandler.h index 9789e93cee9..0c082a3b9dd 100644 --- a/source/blender/io/collada/ErrorHandler.h +++ b/source/blender/io/collada/ErrorHandler.h @@ -46,7 +46,7 @@ class ErrorHandler : public COLLADASaxFWL::IErrorHandler { } private: - /** Disable default copy ctor. */ + /** Disable default copy constructor. */ ErrorHandler(const ErrorHandler &pre); /** Disable default assignment operator. */ const ErrorHandler &operator=(const ErrorHandler &pre); diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc index e382fa6bb1d..ab83ea2c3c4 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc @@ -53,7 +53,7 @@ bool HierarchyContext::operator<(const HierarchyContext &other) const if (object != other.object) { return object < other.object; } - if (duplicator != NULL && duplicator == other.duplicator) { + if (duplicator != nullptr && duplicator == other.duplicator) { // Only resort to string comparisons when both objects are created by the same duplicator. return export_name < other.export_name; } diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc index f8e0a03abfa..cf962446d04 100644 --- a/source/blender/io/usd/intern/usd_capi.cc +++ b/source/blender/io/usd/intern/usd_capi.cc @@ -91,7 +91,8 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z)); usd_stage->SetMetadata(pxr::UsdGeomTokens->metersPerUnit, pxr::VtValue(scene->unit.scale_length)); - usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender ") + versionstr); + usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender v") + + BKE_blender_version_string()); // Set up the stage for animated data. if (data->params.export_animation) { @@ -185,7 +186,7 @@ bool USD_export(bContext *C, /* setup job */ WM_jobs_customdata_set(wm_job, job, MEM_freeN); WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, USD::export_startjob, NULL, NULL, USD::export_endjob); + WM_jobs_callbacks(wm_job, USD::export_startjob, nullptr, nullptr, USD::export_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); } diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index 909869d2af1..841501bcf42 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -79,7 +79,7 @@ void USDGenericMeshWriter::do_write(HierarchyContext &context) bool needsfree = false; Mesh *mesh = get_export_mesh(object_eval, needsfree); - if (mesh == NULL) { + if (mesh == nullptr) { return; } @@ -100,7 +100,7 @@ void USDGenericMeshWriter::do_write(HierarchyContext &context) void USDGenericMeshWriter::free_export_mesh(Mesh *mesh) { - BKE_id_free(NULL, mesh); + BKE_id_free(nullptr, mesh); } struct USDMeshData { diff --git a/source/blender/io/usd/intern/usd_writer_transform.cc b/source/blender/io/usd/intern/usd_writer_transform.cc index 038f2b17b1a..0694d873002 100644 --- a/source/blender/io/usd/intern/usd_writer_transform.cc +++ b/source/blender/io/usd/intern/usd_writer_transform.cc @@ -50,7 +50,7 @@ void USDTransformWriter::do_write(HierarchyContext &context) bool USDTransformWriter::check_is_animated(const HierarchyContext &context) const { - if (context.duplicator != NULL) { + if (context.duplicator != nullptr) { /* This object is being duplicated, so could be emitted by a particle system and thus * influenced by forces. TODO(Sybren): Make this more strict. Probably better to get from the * depsgraph whether this object instance has a time source. */ diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 39f22fb9555..4f2bbc4ee73 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -327,7 +327,7 @@ typedef struct Library { /* Temp data needed by read/write code. */ int temp_index; - /** See BLENDER_VERSION, BLENDER_SUBVERSION, needed for do_versions. */ + /** See BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION, needed for do_versions. */ short versionfile, subversionfile; } Library; diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index c143c2a442a..be7c894b4e4 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -331,9 +331,15 @@ typedef enum eBrushClothForceFalloffType { BRUSH_CLOTH_FORCE_FALLOFF_PLANE = 1, } eBrushClothForceFalloffType; +typedef enum eBrushPoseDeformType { + BRUSH_POSE_DEFORM_ROTATE_TWIST = 0, + BRUSH_POSE_DEFORM_SCALE_TRASLATE = 1, +} eBrushPoseDeformType; + typedef enum eBrushPoseOriginType { BRUSH_POSE_ORIGIN_TOPOLOGY = 0, BRUSH_POSE_ORIGIN_FACE_SETS = 1, + BRUSH_POSE_ORIGIN_FACE_SETS_FK = 2, } eBrushPoseOriginType; /* Gpencilsettings.Vertex_mode */ @@ -478,7 +484,7 @@ typedef struct Brush { char gpencil_sculpt_tool; /** Active grease pencil weight tool. */ char gpencil_weight_tool; - char _pad1[6]; + char _pad1[2]; float autosmooth_factor; @@ -510,6 +516,7 @@ typedef struct Brush { float elastic_deform_volume_preservation; /* pose */ + int pose_deform_type; float pose_offset; int pose_smooth_iterations; int pose_ik_segments; diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 6a081a7f5a7..b2902407a15 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -496,11 +496,11 @@ typedef enum eBezTriple_KeyframeType { #define BEZT_ISSEL_ALL(bezt) \ (((bezt)->f2 & SELECT) && ((bezt)->f1 & SELECT) && ((bezt)->f3 & SELECT)) #define BEZT_ISSEL_ALL_HIDDENHANDLES(v3d, bezt) \ - ((((v3d) != NULL) && ((v3d)->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) ? \ + ((((v3d) != NULL) && ((v3d)->overlay.handle_display == CURVE_HANDLE_NONE)) ? \ (bezt)->f2 & SELECT : \ BEZT_ISSEL_ALL(bezt)) #define BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt) \ - ((((v3d) != NULL) && ((v3d)->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) ? \ + ((((v3d) != NULL) && ((v3d)->overlay.handle_display == CURVE_HANDLE_NONE)) ? \ (bezt)->f2 & SELECT : \ BEZT_ISSEL_ANY(bezt)) diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index e99d7fd5609..ef3b2015758 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -76,7 +76,8 @@ typedef struct CustomData { * MUST be >= CD_NUMTYPES, but we cant use a define here. * Correct size is ensured in CustomData_update_typemap assert(). */ - int typemap[47]; + int typemap[48]; + char _pad[4]; /** Number of layers, size of layers array. */ int totlayer, maxlayer; /** In editmode, total size of all data layers. */ @@ -153,7 +154,9 @@ typedef enum CustomDataType { CD_HAIRCURVE = 45, CD_HAIRMAPPING = 46, - CD_NUMTYPES = 47, + CD_PROP_COLOR = 47, + + CD_NUMTYPES = 48, } CustomDataType; /* Bits for CustomDataMask */ @@ -202,6 +205,7 @@ typedef enum CustomDataType { #define CD_MASK_TESSLOOPNORMAL (1LL << CD_TESSLOOPNORMAL) #define CD_MASK_CUSTOMLOOPNORMAL (1LL << CD_CUSTOMLOOPNORMAL) #define CD_MASK_SCULPT_FACE_SETS (1LL << CD_SCULPT_FACE_SETS) +#define CD_MASK_PROP_COLOR (1LL << CD_PROP_COLOR) /** Data types that may be defined for all mesh elements types. */ #define CD_MASK_GENERIC_DATA (CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR) diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index dc1a2b5ff1d..acc020ec710 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -33,6 +33,7 @@ extern "C" { #endif struct AnimData; +struct BVHCache; struct Ipo; struct Key; struct LinkNode; @@ -99,8 +100,8 @@ typedef struct Mesh_Runtime { struct MLoopTri_Store looptris; - /** 'BVHCache', for 'BKE_bvhutil.c' */ - struct LinkNode *bvh_cache; + /** `BVHCache` defined in 'BKE_bvhutil.c' */ + struct BVHCache *bvh_cache; /** Non-manifold boundary data for Shrinkwrap Target Project. */ struct ShrinkwrapBoundaryData *shrinkwrap_data; @@ -112,7 +113,20 @@ typedef struct Mesh_Runtime { * In the future we may leave the mesh-data empty * since its not needed if we can use edit-mesh data. */ char is_original; - char _pad[6]; + + /** #eMeshWrapperType and others. */ + char wrapper_type; + /** + * A type mask from wrapper_type, + * in case there are differences in finalizing logic between types. + */ + char wrapper_type_finalize; + + char _pad[4]; + + /** Needed in case we need to lazily initialize the mesh. */ + CustomData_MeshMasks cd_mask_extra; + } Mesh_Runtime; typedef struct Mesh { @@ -228,6 +242,15 @@ typedef struct TFace { /* **************** MESH ********************* */ +/** #Mesh_Runtime.wrapper_type */ +typedef enum eMeshWrapperType { + /** Use mesh data (#Mesh.mvert,#Mesh.medge, #Mesh.mloop, #Mesh.mpoly). */ + ME_WRAPPER_TYPE_MDATA = 0, + /** Use edit-mesh data (#Mesh.#edit_mesh, #Mesh_Runtime.edit_data). */ + ME_WRAPPER_TYPE_BMESH = 1, + /* ME_WRAPPER_TYPE_SUBD = 2, */ /* TODO */ +} eMeshWrapperType; + /* texflag */ enum { ME_AUTOSPACE = 1, diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index f48024cd55a..04deecde43e 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -344,6 +344,10 @@ typedef struct MLoopCol { unsigned char r, g, b, a; } MLoopCol; +typedef struct MPropCol { + float col[4]; +} MPropCol; + /** Multi-Resolution loop data. */ typedef struct MDisps { /* Strange bug in SDNA: if disps pointer comes first, it fails to see totdisp */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 609d3782997..a2b96ac2772 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1418,7 +1418,7 @@ typedef struct WeightVGEditModifierData { /* WeightVGEdit flags. */ enum { - /* (1 << 0) is free for future use! */ + MOD_WVG_EDIT_WEIGHTS_NORMALIZE = (1 << 0), MOD_WVG_INVERT_FALLOFF = (1 << 1), MOD_WVG_EDIT_INVERT_VGROUP_MASK = (1 << 2), /** Add vertices with higher weight than threshold to vgroup. */ @@ -1506,6 +1506,9 @@ enum { /* WeightVGMix->flag */ enum { MOD_WVG_MIX_INVERT_VGROUP_MASK = (1 << 0), + MOD_WVG_MIX_WEIGHTS_NORMALIZE = (1 << 1), + MOD_WVG_MIX_INVERT_VGROUP_A = (1 << 2), + MOD_WVG_MIX_INVERT_VGROUP_B = (1 << 3), }; typedef struct WeightVGProximityModifierData { @@ -1568,6 +1571,7 @@ enum { MOD_WVG_PROXIMITY_GEOM_FACES = (1 << 2), MOD_WVG_PROXIMITY_INVERT_VGROUP_MASK = (1 << 3), MOD_WVG_PROXIMITY_INVERT_FALLOFF = (1 << 4), + MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE = (1 << 3), }; /* Defines common to all WeightVG modifiers. */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 8c34a7cb0a1..c50e48982b3 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -908,8 +908,6 @@ typedef struct ImagePaintSettings { /** Mode used for texture painting. */ int mode; - /** Wm handle. */ - void *paintcursor; /** Workaround until we support true layer masks. */ struct Image *stencil; /** Clone layer for image mode for projective texture painting. */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 8f4f066efbb..31a8d967ccf 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -833,9 +833,10 @@ typedef enum eFileSel_Params_RenameFlag { FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE = 1 << 3, } eFileSel_Params_RenameFlag; -/* files in filesel list: file types - * Note we could use mere values (instead of bitflags) for file types themselves, - * but since we do not lack of bytes currently... +/** + * Files in the file selector list: file types + * Note we could use mere values (instead of bit-flags) for file types themselves, + * but since we do not lack of bytes currently. */ typedef enum eFileSel_File_Types { FILE_TYPE_BLENDER = (1 << 2), diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 019e4c9ea9e..63e7a90547e 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1189,7 +1189,7 @@ typedef enum eColorPicker_Types { } eColorPicker_Types; /** - * Timecode display styles + * Time-code display styles. * #UserDef.timecode_style */ typedef enum eTimecodeStyles { diff --git a/source/blender/makesdna/DNA_view3d_defaults.h b/source/blender/makesdna/DNA_view3d_defaults.h index 20b491c47f2..10eadf368ef 100644 --- a/source/blender/makesdna/DNA_view3d_defaults.h +++ b/source/blender/makesdna/DNA_view3d_defaults.h @@ -64,8 +64,8 @@ .edit_flag = V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS | \ V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE | \ V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES | \ - V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS | \ - V3D_OVERLAY_EDIT_CU_HANDLES, \ + V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS, \ + .handle_display = CURVE_HANDLE_SELECTED, \ \ .gpencil_paper_opacity = 0.5f, \ .gpencil_grid_opacity = 0.9f, \ diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 6d8d16c4313..ef174f5858f 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -228,9 +228,20 @@ typedef struct View3DOverlay { /** Factor for mixing vertex paint with original color */ float gpencil_vertex_paint_opacity; - char _pad4[4]; + /** Handles display type for curves. */ + int handle_display; } View3DOverlay; +/* View3DOverlay->handle_display */ +typedef enum eHandleDisplay { + /* Display only selected points. */ + CURVE_HANDLE_SELECTED = 0, + /* Display all handles. */ + CURVE_HANDLE_ALL = 1, + /* No display handles. */ + CURVE_HANDLE_NONE = 2, +} eHandleDisplay; + typedef struct View3D_Runtime { /** Nkey panel stores stuff here. */ void *properties_storage; @@ -522,7 +533,9 @@ enum { V3D_OVERLAY_EDIT_FACE_AREA = (1 << 18), V3D_OVERLAY_EDIT_INDICES = (1 << 19), - V3D_OVERLAY_EDIT_CU_HANDLES = (1 << 20), + /* Deprecated. */ + /* V3D_OVERLAY_EDIT_CU_HANDLES = (1 << 20), */ + V3D_OVERLAY_EDIT_CU_NORMALS = (1 << 21), }; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index d2e27bdbcad..65c43ebc151 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -71,6 +71,7 @@ extern StructRNA RNA_BackgroundImage; extern StructRNA RNA_BevelModifier; extern StructRNA RNA_BezierSplinePoint; extern StructRNA RNA_BlendData; +extern StructRNA RNA_BlendDataLibraries; extern StructRNA RNA_BlendTexture; extern StructRNA RNA_BlenderRNA; extern StructRNA RNA_BoidRule; diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 7a7ab1085dd..1bcf7f434f2 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -50,6 +50,7 @@ void RNA_free(BlenderRNA *brna); void RNA_define_verify_sdna(bool verify); void RNA_define_animate_sdna(bool animate); void RNA_define_fallback_property_update(int noteflag, const char *updatefunc); +void RNA_define_lib_overridable(const bool make_overridable); void RNA_init(void); void RNA_exit(void); diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 86a088f38ed..2960cea7f53 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -637,7 +637,7 @@ static char *rna_def_property_get_func( if (!manualfunc) { if (!dp->dnastructname || !dp->dnaname) { CLOG_ERROR(&LOG, "%s.%s has no valid dna info.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return NULL; } @@ -654,7 +654,7 @@ static char *rna_def_property_get_func( prop->identifier, dp->dnatype, RNA_property_typename(prop->type)); - DefRNA.error = 1; + DefRNA.error = true; return NULL; } } @@ -667,7 +667,7 @@ static char *rna_def_property_get_func( prop->identifier, dp->dnatype, RNA_property_typename(prop->type)); - DefRNA.error = 1; + DefRNA.error = true; return NULL; } } @@ -679,7 +679,7 @@ static char *rna_def_property_get_func( prop->identifier, dp->dnatype, RNA_property_typename(prop->type)); - DefRNA.error = 1; + DefRNA.error = true; return NULL; } } @@ -1020,7 +1020,7 @@ static char *rna_def_property_set_func( if (!dp->dnastructname || !dp->dnaname) { if (prop->flag & PROP_EDITABLE) { CLOG_ERROR(&LOG, "%s.%s has no valid dna info.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } return NULL; } @@ -1263,7 +1263,7 @@ static char *rna_def_property_length_func( if (!manualfunc) { if (!dp->dnastructname || !dp->dnaname) { CLOG_ERROR(&LOG, "%s.%s has no valid dna info.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return NULL; } } @@ -1289,7 +1289,7 @@ static char *rna_def_property_length_func( if (prop->type == PROP_COLLECTION && (!(dp->dnalengthname || dp->dnalengthfixed) || !dp->dnaname)) { CLOG_ERROR(&LOG, "%s.%s has no valid dna info.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return NULL; } } @@ -1338,7 +1338,7 @@ static char *rna_def_property_begin_func( if (!manualfunc) { if (!dp->dnastructname || !dp->dnaname) { CLOG_ERROR(&LOG, "%s.%s has no valid dna info.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return NULL; } } @@ -1823,6 +1823,10 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp) case PROP_ENUM: { EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop; + if (!eprop->get && !eprop->set) { + rna_set_raw_property(dp, prop); + } + eprop->get = (void *)rna_def_property_get_func(f, srna, prop, dp, (const char *)eprop->get); eprop->set = (void *)rna_def_property_set_func(f, srna, prop, dp, (const char *)eprop->set); break; @@ -1844,7 +1848,7 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp) if (!pprop->type) { CLOG_ERROR( &LOG, "%s.%s, pointer must have a struct type.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } break; } @@ -1892,21 +1896,21 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp) "%s.%s, collection must have a begin function.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } if (!cprop->next) { CLOG_ERROR(&LOG, "%s.%s, collection must have a next function.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } if (!cprop->get) { CLOG_ERROR(&LOG, "%s.%s, collection must have a get function.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } } if (!cprop->item_type) { @@ -1914,7 +1918,7 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp) "%s.%s, collection must have a struct type.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } break; } @@ -3652,7 +3656,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr errnest, prop->identifier, eprop->defaultvalue & ~totflag); - DefRNA.error = 1; + DefRNA.error = true; } } else { @@ -3662,7 +3666,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr srna->identifier, errnest, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } } } @@ -3672,7 +3676,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr srna->identifier, errnest, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } break; } @@ -4214,7 +4218,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE if (srna->reg && !srna->refine) { CLOG_ERROR( &LOG, "%s has a register function, must also have refine function.", srna->identifier); - DefRNA.error = 1; + DefRNA.error = true; } func = srna->functions.first; @@ -4705,7 +4709,8 @@ static const char *cpp_classes = " DynamicArray() : data(NULL), length(0) {}\n" " DynamicArray(int new_length) : data(NULL), length(new_length) { data = (T " "*)malloc(sizeof(T) * new_length); }\n" - " DynamicArray(const DynamicArray<T>& other) { copy_from(other); }\n" + " DynamicArray(const DynamicArray<T>& other) : data(NULL), length(0) { copy_from(other); " + "}\n" " const DynamicArray<T>& operator = (const DynamicArray<T>& other) { copy_from(other); " "return *this; }\n" "\n" diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 85892758a88..2197764794b 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -2182,7 +2182,7 @@ bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop) } for (index = 0; index < len; index++) { - if (rna_get_fcurve(ptr, prop, index, NULL, NULL, &driven, &special)) { + if (BKE_fcurve_find_by_rna(ptr, prop, index, NULL, NULL, &driven, &special)) { return true; } } @@ -4386,8 +4386,8 @@ static int rna_raw_access(ReportList *reports, /* check type */ itemtype = RNA_property_type(itemprop); - if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { - BKE_report(reports, RPT_ERROR, "Only boolean, int and float properties supported"); + if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) { + BKE_report(reports, RPT_ERROR, "Only boolean, int float and enum properties supported"); return 0; } diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index facbf8d59cc..e67366fc7ef 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -147,7 +147,7 @@ static FCurve *rna_Action_fcurve_find(bAction *act, } /* Returns NULL if not found. */ - return list_find_fcurve(&act->curves, data_path, index); + return BKE_fcurve_find(&act->curves, data_path, index); } static void rna_Action_fcurve_remove(bAction *act, ReportList *reports, PointerRNA *fcu_ptr) @@ -164,7 +164,7 @@ static void rna_Action_fcurve_remove(bAction *act, ReportList *reports, PointerR } action_groups_remove_channel(act, fcu); - free_fcurve(fcu); + BKE_fcurve_free(fcu); RNA_POINTER_INVALIDATE(fcu_ptr); } else { @@ -174,7 +174,7 @@ static void rna_Action_fcurve_remove(bAction *act, ReportList *reports, PointerR } BLI_remlink(&act->curves, fcu); - free_fcurve(fcu); + BKE_fcurve_free(fcu); RNA_POINTER_INVALIDATE(fcu_ptr); } diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 7ea44bce6db..823446a9d3b 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -648,7 +648,7 @@ static FCurve *rna_Driver_from_existing(AnimData *adt, bContext *C, FCurve *src_ } else { /* just make a copy of the existing one and add to self */ - FCurve *new_fcu = copy_fcurve(src_driver); + FCurve *new_fcu = BKE_fcurve_copy(src_driver); /* XXX: if we impose any ordering on these someday, this will be problematic */ BLI_addtail(&adt->drivers, new_fcu); @@ -664,7 +664,7 @@ static FCurve *rna_Driver_new( return NULL; } - if (list_find_fcurve(&adt->drivers, rna_path, array_index)) { + if (BKE_fcurve_find(&adt->drivers, rna_path, array_index)) { BKE_reportf(reports, RPT_ERROR, "Driver '%s[%d]' already exists", rna_path, array_index); return NULL; } @@ -683,7 +683,7 @@ static void rna_Driver_remove(AnimData *adt, Main *bmain, ReportList *reports, F BKE_report(reports, RPT_ERROR, "Driver not found in this animation data"); return; } - free_fcurve(fcu); + BKE_fcurve_free(fcu); DEG_relations_tag_update(bmain); } @@ -698,7 +698,7 @@ static FCurve *rna_Driver_find(AnimData *adt, } /* Returns NULL if not found. */ - return list_find_fcurve(&adt->drivers, data_path, index); + return BKE_fcurve_find(&adt->drivers, data_path, index); } bool rna_AnimaData_override_apply(Main *UNUSED(bmain), diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index fe35af8c2e0..8454d5c125f 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -176,6 +176,20 @@ static void rna_Armature_redraw_data(Main *UNUSED(bmain), Scene *UNUSED(scene), WM_main_add_notifier(NC_GEOM | ND_DATA, id); } +/* Unselect bones when hidden */ +static void rna_Bone_hide_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + bArmature *arm = (bArmature *)ptr->owner_id; + Bone *bone = (Bone *)ptr->data; + + if (bone->flag & BONE_HIDDEN_P) { + bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + + WM_main_add_notifier(NC_OBJECT | ND_POSE, arm); + DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE); +} + /* called whenever a bone is renamed */ static void rna_Bone_update_renamed(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { @@ -1143,7 +1157,8 @@ static void rna_def_bone(BlenderRNA *brna) prop, "Hide", "Bone is not visible when it is not in Edit Mode (i.e. in Object or Pose Modes)"); - RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1); + RNA_def_property_update(prop, 0, "rna_Bone_hide_update"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_SELECTED); @@ -1312,7 +1327,7 @@ static void rna_def_edit_bone(BlenderRNA *brna) prop, "Editbone Matrix", "Matrix combining loc/rot of the bone (head position, direction and roll), " - "in armature space (WARNING: does not include/support bone's length/size)"); + "in armature space (does not include/support bone's length/size)"); RNA_def_property_float_funcs(prop, "rna_EditBone_matrix_get", "rna_EditBone_matrix_set", NULL); RNA_api_armature_edit_bone(srna); diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index d3b607fcb76..209e5a1ff8b 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1960,6 +1960,12 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem brush_pose_deform_type_items[] = { + {BRUSH_POSE_DEFORM_ROTATE_TWIST, "ROTATE_TWIST", 0, "Rotate/Twist", ""}, + {BRUSH_POSE_DEFORM_SCALE_TRASLATE, "SCALE_TRANSLATE", 0, "Scale/Translate", ""}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem brush_pose_origin_type_items[] = { {BRUSH_POSE_ORIGIN_TOPOLOGY, "TOPOLOGY", @@ -1972,6 +1978,11 @@ static void rna_def_brush(BlenderRNA *brna) 0, "Face Sets", "Creates a pose segment per face sets, starting from the active face set"}, + {BRUSH_POSE_ORIGIN_FACE_SETS_FK, + "FACE_SETS_FK", + 0, + "Face Sets FK", + "Simulates an FK deformation using the Face Set under the cursor as control"}, {0, NULL, 0, NULL, NULL}, }; @@ -2095,6 +2106,11 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "pose_deform_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_pose_deform_type_items); + RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "pose_origin_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, brush_pose_origin_type_items); RNA_def_property_ui_text(prop, diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 47a09233769..79ee9619e36 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -193,6 +193,8 @@ static void rna_def_camera_background_image(BlenderRNA *brna) RNA_def_struct_ui_text( srna, "Background Image", "Image and settings for display in the 3D View background"); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "source"); RNA_def_property_enum_items(prop, bgpic_source_items); @@ -301,6 +303,8 @@ static void rna_def_camera_background_image(BlenderRNA *brna) RNA_def_property_enum_items(prop, bgpic_camera_frame_items); RNA_def_property_ui_text(prop, "Frame Method", "How the image fits in the camera frame"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + RNA_define_lib_overridable(false); } static void rna_def_camera_background_images(BlenderRNA *brna, PropertyRNA *cprop) @@ -356,6 +360,8 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna) RNA_def_struct_nested(brna, srna, "Camera"); RNA_def_struct_ui_text(srna, "Stereo", "Stereoscopy settings for a Camera data-block"); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "convergence_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, convergence_mode_items); RNA_def_property_ui_text(prop, "Mode", ""); @@ -409,6 +415,8 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Pole Merge End Angle", "Angle at which interocular distance is 0"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + RNA_define_lib_overridable(false); } static void rna_def_camera_dof_settings_data(BlenderRNA *brna) @@ -421,6 +429,8 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_CameraDOFSettings_path"); RNA_def_struct_ui_text(srna, "Depth of Field", "Depth of Field settings"); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_DOF_ENABLED); RNA_def_property_ui_text(prop, "Depth of Field", "Use Depth of Field"); @@ -469,6 +479,8 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna) RNA_def_property_range(prop, 0.01f, FLT_MAX); RNA_def_property_ui_range(prop, 1.0f, 2.0f, 0.1, 3); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update"); + + RNA_define_lib_overridable(false); } void RNA_def_camera(BlenderRNA *brna) @@ -505,6 +517,8 @@ void RNA_def_camera(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Camera", "Camera data-block for storing camera settings"); RNA_def_struct_ui_icon(srna, ICON_CAMERA_DATA); + RNA_define_lib_overridable(true); + /* Enums */ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_type_items); @@ -736,6 +750,8 @@ void RNA_def_camera(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Background Images", "List of background images"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + RNA_define_lib_overridable(false); + rna_def_animdata_common(srna); rna_def_camera_background_image(brna); diff --git a/source/blender/makesrna/intern/rna_collection.c b/source/blender/makesrna/intern/rna_collection.c index fe64ead3f89..fbc2b871026 100644 --- a/source/blender/makesrna/intern/rna_collection.c +++ b/source/blender/makesrna/intern/rna_collection.c @@ -394,6 +394,8 @@ void RNA_def_collections(BlenderRNA *brna) * removed if no objects are in the collection and not in a scene. */ RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "instance_offset", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_ui_text( prop, "Instance Offset", "Offset from the origin to use when instancing"); @@ -402,7 +404,6 @@ void RNA_def_collections(BlenderRNA *brna) prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Collection_objects_override_apply"); RNA_def_property_ui_text(prop, "Objects", "Objects that are directly in this collection"); RNA_def_property_collection_funcs(prop, @@ -421,6 +422,7 @@ void RNA_def_collections(BlenderRNA *brna) RNA_def_property_ui_text( prop, "All Objects", "Objects that are in this collection and its child collections"); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_collection_funcs(prop, "rna_Collection_all_objects_begin", "rna_iterator_listbase_next", @@ -433,7 +435,6 @@ void RNA_def_collections(BlenderRNA *brna) prop = RNA_def_property(srna, "children", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Collection"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Collection_children_override_apply"); RNA_def_property_ui_text( prop, "Children", "Collections that are immediate children of this collection"); @@ -452,7 +453,6 @@ void RNA_def_collections(BlenderRNA *brna) prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_SELECT); RNA_def_property_boolean_funcs(prop, NULL, "rna_Collection_hide_select_set"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, -1); RNA_def_property_ui_text(prop, "Disable Selection", "Disable selection in viewport"); @@ -461,7 +461,6 @@ void RNA_def_collections(BlenderRNA *brna) prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_VIEWPORT); RNA_def_property_boolean_funcs(prop, NULL, "rna_Collection_hide_viewport_set"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1); RNA_def_property_ui_text(prop, "Disable in Viewports", "Globally disable in viewports"); @@ -470,11 +469,12 @@ void RNA_def_collections(BlenderRNA *brna) prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_RENDER); RNA_def_property_boolean_funcs(prop, NULL, "rna_Collection_hide_render_set"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, -1); RNA_def_property_ui_text(prop, "Disable in Renders", "Globally disable in renders"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update"); + + RNA_define_lib_overridable(false); } #endif diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 9f627f9d407..12265a8e1f7 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -389,7 +389,7 @@ static void rna_Constraint_name_set(PointerRNA *ptr, const char *value) /* make sure name is unique */ if (ptr->owner_id) { Object *ob = (Object *)ptr->owner_id; - ListBase *list = get_constraint_lb(ob, con, NULL); + ListBase *list = ED_object_constraint_list_from_constraint(ob, con, NULL); /* if we have the list, check for unique name, otherwise give up */ if (list) { @@ -404,7 +404,7 @@ static void rna_Constraint_name_set(PointerRNA *ptr, const char *value) static char *rna_Constraint_do_compute_path(Object *ob, bConstraint *con) { bPoseChannel *pchan; - ListBase *lb = get_constraint_lb(ob, con, &pchan); + ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, &pchan); if (lb == NULL) { printf("%s: internal error, constraint '%s' not found in object '%s'\n", @@ -824,6 +824,8 @@ static void rna_def_constraint_headtail_common(StructRNA *srna) { PropertyRNA *prop; + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, "bConstraint", "headtail"); RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1"); @@ -835,23 +837,28 @@ static void rna_def_constraint_headtail_common(StructRNA *srna) "Follow B-Bone", "Follow shape of B-Bone segments when calculating Head/Tail position"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_target_common(StructRNA *srna) { PropertyRNA *prop; + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "tar"); RNA_def_property_ui_text(prop, "Target", "Target object"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop = RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "subtarget"); RNA_def_property_ui_text(prop, "Sub-Target", "Armature bone, mesh or lattice vertex group, ..."); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constrainttarget(BlenderRNA *brna) @@ -864,11 +871,12 @@ static void rna_def_constrainttarget(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_ConstraintTarget_path"); RNA_def_struct_sdna(srna, "bConstraintTarget"); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "tar"); RNA_def_property_ui_text(prop, "Target", "Target object"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update( prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_dependency_update"); @@ -879,6 +887,8 @@ static void rna_def_constrainttarget(BlenderRNA *brna) prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_dependency_update"); /* space, flag and type still to do */ + + RNA_define_lib_overridable(false); } static void rna_def_constrainttarget_bone(BlenderRNA *brna) @@ -892,13 +902,14 @@ static void rna_def_constrainttarget_bone(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_ConstraintTarget_path"); RNA_def_struct_sdna(srna, "bConstraintTarget"); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "tar"); RNA_def_property_ui_text(prop, "Target", "Target armature"); RNA_def_property_pointer_funcs( prop, NULL, "rna_ConstraintTargetBone_target_set", NULL, "rna_Armature_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update( prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_dependency_update"); @@ -913,6 +924,8 @@ static void rna_def_constrainttarget_bone(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Blend Weight", "Blending weight of this bone"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_childof(BlenderRNA *brna) @@ -928,6 +941,8 @@ static void rna_def_constraint_childof(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_location_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CHILDOF_LOCX); RNA_def_property_ui_text(prop, "Location X", "Use X Location of Parent"); @@ -985,6 +1000,8 @@ static void rna_def_constraint_childof(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Inverse Matrix", "Transformation matrix to apply before"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_python(BlenderRNA *brna) @@ -996,6 +1013,8 @@ static void rna_def_constraint_python(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Python Constraint", "Use Python script for constraint evaluation"); RNA_def_struct_sdna_from(srna, "bPythonConstraint", "data"); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "targets", NULL); RNA_def_property_struct_type(prop, "ConstraintTarget"); @@ -1021,6 +1040,8 @@ static void rna_def_constraint_python(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", PYCON_SCRIPTERROR); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Script Error", "The linked Python script has thrown an error"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_armature_deform_targets(BlenderRNA *brna, PropertyRNA *cprop) @@ -1065,11 +1086,12 @@ static void rna_def_constraint_armature_deform(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bArmatureConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_ARMATURE); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "targets", NULL); RNA_def_property_struct_type(prop, "ConstraintTargetBone"); RNA_def_property_ui_text(prop, "Targets", "Target Bones"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); rna_def_constraint_armature_deform_targets(brna, prop); prop = RNA_def_property(srna, "use_deform_preserve_volume", PROP_BOOLEAN, PROP_NONE); @@ -1095,6 +1117,8 @@ static void rna_def_constraint_armature_deform(BlenderRNA *brna) "Use the current bone location for envelopes and choosing B-Bone " "segments instead of rest position"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_kinematic(BlenderRNA *brna) @@ -1121,6 +1145,8 @@ static void rna_def_constraint_kinematic(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "Iterations", "Maximum number of solving iterations"); @@ -1130,7 +1156,6 @@ static void rna_def_constraint_kinematic(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "poletar"); RNA_def_property_ui_text(prop, "Pole Target", "Object for pole rotation"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop = RNA_def_property(srna, "pole_subtarget", PROP_STRING, PROP_NONE); @@ -1240,6 +1265,8 @@ static void rna_def_constraint_kinematic(BlenderRNA *brna) RNA_def_property_range(prop, 0.0, 100.f); RNA_def_property_ui_text(prop, "Distance", "Radius of limiting sphere"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_track_to(BlenderRNA *brna) @@ -1266,6 +1293,8 @@ static void rna_def_constraint_track_to(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_CON_TRACKTO); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "reserved1"); RNA_def_property_enum_items(prop, track_axis_items); @@ -1283,6 +1312,8 @@ static void rna_def_constraint_track_to(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Target Z", "Target's Z axis, not World Z axis, will constraint the Up direction"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_locate_like(BlenderRNA *brna) @@ -1300,6 +1331,8 @@ static void rna_def_constraint_locate_like(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LOCLIKE_X); RNA_def_property_ui_text(prop, "Copy X", "Copy the target's X location"); @@ -1334,6 +1367,8 @@ static void rna_def_constraint_locate_like(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", LOCLIKE_OFFSET); RNA_def_property_ui_text(prop, "Offset", "Add original location into copied location"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_rotate_like(BlenderRNA *brna) @@ -1370,6 +1405,8 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ROTLIKE_X); RNA_def_property_ui_text(prop, "Copy X", "Copy the target's X rotation"); @@ -1420,6 +1457,8 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Offset", "DEPRECATED: Add original rotation into copied rotation"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_size_like(BlenderRNA *brna) @@ -1434,6 +1473,8 @@ static void rna_def_constraint_size_like(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SIZELIKE_X); RNA_def_property_ui_text(prop, "Copy X", "Copy the target's X scale"); @@ -1476,6 +1517,8 @@ static void rna_def_constraint_size_like(BlenderRNA *brna) "Additive", "Use addition instead of multiplication to combine scale (2.7 compatibility)"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_same_volume(BlenderRNA *brna) @@ -1518,6 +1561,8 @@ static void rna_def_constraint_same_volume(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bSameVolumeConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_SAMEVOL); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "free_axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "free_axis"); RNA_def_property_enum_items(prop, axis_items); @@ -1535,6 +1580,8 @@ static void rna_def_constraint_same_volume(BlenderRNA *brna) RNA_def_property_range(prop, 0.001f, 100.0f); RNA_def_property_ui_text(prop, "Volume", "Volume of the bone at rest"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_transform_like(BlenderRNA *brna) @@ -1575,12 +1622,16 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mix_mode"); RNA_def_property_enum_items(prop, mix_mode_items); RNA_def_property_ui_text( prop, "Mix Mode", "Specify how the copied and existing transformations are combined"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_minmax(BlenderRNA *brna) @@ -1606,6 +1657,8 @@ static void rna_def_constraint_minmax(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "floor_location", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "minmaxflag"); RNA_def_property_enum_items(prop, minmax_items); @@ -1622,6 +1675,8 @@ static void rna_def_constraint_minmax(BlenderRNA *brna) RNA_def_property_ui_range(prop, -100.0f, 100.0f, 1, -1); RNA_def_property_ui_text(prop, "Offset", "Offset of floor from object origin"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_action(BlenderRNA *brna) @@ -1673,6 +1728,8 @@ static void rna_def_constraint_action(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mix_mode"); RNA_def_property_enum_items(prop, mix_mode_items); @@ -1697,7 +1754,6 @@ static void rna_def_constraint_action(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Action_id_poll"); RNA_def_property_ui_text(prop, "Action", "The constraining action"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); prop = RNA_def_property(srna, "use_bone_object_action", PROP_BOOLEAN, PROP_NONE); @@ -1733,6 +1789,8 @@ static void rna_def_constraint_action(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Minimum", "Minimum value for target channel range"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_ActionConstraint_minmax_range"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_locked_track(BlenderRNA *brna) @@ -1760,6 +1818,8 @@ static void rna_def_constraint_locked_track(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "trackflag"); RNA_def_property_enum_items(prop, track_axis_items); @@ -1771,6 +1831,8 @@ static void rna_def_constraint_locked_track(BlenderRNA *brna) RNA_def_property_enum_items(prop, lock_items); RNA_def_property_ui_text(prop, "Locked Axis", "Axis that points upward"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_follow_path(BlenderRNA *brna) @@ -1800,12 +1862,13 @@ static void rna_def_constraint_follow_path(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bFollowPathConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_FOLLOWPATH); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "tar"); RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Curve_object_poll"); RNA_def_property_ui_text(prop, "Target", "Target Curve object"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_TIME); @@ -1852,6 +1915,8 @@ static void rna_def_constraint_follow_path(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "followflag", FOLLOWPATH_RADIUS); RNA_def_property_ui_text(prop, "Curve Radius", "Object is scaled by the curve radius"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_stretch_to(BlenderRNA *brna) @@ -1888,6 +1953,8 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "volume", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "volmode"); RNA_def_property_enum_items(prop, volume_items); @@ -1941,6 +2008,8 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Volume Variation Smoothness", "Strength of volume stretching clamping"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_clamp_to(BlenderRNA *brna) @@ -1964,12 +2033,13 @@ static void rna_def_constraint_clamp_to(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bClampToConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_CLAMPTO); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "tar"); RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Curve_object_poll"); RNA_def_property_ui_text(prop, "Target", "Target Object (Curves only)"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop = RNA_def_property(srna, "main_axis", PROP_ENUM, PROP_NONE); @@ -1983,6 +2053,8 @@ static void rna_def_constraint_clamp_to(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Cyclic", "Treat curve as cyclic curve (no clamping to curve bounding box)"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_transform(BlenderRNA *brna) @@ -2033,6 +2105,8 @@ static void rna_def_constraint_transform(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "map_from", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "from"); RNA_def_property_enum_items(prop, transform_items); @@ -2323,6 +2397,8 @@ static void rna_def_constraint_transform(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Scale Mix Mode", "Specify how to combine the new scale with original"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_location_limit(BlenderRNA *brna) @@ -2336,6 +2412,8 @@ static void rna_def_constraint_location_limit(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bLocLimitConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_LOCLIMIT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_min_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LIMIT_XMIN); RNA_def_property_ui_text(prop, "Minimum X", "Use the minimum X value"); @@ -2407,6 +2485,8 @@ static void rna_def_constraint_location_limit(BlenderRNA *brna) RNA_def_property_ui_text( prop, "For Transform", "Transforms are affected by this constraint as well"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_rotation_limit(BlenderRNA *brna) @@ -2420,6 +2500,8 @@ static void rna_def_constraint_rotation_limit(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bRotLimitConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_ROTLIMIT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_limit_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LIMIT_XROT); RNA_def_property_ui_text(prop, "Limit X", "Use the minimum X value"); @@ -2476,6 +2558,8 @@ static void rna_def_constraint_rotation_limit(BlenderRNA *brna) RNA_def_property_ui_text( prop, "For Transform", "Transforms are affected by this constraint as well"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_size_limit(BlenderRNA *brna) @@ -2489,6 +2573,8 @@ static void rna_def_constraint_size_limit(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bSizeLimitConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_SIZELIMIT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_min_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LIMIT_XMIN); RNA_def_property_ui_text(prop, "Minimum X", "Use the minimum X value"); @@ -2560,6 +2646,8 @@ static void rna_def_constraint_size_limit(BlenderRNA *brna) RNA_def_property_ui_text( prop, "For Transform", "Transforms are affected by this constraint as well"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_distance_limit(BlenderRNA *brna) @@ -2578,6 +2666,8 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "dist"); RNA_def_property_ui_range(prop, 0.0f, 100.0f, 10, 3); @@ -2596,6 +2686,8 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna) RNA_def_property_ui_text( prop, "For Transform", "Transforms are affected by this constraint as well"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_shrinkwrap(BlenderRNA *brna) @@ -2649,12 +2741,13 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bShrinkwrapConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_SHRINKWRAP); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "target"); /* TODO, mesh type */ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Mesh_object_poll"); RNA_def_property_ui_text(prop, "Target", "Target Mesh object"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop = RNA_def_property(srna, "shrinkwrap_type", PROP_ENUM, PROP_NONE); @@ -2734,6 +2827,8 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna) RNA_def_property_enum_items(prop, track_axis_items); RNA_def_property_ui_text(prop, "Track Axis", "Axis that is aligned to the normal"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_damped_track(BlenderRNA *brna) @@ -2752,11 +2847,15 @@ static void rna_def_constraint_damped_track(BlenderRNA *brna) rna_def_constraint_target_common(srna); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "trackflag"); RNA_def_property_enum_items(prop, track_axis_items); RNA_def_property_ui_text(prop, "Track Axis", "Axis that points to the target object"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_spline_ik(BlenderRNA *brna) @@ -2804,13 +2903,14 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bSplineIKConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_SPLINEIK); + RNA_define_lib_overridable(true); + /* target chain */ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "tar"); RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Curve_object_poll"); RNA_def_property_ui_text(prop, "Target", "Curve that controls this relationship"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop = RNA_def_property(srna, "chain_count", PROP_INT, PROP_NONE); @@ -2922,6 +3022,8 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Volume Variation Smoothness", "Strength of volume stretching clamping"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_pivot(BlenderRNA *brna) @@ -2973,13 +3075,14 @@ static void rna_def_constraint_pivot(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_CON_PIVOT); + RNA_define_lib_overridable(true); + /* target-defined pivot */ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "tar"); RNA_def_property_ui_text( prop, "Target", "Target Object, defining the position of the pivot when defined"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop = RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE); @@ -3011,6 +3114,8 @@ static void rna_def_constraint_pivot(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Enabled Rotation Range", "Rotation range on which pivoting should occur"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_follow_track(BlenderRNA *brna) @@ -3031,12 +3136,13 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bFollowTrackConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_FOLLOWTRACK); + RNA_define_lib_overridable(true); + /* movie clip */ prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "clip"); RNA_def_property_ui_text(prop, "Movie Clip", "Movie Clip to get tracking data from"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); /* track */ @@ -3070,7 +3176,6 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Camera", "Camera to which motion is parented (if empty active scene camera is used)"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); RNA_def_property_pointer_funcs(prop, NULL, @@ -3086,7 +3191,6 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna) "Depth Object", "Object used to define depth in camera space by projecting onto surface of this object"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); RNA_def_property_pointer_funcs(prop, NULL, @@ -3106,6 +3210,8 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", FOLLOWTRACK_USE_UNDISTORTION); RNA_def_property_ui_text(prop, "Undistort", "Parent to undistorted position of 2D track"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_camera_solver(BlenderRNA *brna) @@ -3119,12 +3225,13 @@ static void rna_def_constraint_camera_solver(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bCameraSolverConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_CAMERASOLVER); + RNA_define_lib_overridable(true); + /* movie clip */ prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "clip"); RNA_def_property_ui_text(prop, "Movie Clip", "Movie Clip to get tracking data from"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); /* use default clip */ @@ -3132,6 +3239,8 @@ static void rna_def_constraint_camera_solver(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", CAMERASOLVER_ACTIVECLIP); RNA_def_property_ui_text(prop, "Active Clip", "Use active clip defined in scene"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_object_solver(BlenderRNA *brna) @@ -3145,12 +3254,13 @@ static void rna_def_constraint_object_solver(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bObjectSolverConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_OBJECTSOLVER); + RNA_define_lib_overridable(true); + /* movie clip */ prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "clip"); RNA_def_property_ui_text(prop, "Movie Clip", "Movie Clip to get tracking data from"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); /* use default clip */ @@ -3177,13 +3287,14 @@ static void rna_def_constraint_object_solver(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Camera", "Camera to which motion is parented (if empty active scene camera is used)"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Constraint_objectSolver_camera_set", NULL, "rna_Constraint_cameraObject_poll"); + + RNA_define_lib_overridable(false); } static void rna_def_constraint_transform_cache(BlenderRNA *brna) @@ -3197,12 +3308,13 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bTransformCacheConstraint", "data"); RNA_def_struct_ui_icon(srna, ICON_CON_TRANSFORM_CACHE); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "cache_file", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "cache_file"); RNA_def_property_struct_type(prop, "CacheFile"); RNA_def_property_ui_text(prop, "Cache File", ""); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Constraint_dependency_update"); prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE); @@ -3211,6 +3323,8 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna) "Object Path", "Path to the object in the Alembic archive used to lookup the transform matrix"); RNA_def_property_update(prop, 0, "rna_Constraint_update"); + + RNA_define_lib_overridable(false); } /* base struct for constraints */ @@ -3241,6 +3355,8 @@ void RNA_def_constraint(BlenderRNA *brna) RNA_def_property_enum_items(prop, rna_enum_constraint_type_items); RNA_def_property_ui_text(prop, "Type", ""); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "owner_space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "ownspace"); RNA_def_property_enum_items(prop, owner_space_pchan_items); @@ -3258,7 +3374,6 @@ void RNA_def_constraint(BlenderRNA *brna) /* flags */ prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_OFF); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Disable", "Enable/Disable Constraint"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1); @@ -3267,7 +3382,6 @@ void RNA_def_constraint(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); RNA_def_property_boolean_sdna(prop, NULL, "ui_expand_flag", 0); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); - RNA_def_property_ui_text(prop, "Expanded", "Constraint's panel is expanded in UI"); RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1); /* XXX this is really an internal flag, @@ -3315,6 +3429,8 @@ void RNA_def_constraint(BlenderRNA *brna) "Rot error", "Amount of residual error in radians for constraints that work on orientation"); + RNA_define_lib_overridable(false); + /* pointers */ rna_def_constrainttarget(brna); rna_def_constrainttarget_bone(brna); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 7a439a11a54..d6bedc61424 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -61,7 +61,18 @@ static CLG_LogRef LOG = {"rna.define"}; /* Global used during defining */ -BlenderDefRNA DefRNA = {NULL, {NULL, NULL}, {NULL, NULL}, NULL, 0, 0, 0, 1, 1}; +BlenderDefRNA DefRNA = { + .sdna = NULL, + .structs = {NULL, NULL}, + .allocs = {NULL, NULL}, + .laststruct = NULL, + .error = 0, + .silent = false, + .preprocess = false, + .verify = true, + .animate = true, + .make_overridable = false, +}; #ifndef RNA_RUNTIME static struct { @@ -691,13 +702,13 @@ BlenderRNA *RNA_create(void) BLI_listbase_clear(&DefRNA.structs); brna->structs_map = BLI_ghash_str_new_ex(__func__, 2048); - DefRNA.error = 0; - DefRNA.preprocess = 1; + DefRNA.error = false; + DefRNA.preprocess = true; DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false, &error_message); if (DefRNA.sdna == NULL) { CLOG_ERROR(&LOG, "Failed to decode SDNA: %s.", error_message); - DefRNA.error = 1; + DefRNA.error = true; } /* We need both alias and static (on-disk) DNA names. */ @@ -737,7 +748,7 @@ void RNA_define_free(BlenderRNA *UNUSED(brna)) DefRNA.sdna = NULL; } - DefRNA.error = 0; + DefRNA.error = false; } void RNA_define_verify_sdna(bool verify) @@ -745,6 +756,15 @@ void RNA_define_verify_sdna(bool verify) DefRNA.verify = verify; } +/** + * Properties defined when this is enabled are lib-overridable by default (except for Pointer + * ones). + */ +void RNA_define_lib_overridable(const bool make_overridable) +{ + DefRNA.make_overridable = make_overridable; +} + #ifndef RNA_RUNTIME void RNA_define_animate_sdna(bool animate) { @@ -910,7 +930,7 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN if (rna_validate_identifier(identifier, error, false) == 0) { CLOG_ERROR(&LOG, "struct identifier \"%s\" error - %s", identifier, error); - DefRNA.error = 1; + DefRNA.error = true; } } @@ -1040,7 +1060,7 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char * srnafrom = BLI_ghash_lookup(brna->structs_map, from); if (!srnafrom) { CLOG_ERROR(&LOG, "struct %s not found to define %s.", from, identifier); - DefRNA.error = 1; + DefRNA.error = true; } } @@ -1065,7 +1085,7 @@ void RNA_def_struct_sdna(StructRNA *srna, const char *structname) if (DNA_struct_find_nr_wrapper(DefRNA.sdna, structname) == -1) { if (!DefRNA.silent) { CLOG_ERROR(&LOG, "%s not found.", structname); - DefRNA.error = 1; + DefRNA.error = true; } return; } @@ -1093,7 +1113,7 @@ void RNA_def_struct_sdna_from(StructRNA *srna, const char *structname, const cha if (DNA_struct_find_nr_wrapper(DefRNA.sdna, structname) == -1) { if (!DefRNA.silent) { CLOG_ERROR(&LOG, "%s not found.", structname); - DefRNA.error = 1; + DefRNA.error = true; } return; } @@ -1106,7 +1126,7 @@ void RNA_def_struct_name_property(struct StructRNA *srna, struct PropertyRNA *pr { if (prop->type != PROP_STRING) { CLOG_ERROR(&LOG, "\"%s.%s\", must be a string property.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } else { srna->nameproperty = prop; @@ -1121,7 +1141,7 @@ void RNA_def_struct_nested(BlenderRNA *brna, StructRNA *srna, const char *struct srnafrom = BLI_ghash_lookup(brna->structs_map, structname); if (!srnafrom) { CLOG_ERROR(&LOG, "struct %s not found for %s.", structname, srna->identifier); - DefRNA.error = 1; + DefRNA.error = true; } srna->nested = srnafrom; @@ -1271,7 +1291,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, if (rna_validate_identifier(identifier, error, true) == 0) { CLOG_ERROR( &LOG, "property identifier \"%s.%s\" - %s", CONTAINER_RNA_ID(cont), identifier, error); - DefRNA.error = 1; + DefRNA.error = true; } dcont = rna_find_container_def(cont); @@ -1279,7 +1299,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, /* XXX - toto, detect supertype collisions */ if (rna_findlink(&dcont->properties, identifier)) { CLOG_ERROR(&LOG, "duplicate identifier \"%s.%s\"", CONTAINER_RNA_ID(cont), identifier); - DefRNA.error = 1; + DefRNA.error = true; } dprop = MEM_callocN(sizeof(PropertyDefRNA), "PropertyDefRNA"); @@ -1294,7 +1314,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, CONTAINER_RNA_ID(cont), identifier, error); - DefRNA.error = 1; + DefRNA.error = true; } #endif } @@ -1309,7 +1329,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, "subtype does not apply to 'PROP_BOOLEAN' \"%s.%s\"", CONTAINER_RNA_ID(cont), identifier); - DefRNA.error = 1; + DefRNA.error = true; } } break; @@ -1322,7 +1342,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, "subtype does not apply to 'PROP_INT' \"%s.%s\"", CONTAINER_RNA_ID(cont), identifier); - DefRNA.error = 1; + DefRNA.error = true; } #endif @@ -1371,7 +1391,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, break; default: CLOG_ERROR(&LOG, "\"%s.%s\", invalid property type.", CONTAINER_RNA_ID(cont), identifier); - DefRNA.error = 1; + DefRNA.error = true; return NULL; } @@ -1404,6 +1424,12 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, } } +#ifndef RNA_RUNTIME + if (DefRNA.make_overridable) { + prop->flag_override |= PROPOVERRIDE_OVERRIDABLE_LIBRARY; + } +#endif + if (type == PROP_STRING) { /* used so generated 'get/length/set' functions skip a NULL check * in some cases we want it */ @@ -1413,42 +1439,42 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, if (DefRNA.preprocess) { switch (type) { case PROP_BOOLEAN: - DefRNA.silent = 1; + DefRNA.silent = true; RNA_def_property_boolean_sdna(prop, NULL, identifier, 0); - DefRNA.silent = 0; + DefRNA.silent = false; break; case PROP_INT: { - DefRNA.silent = 1; + DefRNA.silent = true; RNA_def_property_int_sdna(prop, NULL, identifier); - DefRNA.silent = 0; + DefRNA.silent = false; break; } case PROP_FLOAT: { - DefRNA.silent = 1; + DefRNA.silent = true; RNA_def_property_float_sdna(prop, NULL, identifier); - DefRNA.silent = 0; + DefRNA.silent = false; break; } case PROP_STRING: { - DefRNA.silent = 1; + DefRNA.silent = true; RNA_def_property_string_sdna(prop, NULL, identifier); - DefRNA.silent = 0; + DefRNA.silent = false; break; } case PROP_ENUM: - DefRNA.silent = 1; + DefRNA.silent = true; RNA_def_property_enum_sdna(prop, NULL, identifier); - DefRNA.silent = 0; + DefRNA.silent = false; break; case PROP_POINTER: - DefRNA.silent = 1; + DefRNA.silent = true; RNA_def_property_pointer_sdna(prop, NULL, identifier); - DefRNA.silent = 0; + DefRNA.silent = false; break; case PROP_COLLECTION: - DefRNA.silent = 1; + DefRNA.silent = true; RNA_def_property_collection_sdna(prop, NULL, identifier, NULL); - DefRNA.silent = 0; + DefRNA.silent = false; break; } } @@ -1543,7 +1569,7 @@ void RNA_def_property_array(PropertyRNA *prop, int length) "\"%s.%s\", array length must be zero of greater.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return; } @@ -1553,7 +1579,7 @@ void RNA_def_property_array(PropertyRNA *prop, int length) srna->identifier, prop->identifier, RNA_MAX_ARRAY_LENGTH); - DefRNA.error = 1; + DefRNA.error = true; return; } @@ -1563,7 +1589,7 @@ void RNA_def_property_array(PropertyRNA *prop, int length) srna->identifier, prop->identifier, prop->arraydimension); - DefRNA.error = 1; + DefRNA.error = true; return; } @@ -1580,7 +1606,7 @@ void RNA_def_property_array(PropertyRNA *prop, int length) "\"%s.%s\", only boolean/int/float can be array.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1606,7 +1632,7 @@ void RNA_def_property_multi_array(PropertyRNA *prop, int dimension, const int le srna->identifier, prop->identifier, RNA_MAX_ARRAY_DIMENSION); - DefRNA.error = 1; + DefRNA.error = true; return; } @@ -1620,7 +1646,7 @@ void RNA_def_property_multi_array(PropertyRNA *prop, int dimension, const int le "\"%s.%s\", only boolean/int/float can be array.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } @@ -1680,22 +1706,22 @@ void RNA_def_property_ui_range( #ifndef NDEBUG if (min > max) { CLOG_ERROR(&LOG, "\"%s.%s\", min > max.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } if (step < 0 || step > 100) { CLOG_ERROR(&LOG, "\"%s.%s\", step outside range.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } if (step == 0) { CLOG_ERROR(&LOG, "\"%s.%s\", step is zero.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) { CLOG_ERROR(&LOG, "\"%s.%s\", precision outside range.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } #endif @@ -1718,7 +1744,7 @@ void RNA_def_property_ui_range( default: CLOG_ERROR( &LOG, "\"%s.%s\", invalid type for ui range.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1730,7 +1756,7 @@ void RNA_def_property_range(PropertyRNA *prop, double min, double max) #ifdef DEBUG if (min > max) { CLOG_ERROR(&LOG, "\"%s.%s\", min > max.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } #endif @@ -1753,7 +1779,7 @@ void RNA_def_property_range(PropertyRNA *prop, double min, double max) } default: CLOG_ERROR(&LOG, "\"%s.%s\", invalid type for range.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1781,7 +1807,7 @@ void RNA_def_property_struct_type(PropertyRNA *prop, const char *type) default: CLOG_ERROR( &LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1814,7 +1840,7 @@ void RNA_def_property_struct_runtime(PropertyRNA *prop, StructRNA *type) default: CLOG_ERROR( &LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1831,7 +1857,7 @@ void RNA_def_property_enum_native_type(PropertyRNA *prop, const char *native_enu default: CLOG_ERROR( &LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1856,7 +1882,7 @@ void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item "\"%s.%s\", enum identifiers must not contain spaces.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } else if (item[i].value == eprop->defaultvalue) { @@ -1879,7 +1905,7 @@ void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item default: CLOG_ERROR( &LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1896,7 +1922,7 @@ void RNA_def_property_string_maxlength(PropertyRNA *prop, int maxlength) } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1920,7 +1946,7 @@ void RNA_def_property_boolean_default(PropertyRNA *prop, bool value) } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1937,7 +1963,7 @@ void RNA_def_property_boolean_array_default(PropertyRNA *prop, const bool *array } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1959,7 +1985,7 @@ void RNA_def_property_int_default(PropertyRNA *prop, int value) } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -1981,7 +2007,7 @@ void RNA_def_property_int_array_default(PropertyRNA *prop, const int *array) } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -2003,7 +2029,7 @@ void RNA_def_property_float_default(PropertyRNA *prop, float value) } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -2025,7 +2051,7 @@ void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array) } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -2043,7 +2069,7 @@ void RNA_def_property_string_default(PropertyRNA *prop, const char *value) "\"%s.%s\", NULL string passed (dont call in this case).", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } @@ -2052,7 +2078,7 @@ void RNA_def_property_string_default(PropertyRNA *prop, const char *value) "\"%s.%s\", empty string passed (dont call in this case).", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; // BLI_assert(0); break; } @@ -2066,7 +2092,7 @@ void RNA_def_property_string_default(PropertyRNA *prop, const char *value) } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -2096,7 +2122,7 @@ void RNA_def_property_enum_default(PropertyRNA *prop, int value) srna->identifier, prop->identifier, eprop->defaultvalue & ~totflag); - DefRNA.error = 1; + DefRNA.error = true; } } else { @@ -2113,7 +2139,7 @@ void RNA_def_property_enum_default(PropertyRNA *prop, int value) else { CLOG_ERROR( &LOG, "\"%s.%s\", default is not in items.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; } } } @@ -2122,7 +2148,7 @@ void RNA_def_property_enum_default(PropertyRNA *prop, int value) } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -2175,7 +2201,7 @@ static PropertyDefRNA *rna_def_property_sdna(PropertyRNA *prop, structname, propname, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return NULL; } } @@ -2219,13 +2245,13 @@ void RNA_def_property_boolean_sdna(PropertyRNA *prop, if (prop->type != PROP_BOOLEAN) { CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return; } if ((dp = rna_def_property_sdna(prop, structname, propname))) { - if (DefRNA.silent == 0) { + if (!DefRNA.silent) { /* error check to ensure floats are not wrapped as ints/bools */ if (dp->dnatype && *dp->dnatype && IS_DNATYPE_BOOLEAN_COMPAT(dp->dnatype) == 0) { CLOG_ERROR(&LOG, @@ -2234,7 +2260,7 @@ void RNA_def_property_boolean_sdna(PropertyRNA *prop, prop->identifier, dp->dnatype, RNA_property_typename(prop->type)); - DefRNA.error = 1; + DefRNA.error = true; return; } } @@ -2323,14 +2349,14 @@ void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const if (prop->type != PROP_INT) { CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return; } if ((dp = rna_def_property_sdna(prop, structname, propname))) { /* error check to ensure floats are not wrapped as ints/bools */ - if (DefRNA.silent == 0) { + if (!DefRNA.silent) { if (dp->dnatype && *dp->dnatype && IS_DNATYPE_INT_COMPAT(dp->dnatype) == 0) { CLOG_ERROR(&LOG, "%s.%s is a '%s' but wrapped as type '%s'.", @@ -2338,7 +2364,7 @@ void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const prop->identifier, dp->dnatype, RNA_property_typename(prop->type)); - DefRNA.error = 1; + DefRNA.error = true; return; } } @@ -2470,13 +2496,13 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons if (prop->type != PROP_FLOAT) { CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return; } if ((dp = rna_def_property_sdna(prop, structname, propname))) { /* silent is for internal use */ - if (DefRNA.silent == 0) { + if (!DefRNA.silent) { if (dp->dnatype && *dp->dnatype && IS_DNATYPE_FLOAT_COMPAT(dp->dnatype) == 0) { /* Colors are an exception. these get translated. */ if (prop->subtype != PROP_COLOR_GAMMA) { @@ -2486,7 +2512,7 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons prop->identifier, dp->dnatype, RNA_property_typename(prop->type)); - DefRNA.error = 1; + DefRNA.error = true; return; } } @@ -2578,7 +2604,7 @@ void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const if (prop->type != PROP_ENUM) { CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return; } @@ -2589,7 +2615,7 @@ void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const if (!DefRNA.silent) { CLOG_ERROR(&LOG, "\"%s.%s\", array not supported for enum type.", structname, propname); - DefRNA.error = 1; + DefRNA.error = true; } } @@ -2672,7 +2698,7 @@ void RNA_def_property_string_sdna(PropertyRNA *prop, const char *structname, con if (prop->type != PROP_STRING) { CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return; } @@ -2716,7 +2742,7 @@ void RNA_def_property_pointer_sdna(PropertyRNA *prop, const char *structname, co if (prop->type != PROP_POINTER) { CLOG_ERROR(&LOG, "\"%s.%s\", type is not pointer.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return; } @@ -2727,7 +2753,7 @@ void RNA_def_property_pointer_sdna(PropertyRNA *prop, const char *structname, co if (!DefRNA.silent) { CLOG_ERROR(&LOG, "\"%s.%s\", array not supported for pointer type.", structname, propname); - DefRNA.error = 1; + DefRNA.error = true; } } } @@ -2749,7 +2775,7 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop, if (prop->type != PROP_COLLECTION) { CLOG_ERROR(&LOG, "\"%s.%s\", type is not collection.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; return; } @@ -2760,7 +2786,7 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop, if (!DefRNA.silent) { CLOG_ERROR(&LOG, "\"%s.%s\", array of collections not supported.", structname, propname); - DefRNA.error = 1; + DefRNA.error = true; } } @@ -2806,7 +2832,7 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop, else { if (!DefRNA.silent) { CLOG_ERROR(&LOG, "\"%s.%s\" not found.", structname, lengthpropname); - DefRNA.error = 1; + DefRNA.error = true; } } } @@ -2904,7 +2930,7 @@ void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getleng if (!(prop->flag & PROP_DYNAMIC)) { CLOG_ERROR(&LOG, "property is a not dynamic array."); - DefRNA.error = 1; + DefRNA.error = true; return; } @@ -2946,7 +2972,7 @@ void RNA_def_property_boolean_funcs(PropertyRNA *prop, const char *get, const ch } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -3036,7 +3062,7 @@ void RNA_def_property_int_funcs(PropertyRNA *prop, } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -3134,7 +3160,7 @@ void RNA_def_property_float_funcs(PropertyRNA *prop, } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -3222,7 +3248,7 @@ void RNA_def_property_enum_funcs(PropertyRNA *prop, } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -3289,7 +3315,7 @@ void RNA_def_property_string_funcs(PropertyRNA *prop, } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -3351,7 +3377,7 @@ void RNA_def_property_pointer_funcs( } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not pointer.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -3405,7 +3431,7 @@ void RNA_def_property_collection_funcs(PropertyRNA *prop, } default: CLOG_ERROR(&LOG, "\"%s.%s\", type is not collection.", srna->identifier, prop->identifier); - DefRNA.error = 1; + DefRNA.error = true; break; } } @@ -4170,7 +4196,7 @@ static FunctionRNA *rna_def_function(StructRNA *srna, const char *identifier) if (rna_validate_identifier(identifier, error, false) == 0) { CLOG_ERROR(&LOG, "function identifier \"%s\" - %s", identifier, error); - DefRNA.error = 1; + DefRNA.error = true; } } diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 9fceafd8374..e49186f4cb1 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -579,7 +579,7 @@ static void rna_FCurve_group_set(PointerRNA *ptr, /* calculate time extents of F-Curve */ static void rna_FCurve_range(FCurve *fcu, float range[2]) { - calc_fcurve_range(fcu, range, range + 1, false, false); + BKE_fcurve_calc_range(fcu, range, range + 1, false, false); } static bool rna_FCurve_is_empty_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index 93c7c1f3480..94ba09b2bb8 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -227,8 +227,11 @@ static void rna_Fluid_flip_parts_update(Main *bmain, Scene *scene, PointerRNA *p mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid); bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_FLIP); - /* Only create a particle system in liquid domain mode. */ + /* Only create a particle system in liquid domain mode. + * Remove any remaining data from a liquid sim when switching to gas. */ if (mmd->domain->type != FLUID_DOMAIN_TYPE_LIQUID) { + rna_Fluid_parts_delete(ptr, PART_FLUID_FLIP); + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP; rna_Fluid_domain_reset(bmain, scene, ptr); return; } diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 5f1ff0d8745..a52811a9a9a 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -121,7 +121,7 @@ static const EnumPropertyItem rna_enum_layer_blend_modes_items[] = { {eGplBlendMode_Divide, "DIVIDE", 0, "Divide", ""}, {0, NULL, 0, NULL, NULL}}; -static EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = { +static const EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = { {GP_STROKE_CAP_ROUND, "ROUND", 0, "Rounded", ""}, {GP_STROKE_CAP_FLAT, "FLAT", 0, "Flat", ""}, {0, NULL, 0, NULL, NULL}, diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index cb59eee6afa..44f118a8744 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -118,7 +118,14 @@ typedef struct BlenderDefRNA { ListBase structs; ListBase allocs; struct StructRNA *laststruct; - int error, silent, preprocess, verify, animate; + bool error; + bool silent; + bool preprocess; + bool verify; + bool animate; + /** Whether RNA properties defined should be overridable or not by default. */ + bool make_overridable; + /* Keep last. */ #ifndef RNA_RUNTIME struct { diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c index c19dafb3bc6..2caf315e09e 100644 --- a/source/blender/makesrna/intern/rna_light.c +++ b/source/blender/makesrna/intern/rna_light.c @@ -186,25 +186,45 @@ static void rna_def_light(BlenderRNA *brna) rna_def_animdata_common(srna); } -static void rna_def_light_energy(StructRNA *srna, bool distant) +static void rna_def_light_energy(StructRNA *srna, const short light_type) { PropertyRNA *prop; - if (distant) { - /* Distant light strength has no unit defined, it's proportional to - * Watt/m^2 and is not sensitive to scene unit scale. */ - prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE); - RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); - RNA_def_property_ui_text(prop, "Strength", "Amount of light emitted"); - RNA_def_property_update(prop, 0, "rna_Light_draw_update"); - } - else { - /* Lights with a location have power in Watt, which is sensitive to - * scene unit scale. */ - prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_POWER); - RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5); - RNA_def_property_ui_text(prop, "Power", "Amount of light emitted"); - RNA_def_property_update(prop, 0, "rna_Light_draw_update"); + switch (light_type) { + case LA_SUN: { + /* Distant light strength has no unit defined, + * it's proportional to 'watt/m^2' and is not sensitive to scene unit scale. */ + prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); + RNA_def_property_ui_text( + prop, "Strength", "Sunlight strength in watts per meter squared (W/m^2)"); + RNA_def_property_update(prop, 0, "rna_Light_draw_update"); + break; + } + case LA_SPOT: { + /* Lights with a location have power in Watts, + * which is sensitive to scene unit scale. */ + prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_POWER); + RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5); + RNA_def_property_ui_text(prop, + "Power", + "The energy this light would emit over its entire area " + "if it wasn't limited by the spot angle"); + RNA_def_property_update(prop, 0, "rna_Light_draw_update"); + break; + } + default: { + /* Lights with a location have power in Watts, + * which is sensitive to scene unit scale. */ + prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_POWER); + RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5); + RNA_def_property_ui_text( + prop, + "Power", + "Light energy emitted over the entire area of the light in all directions"); + RNA_def_property_update(prop, 0, "rna_Light_draw_update"); + break; + } } } @@ -395,7 +415,7 @@ static void rna_def_point_light(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Point Light", "Omnidirectional point Light"); RNA_def_struct_ui_icon(srna, ICON_LIGHT_POINT); - rna_def_light_energy(srna, false); + rna_def_light_energy(srna, LA_LOCAL); rna_def_light_falloff(srna); rna_def_light_shadow(srna, false); } @@ -418,7 +438,7 @@ static void rna_def_area_light(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Area Light", "Directional area Light"); RNA_def_struct_ui_icon(srna, ICON_LIGHT_AREA); - rna_def_light_energy(srna, false); + rna_def_light_energy(srna, LA_AREA); rna_def_light_shadow(srna, false); rna_def_light_falloff(srna); @@ -457,7 +477,7 @@ static void rna_def_spot_light(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Spot Light", "Directional cone Light"); RNA_def_struct_ui_icon(srna, ICON_LIGHT_SPOT); - rna_def_light_energy(srna, false); + rna_def_light_energy(srna, LA_SPOT); rna_def_light_falloff(srna); rna_def_light_shadow(srna, false); @@ -503,7 +523,7 @@ static void rna_def_sun_light(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Angle", "Angular diameter of the Sun as seen from the Earth"); RNA_def_property_update(prop, 0, "rna_Light_update"); - rna_def_light_energy(srna, true); + rna_def_light_energy(srna, LA_SUN); rna_def_light_shadow(srna, true); } diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 2e97f97375d..e9b8595ce3c 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1682,6 +1682,8 @@ static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const c PropertyRNA *prop; + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "uv_smooth", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "uv_smooth"); RNA_def_property_enum_items(prop, prop_uv_smooth_items); @@ -1702,6 +1704,8 @@ static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const c RNA_def_property_ui_text(prop, "Subdivision Type", "Select type of subdivision algorithm"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_define_lib_overridable(false); + return prop; } @@ -1717,6 +1721,8 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna) rna_def_property_subdivision_common(srna, "subdivType"); + RNA_define_lib_overridable(true); + /* see CCGSUBSURF_LEVEL_MAX for max limit */ prop = RNA_def_property(srna, "levels", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "levels"); @@ -1743,6 +1749,8 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Use Creases", "Use mesh edge crease information to sharpen edges"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_generic_map_info(StructRNA *srna) @@ -1769,10 +1777,11 @@ static void rna_def_modifier_generic_map_info(StructRNA *srna) PropertyRNA *prop; + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Texture", ""); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE); @@ -1792,13 +1801,14 @@ static void rna_def_modifier_generic_map_info(StructRNA *srna) RNA_def_property_ui_text( prop, "Texture Coordinate Object", "Object to set the texture coordinates"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "texture_coords_bone", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "map_bone"); RNA_def_property_ui_text(prop, "Texture Coordinate Bone", "Bone to set the texture coordinates"); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_warp(BlenderRNA *brna) @@ -1811,11 +1821,12 @@ static void rna_def_modifier_warp(BlenderRNA *brna) RNA_def_struct_sdna(srna, "WarpModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_WARP); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "object_from", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "object_from"); RNA_def_property_ui_text(prop, "Object From", "Object to transform from"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "bone_from", PROP_STRING, PROP_NONE); @@ -1827,7 +1838,6 @@ static void rna_def_modifier_warp(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "object_to"); RNA_def_property_ui_text(prop, "Object To", "Object to transform to"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "bone_to", PROP_STRING, PROP_NONE); @@ -1872,6 +1882,8 @@ static void rna_def_modifier_warp(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_define_lib_overridable(false); + rna_def_modifier_generic_map_info(srna); } @@ -1885,6 +1897,8 @@ static void rna_def_modifier_multires(BlenderRNA *brna) RNA_def_struct_sdna(srna, "MultiresModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_MULTIRES); + RNA_define_lib_overridable(true); + prop = rna_def_property_subdivision_common(srna, "simple"); RNA_def_property_enum_funcs(prop, NULL, "rna_MultiresModifier_type_set", NULL); @@ -1936,6 +1950,8 @@ static void rna_def_modifier_multires(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Use Creases", "Use mesh edge crease information to sharpen edges"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_lattice(BlenderRNA *brna) @@ -1948,12 +1964,13 @@ static void rna_def_modifier_lattice(BlenderRNA *brna) RNA_def_struct_sdna(srna, "LatticeModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_LATTICE); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Lattice object to deform with"); RNA_def_property_pointer_funcs( prop, NULL, "rna_LatticeModifier_object_set", NULL, "rna_Lattice_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); @@ -1975,6 +1992,8 @@ static void rna_def_modifier_lattice(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0, 1, 10, 2); RNA_def_property_ui_text(prop, "Strength", "Strength of modifier effect"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_curve(BlenderRNA *brna) @@ -1997,12 +2016,13 @@ static void rna_def_modifier_curve(BlenderRNA *brna) RNA_def_struct_sdna(srna, "CurveModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_CURVE); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Curve object to deform with"); RNA_def_property_pointer_funcs( prop, NULL, "rna_CurveModifier_object_set", NULL, "rna_Curve_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_CurveModifier_dependency_update"); prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); @@ -2024,6 +2044,8 @@ static void rna_def_modifier_curve(BlenderRNA *brna) RNA_def_property_enum_items(prop, prop_deform_axis_items); RNA_def_property_ui_text(prop, "Deform Axis", "The axis that the curve deforms along"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_build(BlenderRNA *brna) @@ -2036,6 +2058,8 @@ static void rna_def_modifier_build(BlenderRNA *brna) RNA_def_struct_sdna(srna, "BuildModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_BUILD); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_TIME); RNA_def_property_float_sdna(prop, NULL, "start"); RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF); @@ -2062,6 +2086,8 @@ static void rna_def_modifier_build(BlenderRNA *brna) RNA_def_property_range(prop, 1, MAXFRAMEF); RNA_def_property_ui_text(prop, "Seed", "Seed for random if used"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_mirror(BlenderRNA *brna) @@ -2074,6 +2100,8 @@ static void rna_def_modifier_mirror(BlenderRNA *brna) RNA_def_struct_sdna(srna, "MirrorModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_MIRROR); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_axis", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_AXIS_X); RNA_def_property_array(prop, 3); @@ -2172,8 +2200,9 @@ static void rna_def_modifier_mirror(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "mirror_ob"); RNA_def_property_ui_text(prop, "Mirror Object", "Object to use as mirror"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_decimate(BlenderRNA *brna) @@ -2199,6 +2228,8 @@ static void rna_def_modifier_decimate(BlenderRNA *brna) RNA_def_struct_sdna(srna, "DecimateModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_DECIM); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "decimate_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, modifier_decim_mode_items); @@ -2287,6 +2318,8 @@ static void rna_def_modifier_decimate(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( prop, "Face Count", "The current number of faces in the decimated mesh"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_wave(BlenderRNA *brna) @@ -2299,6 +2332,8 @@ static void rna_def_modifier_wave(BlenderRNA *brna) RNA_def_struct_sdna(srna, "WaveModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_WAVE); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WAVE_X); RNA_def_property_ui_text(prop, "X", "X axis motion"); @@ -2382,7 +2417,6 @@ static void rna_def_modifier_wave(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "objectcenter"); RNA_def_property_ui_text(prop, "Start Position Object", "Object which defines the wave center"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); @@ -2426,6 +2460,8 @@ static void rna_def_modifier_wave(BlenderRNA *brna) "the more narrow the wave"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_define_lib_overridable(false); + rna_def_modifier_generic_map_info(srna); } @@ -2439,12 +2475,13 @@ static void rna_def_modifier_armature(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ArmatureModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_ARMATURE); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Armature object to deform with"); RNA_def_property_pointer_funcs( prop, NULL, "rna_ArmatureModifier_object_set", NULL, "rna_Armature_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE); @@ -2486,6 +2523,8 @@ static void rna_def_modifier_armature(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "deformflag", ARM_DEF_INVERT_VGROUP); RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_hook(BlenderRNA *brna) @@ -2501,6 +2540,8 @@ static void rna_def_modifier_hook(BlenderRNA *brna) RNA_def_struct_sdna(srna, "HookModifierData"); RNA_def_struct_ui_icon(srna, ICON_HOOK); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "force"); RNA_def_property_range(prop, 0, 1); @@ -2543,7 +2584,6 @@ static void rna_def_modifier_hook(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Object", "Parent Object for hook, also recalculates and clears offset"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_override_funcs(prop, NULL, NULL, "rna_HookModifier_object_override_apply"); RNA_def_property_pointer_funcs(prop, NULL, "rna_HookModifier_object_set", NULL, NULL); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); @@ -2595,6 +2635,8 @@ static void rna_def_modifier_hook(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_HOOK_INVERT_VGROUP); RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_softbody(BlenderRNA *brna) @@ -2645,12 +2687,13 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) RNA_def_struct_sdna(srna, "BooleanModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_BOOLEAN); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Mesh object to use for Boolean operation"); RNA_def_property_pointer_funcs( prop, NULL, "rna_BooleanModifier_object_set", NULL, "rna_Mesh_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); @@ -2687,6 +2730,8 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_ENUM_FLAG); RNA_def_property_ui_text(prop, "Debug", "Debugging options, only when started with '-d'"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_array(BlenderRNA *brna) @@ -2714,6 +2759,8 @@ static void rna_def_modifier_array(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ArrayModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_ARRAY); + RNA_define_lib_overridable(true); + /* Length parameters */ prop = RNA_def_property(srna, "fit_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_fit_type_items); @@ -2739,7 +2786,6 @@ static void rna_def_modifier_array(BlenderRNA *brna) RNA_def_property_pointer_funcs( prop, NULL, "rna_ArrayModifier_curve_ob_set", NULL, "rna_Curve_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_ArrayModifier_dependency_update"); /* Offset parameters */ @@ -2804,7 +2850,6 @@ static void rna_def_modifier_array(BlenderRNA *brna) "Use the location and rotation of another object to determine the distance and " "rotational change between arrayed items"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); /* Caps */ @@ -2813,15 +2858,13 @@ static void rna_def_modifier_array(BlenderRNA *brna) RNA_def_property_pointer_funcs( prop, NULL, "rna_ArrayModifier_start_cap_set", NULL, "rna_Mesh_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "end_cap", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "End Cap", "Mesh object to use as an end cap"); RNA_def_property_pointer_funcs( prop, NULL, "rna_ArrayModifier_end_cap_set", NULL, "rna_Mesh_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "offset_u", PROP_FLOAT, PROP_FACTOR); @@ -2837,6 +2880,8 @@ static void rna_def_modifier_array(BlenderRNA *brna) RNA_def_property_ui_range(prop, -1, 1, 2, 4); RNA_def_property_ui_text(prop, "V Offset", "Amount to offset array UVs on the V axis"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_edgesplit(BlenderRNA *brna) @@ -2850,6 +2895,8 @@ static void rna_def_modifier_edgesplit(BlenderRNA *brna) RNA_def_struct_sdna(srna, "EdgeSplitModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_EDGESPLIT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_ANGLE); RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f)); RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 2); @@ -2865,6 +2912,8 @@ static void rna_def_modifier_edgesplit(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_EDGESPLIT_FROMFLAG); RNA_def_property_ui_text(prop, "Use Sharp Edges", "Split edges that are marked as sharp"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_displace(BlenderRNA *brna) @@ -2918,6 +2967,8 @@ static void rna_def_modifier_displace(BlenderRNA *brna) RNA_def_struct_sdna(srna, "DisplaceModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_DISPLACE); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "defgrp_name"); RNA_def_property_ui_text( @@ -2955,6 +3006,8 @@ static void rna_def_modifier_displace(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_define_lib_overridable(false); + rna_def_modifier_generic_map_info(srna); } @@ -2969,6 +3022,8 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_struct_sdna(srna, "UVProjectModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_UVPROJECT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "uvlayer_name"); RNA_def_property_ui_text(prop, "UV Map", "UV map name"); @@ -3035,9 +3090,10 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_pointer_funcs( prop, "rna_UVProjector_object_get", "rna_UVProjector_object_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Object", "Object to use as projector transform"); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_smooth(BlenderRNA *brna) @@ -3050,6 +3106,8 @@ static void rna_def_modifier_smooth(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SmoothModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SMOOTH_X); RNA_def_property_ui_text(prop, "X", "Smooth object along X axis"); @@ -3091,6 +3149,8 @@ static void rna_def_modifier_smooth(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SMOOTH_INVERT_VGROUP); RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_correctivesmooth(BlenderRNA *brna) @@ -3132,6 +3192,8 @@ static void rna_def_modifier_correctivesmooth(BlenderRNA *brna) RNA_def_struct_sdna(srna, "CorrectiveSmoothModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "lambda"); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); @@ -3195,6 +3257,8 @@ static void rna_def_modifier_correctivesmooth(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Pin Boundaries", "Excludes boundary vertices from being smoothed"); RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna) @@ -3207,6 +3271,8 @@ static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna) RNA_def_struct_sdna(srna, "LaplacianSmoothModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_LAPLACIANSMOOTH_X); RNA_def_property_ui_text(prop, "X", "Smooth object along X axis"); @@ -3265,6 +3331,8 @@ static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_LAPLACIANSMOOTH_INVERT_VGROUP); RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_cast(BlenderRNA *brna) @@ -3284,6 +3352,8 @@ static void rna_def_modifier_cast(BlenderRNA *brna) RNA_def_struct_sdna(srna, "CastModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_CAST); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "cast_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, prop_cast_type_items); @@ -3297,7 +3367,6 @@ static void rna_def_modifier_cast(BlenderRNA *brna) "Control object: if available, its location determines the center of the effect"); RNA_def_property_pointer_funcs(prop, NULL, "rna_CastModifier_object_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE); @@ -3360,6 +3429,8 @@ static void rna_def_modifier_cast(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name"); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CastModifier_defgrp_name_set"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_meshdeform(BlenderRNA *brna) @@ -3380,12 +3451,13 @@ static void rna_def_modifier_meshdeform(BlenderRNA *brna) RNA_def_struct_sdna(srna, "MeshDeformModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Mesh object to deform with"); RNA_def_property_pointer_funcs( prop, NULL, "rna_MeshDeformModifier_object_set", NULL, "rna_Mesh_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "is_bound", PROP_BOOLEAN, PROP_NONE); @@ -3424,6 +3496,8 @@ static void rna_def_modifier_meshdeform(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Mode", "Method of binding vertices are bound to cage mesh"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); # endif + + RNA_define_lib_overridable(false); } static void rna_def_modifier_particlesystem(BlenderRNA *brna) @@ -3436,10 +3510,14 @@ static void rna_def_modifier_particlesystem(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ParticleSystemModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_PARTICLES); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "psys"); RNA_def_property_ui_text(prop, "Particle System", "Particle System that this modifier controls"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_particleinstance(BlenderRNA *brna) @@ -3466,12 +3544,13 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ParticleInstanceModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_PARTICLES); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "ob"); RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Mesh_object_poll"); RNA_def_property_ui_text(prop, "Object", "Object that has the particle system"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "particle_system_index", PROP_INT, PROP_NONE); @@ -3593,6 +3672,8 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Value Layer Name", "Custom data layer name for the randomized value"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_explode(BlenderRNA *brna) @@ -3606,6 +3687,8 @@ static void rna_def_modifier_explode(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ExplodeModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_EXPLODE); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, "rna_ExplodeModifier_vgroup_get", @@ -3653,6 +3736,8 @@ static void rna_def_modifier_explode(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", eExplodeFlag_INVERT_VGROUP); RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_cloth(BlenderRNA *brna) @@ -3665,6 +3750,8 @@ static void rna_def_modifier_cloth(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ClothModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_CLOTH); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "sim_parms"); @@ -3698,6 +3785,8 @@ static void rna_def_modifier_cloth(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "hair_grid_res"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Hair Grid Resolution", ""); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_fluid(BlenderRNA *brna) @@ -3718,6 +3807,8 @@ static void rna_def_modifier_fluid(BlenderRNA *brna) RNA_def_struct_sdna(srna, "FluidModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_FLUIDSIM); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "domain_settings", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "domain"); RNA_def_property_ui_text(prop, "Domain Settings", ""); @@ -3736,6 +3827,8 @@ static void rna_def_modifier_fluid(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Type", ""); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_fluid_set_type"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_dynamic_paint(BlenderRNA *brna) @@ -3748,6 +3841,8 @@ static void rna_def_modifier_dynamic_paint(BlenderRNA *brna) RNA_def_struct_sdna(srna, "DynamicPaintModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_DYNAMICPAINT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "canvas_settings", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "canvas"); RNA_def_property_ui_text(prop, "Canvas Settings", ""); @@ -3761,6 +3856,8 @@ static void rna_def_modifier_dynamic_paint(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, rna_enum_prop_dynamicpaint_type_items); RNA_def_property_ui_text(prop, "Type", ""); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_collision(BlenderRNA *brna) @@ -3775,11 +3872,15 @@ static void rna_def_modifier_collision(BlenderRNA *brna) RNA_def_struct_sdna(srna, "CollisionModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_PHYSICS); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "CollisionSettings"); RNA_def_property_pointer_funcs(prop, "rna_CollisionModifier_settings_get", NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Settings", ""); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_bevel(BlenderRNA *brna) @@ -3870,6 +3971,8 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_struct_sdna(srna, "BevelModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_BEVEL); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "width", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "value"); RNA_def_property_range(prop, 0, FLT_MAX); @@ -4008,6 +4111,8 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Vertex Mesh Method", "The method to use to create the mesh at intersections"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) @@ -4062,6 +4167,8 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ShrinkwrapModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_SHRINKWRAP); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "wrap_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "shrinkType"); RNA_def_property_enum_items(prop, shrink_type_items); @@ -4091,7 +4198,6 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) RNA_def_property_pointer_funcs( prop, NULL, "rna_ShrinkwrapModifier_target_set", NULL, "rna_Mesh_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "auxiliary_target", PROP_POINTER, PROP_NONE); @@ -4100,7 +4206,6 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) RNA_def_property_pointer_funcs( prop, NULL, "rna_ShrinkwrapModifier_auxTarget_set", NULL, "rna_Mesh_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); @@ -4172,6 +4277,8 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "shrinkOpts", MOD_SHRINKWRAP_INVERT_VGROUP); RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_mask(BlenderRNA *brna) @@ -4190,6 +4297,8 @@ static void rna_def_modifier_mask(BlenderRNA *brna) RNA_def_struct_sdna(srna, "MaskModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_MASK); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, modifier_mask_mode_items); RNA_def_property_ui_text(prop, "Mode", ""); @@ -4201,7 +4310,6 @@ static void rna_def_modifier_mask(BlenderRNA *brna) RNA_def_property_pointer_funcs( prop, NULL, "rna_MaskModifier_ob_arm_set", NULL, "rna_Armature_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); @@ -4221,6 +4329,8 @@ static void rna_def_modifier_mask(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0, 1, 0.1, 3); RNA_def_property_ui_text(prop, "Threshold", "Weights over this threshold remain"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_simpledeform(BlenderRNA *brna) @@ -4260,6 +4370,8 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SimpleDeformModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_SIMPLEDEFORM); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "deform_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, simple_deform_mode_items); @@ -4280,7 +4392,6 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna) prop = RNA_def_property(srna, "origin", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Origin", "Offset the origin and orientation of the deformation"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); @@ -4324,6 +4435,8 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP); RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_surface(BlenderRNA *brna) @@ -4400,6 +4513,8 @@ static void rna_def_modifier_solidify(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SolidifyModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_SOLIDIFY); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "solidify_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, mode_items); @@ -4570,6 +4685,8 @@ static void rna_def_modifier_solidify(BlenderRNA *brna) RNA_def_property_ui_range(prop, -1.0, 1.0, 0.1, 3); RNA_def_property_ui_text(prop, "Bevel Convex", "Edge bevel weight to be added to outside edges"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_screw(BlenderRNA *brna) @@ -4582,11 +4699,12 @@ static void rna_def_modifier_screw(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ScrewModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_SCREW); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "ob_axis"); RNA_def_property_ui_text(prop, "Object", "Object to define the screw axis"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "steps", PROP_INT, PROP_UNSIGNED); @@ -4680,6 +4798,8 @@ static void rna_def_modifier_screw(BlenderRNA *brna) prop, "Object Angle", "Use the angle between the objects rather than the fixed angle"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); # endif + + RNA_define_lib_overridable(false); } static void rna_def_modifier_uvwarp(BlenderRNA *brna) @@ -4692,6 +4812,8 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna) RNA_def_struct_sdna(srna, "UVWarpModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_UVPROJECT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "axis_u", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "axis_u"); RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items); @@ -4728,7 +4850,6 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "object_src"); RNA_def_property_ui_text(prop, "Object From", "Object defining offset"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "bone_from", PROP_STRING, PROP_NONE); @@ -4740,7 +4861,6 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "object_dst"); RNA_def_property_ui_text(prop, "Object To", "Object defining offset"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "bone_to", PROP_STRING, PROP_NONE); @@ -4764,10 +4884,13 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna) RNA_def_property_ui_text(prop, "UV Layer", "UV Layer name"); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_UVWarpModifier_uvlayer_name_set"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna), StructRNA *srna, + const char *mask_flags, const char *mask_vgroup_setter, const char *mask_uvlayer_setter) { @@ -4797,6 +4920,8 @@ static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna), PropertyRNA *prop; + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "mask_constant", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1); @@ -4810,10 +4935,14 @@ static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna), RNA_def_property_string_funcs(prop, NULL, NULL, mask_vgroup_setter); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "invert_mask_vertex_group", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, mask_flags, MOD_WVG_EDIT_INVERT_VGROUP_MASK); + RNA_def_property_ui_text(prop, "Invert", "Invert vertex group mask influence"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "mask_texture", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Masking Tex", "Masking texture"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "mask_tex_use_channel", PROP_ENUM, PROP_NONE); @@ -4842,7 +4971,6 @@ static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna), "Which object to take texture " "coordinates from"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "mask_tex_map_bone", PROP_STRING, PROP_NONE); @@ -4850,6 +4978,8 @@ static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna), RNA_def_property_ui_text( prop, "Texture Coordinate Bone", "Which bone to take texture coordinates from"); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_weightvgedit(BlenderRNA *brna) @@ -4879,6 +5009,8 @@ static void rna_def_modifier_weightvgedit(BlenderRNA *brna) RNA_def_struct_sdna(srna, "WeightVGEditModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_VERTEX_WEIGHT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "defgrp_name"); RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name"); @@ -4896,6 +5028,14 @@ static void rna_def_modifier_weightvgedit(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert Falloff", "Invert the resulting falloff weight"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "edit_flags", MOD_WVG_EDIT_WEIGHTS_NORMALIZE); + RNA_def_property_ui_text( + prop, + "Normalize Weights", + "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "map_curve", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "cmap_curve"); RNA_def_property_ui_text(prop, "Mapping Curve", "Custom mapping curve"); @@ -4946,16 +5086,14 @@ static void rna_def_modifier_weightvgedit(BlenderRNA *brna) "to be removed from the vgroup"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_define_lib_overridable(false); + /* Common masking properties. */ rna_def_modifier_weightvg_mask(brna, srna, + "edit_flags", "rna_WeightVGEditModifier_mask_defgrp_name_set", "rna_WeightVGEditModifier_mask_tex_uvlayer_name_set"); - - prop = RNA_def_property(srna, "invert_mask_vertex_group", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "edit_flags", MOD_WVG_EDIT_INVERT_VGROUP_MASK); - RNA_def_property_ui_text(prop, "Invert", "Invert vertex group mask influence"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_weightvgmix(BlenderRNA *brna) @@ -5000,6 +5138,8 @@ static void rna_def_modifier_weightvgmix(BlenderRNA *brna) RNA_def_struct_sdna(srna, "WeightVGMixModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_VERTEX_WEIGHT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "vertex_group_a", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "defgrp_name_a"); RNA_def_property_ui_text(prop, "Vertex Group A", "First vertex group name"); @@ -5012,6 +5152,16 @@ static void rna_def_modifier_weightvgmix(BlenderRNA *brna) RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightVGMixModifier_defgrp_name_b_set"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "invert_vertex_group_a", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_INVERT_VGROUP_A); + RNA_def_property_ui_text(prop, "Invert Weights A", "Invert the influence of vertex group A"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "invert_vertex_group_b", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_INVERT_VGROUP_B); + RNA_def_property_ui_text(prop, "Invert Weights B", "Invert the influence of vertex group B"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "default_weight_a", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0, 1.0f); RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1); @@ -5043,16 +5193,22 @@ static void rna_def_modifier_weightvgmix(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Vertex Set", "Which vertices should be affected"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_WEIGHTS_NORMALIZE); + RNA_def_property_ui_text( + prop, + "Normalize Weights", + "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); + /* Common masking properties. */ rna_def_modifier_weightvg_mask(brna, srna, + "flag", "rna_WeightVGMixModifier_mask_defgrp_name_set", "rna_WeightVGMixModifier_mask_tex_uvlayer_name_set"); - - prop = RNA_def_property(srna, "invert_mask_vertex_group", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_INVERT_VGROUP_MASK); - RNA_def_property_ui_text(prop, "Invert", "Invert vertex group mask influence"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) @@ -5106,6 +5262,8 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) RNA_def_struct_sdna(srna, "WeightVGProximityModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_VERTEX_WEIGHT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "defgrp_name"); RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name"); @@ -5133,7 +5291,6 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "proximity_ob_target"); RNA_def_property_ui_text(prop, "Target Object", "Object to calculate vertices distances from"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "min_dist", PROP_FLOAT, PROP_DISTANCE); @@ -5159,17 +5316,23 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert Falloff", "Invert the resulting falloff weight"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, NULL, "proximity_flags", MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE); + RNA_def_property_ui_text( + prop, + "Normalize Weights", + "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); + /* Common masking properties. */ rna_def_modifier_weightvg_mask(brna, srna, + "proximity_flags", "rna_WeightVGProximityModifier_mask_defgrp_name_set", "rna_WeightVGProximityModifier_mask_tex_uvlayer_name_set"); - - prop = RNA_def_property(srna, "invert_mask_vertex_group", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna( - prop, NULL, "proximity_flags", MOD_WVG_PROXIMITY_INVERT_VGROUP_MASK); - RNA_def_property_ui_text(prop, "Invert", "Invert vertex group mask influence"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_remesh(BlenderRNA *brna) @@ -5205,6 +5368,8 @@ static void rna_def_modifier_remesh(BlenderRNA *brna) RNA_def_struct_sdna(srna, "RemeshModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_REMESH); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", ""); @@ -5273,6 +5438,8 @@ static void rna_def_modifier_remesh(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Smooth Shading", "Output faces with smooth shading rather than flat shaded"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_ocean(BlenderRNA *brna) @@ -5330,6 +5497,8 @@ static void rna_def_modifier_ocean(BlenderRNA *brna) RNA_def_struct_sdna(srna, "OceanModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_OCEAN); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "geometry_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "geometry_mode"); RNA_def_property_enum_items(prop, geometry_items); @@ -5523,6 +5692,8 @@ static void rna_def_modifier_ocean(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Cache Path", "Path to a folder to store external baked images"); /*RNA_def_property_update(prop, 0, "rna_Modifier_update"); */ /* XXX how to update? */ + + RNA_define_lib_overridable(false); } static void rna_def_modifier_skin(BlenderRNA *brna) @@ -5535,6 +5706,8 @@ static void rna_def_modifier_skin(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SkinModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_SKIN); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "branch_smoothing", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Branch Smoothing", "Smooth complex geometry around branches"); RNA_def_property_ui_range(prop, 0, 1, 1, -1); @@ -5560,6 +5733,8 @@ static void rna_def_modifier_skin(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "symmetry_axes", MOD_SKIN_SYMM_Z); RNA_def_property_ui_text(prop, "Z", "Avoid making unsymmetrical quads across the Z axis"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_triangulate(BlenderRNA *brna) @@ -5572,6 +5747,8 @@ static void rna_def_modifier_triangulate(BlenderRNA *brna) RNA_def_struct_sdna(srna, "TriangulateModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_TRIANGULATE); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "quad_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "quad_method"); RNA_def_property_enum_items(prop, rna_enum_modifier_triangulate_quad_method_items); @@ -5602,6 +5779,8 @@ static void rna_def_modifier_triangulate(BlenderRNA *brna) "Try to preserve custom normals (WARNING: depending on chosen triangulation method, " "shading may not be fully preserved, 'Fixed' method usually gives the best result here)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_meshcache(BlenderRNA *brna) @@ -5668,6 +5847,8 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna) RNA_def_struct_sdna(srna, "MeshCacheModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "cache_format", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, prop_format_type_items); @@ -5762,6 +5943,8 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Evaluation Factor", "Evaluation time in seconds"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_meshseqcache(BlenderRNA *brna) @@ -5774,12 +5957,13 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna) RNA_def_struct_sdna(srna, "MeshSeqCacheModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "cache_file", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "cache_file"); RNA_def_property_struct_type(prop, "CacheFile"); RNA_def_property_ui_text(prop, "Cache File", ""); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE); @@ -5804,6 +5988,8 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Read Data", "Data to read from the cache"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_laplaciandeform(BlenderRNA *brna) @@ -5816,6 +6002,8 @@ static void rna_def_modifier_laplaciandeform(BlenderRNA *brna) RNA_def_struct_sdna(srna, "LaplacianDeformModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "anchor_grp_name"); RNA_def_property_ui_text( @@ -5839,6 +6027,8 @@ static void rna_def_modifier_laplaciandeform(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_define_lib_overridable(false); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } @@ -5852,6 +6042,8 @@ static void rna_def_modifier_weld(BlenderRNA *brna) RNA_def_struct_sdna(srna, "WeldModifierData"); RNA_def_struct_ui_icon(srna, ICON_AUTOMERGE_OFF); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "merge_dist"); RNA_def_property_range(prop, 0, FLT_MAX); @@ -5879,6 +6071,8 @@ static void rna_def_modifier_weld(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WELD_INVERT_VGROUP); RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_wireframe(BlenderRNA *brna) @@ -5891,6 +6085,8 @@ static void rna_def_modifier_wireframe(BlenderRNA *brna) RNA_def_struct_sdna(srna, "WireframeModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_WIREFRAME); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "thickness", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "offset"); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); @@ -5962,6 +6158,8 @@ static void rna_def_modifier_wireframe(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WIREFRAME_INVERT_VGROUP); RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_datatransfer(BlenderRNA *brna) @@ -6019,11 +6217,12 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna) RNA_def_struct_sdna(srna, "DataTransferModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_DATA_TRANSFER); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "ob_source"); RNA_def_property_ui_text(prop, "Source Object", "Object to transfer data from"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_pointer_funcs( prop, NULL, "rna_DataTransferModifier_ob_source_set", NULL, "rna_Mesh_object_poll"); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); @@ -6319,6 +6518,8 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna) srna, "invert_vertex_group", false, "Invert", "Invert vertex group influence"); RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DATATRANSFER_INVERT_VGROUP); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_normaledit(BlenderRNA *brna) @@ -6358,6 +6559,8 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna) RNA_def_struct_sdna(srna, "NormalEditModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_NORMALEDIT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_mode_items); RNA_def_property_ui_text(prop, "Mode", "How to affect (generate) normals"); @@ -6429,7 +6632,6 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Target", "Target object used to affect normals"); RNA_def_property_pointer_funcs(prop, NULL, "rna_NormalEditModifier_target_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "use_direction_parallel", PROP_BOOLEAN, PROP_NONE); @@ -6440,6 +6642,8 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna) "Use same direction for all normals, from origin to target's center " "(Directional mode only)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_surfacedeform(BlenderRNA *brna) @@ -6452,12 +6656,13 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SurfaceDeformModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Target", "Mesh object to deform with"); RNA_def_property_pointer_funcs( prop, NULL, "rna_SurfaceDeformModifier_target_set", NULL, "rna_Mesh_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE); @@ -6488,6 +6693,8 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna) RNA_def_property_ui_range(prop, -100, 100, 10, 2); RNA_def_property_ui_text(prop, "Strength", "Strength of modifier deformations"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_weightednormal(BlenderRNA *brna) @@ -6519,6 +6726,8 @@ static void rna_def_modifier_weightednormal(BlenderRNA *brna) RNA_def_struct_sdna(srna, "WeightedNormalModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_NORMALEDIT); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "weight", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 1, 100); RNA_def_property_ui_range(prop, 1, 100, 1, -1); @@ -6565,6 +6774,8 @@ static void rna_def_modifier_weightednormal(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_FACE_INFLUENCE); RNA_def_property_ui_text(prop, "Face Influence", "Use influence of face for weighting"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } static void rna_def_modifier_simulation_access(BlenderRNA *brna) @@ -6577,6 +6788,8 @@ static void rna_def_modifier_simulation_access(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SimulationModifierData"); RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */ + RNA_define_lib_overridable(true); + # ifdef WITH_NEW_SIMULATION_TYPE prop = RNA_def_property(srna, "simulation", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Simulation", "Simulation to access"); @@ -6588,6 +6801,8 @@ static void rna_def_modifier_simulation_access(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Data Path", "Identifier of the simulation component that should be accessed"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); } void RNA_def_modifier(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index 230d62d2a23..b0dda1237b0 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -382,7 +382,7 @@ static FCurve *rna_NlaStrip_fcurve_find(NlaStrip *strip, } /* Returns NULL if not found. */ - return list_find_fcurve(&strip->fcurves, data_path, index); + return BKE_fcurve_find(&strip->fcurves, data_path, index); } static NlaStrip *rna_NlaStrip_new(ID *id, diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index a27d77df32a..79a9e0be051 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1471,7 +1471,7 @@ static void rna_Object_constraints_remove(Object *object, RNA_POINTER_INVALIDATE(con_ptr); ED_object_constraint_update(bmain, object); - ED_object_constraint_set_active(object, NULL); + ED_object_constraint_active_set(object, NULL); WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, object); } @@ -1480,7 +1480,7 @@ static void rna_Object_constraints_clear(Object *object, Main *bmain) BKE_constraints_free(&object->constraints); ED_object_constraint_update(bmain, object); - ED_object_constraint_set_active(object, NULL); + ED_object_constraint_active_set(object, NULL); WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, object); } diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 2c9bdd31141..3b80714bcc5 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -41,6 +41,8 @@ #include "DEG_depsgraph.h" +#include "ED_outliner.h" + #include "rna_internal.h" /* own include */ static const EnumPropertyItem space_items[] = { @@ -114,6 +116,7 @@ static void rna_Object_select_set( Scene *scene = CTX_data_scene(C); DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); + ED_outliner_select_sync_from_object_tag(C); } static bool rna_Object_select_get(Object *ob, bContext *C, ViewLayer *view_layer) diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 6c21e4ad01b..6af031eb7b0 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -131,7 +131,7 @@ static void engine_bind_display_space_shader(RenderEngine *UNUSED(engine), Scene GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE); GPU_shader_bind(shader); - int img_loc = GPU_shader_get_uniform_ensure(shader, "image"); + int img_loc = GPU_shader_get_uniform(shader, "image"); GPU_shader_uniform_int(shader, img_loc, 0); } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index e3d779ce7fb..7e9753b090a 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2198,12 +2198,12 @@ static void rna_Scene_update_active_object_data(bContext *C, PointerRNA *UNUSED( } } -static void rna_SceneCamera_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_SceneCamera_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; Object *camera = scene->camera; - BKE_sequence_invalidate_scene_strips(bmain, scene); + BKE_sequencer_cache_cleanup(scene); if (camera && (camera->type == OB_CAMERA)) { DEG_id_tag_update(&camera->id, ID_RECALC_GEOMETRY); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index e770b669ca2..1d03b16d5bb 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -160,7 +160,7 @@ static void rna_Scene_ray_cast(Scene *scene, normalize_v3(direction); Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true); - SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, 0); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, 0); bool ret = ED_transform_snap_object_project_ray_ex(sctx, depsgraph, diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index fd8ddfff14f..39ea054456f 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -874,13 +874,6 @@ static void rna_Sequence_reopen_files_update(Main *bmain, Scene *UNUSED(scene), } } -static void rna_Sequence_mute_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) -{ - Scene *scene = (Scene *)ptr->owner_id; - - DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); -} - static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; @@ -1690,7 +1683,7 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_CHECKBOX_HLT, -1); RNA_def_property_ui_text( prop, "Mute", "Disable strip so that it cannot be viewed in the output"); - RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_mute_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_LOCK); @@ -2023,7 +2016,7 @@ static void rna_def_editor(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Prefetch Frames", - "Render frames ahead of playhead in the background for faster playback"); + "Render frames ahead of current frame in the background for faster playback"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL); prop = RNA_def_property(srna, "recycle_max_cost", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index c719aa99fd8..df0d514fabf 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -483,6 +483,13 @@ const EnumPropertyItem rna_enum_file_sort_items[] = { {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem rna_enum_curve_display_handle_items[] = { + {CURVE_HANDLE_NONE, "NONE", 0, "None", ""}, + {CURVE_HANDLE_SELECTED, "SELECTED", 0, "Selected", ""}, + {CURVE_HANDLE_ALL, "ALL", 0, "All", ""}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include "DNA_anim_types.h" @@ -3817,9 +3824,11 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) prop, "Indices", "Display the index numbers of selected vertices, edges, and faces"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "show_curve_handles", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_CU_HANDLES); - RNA_def_property_ui_text(prop, "Draw Handles", "Display Bezier handles in editmode"); + prop = RNA_def_property(srna, "display_handle", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "overlay.handle_display"); + RNA_def_property_enum_items(prop, rna_enum_curve_display_handle_items); + RNA_def_property_ui_text( + prop, "Display Handles", "Limit the display of curve handles in edit mode"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_curve_normals", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 5db525a9f6f..e47b2b51acf 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -485,6 +485,21 @@ static void rna_uiTemplateAnyID(uiLayout *layout, uiTemplateAnyID(layout, ptr, propname, proptypename, name); } +static void rna_uiTemplateCacheFile(uiLayout *layout, + bContext *C, + PointerRNA *ptr, + const char *propname) +{ + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); + + if (!prop) { + RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); + return; + } + + uiTemplateCacheFile(layout, C, ptr, propname); +} + static void rna_uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propname, @@ -1568,7 +1583,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_float_array( func, "color", 4, node_socket_color_default, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f); - func = RNA_def_function(srna, "template_cache_file", "uiTemplateCacheFile"); + func = RNA_def_function(srna, "template_cache_file", "rna_uiTemplateCacheFile"); RNA_def_function_ui_description( func, "Item(s). User interface for selecting cache files and their source paths"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index aa138517209..49a0121dadb 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -360,7 +360,7 @@ static void rna_userdef_load_ui_update(Main *UNUSED(bmain), Scene *UNUSED(scene) static void rna_userdef_anisotropic_update(Main *bmain, Scene *scene, PointerRNA *ptr) { - GPU_set_anisotropic(bmain, U.anisotropic_filter); + GPU_set_anisotropic(U.anisotropic_filter); rna_userdef_update(bmain, scene, ptr); } @@ -4716,7 +4716,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop = RNA_def_property(srna, "use_text_antialiasing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_AA); - RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased"); + RNA_def_property_ui_text(prop, "Text Anti-Aliasing", "Draw user interface text anti-aliased"); RNA_def_property_update(prop, 0, "rna_userdef_text_update"); prop = RNA_def_property(srna, "text_hinting", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c index 826d4039c55..742d3da27ac 100644 --- a/source/blender/makesrna/intern/rna_wm_gizmo.c +++ b/source/blender/makesrna/intern/rna_wm_gizmo.c @@ -401,12 +401,14 @@ RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_offset_scale, flag, WM_GIZMO_DRAW_OF RNA_GIZMO_GENERIC_FLAG_NEG_RW_DEF(flag_use_draw_scale, flag, WM_GIZMO_DRAW_OFFSET_SCALE); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide, flag, WM_GIZMO_HIDDEN); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide_select, flag, WM_GIZMO_HIDDEN_SELECT); +RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide_keymap, flag, WM_GIZMO_HIDDEN_KEYMAP); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_grab_cursor, flag, WM_GIZMO_MOVE_CURSOR); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_select_background, flag, WM_GIZMO_SELECT_BACKGROUND); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_operator_tool_properties, flag, WM_GIZMO_OPERATOR_TOOL_INIT); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_event_handle_all, flag, WM_GIZMO_EVENT_HANDLE_ALL); +RNA_GIZMO_GENERIC_FLAG_NEG_RW_DEF(flag_use_tooltip, flag, WM_GIZMO_NO_TOOLTIP); /* wmGizmo.state */ RNA_GIZMO_FLAG_RO_DEF(state_is_highlight, state, WM_GIZMO_STATE_HIGHLIGHT); @@ -1202,6 +1204,12 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) prop, "rna_Gizmo_flag_hide_select_get", "rna_Gizmo_flag_hide_select_set"); RNA_def_property_ui_text(prop, "Hide Select", ""); RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); + /* WM_GIZMO_HIDDEN_KEYMAP */ + prop = RNA_def_property(srna, "hide_keymap", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_Gizmo_flag_hide_keymap_get", "rna_Gizmo_flag_hide_keymap_set"); + RNA_def_property_ui_text(prop, "Hide Keymap", "Ignore the key-map for this gizmo"); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_MOVE_CURSOR */ prop = RNA_def_property(srna, "use_grab_cursor", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( @@ -1271,6 +1279,13 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) "do not pass events through to be handled by other keymaps"); RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); + /* WM_GIZMO_NO_TOOLTIP (negated) */ + prop = RNA_def_property(srna, "use_tooltip", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_Gizmo_flag_use_tooltip_get", "rna_Gizmo_flag_use_tooltip_set"); + RNA_def_property_ui_text(prop, "Use Tooltip", "Use tool-tips when hovering over this gizmo"); + /* No update needed. */ + /* wmGizmo.state (readonly) */ /* WM_GIZMO_STATE_HIGHLIGHT */ prop = RNA_def_property(srna, "is_highlight", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c index 32e348ea72f..5f110189dd6 100644 --- a/source/blender/makesrna/intern/rna_workspace.c +++ b/source/blender/makesrna/intern/rna_workspace.c @@ -59,7 +59,7 @@ static void rna_window_update_all(Main *UNUSED(bmain), void rna_workspace_screens_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { WorkSpace *workspace = (WorkSpace *)ptr->owner_id; - rna_iterator_listbase_begin(iter, BKE_workspace_layouts_get(workspace), NULL); + rna_iterator_listbase_begin(iter, &workspace->layouts, NULL); } static PointerRNA rna_workspace_screens_item_get(CollectionPropertyIterator *iter) diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index e4b043279ce..84651f79e8a 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -173,6 +173,11 @@ static void deformVertsEM(ModifierData *md, ArmatureModifierData *amd = (ArmatureModifierData *)md; Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ armature_deform_verts(amd->object, @@ -252,25 +257,17 @@ static void deformMatrices(ModifierData *md, static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row, *col; + uiLayout *col; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); uiItemR(layout, &ptr, "object", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); col = uiLayoutColumn(layout, true); uiItemR(col, &ptr, "use_deform_preserve_volume", 0, NULL, ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index b05a9021bff..68e12a8bbef 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -841,7 +841,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index b2f73dd082b..76b8985975e 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -277,15 +277,12 @@ static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row, *col; + uiLayout *col; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -325,12 +322,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(col, &ptr, "angle_limit", 0, NULL, ICON_NONE); } else if (limit_method == MOD_BEVEL_VGROUP) { - row = uiLayoutRow(col, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(col, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); } modifier_panel_end(layout, &ptr); diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 249711fb132..c2412b295ff 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -363,7 +363,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index cb72e574dad..93f97c7c5b8 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -290,7 +290,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index a6137ae2990..6ce3cc52ef2 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -513,10 +513,15 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); } - if (mesh_src) { + if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) { BLI_assert(mesh_src->totvert == numVerts); } + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + if (cmd->type == MOD_CAST_TYPE_CUBOID) { cuboid_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); } @@ -531,16 +536,13 @@ static void deformVertsEM(ModifierData *md, static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row; + uiLayout *row; uiLayout *layout = panel->layout; int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; PointerRNA cast_object_ptr = RNA_pointer_get(&ptr, "object"); uiLayoutSetPropSep(layout, true); @@ -557,12 +559,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "size", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "use_radius_as_size", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); uiItemR(layout, &ptr, "object", 0, NULL, ICON_NONE); if (!RNA_pointer_is_null(&cast_object_ptr)) { diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index fcb6915709a..c7551b1be00 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -270,7 +270,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - modifier_panel_buttons(C, panel); uiItemL(layout, IFACE_("Settings are inside the Physics tab"), ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index 892fa8a0e12..3d9f59fba24 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -767,6 +767,11 @@ static void deformVertsEM(ModifierData *md, Mesh *mesh_src = MOD_deform_mesh_eval_get( ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + correctivesmooth_modifier_do( md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, editData); @@ -777,15 +782,11 @@ static void deformVertsEM(ModifierData *md, static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -794,12 +795,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "scale", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "smooth_type", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); uiItemR(layout, &ptr, "use_only_smooth", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "use_pin_boundary", 0, NULL, ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index 72e794bd2e8..491827720f0 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -153,6 +153,11 @@ static void deformVertsEM(ModifierData *md, { Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + deformVerts(md, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { @@ -162,28 +167,18 @@ static void deformVertsEM(ModifierData *md, static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); uiItemR(layout, &ptr, "object", 0, IFACE_("Curve Object"), ICON_NONE); uiItemR(layout, &ptr, "deform_axis", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index 4f2fc8ceebb..e9436147649 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -251,12 +251,9 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; - row = uiLayoutRow(layout, true); uiItemR(row, &ptr, "object", 0, IFACE_("Source"), ICON_NONE); sub = uiLayoutRow(row, true); @@ -266,12 +263,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "mix_mode", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "mix_factor", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutColumn(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); uiItemO(layout, "Generate Data Layers", ICON_NONE, "OBJECT_OT_datalayout_transfer"); diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index ab60182ff5e..5b494baea1a 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -84,7 +84,7 @@ static DecimateModifierData *getOriginalModifierData(const DecimateModifierData const ModifierEvalContext *ctx) { Object *ob_orig = DEG_get_original_object(ctx->object); - return (DecimateModifierData *)BKE_modifiers_findny_name(ob_orig, dmd->modifier.name); + return (DecimateModifierData *)BKE_modifiers_findby_name(ob_orig, dmd->modifier.name); } static void updateFaceCount(const ModifierEvalContext *ctx, @@ -234,14 +234,12 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); int decimate_type = RNA_enum_get(&ptr, "decimate_type"); char count_info[32]; snprintf(count_info, 32, IFACE_("Face Count: %d"), RNA_int_get(&ptr, "face_count")); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiItemR(layout, &ptr, "decimate_type", 0, NULL, ICON_NONE); @@ -259,13 +257,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "use_collapse_triangulate", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutColumn(row, true); - uiLayoutSetPropDecorate(sub, false); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); } else if (decimate_type == MOD_DECIM_MODE_UNSUBDIV) { uiItemR(layout, &ptr, "iterations", 0, NULL, ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 42cdb87e289..d562559d66d 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -418,6 +418,11 @@ static void deformVertsEM(ModifierData *md, Mesh *mesh_src = MOD_deform_mesh_eval_get( ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { @@ -427,17 +432,15 @@ static void deformVertsEM(ModifierData *md, static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row, *col; + uiLayout *col; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); PointerRNA texture_ptr = RNA_pointer_get(&ptr, "texture"); bool has_texture = !RNA_pointer_is_null(&texture_ptr); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; int texture_coords = RNA_enum_get(&ptr, "texture_coords"); uiLayoutSetPropSep(layout, true); @@ -484,12 +487,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE); uiItemR(col, &ptr, "mid_level", 0, NULL, ICON_NONE); - row = uiLayoutRow(col, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutColumn(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(col, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index 0d40b684b39..f8a100f1f0a 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -189,7 +189,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - modifier_panel_buttons(C, panel); uiItemL(layout, IFACE_("Settings are inside the Physics tab"), ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 42ea46d299a..0134b5c9d64 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -145,7 +145,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 6a51c8dd90a..0c1eedd429a 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -1187,14 +1187,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row; + uiLayout *row; uiLayout *layout = panel->layout; int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data"); bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; @@ -1213,12 +1212,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "use_edge_cut", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "use_size", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); row = uiLayoutRow(layout, false); uiLayoutSetActive(row, has_vertex_group); diff --git a/source/blender/modifiers/intern/MOD_fluid.c b/source/blender/modifiers/intern/MOD_fluid.c index cf97ccc3b75..0ef062d72d5 100644 --- a/source/blender/modifiers/intern/MOD_fluid.c +++ b/source/blender/modifiers/intern/MOD_fluid.c @@ -211,7 +211,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - modifier_panel_buttons(C, panel); uiItemL(layout, IFACE_("Settings are inside the Physics tab"), ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 6dd9734a1bd..2eff026c040 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -401,16 +401,14 @@ static void deformVertsEM(struct ModifierData *md, static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row, *col; + uiLayout *row, *col; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); PointerRNA hook_object_ptr = RNA_pointer_get(&ptr, "object"); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -422,13 +420,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemPointerR( col, &ptr, "subtarget", &hook_object_data_ptr, "bones", IFACE_("Bone"), ICON_NONE); } - col = uiLayoutColumn(layout, false); - row = uiLayoutRow(col, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); uiItemR(layout, &ptr, "strength", UI_ITEM_R_SLIDER, NULL, ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index 320293ea9e5..b7975bec77a 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -39,6 +39,7 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" +#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_particle.h" @@ -794,6 +795,11 @@ static void deformVertsEM(ModifierData *md, Mesh *mesh_src = MOD_deform_mesh_eval_get( ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + LaplacianDeformModifier_do( (LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts); @@ -815,13 +821,12 @@ static void freeData(ModifierData *md) static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row; + uiLayout *row; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); bool is_bind = RNA_boolean_get(&ptr, "is_bind"); bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; @@ -830,20 +835,14 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "iterations", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiLayoutSetEnabled(row, !is_bind); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); uiItemS(layout); row = uiLayoutRow(layout, true); uiLayoutSetEnabled(row, has_vertex_group); uiItemO(row, - (RNA_boolean_get(&ptr, "is_bind") ? IFACE_("Unbind") : IFACE_("Bind")), + is_bind ? IFACE_("Unbind") : IFACE_("Bind"), ICON_NONE, "OBJECT_OT_laplaciandeform_bind"); diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index 1cb3145d9f3..130c280c5f2 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -570,6 +570,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + laplaciansmoothModifier_do( (LaplacianSmoothModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts); @@ -580,16 +585,13 @@ static void deformVertsEM(ModifierData *md, static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row; + uiLayout *row; uiLayout *layout = panel->layout; int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -606,12 +608,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "use_volume_preserve", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "use_normalized", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c index cd1be8d8a8e..31cfe3bb407 100644 --- a/source/blender/modifiers/intern/MOD_lattice.c +++ b/source/blender/modifiers/intern/MOD_lattice.c @@ -136,6 +136,11 @@ static void deformVertsEM(ModifierData *md, struct Mesh *mesh_src = MOD_deform_mesh_eval_get( ctx->object, em, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + deformVerts(md, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { @@ -145,26 +150,17 @@ static void deformVertsEM(ModifierData *md, static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); uiItemR(layout, &ptr, "object", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); uiItemR(layout, &ptr, "strength", UI_ITEM_R_SLIDER, NULL, ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index 76b5690a316..c6de980d674 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -411,10 +411,8 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); int mode = RNA_enum_get(&ptr, "mode"); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiItemR(layout, &ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE); @@ -428,12 +426,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); } else if (mode == MOD_MASK_MODE_VGROUP) { - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr); } uiItemR(layout, &ptr, "threshold", 0, NULL, ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c index 0a88106a724..2d104e1e0c2 100644 --- a/source/blender/modifiers/intern/MOD_meshcache.c +++ b/source/blender/modifiers/intern/MOD_meshcache.c @@ -303,7 +303,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index fde143b331b..c24515e01eb 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -490,6 +490,11 @@ static void deformVertsEM(ModifierData *md, Mesh *mesh_src = MOD_deform_mesh_eval_get( ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + meshdeformModifier_do(md, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { @@ -566,16 +571,14 @@ void BKE_modifier_mdef_compact_influences(ModifierData *md) static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row, *col; + uiLayout *col; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); bool is_bound = RNA_boolean_get(&ptr, "is_bound"); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -583,12 +586,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiLayoutSetEnabled(col, !is_bound); uiItemR(col, &ptr, "object", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); col = uiLayoutColumn(layout, false); uiLayoutSetEnabled(col, !is_bound); diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 5834b78f145..801badc382c 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -204,7 +204,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); PointerRNA cache_file_ptr = RNA_pointer_get(&ptr, "cache_file"); bool has_cache_file = !RNA_pointer_is_null(&cache_file_ptr); diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 808ddf235f1..949b115a25f 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -134,7 +134,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); col = uiLayoutColumn(layout, false); uiLayoutSetPropSep(col, true); diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index 4ef4b952ff8..75ec5eb5be7 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -294,7 +294,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); MultiresModifierData *mmd = (MultiresModifierData *)ptr.data; - modifier_panel_buttons(C, panel); PointerRNA op_ptr; diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 1f5c261bf40..c1901a97cda 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -708,7 +708,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); @@ -724,10 +723,10 @@ static void panel_draw(const bContext *C, Panel *panel) modifier_panel_end(layout, &ptr); } +/* This panel could be open by default, but it isn't currently. */ static void mix_mode_panel_draw(const bContext *C, Panel *panel) { - /* This panel could be open by default. */ - uiLayout *row, *sub; + uiLayout *row; uiLayout *layout = panel->layout; PointerRNA ptr; @@ -736,17 +735,10 @@ static void mix_mode_panel_draw(const bContext *C, Panel *panel) uiLayoutSetPropSep(layout, true); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; - uiItemR(layout, &ptr, "mix_mode", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "mix_factor", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutColumn(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); row = uiLayoutRow(layout, true); uiItemR(row, &ptr, "mix_limit", 0, NULL, ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index e8d2ed13c45..e16a23f54c6 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -517,7 +517,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); @@ -542,6 +541,7 @@ static void panel_draw(const bContext *C, Panel *panel) #else /* WITH_OCEANSIM */ uiItemL(layout, IFACE_("Built without Ocean modifier"), ICON_NONE); + UNUSED_VARS(C); #endif /* WITH_OCEANSIM */ } @@ -669,6 +669,8 @@ static void panelRegister(ARegionType *region_type) modifier_subpanel_register( region_type, "spectrum", "Spectrum", NULL, spectrum_panel_draw, panel_type); modifier_subpanel_register(region_type, "bake", "Bake", NULL, bake_panel_draw, panel_type); +#else + UNUSED_VARS(panel_type); #endif /* WITH_OCEANSIM */ } diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index dc96e2fb9e4..0a9fb964281 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -567,7 +567,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); PointerRNA particle_obj_ptr = RNA_pointer_get(&ptr, "object"); diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index 4edb3c34895..b63fb18de69 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -227,7 +227,7 @@ static void deformVerts(ModifierData *md, if (DEG_is_active(ctx->depsgraph)) { Object *object_orig = DEG_get_original_object(ctx->object); - ModifierData *md_orig = BKE_modifiers_findny_name(object_orig, psmd->modifier.name); + ModifierData *md_orig = BKE_modifiers_findby_name(object_orig, psmd->modifier.name); BLI_assert(md_orig != NULL); ParticleSystemModifierData *psmd_orig = (ParticleSystemModifierData *)md_orig; psmd_orig->flag = psmd->flag; @@ -263,10 +263,30 @@ static void panel_draw(const bContext *C, Panel *panel) uiLayout *layout = panel->layout; PointerRNA ptr; - modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + PointerRNA ob_ptr; + modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); + + Object *ob = ob_ptr.data; + ModifierData *md = (ModifierData *)ptr.data; + ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; uiItemL(layout, IFACE_("Settings are in the particle tab"), ICON_NONE); + if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) { + if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB)) { + uiItemO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"), + ICON_NONE, + "OBJECT_OT_duplicates_make_real"); + } + else if (psys->part->ren_as == PART_DRAW_PATH) { + uiItemO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"), + ICON_NONE, + "OBJECT_OT_modifier_convert"); + } + } + modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c index cbc64989f55..a76b3acb783 100644 --- a/source/blender/modifiers/intern/MOD_remesh.c +++ b/source/blender/modifiers/intern/MOD_remesh.c @@ -246,7 +246,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); int mode = RNA_enum_get(&ptr, "mode"); @@ -277,6 +276,7 @@ static void panel_draw(const bContext *C, Panel *panel) #else /* WITH_MOD_REMESH */ uiItemL(layout, IFACE_("Built without Remesh modifier"), ICON_NONE); + UNUSED_VARS(C); #endif /* WITH_MOD_REMESH */ } diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 5a478438ef9..b1c49ba2fec 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -1176,7 +1176,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - modifier_panel_buttons(C, panel); PointerRNA screw_obj_ptr = RNA_pointer_get(&ptr, "object"); diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index fcd11904d2b..c0f7a0a7db0 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -153,6 +153,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); } + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + struct MDeformVert *dvert = NULL; int defgrp_index = -1; if (swmd->vgroup_name[0] != '\0') { @@ -211,18 +216,16 @@ static bool dependsOnNormals(ModifierData *md) static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row, *col; + uiLayout *row, *col; uiLayout *layout = panel->layout; int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; int wrap_method = RNA_enum_get(&ptr, "wrap_method"); uiItemR(layout, &ptr, "wrap_method", 0, NULL, ICON_NONE); @@ -260,12 +263,7 @@ static void panel_draw(const bContext *C, Panel *panel) } uiItemR(layout, &ptr, "offset", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutColumn(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index 103e2a3685d..3a3b3a4f3ce 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -451,6 +451,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); } + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + SimpleDeformModifier_do(sdmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { @@ -466,7 +471,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); int deform_method = RNA_enum_get(&ptr, "deform_method"); @@ -490,7 +494,7 @@ static void panel_draw(const bContext *C, Panel *panel) static void restrictions_panel_draw(const bContext *C, Panel *panel) { - uiLayout *col, *row, *sub; + uiLayout *row; uiLayout *layout = panel->layout; int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE; @@ -499,7 +503,6 @@ static void restrictions_panel_draw(const bContext *C, Panel *panel) modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); int deform_method = RNA_enum_get(&ptr, "deform_method"); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -523,13 +526,7 @@ static void restrictions_panel_draw(const bContext *C, Panel *panel) } } - col = uiLayoutColumn(layout, true); - row = uiLayoutRow(col, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); } static void panelRegister(ARegionType *region_type) diff --git a/source/blender/modifiers/intern/MOD_simulation.cc b/source/blender/modifiers/intern/MOD_simulation.cc index 54d07bbc178..a9af48b682f 100644 --- a/source/blender/modifiers/intern/MOD_simulation.cc +++ b/source/blender/modifiers/intern/MOD_simulation.cc @@ -97,7 +97,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiItemR(layout, &ptr, "simulation", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "data_path", 0, NULL, ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 673407cf2d5..38d7b31a335 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -935,7 +935,13 @@ static Mesh *subdivide_base(Mesh *orig) u = e->v1; radrat = (half_v2(outnode[e->v2].radius) / half_v2(outnode[e->v1].radius)); - radrat = (radrat + 1) / 2; + if (isfinite(radrat)) { + radrat = (radrat + 1) / 2; + } + else { + /* Happens when skin is scaled to zero. */ + radrat = 1.0f; + } /* Add vertices and edge segments */ for (j = 0; j < edge_subd[i]; j++, v++, outedge++) { @@ -1950,7 +1956,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); PointerRNA op_ptr; diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c index d3a2da6ace4..21313746ce3 100644 --- a/source/blender/modifiers/intern/MOD_smooth.c +++ b/source/blender/modifiers/intern/MOD_smooth.c @@ -227,6 +227,9 @@ static void deformVertsEM(ModifierData *md, /* mesh_src is needed for vgroups, and taking edges into account. */ mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(campbell): use edit-mode data only (remove this line). */ + BKE_mesh_wrapper_ensure_mdata(mesh_src); + smoothModifier_do(smd, ctx->object, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { @@ -236,16 +239,13 @@ static void deformVertsEM(ModifierData *md, static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row, *col; + uiLayout *row, *col; uiLayout *layout = panel->layout; int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -258,12 +258,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(col, &ptr, "factor", 0, NULL, ICON_NONE); uiItemR(col, &ptr, "iterations", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index c9a3e780040..09351450d3b 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -105,7 +105,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); int solidify_mode = RNA_enum_get(&ptr, "solidify_mode"); bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; @@ -134,12 +133,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemS(layout); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetPropDecorate(sub, false); - uiLayoutSetActive(sub, has_vertex_group); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); row = uiLayoutRow(layout, false); uiLayoutSetActive(row, has_vertex_group); uiItemR(row, &ptr, "thickness_vertex_group", 0, IFACE_("Factor"), ICON_NONE); @@ -228,6 +222,7 @@ static void clamp_panel_draw(const bContext *C, Panel *panel) static void vertex_group_panel_draw(const bContext *C, Panel *panel) { + uiLayout *col; uiLayout *layout = panel->layout; PointerRNA ptr; @@ -236,8 +231,9 @@ static void vertex_group_panel_draw(const bContext *C, Panel *panel) uiLayoutSetPropSep(layout, true); - uiItemPointerR(layout, &ptr, "shell_vertex_group", &ob_ptr, "vertex_groups", "Shell", ICON_NONE); - uiItemPointerR(layout, &ptr, "rim_vertex_group", &ob_ptr, "vertex_groups", "Rim", ICON_NONE); + col = uiLayoutColumn(layout, false); + uiItemPointerR(col, &ptr, "shell_vertex_group", &ob_ptr, "vertex_groups", "Shell", ICON_NONE); + uiItemPointerR(col, &ptr, "rim_vertex_group", &ob_ptr, "vertex_groups", "Rim", ICON_NONE); } static void panelRegister(ARegionType *region_type) diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 9e3d13432a0..affd3eece0a 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -328,22 +328,22 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - PointerRNA scene_ptr; - Scene *scene = CTX_data_scene(C); - RNA_id_pointer_create(&scene->id, &scene_ptr); /* Only test for adaptive subdivision if built with cycles. */ bool show_adaptive_options = false; bool ob_use_adaptive_subdivision = false; PointerRNA cycles_ptr = {NULL}; PointerRNA ob_cycles_ptr = {NULL}; #ifdef WITH_CYCLES - cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles"); - ob_cycles_ptr = RNA_pointer_get(&ob_ptr, "cycles"); - if (!RNA_pointer_is_null(&ob_cycles_ptr)) { - ob_use_adaptive_subdivision = RNA_boolean_get(&ob_cycles_ptr, "use_adaptive_subdivision"); - show_adaptive_options = get_show_adaptive_options(C, panel); + PointerRNA scene_ptr; + Scene *scene = CTX_data_scene(C); + RNA_id_pointer_create(&scene->id, &scene_ptr); + if (BKE_scene_uses_cycles(scene)) { + cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles"); + ob_cycles_ptr = RNA_pointer_get(&ob_ptr, "cycles"); + if (!RNA_pointer_is_null(&ob_cycles_ptr)) { + ob_use_adaptive_subdivision = RNA_boolean_get(&ob_cycles_ptr, "use_adaptive_subdivision"); + show_adaptive_options = get_show_adaptive_options(C, panel); + } } #endif @@ -358,30 +358,27 @@ static void panel_draw(const bContext *C, Panel *panel) 0, IFACE_("Adaptive Subdivision"), ICON_NONE); - if (ob_use_adaptive_subdivision) { - uiItemR(layout, &ob_cycles_ptr, "dicing_rate", 0, NULL, ICON_NONE); - float render = MAX2(RNA_float_get(&cycles_ptr, "dicing_rate") * - RNA_float_get(&ob_cycles_ptr, "dicing_rate"), - 0.1f); - float preview = MAX2(RNA_float_get(&cycles_ptr, "preview_dicing_rate") * - RNA_float_get(&ob_cycles_ptr, "dicing_rate"), - 0.1f); - char output[64]; - snprintf(output, 64, "Final Scale: Render %.2f px, Viewport %.2f px", render, preview); - uiItemL(layout, output, ICON_NONE); - - uiItemS(layout); - - uiItemR(layout, &ptr, "levels", 0, IFACE_("Levels Viewport"), ICON_NONE); - } - else { - uiItemR(layout, &ptr, "render_levels", 0, IFACE_("Levels Viewport"), ICON_NONE); - uiItemR(layout, &ptr, "levels", 0, IFACE_("Viewport"), ICON_NONE); - } } - else { + if (ob_use_adaptive_subdivision && show_adaptive_options) { + uiItemR(layout, &ob_cycles_ptr, "dicing_rate", 0, NULL, ICON_NONE); + float render = MAX2(RNA_float_get(&cycles_ptr, "dicing_rate") * + RNA_float_get(&ob_cycles_ptr, "dicing_rate"), + 0.1f); + float preview = MAX2(RNA_float_get(&cycles_ptr, "preview_dicing_rate") * + RNA_float_get(&ob_cycles_ptr, "dicing_rate"), + 0.1f); + char output[64]; + snprintf(output, 64, "Final Scale: Render %.2f px, Viewport %.2f px", render, preview); + uiItemL(layout, output, ICON_NONE); + + uiItemS(layout); + uiItemR(layout, &ptr, "levels", 0, IFACE_("Levels Viewport"), ICON_NONE); - uiItemR(layout, &ptr, "render_levels", 0, IFACE_("Render"), ICON_NONE); + } + else { + uiLayout *col = uiLayoutColumn(layout, true); + uiItemR(col, &ptr, "levels", 0, IFACE_("Levels Viewport"), ICON_NONE); + uiItemR(col, &ptr, "render_levels", 0, IFACE_("Render"), ICON_NONE); } uiItemR(layout, &ptr, "show_only_control_edges", 0, NULL, ICON_NONE); @@ -400,10 +397,13 @@ static void advanced_panel_draw(const bContext *C, Panel *panel) bool ob_use_adaptive_subdivision = false; bool show_adaptive_options = false; #ifdef WITH_CYCLES - PointerRNA ob_cycles_ptr = RNA_pointer_get(&ob_ptr, "cycles"); - if (!RNA_pointer_is_null(&ob_cycles_ptr)) { - ob_use_adaptive_subdivision = RNA_boolean_get(&ob_cycles_ptr, "use_adaptive_subdivision"); - show_adaptive_options = get_show_adaptive_options(C, panel); + Scene *scene = CTX_data_scene(C); + if (BKE_scene_uses_cycles(scene)) { + PointerRNA ob_cycles_ptr = RNA_pointer_get(&ob_ptr, "cycles"); + if (!RNA_pointer_is_null(&ob_cycles_ptr)) { + ob_use_adaptive_subdivision = RNA_boolean_get(&ob_cycles_ptr, "use_adaptive_subdivision"); + show_adaptive_options = get_show_adaptive_options(C, panel); + } } #endif @@ -413,6 +413,8 @@ static void advanced_panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "quality", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "uv_smooth", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "use_creases", 0, NULL, ICON_NONE); + + modifier_panel_end(layout, &ptr); } static void panelRegister(ARegionType *region_type) diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index 6be321eaa4e..4a2ed1d71db 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -1397,18 +1397,16 @@ static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *row, *col, *sub; + uiLayout *col; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); PointerRNA target_ptr = RNA_pointer_get(&ptr, "target"); bool is_bound = RNA_boolean_get(&ptr, "is_bound"); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -1419,13 +1417,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(col, &ptr, "falloff", 0, NULL, ICON_NONE); uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE); - row = uiLayoutRow(col, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetPropDecorate(sub, false); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); uiItemS(layout); diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index 1857744512d..351a1016a35 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -133,7 +133,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c index 58906c02c98..973afe5fef6 100644 --- a/source/blender/modifiers/intern/MOD_ui_common.c +++ b/source/blender/modifiers/intern/MOD_ui_common.c @@ -33,6 +33,7 @@ #include "DNA_particle_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "ED_object.h" @@ -49,13 +50,24 @@ #include "MOD_modifiertypes.h" #include "MOD_ui_common.h" /* Self include */ +static Object *get_modifier_object(const bContext *C) +{ + SpaceProperties *sbuts = CTX_wm_space_properties(C); + if (sbuts != NULL && (sbuts->pinid != NULL) && GS(sbuts->pinid->name) == ID_OB) { + return (Object *)sbuts->pinid; + } + else { + return CTX_data_active_object(C); + } +} + /** * Poll function so these modifier panels don't show for other object types with modifiers (only * grease pencil currently). */ static bool modifier_ui_poll(const bContext *C, PanelType *UNUSED(pt)) { - Object *ob = CTX_data_active_object(C); + Object *ob = get_modifier_object(C); return (ob != NULL) && (ob->type != OB_GPENCIL); } @@ -69,7 +81,7 @@ static bool modifier_ui_poll(const bContext *C, PanelType *UNUSED(pt)) */ static void modifier_reorder(bContext *C, Panel *panel, int new_index) { - Object *ob = CTX_data_active_object(C); + Object *ob = get_modifier_object(C); ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index); PointerRNA props_ptr; @@ -83,14 +95,14 @@ static void modifier_reorder(bContext *C, Panel *panel, int new_index) static short get_modifier_expand_flag(const bContext *C, Panel *panel) { - Object *ob = CTX_data_active_object(C); + Object *ob = get_modifier_object(C); ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index); return md->ui_expand_flag; } static void set_modifier_expand_flag(const bContext *C, Panel *panel, short expand_flag) { - Object *ob = CTX_data_active_object(C); + Object *ob = get_modifier_object(C); ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index); md->ui_expand_flag = expand_flag; } @@ -114,14 +126,17 @@ void modifier_panel_end(uiLayout *layout, PointerRNA *ptr) } /** - * Gets RNA pointers for the active object and the panel's modifier data. + * Gets RNA pointers for the active object and the panel's modifier data. Also locks + * the layout if the modifer is from a linked object, and sets the context pointer. */ +#define ERROR_LIBDATA_MESSAGE TIP_("External library data") void modifier_panel_get_property_pointers(const bContext *C, Panel *panel, PointerRNA *r_ob_ptr, PointerRNA *r_md_ptr) { - Object *ob = CTX_data_active_object(C); + Object *ob = get_modifier_object(C); + ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index); RNA_pointer_create(&ob->id, &RNA_Modifier, md, r_md_ptr); @@ -130,86 +145,41 @@ void modifier_panel_get_property_pointers(const bContext *C, RNA_pointer_create(&ob->id, &RNA_Object, ob, r_ob_ptr); } - uiLayoutSetContextPointer(panel->layout, "modifier", r_md_ptr); -} - -#define ERROR_LIBDATA_MESSAGE TIP_("Can't edit external library data") -void modifier_panel_buttons(const bContext *C, Panel *panel) -{ - uiLayout *row, *sub; - uiBlock *block; - uiLayout *layout = panel->layout; - - row = uiLayoutRow(layout, false); - - uiLayoutSetScaleY(row, 0.8f); - - Object *ob = CTX_data_active_object(C); - ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index); - - block = uiLayoutGetBlock(row); + uiBlock *block = uiLayoutGetBlock(panel->layout); UI_block_lock_set( block, BKE_object_obdata_is_libdata(ob) || ID_IS_LINKED(ob), ERROR_LIBDATA_MESSAGE); - if (md->type == eModifierType_ParticleSystem) { - ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; - - if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) { - if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB)) { - uiItemO(row, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"), - ICON_NONE, - "OBJECT_OT_duplicates_make_real"); - } - else if (psys->part->ren_as == PART_DRAW_PATH) { - uiItemO(row, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"), - ICON_NONE, - "OBJECT_OT_modifier_convert"); - } - } - } - else { - uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT); + uiLayoutSetContextPointer(panel->layout, "modifier", r_md_ptr); +} - sub = uiLayoutRow(row, false); - uiItemEnumO(sub, - "OBJECT_OT_modifier_apply", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"), - 0, - "apply_as", - MODIFIER_APPLY_DATA); - - if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) { - uiItemEnumO(sub, - "OBJECT_OT_modifier_apply", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Shape"), - 0, - "apply_as", - MODIFIER_APPLY_SHAPE); - } +/** + * Helper function for modifier layouts to draw vertex group settings. + */ +void modifier_vgroup_ui(uiLayout *layout, + PointerRNA *ptr, + PointerRNA *ob_ptr, + const char *vgroup_prop, + const char *invert_vgroup_prop, + const char *text) +{ + bool has_vertex_group = RNA_string_length(ptr, vgroup_prop) != 0; + + uiLayout *row = uiLayoutRow(layout, true); + uiItemPointerR(row, ptr, vgroup_prop, ob_ptr, "vertex_groups", text, ICON_NONE); + if (invert_vgroup_prop != NULL) { + uiLayout *sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, has_vertex_group); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, ptr, invert_vgroup_prop, 0, "", ICON_ARROW_LEFTRIGHT); } - - if (!ELEM(md->type, - eModifierType_Fluidsim, - eModifierType_Softbody, - eModifierType_ParticleSystem, - eModifierType_Cloth, - eModifierType_Fluid)) { - uiItemO(row, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Duplicate"), - 0, - "OBJECT_OT_modifier_copy"); - - row = uiLayoutRow(layout, false); - uiLayoutSetScaleY(row, 0.2f); - uiItemS(row); + if (uiLayoutGetPropDecorate(layout)) { + uiItemL(row, "", ICON_BLANK1); } } /** - * Check whether Modifier is a simulation or not.Used for switching to the physics/particles - * context tab. + * Check whether Modifier is a simulation or not. Used for switching to the + * physics/particles context tab. */ static int modifier_is_simulation(ModifierData *md) { @@ -255,18 +225,63 @@ static bool modifier_can_delete(ModifierData *md) return true; } +static void modifier_ops_extra_draw(bContext *UNUSED(C), uiLayout *layout, void *md_v) +{ + ModifierData *md = (ModifierData *)md_v; + + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + + uiItemEnumO(layout, + "OBJECT_OT_modifier_apply", + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"), + 0, + "apply_as", + MODIFIER_APPLY_DATA); + + if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) { + uiItemEnumO(layout, + "OBJECT_OT_modifier_apply", + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply As Shapekey"), + ICON_SHAPEKEY_DATA, + "apply_as", + MODIFIER_APPLY_SHAPE); + } + + if (!ELEM(md->type, + eModifierType_Fluidsim, + eModifierType_Softbody, + eModifierType_ParticleSystem, + eModifierType_Cloth, + eModifierType_Fluid)) { + uiItemO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Duplicate"), + ICON_DUPLICATE, + "OBJECT_OT_modifier_copy"); + } + + if (modifier_can_delete(md) && !modifier_is_simulation(md)) { + uiItemO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete"), + ICON_X, + "OBJECT_OT_modifier_remove"); + } +} + static void modifier_panel_header(const bContext *C, Panel *panel) { uiLayout *row, *sub; uiLayout *layout = panel->layout; PointerRNA ptr; - modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + Object *ob = get_modifier_object(C); + + /* Don't use #modifier_panel_get_property_pointers, we don't want to lock the header. */ + ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index); + RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr); + uiLayoutSetContextPointer(panel->layout, "modifier", &ptr); - ModifierData *md = ptr.data; const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); int index = panel->runtime.list_index; bool narrow_panel = (panel->sizex < UI_UNIT_X * 8 && panel->sizex != 0); @@ -292,6 +307,7 @@ static void modifier_panel_header(const bContext *C, Panel *panel) layout, "", ICON_PROPERTIES, "WM_OT_properties_context_change", "context", "PARTICLES"); } + /* Mode switching buttons. */ row = uiLayoutRow(layout, true); if (ob->type == OB_MESH) { int last_cage_index; @@ -323,12 +339,9 @@ static void modifier_panel_header(const bContext *C, Panel *panel) } row = uiLayoutRow(layout, false); - uiLayoutSetEmboss(row, UI_EMBOSS_NONE); - if (modifier_can_delete(md) && !modifier_is_simulation(md)) { - uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove"); - } + uiItemMenuF(row, "", ICON_DOWNARROW_HLT, modifier_ops_extra_draw, md); - /* Some extra padding at the end, so 'x' icon isn't too close to drag button. */ + /* Some padding at the end, so the buttons aren't too close to the drag button. */ uiItemS(layout); } @@ -343,7 +356,6 @@ static void modifier_panel_header(const bContext *C, Panel *panel) */ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw) { - /* Get the name for the modifier's panel. */ char panel_idname[BKE_ST_MAXNAME]; BKE_modifier_type_panel_id(type, panel_idname); @@ -372,7 +384,7 @@ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, } /** - * Add a child panel to the parent. + * Add a shild panel to the parent. * * \note To create the panel type's idname, it appends the \a name argument to the \a parent's * idname. diff --git a/source/blender/modifiers/intern/MOD_ui_common.h b/source/blender/modifiers/intern/MOD_ui_common.h index cb18fb93973..59c0fe1c413 100644 --- a/source/blender/modifiers/intern/MOD_ui_common.h +++ b/source/blender/modifiers/intern/MOD_ui_common.h @@ -34,10 +34,17 @@ struct ARegionType; struct bContext; struct PanelType; struct uiLayout; -typedef void (*PanelDrawFn)(const bContext *, Panel *); +typedef void (*PanelDrawFn)(const bContext *, struct Panel *); void modifier_panel_buttons(const struct bContext *C, struct Panel *panel); +void modifier_vgroup_ui(struct uiLayout *layout, + struct PointerRNA *ptr, + struct PointerRNA *ob_ptr, + const char *vgroup_prop, + const char *invert_vgroup_prop, + const char *text); + void modifier_panel_end(struct uiLayout *layout, PointerRNA *ptr); void modifier_panel_get_property_pointers(const bContext *C, diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index bd453c24a31..4999c77c355 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -196,7 +196,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, } else if (ob->type == OB_MESH) { if (em) { - mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data); + mesh = BKE_mesh_wrapper_from_editmesh_with_coords(em, NULL, vertexCos, ob->data); } else { /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether @@ -209,9 +209,12 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, mesh->runtime.deformed_only = 1; } + if (em != NULL) { + /* pass */ + } /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether * we really need vertexCos here. */ - if (vertexCos) { + else if (vertexCos) { BKE_mesh_vert_coords_apply(mesh, vertexCos); mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; } @@ -241,7 +244,9 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, } } - BLI_assert(mesh == NULL || mesh->totvert == num_verts); + if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) { + BLI_assert(mesh->totvert == num_verts); + } return mesh; } diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 32aaa4992e3..07a57806f87 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -332,7 +332,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data"); diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c index 9f4e8b76a0f..a8321cdc26a 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.c +++ b/source/blender/modifiers/intern/MOD_uvwarp.c @@ -258,17 +258,15 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row, *col; + uiLayout *col; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); PointerRNA warp_obj_ptr; PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data"); - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -296,13 +294,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemPointerR(col, &ptr, "bone_to", &warp_obj_data_ptr, "bones", NULL, ICON_NONE); } - col = uiLayoutColumn(layout, true); - row = uiLayoutRow(col, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index fb9908c8455..eab8ba478aa 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -392,6 +392,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); } + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { @@ -401,15 +406,12 @@ static void deformVertsEM(ModifierData *md, static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row, *col; + uiLayout *col; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -432,16 +434,9 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "use_volume_preserve", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemR(row, &ptr, "strength", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "strength", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetPropDecorate(sub, false); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index c07f6cf8ba8..48aca9284eb 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -364,6 +364,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); } + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { @@ -379,9 +384,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -405,12 +407,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(col, &ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemR(col, &ptr, "narrowness", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index 0bd8751fcb2..dc1b7ba8a75 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -713,15 +713,11 @@ static bool dependsOnNormals(ModifierData *UNUSED(md)) static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); @@ -733,12 +729,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "keep_sharp", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "face_influence", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutColumn(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index 5ef6ee8b41d..54d3aa46344 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -52,6 +52,7 @@ #include "DEG_depsgraph_query.h" #include "MEM_guardedalloc.h" +#include "MOD_ui_common.h" #include "MOD_util.h" #include "MOD_weightvg_util.h" #include "RE_shader_ext.h" /* Texture masking. */ @@ -280,16 +281,45 @@ void weightvg_update_vg(MDeformVert *dvert, const bool do_add, const float add_thresh, const bool do_rem, - const float rem_thresh) + const float rem_thresh, + const bool do_normalize) { int i; + float min_w = weights[0]; + float norm_fac = 1.0f; + if (do_normalize) { + float max_w = weights[0]; + for (i = 1; i < num; i++) { + const float w = weights[i]; + + /* No need to clamp here, normalization will ensure we stay within [0.0, 1.0] range. */ + if (w < min_w) { + min_w = w; + } + else if (w > max_w) { + max_w = w; + } + } + + const float range = max_w - min_w; + if (fabsf(range) > FLT_EPSILON) { + norm_fac = 1.0f / range; + } + else { + min_w = 0.0f; + } + } + for (i = 0; i < num; i++) { float w = weights[i]; MDeformVert *dv = &dvert[indices ? indices[i] : i]; MDeformWeight *dw = dws ? dws[i] : ((defgrp_idx >= 0) ? BKE_defvert_find_index(dv, defgrp_idx) : NULL); + if (do_normalize) { + w = (w - min_w) * norm_fac; + } /* Never allow weights out of [0.0, 1.0] range. */ CLAMP(w, 0.0f, 1.0f); @@ -313,8 +343,6 @@ void weightvg_update_vg(MDeformVert *dvert, */ void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout) { - uiLayout *sub, *row; - PointerRNA mask_texture_ptr = RNA_pointer_get(ptr, "mask_texture"); bool has_mask_texture = !RNA_pointer_is_null(&mask_texture_ptr); bool has_mask_vertex_group = RNA_string_length(ptr, "mask_vertex_group") != 0; @@ -325,12 +353,7 @@ void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiItemR(layout, ptr, "mask_constant", UI_ITEM_R_SLIDER, IFACE_("Global Influence:"), ICON_NONE); if (!has_mask_texture) { - row = uiLayoutRow(layout, true); - uiItemPointerR(row, ptr, "mask_vertex_group", ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutColumn(row, true); - uiLayoutSetPropSep(sub, false); - uiLayoutSetActive(sub, has_mask_vertex_group); - uiItemR(sub, ptr, "invert_mask_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, ptr, ob_ptr, "mask_vertex_group", "invert_mask_vertex_group", NULL); } if (!has_mask_vertex_group) { diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.h b/source/blender/modifiers/intern/MOD_weightvg_util.h index 8be608410be..725574dc0a5 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.h +++ b/source/blender/modifiers/intern/MOD_weightvg_util.h @@ -88,7 +88,8 @@ void weightvg_update_vg(struct MDeformVert *dvert, const bool do_add, const float add_thresh, const bool do_rem, - const float rem_thresh); + const float rem_thresh, + const bool do_normalize); void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout); #endif /* __MOD_WEIGHTVG_UTIL_H__ */ diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index 317e61e286d..9a9ab55a835 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -250,6 +250,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* Do mapping. */ const bool do_invert_mapping = (wmd->edit_flags & MOD_WVG_INVERT_FALLOFF) != 0; + const bool do_normalize = (wmd->edit_flags & MOD_WVG_EDIT_WEIGHTS_NORMALIZE) != 0; if (do_invert_mapping || wmd->falloff_type != MOD_WVG_MAPPING_NONE) { RNG *rng = NULL; @@ -294,7 +295,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * do_add, wmd->add_threshold, do_rem, - wmd->rem_threshold); + wmd->rem_threshold, + do_normalize); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ @@ -320,7 +322,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); @@ -351,6 +352,8 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(sub, &ptr, "remove_threshold", UI_ITEM_R_SLIDER, "Threshold", ICON_NONE); uiItemDecoratorR(row, &ptr, "remove_threshold", 0); + uiItemR(layout, &ptr, "normalize", 0, NULL, ICON_NONE); + modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index a8189a460d1..e089720b3e3 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -235,6 +235,17 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * int numIdx = 0; int i; const bool invert_vgroup_mask = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_MASK) != 0; + const bool do_normalize = (wmd->flag & MOD_WVG_MIX_WEIGHTS_NORMALIZE) != 0; + + /* + * Note that we only invert the weight values within provided vgroups, the selection based on + * which vertice is affected because it belongs or not to a group remains unchanged. + * In other words, vertices not belonging to a group won't be affected, even though their + * inverted 'virtual' weight would be 1.0f. + */ + const bool invert_vgroup_a = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_A) != 0; + const bool invert_vgroup_b = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_B) != 0; + /* Flags. */ #if 0 const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0; @@ -389,8 +400,18 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* Mix weights. */ for (i = 0; i < numIdx; i++) { float weight2; - org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a; - weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b; + if (invert_vgroup_a) { + org_w[i] = 1.0f - (dw1[i] ? dw1[i]->weight : wmd->default_weight_a); + } + else { + org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a; + } + if (invert_vgroup_b) { + weight2 = 1.0f - (dw2[i] ? dw2[i]->weight : wmd->default_weight_b); + } + else { + weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b; + } new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode); } @@ -419,7 +440,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup. */ weightvg_update_vg( - dvert, defgrp_index, dw1, numIdx, indices, org_w, true, -FLT_MAX, false, 0.0f); + dvert, defgrp_index, dw1, numIdx, indices, org_w, true, -FLT_MAX, false, 0.0f, do_normalize); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ @@ -446,21 +467,25 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); - uiItemPointerR(layout, &ptr, "vertex_group_a", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - uiItemR(layout, &ptr, "default_weight_a", 0, NULL, ICON_NONE); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group_a", "invert_vertex_group_a", NULL); + modifier_vgroup_ui( + layout, &ptr, &ob_ptr, "vertex_group_b", "invert_vertex_group_b", IFACE_("B")); + + uiItemS(layout); - uiItemPointerR(layout, &ptr, "vertex_group_b", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - uiItemR(layout, &ptr, "default_weight_b", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "default_weight_a", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "default_weight_b", 0, IFACE_("B"), ICON_NONE); uiItemS(layout); uiItemR(layout, &ptr, "mix_set", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "mix_mode", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "normalize", 0, NULL, ICON_NONE); + modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index a9aafd01843..02d1f7a94aa 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -440,6 +440,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * int i; const bool invert_vgroup_mask = (wmd->proximity_flags & MOD_WVG_PROXIMITY_INVERT_VGROUP_MASK) != 0; + const bool do_normalize = (wmd->proximity_flags & MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE) != 0; /* Flags. */ #if 0 const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0; @@ -615,7 +616,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * invert_vgroup_mask); /* Update vgroup. Note we never add nor remove vertices from vgroup here. */ - weightvg_update_vg(dvert, defgrp_index, dw, numIdx, indices, org_w, false, 0.0f, false, 0.0f); + weightvg_update_vg( + dvert, defgrp_index, dw, numIdx, indices, org_w, false, 0.0f, false, 0.0f, do_normalize); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ @@ -647,7 +649,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); @@ -674,6 +675,10 @@ static void panel_draw(const bContext *C, Panel *panel) uiLayoutSetPropSep(sub, false); uiItemR(row, &ptr, "invert_falloff", 0, "", ICON_ARROW_LEFTRIGHT); modifier_panel_end(layout, &ptr); + + uiItemS(layout); + + uiItemR(layout, &ptr, "normalize", 0, NULL, ICON_NONE); } static void influence_panel_draw(const bContext *C, Panel *panel) diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c index acef6b3e20d..76ca85163d9 100644 --- a/source/blender/modifiers/intern/MOD_weld.c +++ b/source/blender/modifiers/intern/MOD_weld.c @@ -1688,8 +1688,18 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex /* Get overlap map. */ /* TODO: For a better performanse use KD-Tree. */ struct BVHTreeFromMesh treedata; - BVHTree *bvhtree = bvhtree_from_mesh_verts_ex( - &treedata, mvert, totvert, false, v_mask, v_mask_act, wmd->merge_dist / 2, 2, 6, 0, NULL); + BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata, + mvert, + totvert, + false, + v_mask, + v_mask_act, + wmd->merge_dist / 2, + 2, + 6, + 0, + NULL, + NULL); if (v_mask) { MEM_freeN(v_mask); @@ -1942,26 +1952,17 @@ static void requiredDataMask(Object *UNUSED(ob), static void panel_draw(const bContext *C, Panel *panel) { - uiLayout *sub, *row; uiLayout *layout = panel->layout; PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); - - bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; uiLayoutSetPropSep(layout, true); uiItemR(layout, &ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE); uiItemR(layout, &ptr, "max_interactions", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropSep(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, &ptr); } diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index c8c372513d0..66a03ee5d71 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -125,7 +125,6 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ptr; PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); - modifier_panel_buttons(C, panel); uiLayoutSetPropSep(layout, true); @@ -153,7 +152,7 @@ static void panel_draw(const bContext *C, Panel *panel) static void vertex_group_panel_draw(const bContext *C, Panel *panel) { - uiLayout *row, *sub; + uiLayout *row; uiLayout *layout = panel->layout; PointerRNA ptr; @@ -164,12 +163,7 @@ static void vertex_group_panel_draw(const bContext *C, Panel *panel) uiLayoutSetPropSep(layout, true); - row = uiLayoutRow(layout, true); - uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, has_vertex_group); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + modifier_vgroup_ui(layout, &ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); row = uiLayoutRow(layout, true); uiLayoutSetActive(row, has_vertex_group); diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c index 4b7bd964052..578262e9f17 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.c @@ -45,9 +45,18 @@ static int node_shader_gpu_output_material(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - GPUNodeLink *outlink; + GPUNodeLink *outlink, *alpha_threshold_link; - GPU_stack_link(mat, node, "node_output_material", in, out, &outlink); + Material *ma = GPU_material_get_material(mat); + if (ma && ma->blend_method == MA_BM_CLIP) { + alpha_threshold_link = GPU_uniform(&ma->alpha_threshold); + } + else { + static float no_alpha_threshold = -1.0f; + alpha_threshold_link = GPU_uniform(&no_alpha_threshold); + } + + GPU_stack_link(mat, node, "node_output_material", in, out, alpha_threshold_link, &outlink); GPU_material_output_link(mat, outlink); return true; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index fd4efb1b7ec..0cf4b51f307 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -19,6 +19,8 @@ #include "../node_shader_util.h" +#include "GPU_draw.h" + /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_tex_environment_in[] = { @@ -56,6 +58,10 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node_original = node->original ? node->original : node; NodeTexImage *tex_original = node_original->storage; ImageUser *iuser = &tex_original->iuser; + eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER; + if (GPU_get_mipmap()) { + sampler |= GPU_SAMPLER_MIPMAP; + } GPUNodeLink *outalpha; @@ -72,49 +78,41 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, /* Compute texture coordinate. */ if (tex->projection == SHD_PROJ_EQUIRECTANGULAR) { - /* To fix pole issue we clamp the v coordinate. The clamp value depends on the filter size. */ - float clamp_size = (ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART)) ? 1.5 : 0.5; - GPU_link(mat, - "node_tex_environment_equirectangular", - in[0].link, - GPU_constant(&clamp_size), - GPU_image(mat, ima, iuser), - &in[0].link); + GPU_link(mat, "node_tex_environment_equirectangular", in[0].link, &in[0].link); + /* To fix pole issue we clamp the v coordinate. */ + sampler &= ~GPU_SAMPLER_REPEAT_T; + /* Force the highest mipmap and don't do anisotropic filtering. + * This is to fix the artifact caused by derivatives discontinuity. */ + sampler &= ~(GPU_SAMPLER_MIPMAP | GPU_SAMPLER_ANISO); } else { GPU_link(mat, "node_tex_environment_mirror_ball", in[0].link, &in[0].link); + /* Fix pole issue. */ + sampler &= ~GPU_SAMPLER_REPEAT; } - /* Sample texture with correct interpolation. */ + const char *gpufunc; + static const char *names[] = { + "node_tex_image_linear", + "node_tex_image_cubic", + }; + switch (tex->interpolation) { case SHD_INTERP_LINEAR: - /* Force the highest mipmap and don't do anisotropic filtering. - * This is to fix the artifact caused by derivatives discontinuity. */ - GPU_link(mat, - "node_tex_image_linear_no_mip", - in[0].link, - GPU_image(mat, ima, iuser), - &out[0].link, - &outalpha); + gpufunc = names[0]; break; case SHD_INTERP_CLOSEST: - GPU_link(mat, - "node_tex_image_nearest", - in[0].link, - GPU_image(mat, ima, iuser), - &out[0].link, - &outalpha); + sampler &= ~(GPU_SAMPLER_FILTER | GPU_SAMPLER_MIPMAP); + gpufunc = names[0]; break; default: - GPU_link(mat, - "node_tex_image_cubic", - in[0].link, - GPU_image(mat, ima, iuser), - &out[0].link, - &outalpha); + gpufunc = names[1]; break; } + /* Sample texture with correct interpolation. */ + GPU_link(mat, gpufunc, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha); + if (out[0].hasoutput) { if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) || IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c index bfef9341913..cbda72cd228 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c @@ -19,6 +19,8 @@ #include "../node_shader_util.h" +#include "GPU_draw.h" + /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_tex_image_in[] = { @@ -57,31 +59,6 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - static const char *names[] = { - "node_tex_image_linear", - "node_tex_image_nearest", - "node_tex_image_cubic", - "node_tex_image_smart", - }; - static const char *names_tiled[] = { - "node_tex_tile_linear", - "node_tex_tile_nearest", - "node_tex_tile_cubic", - "node_tex_tile_smart", - }; - static const char *names_box[] = { - "tex_box_sample_linear", - "tex_box_sample_nearest", - "tex_box_sample_cubic", - "tex_box_sample_smart", - }; - static const char *names_clip[] = { - "tex_clip_linear", - "tex_clip_nearest", - "tex_clip_cubic", - "tex_clip_smart", - }; - Image *ima = (Image *)node->id; NodeTexImage *tex = node->storage; @@ -91,26 +68,11 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, NodeTexImage *tex_original = node_original->storage; ImageUser *iuser = &tex_original->iuser; - const char *gpu_node_name = (tex->projection == SHD_PROJ_BOX) ? names_box[tex->interpolation] : - names[tex->interpolation]; - bool do_texco_extend = (tex->extension != SHD_IMAGE_EXTENSION_REPEAT); - const bool do_texco_clip = (tex->extension == SHD_IMAGE_EXTENSION_CLIP); - - if (do_texco_extend && (tex->projection != SHD_PROJ_BOX) && - ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART)) { - gpu_node_name = "node_tex_image_cubic_extend"; - /* We do it inside the sampling function */ - do_texco_extend = false; - } - - GPUNodeLink *norm, *col1, *col2, *col3, *input_coords, *gpu_image; - GPUNodeLink *vnor, *ob_mat, *blend; - GPUNodeLink **texco = &in[0].link; - if (!ima) { return GPU_stack_link(mat, node, "node_tex_image_empty", in, out); } + GPUNodeLink **texco = &in[0].link; if (!*texco) { *texco = GPU_attribute(mat, CD_MTFACE, ""); node_shader_gpu_bump_tex_coord(mat, node, texco); @@ -118,88 +80,73 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, node_shader_gpu_tex_mapping(mat, node, in, out); + eGPUSamplerState sampler_state = 0; + + switch (tex->extension) { + case SHD_IMAGE_EXTENSION_REPEAT: + sampler_state |= GPU_SAMPLER_REPEAT; + break; + case SHD_IMAGE_EXTENSION_CLIP: + sampler_state |= GPU_SAMPLER_CLAMP_BORDER; + break; + default: + break; + } + + if (tex->interpolation != SHD_INTERP_CLOSEST) { + sampler_state |= GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER; + sampler_state |= GPU_get_mipmap() ? GPU_SAMPLER_MIPMAP : 0; + } + const bool use_cubic = ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART); + if (ima->source == IMA_SRC_TILED) { + const char *gpu_node_name = use_cubic ? "node_tex_tile_cubic" : "node_tex_tile_linear"; + GPUNodeLink *gpu_image = GPU_image_tiled(mat, ima, iuser, sampler_state); + GPUNodeLink *gpu_image_tile_mapping = GPU_image_tiled_mapping(mat, ima, iuser); /* UDIM tiles needs a samper2DArray and sampler1DArray for tile mapping. */ - GPU_stack_link(mat, - node, - names_tiled[tex->interpolation], - in, - out, - GPU_image_tiled(mat, ima, iuser), - GPU_image_tiled_mapping(mat, ima, iuser)); + GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image, gpu_image_tile_mapping); } else { + const char *gpu_node_name = use_cubic ? "node_tex_image_cubic" : "node_tex_image_linear"; + switch (tex->projection) { - case SHD_PROJ_FLAT: - if (do_texco_clip) { - /* This seems redundant, but is required to ensure the texco link - * is not freed by GPU_link, as it is still needed for GPU_stack_link. - * Intermediate links like this can only be used once and are then - * freed immediately, but if we make it the output link of a set_rgb - * node it will be kept and can be used multiple times. */ - GPU_link(mat, "set_rgb", *texco, texco); - GPU_link(mat, "set_rgb", *texco, &input_coords); - } - if (do_texco_extend) { - GPU_link(mat, "point_texco_clamp", *texco, GPU_image(mat, ima, iuser), texco); - } - GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(mat, ima, iuser)); + case SHD_PROJ_FLAT: { + GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state); + GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image); break; - - case SHD_PROJ_BOX: - vnor = GPU_builtin(GPU_WORLD_NORMAL); - ob_mat = GPU_builtin(GPU_OBJECT_MATRIX); - blend = GPU_uniform(&tex->projection_blend); - gpu_image = GPU_image(mat, ima, iuser); - + } + case SHD_PROJ_BOX: { + gpu_node_name = use_cubic ? "tex_box_sample_cubic" : "tex_box_sample_linear"; + GPUNodeLink *wnor, *col1, *col2, *col3; + GPUNodeLink *vnor = GPU_builtin(GPU_WORLD_NORMAL); + GPUNodeLink *ob_mat = GPU_builtin(GPU_OBJECT_MATRIX); + GPUNodeLink *blend = GPU_uniform(&tex->projection_blend); + GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state); /* equivalent to normal_world_to_object */ - GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &norm); - { - /* See SHD_PROJ_FLAT for explanation. */ - GPU_link(mat, "set_rgb", *texco, texco); - GPU_link(mat, "set_rgb", *texco, &input_coords); - in[0].link = input_coords; - } - GPU_link( - mat, gpu_node_name, *texco, norm, GPU_image(mat, ima, iuser), &col1, &col2, &col3); - GPU_stack_link( - mat, node, "node_tex_image_box", in, out, norm, col1, col2, col3, gpu_image, blend); + GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &wnor); + GPU_link(mat, gpu_node_name, in[0].link, wnor, gpu_image, &col1, &col2, &col3); + GPU_link(mat, "tex_box_blend", wnor, col1, col2, col3, blend, &out[0].link, &out[1].link); break; - - case SHD_PROJ_SPHERE: + } + case SHD_PROJ_SPHERE: { + /* This projection is known to have a derivative discontinuity. + * Hide it by turning off mipmapping. */ + sampler_state &= ~GPU_SAMPLER_MIPMAP; + GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state); GPU_link(mat, "point_texco_remap_square", *texco, texco); GPU_link(mat, "point_map_to_sphere", *texco, texco); - if (do_texco_clip) { - /* See SHD_PROJ_FLAT for explanation. */ - GPU_link(mat, "set_rgb", *texco, texco); - GPU_link(mat, "set_rgb", *texco, &input_coords); - } - if (do_texco_extend) { - GPU_link(mat, "point_texco_clamp", *texco, GPU_image(mat, ima, iuser), texco); - } - GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(mat, ima, iuser)); + GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image); break; - - case SHD_PROJ_TUBE: + } + case SHD_PROJ_TUBE: { + /* This projection is known to have a derivative discontinuity. + * Hide it by turning off mipmapping. */ + sampler_state &= ~GPU_SAMPLER_MIPMAP; + GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state); GPU_link(mat, "point_texco_remap_square", *texco, texco); GPU_link(mat, "point_map_to_tube", *texco, texco); - if (do_texco_clip) { - /* See SHD_PROJ_FLAT for explanation. */ - GPU_link(mat, "set_rgb", *texco, texco); - GPU_link(mat, "set_rgb", *texco, &input_coords); - } - if (do_texco_extend) { - GPU_link(mat, "point_texco_clamp", *texco, GPU_image(mat, ima, iuser), texco); - } - GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(mat, ima, iuser)); + GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image); break; - } - - if (tex->projection != SHD_PROJ_BOX) { - if (do_texco_clip) { - gpu_node_name = names_clip[tex->interpolation]; - in[0].link = input_coords; - GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(mat, ima, iuser), out[0].link); } } } diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 280f09d67c9..311cf2b8c73 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -40,6 +40,7 @@ #include "DNA_screen_types.h" #include "DNA_view3d_types.h" +#include "GPU_context.h" #include "GPU_framebuffer.h" #include "GPU_texture.h" @@ -84,7 +85,7 @@ static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args { BPYGPU_IS_INIT_OR_ERROR_OBJ; - GPUOffScreen *ofs; + GPUOffScreen *ofs = NULL; int width, height, samples = 0; char err_out[256]; @@ -94,7 +95,12 @@ static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args return NULL; } - ofs = GPU_offscreen_create(width, height, samples, true, false, err_out); + if (GPU_context_active_get()) { + ofs = GPU_offscreen_create(width, height, samples, true, false, err_out); + } + else { + strncpy(err_out, "No active GPU context found", 256); + } if (ofs == NULL) { PyErr_Format(PyExc_RuntimeError, diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index 38a5629a2cc..165286c3661 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -78,7 +78,7 @@ static int bpygpu_uniform_location_get(GPUShader *shader, const char *name, const char *error_prefix) { - int uniform = GPU_shader_get_uniform_ensure(shader, name); + int uniform = GPU_shader_get_uniform(shader, name); if (uniform == -1) { PyErr_Format(PyExc_ValueError, "%s: uniform %.32s not found", error_prefix, name); @@ -524,7 +524,7 @@ PyDoc_STRVAR(bpygpu_shader_calc_format_doc, static PyObject *bpygpu_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg)) { BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL); - GPU_vertformat_from_interface(&ret->fmt, GPU_shader_get_interface(self->shader)); + GPU_vertformat_from_shader(&ret->fmt, self->shader); return (PyObject *)ret; } diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 9d0ee0bb500..de8fd87db58 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -380,10 +380,7 @@ void BPy_init_modules(void) PyModule_AddObject(mod, "types", BPY_rna_types()); /* needs to be first so bpy_types can run */ - BPY_library_load_module(mod); - BPY_library_write_module(mod); - - BPY_rna_id_collection_module(mod); + BPY_library_load_type_ready(); BPY_rna_gizmo_module(mod); diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index a9bdef1c3e4..957d49eb04e 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -82,10 +82,10 @@ extern char build_system[]; static PyTypeObject BlenderAppType; static PyStructSequence_Field app_info_fields[] = { - {"version", "The Blender version as a tuple of 3 numbers. eg. (2, 50, 11)"}, + {"version", "The Blender version as a tuple of 3 numbers. eg. (2, 83, 1)"}, {"version_string", "The Blender version formatted as a string"}, - {"version_char", "The Blender version character (for minor releases)"}, {"version_cycle", "The release status of this build alpha/beta/rc/release"}, + {"version_char", "Deprecated, always an empty string"}, {"binary_path", "The location of Blender's executable, useful for utilities that open new instances"}, {"background", @@ -160,12 +160,12 @@ static PyObject *make_app_info(void) #define SetBytesItem(str) PyStructSequence_SET_ITEM(app_info, pos++, PyBytes_FromString(str)) #define SetObjItem(obj) PyStructSequence_SET_ITEM(app_info, pos++, obj) - SetObjItem(PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); - SetObjItem(PyUnicode_FromFormat( - "%d.%02d (sub %d)", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); + SetObjItem( + PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_VERSION_PATCH)); + SetStrItem(BKE_blender_version_string()); - SetStrItem(STRINGIFY(BLENDER_VERSION_CHAR)); SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE)); + SetStrItem(""); SetStrItem(BKE_appdir_program_path()); SetObjItem(PyBool_FromLong(G.background)); SetObjItem(PyBool_FromLong(G.factory_startup)); diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index 28498e116df..dde1d13477f 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -44,8 +44,16 @@ void bpy_app_generic_callback(struct Main *main, static PyTypeObject BlenderAppCbType; static PyStructSequence_Field app_cb_info_fields[] = { - {"frame_change_pre", "on frame change for playback and rendering (before)"}, - {"frame_change_post", "on frame change for playback and rendering (after)"}, + {"frame_change_pre", + "Called after frame change for playback and rendering, before any data is evaluated for the " + "new frame. This makes it possible to change data and relations (for example swap an object " + "to another mesh) for the new frame. Note that this handler is **not** to be used as 'before " + "the frame changes' event. The dependency graph is not available in this handler, as data " + "and relations may have been altered and the dependency graph has not yet been updated for " + "that."}, + {"frame_change_post", + "Called after frame change for playback and rendering, after the data has been evaluated " + "for the new frame."}, {"render_pre", "on render (before)"}, {"render_post", "on render (after)"}, {"render_write", "on writing a render frame (directly after the frame is written)"}, diff --git a/source/blender/python/intern/bpy_library.h b/source/blender/python/intern/bpy_library.h index 3fd116d7028..6840807d2b0 100644 --- a/source/blender/python/intern/bpy_library.h +++ b/source/blender/python/intern/bpy_library.h @@ -21,7 +21,9 @@ #ifndef __BPY_LIBRARY_H__ #define __BPY_LIBRARY_H__ -int BPY_library_load_module(PyObject *mod_par); -int BPY_library_write_module(PyObject *mod_par); +int BPY_library_load_type_ready(void); +extern PyMethodDef BPY_library_load_method_def; + +extern PyMethodDef BPY_library_write_method_def; #endif /* __BPY_LIBRARY_H__ */ diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 989b7931444..05cbc9af601 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -459,15 +459,15 @@ static PyObject *bpy_lib_dir(BPy_Library *self) return PyDict_Keys(self->dict); } -int BPY_library_load_module(PyObject *mod_par) +PyMethodDef BPY_library_load_method_def = { + "load", + (PyCFunction)bpy_lib_load, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_lib_load_doc, +}; + +int BPY_library_load_type_ready(void) { - static PyMethodDef load_meth = { - "load", - (PyCFunction)bpy_lib_load, - METH_STATIC | METH_VARARGS | METH_KEYWORDS, - bpy_lib_load_doc, - }; - PyModule_AddObject(mod_par, "_library_load", PyCFunction_New(&load_meth, NULL)); /* some compilers don't like accessing this directly, delay assignment */ bpy_lib_Type.tp_getattro = PyObject_GenericGetAttr; diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c index 6c8f1deb126..fec0cef7b05 100644 --- a/source/blender/python/intern/bpy_library_write.c +++ b/source/blender/python/intern/bpy_library_write.c @@ -204,16 +204,9 @@ finally: return ret; } -int BPY_library_write_module(PyObject *mod_par) -{ - static PyMethodDef write_meth = { - "write", - (PyCFunction)bpy_lib_write, - METH_STATIC | METH_VARARGS | METH_KEYWORDS, - bpy_lib_write_doc, - }; - - PyModule_AddObject(mod_par, "_library_write", PyCFunction_New(&write_meth, NULL)); - - return 0; -} +PyMethodDef BPY_library_write_method_def = { + "write", + (PyCFunction)bpy_lib_write, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_lib_write_doc, +}; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 39485f322d4..179daad2f60 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -9040,32 +9040,41 @@ void pyrna_struct_type_extend_capi(struct StructRNA *srna, struct PyMethodDef *method, struct PyGetSetDef *getset) { - PyObject *cls = pyrna_srna_Subtype(srna); + /* See 'add_methods' in Python's 'typeobject.c'. */ + PyTypeObject *type = (PyTypeObject *)pyrna_srna_Subtype(srna); + PyObject *dict = type->tp_dict; if (method != NULL) { for (; method->ml_name != NULL; method++) { - PyObject *func = PyCFunction_New(method, NULL); - PyObject *args = PyTuple_New(1); - PyTuple_SET_ITEM(args, 0, func); - PyObject *classmethod = PyObject_CallObject((PyObject *)&PyClassMethod_Type, args); + PyObject *py_method; - PyObject_SetAttrString(cls, method->ml_name, classmethod); + if (method->ml_flags & METH_CLASS) { + PyObject *cfunc = PyCFunction_New(method, (PyObject *)type); + py_method = PyClassMethod_New(cfunc); + Py_DECREF(cfunc); + } + else { + /* Currently only static and class methods are used. */ + BLI_assert(method->ml_flags & METH_STATIC); + py_method = PyCFunction_New(method, NULL); + } - Py_DECREF(classmethod); - Py_DECREF(args); /* Clears 'func' too. */ + int err = PyDict_SetItemString(dict, method->ml_name, py_method); + Py_DECREF(py_method); + BLI_assert(!(err < 0)); + UNUSED_VARS_NDEBUG(err); } } if (getset != NULL) { - PyObject *dict = ((PyTypeObject *)cls)->tp_dict; for (; getset->name != NULL; getset++) { - PyObject *descr = PyDescr_NewGetSet((PyTypeObject *)cls, getset); + PyObject *descr = PyDescr_NewGetSet(type, getset); /* Ensure we're not overwriting anything that already exists. */ BLI_assert(PyDict_GetItem(dict, PyDescr_NAME(descr)) == NULL); PyDict_SetItem(dict, PyDescr_NAME(descr), descr); Py_DECREF(descr); } } - Py_DECREF(cls); + Py_DECREF(type); } /* Access to 'owner_id' internal global. */ diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index d8043ee2fdf..d792b2032b5 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -354,7 +354,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb if (prop) { NlaStrip *strip = ptr.data; - FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); + FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index); result = insert_keyframe_direct(&reports, ptr, prop, fcu, cfra, keytype, NULL, options); } @@ -462,7 +462,7 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb if (prop) { ID *id = ptr.owner_id; NlaStrip *strip = ptr.data; - FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); + FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index); /* NOTE: This should be true, or else we wouldn't be able to get here. */ BLI_assert(fcu != NULL); @@ -577,13 +577,13 @@ PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args) if (index == -1) { /* all, use a list */ int i = 0; ret = PyList_New(0); - while ((fcu = list_find_fcurve(&adt->drivers, path_full, i++))) { + while ((fcu = BKE_fcurve_find(&adt->drivers, path_full, i++))) { RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr); PyList_APPEND(ret, pyrna_struct_CreatePyObject(&tptr)); } } else { - fcu = list_find_fcurve(&adt->drivers, path_full, index); + fcu = BKE_fcurve_find(&adt->drivers, path_full, index); RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr); ret = pyrna_struct_CreatePyObject(&tptr); } diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c index cc9f5746bba..f9bcb8943f4 100644 --- a/source/blender/python/intern/bpy_rna_callback.c +++ b/source/blender/python/intern/bpy_rna_callback.c @@ -324,10 +324,8 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args) return NULL; } - bContext *C = BPy_GetContext(); - struct wmWindowManager *wm = CTX_wm_manager(C); handle = WM_paint_cursor_activate( - wm, params.space_type, params.region_type, NULL, cb_wm_cursor_draw, (void *)args); + params.space_type, params.region_type, NULL, cb_wm_cursor_draw, (void *)args); } else if (RNA_struct_is_a(srna, &RNA_Space)) { const char *error_prefix = "Space.draw_handler_add"; @@ -424,9 +422,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar args, "OO!:WindowManager.draw_cursor_remove", &cls, &PyCapsule_Type, &py_handle)) { return NULL; } - bContext *C = BPy_GetContext(); - struct wmWindowManager *wm = CTX_wm_manager(C); - WM_paint_cursor_end(wm, handle); + WM_paint_cursor_end(handle); capsule_clear = true; } else if (RNA_struct_is_a(srna, &RNA_Space)) { diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index 6b6ffa97995..b607f1635e6 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -385,32 +385,21 @@ static PyObject *bpy_orphans_purge(PyObject *UNUSED(self), return Py_None; } -int BPY_rna_id_collection_module(PyObject *mod_par) -{ - static PyMethodDef user_map = { - "user_map", (PyCFunction)bpy_user_map, METH_VARARGS | METH_KEYWORDS, bpy_user_map_doc}; - - PyModule_AddObject(mod_par, "_rna_id_collection_user_map", PyCFunction_New(&user_map, NULL)); - - static PyMethodDef batch_remove = { - "batch_remove", - (PyCFunction)bpy_batch_remove, - METH_VARARGS | METH_KEYWORDS, - bpy_batch_remove_doc, - }; - - PyModule_AddObject( - mod_par, "_rna_id_collection_batch_remove", PyCFunction_New(&batch_remove, NULL)); - - static PyMethodDef orphans_purge = { - "orphans_purge", - (PyCFunction)bpy_orphans_purge, - METH_VARARGS | METH_KEYWORDS, - bpy_orphans_purge_doc, - }; - - PyModule_AddObject( - mod_par, "_rna_id_collection_orphans_purge", PyCFunction_New(&orphans_purge, NULL)); - - return 0; -} +PyMethodDef BPY_rna_id_collection_user_map_method_def = { + "user_map", + (PyCFunction)bpy_user_map, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_user_map_doc, +}; +PyMethodDef BPY_rna_id_collection_batch_remove_method_def = { + "batch_remove", + (PyCFunction)bpy_batch_remove, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_batch_remove_doc, +}; +PyMethodDef BPY_rna_id_collection_orphans_purge_method_def = { + "orphans_purge", + (PyCFunction)bpy_orphans_purge, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_orphans_purge_doc, +}; diff --git a/source/blender/python/intern/bpy_rna_id_collection.h b/source/blender/python/intern/bpy_rna_id_collection.h index 8cb375960a9..ee8f4c666a8 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.h +++ b/source/blender/python/intern/bpy_rna_id_collection.h @@ -21,6 +21,8 @@ #ifndef __BPY_RNA_ID_COLLECTION_H__ #define __BPY_RNA_ID_COLLECTION_H__ -int BPY_rna_id_collection_module(PyObject *); +extern PyMethodDef BPY_rna_id_collection_user_map_method_def; +extern PyMethodDef BPY_rna_id_collection_batch_remove_method_def; +extern PyMethodDef BPY_rna_id_collection_orphans_purge_method_def; #endif /* __BPY_RNA_ID_COLLECTION_H__ */ diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c index cfd6b7f54a8..5a2ba4a5cdb 100644 --- a/source/blender/python/intern/bpy_rna_types_capi.c +++ b/source/blender/python/intern/bpy_rna_types_capi.c @@ -33,8 +33,10 @@ #include "BLI_utildefines.h" +#include "bpy_library.h" #include "bpy_rna.h" #include "bpy_rna_callback.h" +#include "bpy_rna_id_collection.h" #include "bpy_rna_types_capi.h" #include "../generic/py_capi_utils.h" @@ -46,6 +48,31 @@ #include "WM_api.h" /* -------------------------------------------------------------------- */ +/** \name Blend Data + * \{ */ + +static struct PyMethodDef pyrna_blenddata_methods[] = { + {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_user_map_method_def */ + {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_batch_remove_method_def */ + {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_orphans_purge_method_def */ + {NULL, NULL, 0, NULL}, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Blend Data Libraries + * \{ */ + +static struct PyMethodDef pyrna_blenddatalibraries_methods[] = { + {NULL, NULL, 0, NULL}, /* #BPY_library_load_method_def */ + {NULL, NULL, 0, NULL}, /* #BPY_library_write_method_def */ + {NULL, NULL, 0, NULL}, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Window Manager Clipboard Property * * Avoid using the RNA API because this value may change between checking it's length @@ -86,11 +113,11 @@ static int pyrna_WindowManager_clipboard_set(PyObject *UNUSED(self), static struct PyMethodDef pyrna_windowmanager_methods[] = { {"draw_cursor_add", (PyCFunction)pyrna_callback_classmethod_add, - METH_VARARGS | METH_STATIC, + METH_VARARGS | METH_CLASS, ""}, {"draw_cursor_remove", (PyCFunction)pyrna_callback_classmethod_remove, - METH_VARARGS | METH_STATIC, + METH_VARARGS | METH_CLASS, ""}, {NULL, NULL, 0, NULL}, }; @@ -147,11 +174,11 @@ PyDoc_STRVAR(pyrna_draw_handler_remove_doc, static struct PyMethodDef pyrna_space_methods[] = { {"draw_handler_add", (PyCFunction)pyrna_callback_classmethod_add, - METH_VARARGS | METH_STATIC, + METH_VARARGS | METH_CLASS, pyrna_draw_handler_add_doc}, {"draw_handler_remove", (PyCFunction)pyrna_callback_classmethod_remove, - METH_VARARGS | METH_STATIC, + METH_VARARGS | METH_CLASS, pyrna_draw_handler_remove_doc}, {NULL, NULL, 0, NULL}, }; @@ -164,7 +191,24 @@ static struct PyMethodDef pyrna_space_methods[] = { void BPY_rna_types_extend_capi(void) { + /* BlendData */ + ARRAY_SET_ITEMS(pyrna_blenddata_methods, + BPY_rna_id_collection_user_map_method_def, + BPY_rna_id_collection_batch_remove_method_def, + BPY_rna_id_collection_orphans_purge_method_def); + BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 4); + pyrna_struct_type_extend_capi(&RNA_BlendData, pyrna_blenddata_methods, NULL); + + /* BlendDataLibraries */ + ARRAY_SET_ITEMS( + pyrna_blenddatalibraries_methods, BPY_library_load_method_def, BPY_library_write_method_def); + BLI_assert(ARRAY_SIZE(pyrna_blenddatalibraries_methods) == 3); + pyrna_struct_type_extend_capi(&RNA_BlendDataLibraries, pyrna_blenddatalibraries_methods, NULL); + + /* Space */ pyrna_struct_type_extend_capi(&RNA_Space, pyrna_space_methods, NULL); + + /* WindowManager */ pyrna_struct_type_extend_capi( &RNA_WindowManager, pyrna_windowmanager_methods, pyrna_windowmanager_getset); } diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index b963021dfd9..f9d2e915fad 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -160,8 +160,7 @@ typedef struct RenderResult { typedef struct RenderStats { int cfra; - int totface, totvert, totstrand, tothalo, totlamp, totpart; - short curfield, curblur, curpart, partsdone, convertdone, curfsa; + int totface, totvert, totlamp, totpart; bool localview; double starttime, lastframetime; const char *infostr, *statstr; diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index cc685610886..af3a6fdd384 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -674,7 +674,7 @@ bool RE_bake_engine(Render *re, /* set render info */ re->i.cfra = re->scene->r.cfra; BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name) - 2); - re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0; + re->i.totface = re->i.totvert = re->i.totlamp = 0; /* render */ engine = re->engine; @@ -812,7 +812,7 @@ int RE_engine_render(Render *re, int do_all) /* set render info */ re->i.cfra = re->scene->r.cfra; BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name)); - re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0; + re->i.totface = re->i.totvert = re->i.totlamp = 0; /* render */ engine = re->engine; diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 138d95af055..2e9f30397db 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -270,8 +270,6 @@ void RE_parts_init(Render *re) /* this is render info for caller, is not reset when parts are freed! */ re->i.totpart = 0; - re->i.curpart = 0; - re->i.partsdone = 0; /* just for readable code.. */ xminb = re->disprect.xmin; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index e0c59596c2a..c66c43ec467 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -203,13 +203,6 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) megs_used_memory, megs_peak_memory); - if (rs->curfield) { - fprintf(stdout, TIP_("Field %d "), rs->curfield); - } - if (rs->curblur) { - fprintf(stdout, TIP_("Blur %d "), rs->curblur); - } - BLI_timecode_string_from_time_simple( info_time_str, sizeof(info_time_str), PIL_check_seconds_timer() - rs->starttime); fprintf(stdout, TIP_("| Time:%s | "), info_time_str); @@ -218,23 +211,12 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) fprintf(stdout, "%s", rs->infostr); } else { - if (rs->tothalo) { - fprintf(stdout, - TIP_("Sce: %s Ve:%d Fa:%d Ha:%d La:%d"), - rs->scene_name, - rs->totvert, - rs->totface, - rs->tothalo, - rs->totlamp); - } - else { - fprintf(stdout, - TIP_("Sce: %s Ve:%d Fa:%d La:%d"), - rs->scene_name, - rs->totvert, - rs->totface, - rs->totlamp); - } + fprintf(stdout, + TIP_("Sce: %s Ve:%d Fa:%d La:%d"), + rs->scene_name, + rs->totvert, + rs->totface, + rs->totlamp); } /* Flush stdout to be sure python callbacks are printing stuff after blender. */ diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index ffa5bc15876..802780b37f1 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -106,6 +106,17 @@ void WM_reinit_gizmomap_all(struct Main *bmain); void WM_script_tag_reload(void); +bool WM_window_find_under_cursor(const wmWindowManager *wm, + const wmWindow *win_ignore, + const wmWindow *win, + const int mval[2], + wmWindow **r_win, + int r_mval[2]); +void WM_window_pixel_sample_read(const wmWindowManager *wm, + const wmWindow *win, + const int pos[2], + float r_col[3]); + uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]); int WM_window_pixels_x(const struct wmWindow *win); @@ -198,14 +209,13 @@ void WM_cursor_grab_disable(struct wmWindow *win, const int mouse_ungrab_xy[2]); void WM_cursor_time(struct wmWindow *win, int nr); struct wmPaintCursor *WM_paint_cursor_activate( - struct wmWindowManager *wm, short space_type, short region_type, bool (*poll)(struct bContext *C), void (*draw)(struct bContext *C, int, int, void *customdata), void *customdata); -bool WM_paint_cursor_end(struct wmWindowManager *wm, struct wmPaintCursor *handle); +bool WM_paint_cursor_end(struct wmPaintCursor *handle); void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *region); void WM_cursor_warp(struct wmWindow *win, int x, int y); diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index ae2810dfb4d..53a3fd5ebda 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -82,7 +82,7 @@ wmKeyMap *WM_keymap_find_all_spaceid_or_empty(struct wmWindowManager *wm, const char *idname, int spaceid, int regionid); -wmKeyMap *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap); +wmKeyMap *WM_keymap_active(const struct wmWindowManager *wm, struct wmKeyMap *keymap); bool WM_keymap_remove(struct wmKeyConfig *keyconfig, struct wmKeyMap *keymap); bool WM_keymap_poll(struct bContext *C, struct wmKeyMap *keymap); diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index 955fb959e92..346ed131c59 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -67,28 +67,33 @@ typedef enum eWM_GizmoFlag { WM_GIZMO_DRAW_VALUE = (1 << 2), WM_GIZMO_HIDDEN = (1 << 3), WM_GIZMO_HIDDEN_SELECT = (1 << 4), + /** Ignore the key-map for this gizmo. */ + WM_GIZMO_HIDDEN_KEYMAP = (1 << 5), /** * When set 'scale_final' value also scales the offset. * Use when offset is to avoid screen-space overlap instead of absolute positioning. */ - WM_GIZMO_DRAW_OFFSET_SCALE = (1 << 5), + WM_GIZMO_DRAW_OFFSET_SCALE = (1 << 6), /** * User should still use 'scale_final' for any handles and UI elements. * This simply skips scale when calculating the final matrix. * Needed when the gizmo needs to align with the interface underneath it. */ - WM_GIZMO_DRAW_NO_SCALE = (1 << 6), + WM_GIZMO_DRAW_NO_SCALE = (1 << 7), /** * Hide the cursor and lock it's position while interacting with this gizmo. */ - WM_GIZMO_MOVE_CURSOR = (1 << 7), + WM_GIZMO_MOVE_CURSOR = (1 << 8), /** Don't write into the depth buffer when selecting. */ - WM_GIZMO_SELECT_BACKGROUND = (1 << 8), + WM_GIZMO_SELECT_BACKGROUND = (1 << 9), /** Use the active tools operator properties when running as an operator. */ - WM_GIZMO_OPERATOR_TOOL_INIT = (1 << 9), + WM_GIZMO_OPERATOR_TOOL_INIT = (1 << 10), /** Don't pass through events to other handlers * (allows click/drag not to have it's events stolen by press events in other keymaps). */ - WM_GIZMO_EVENT_HANDLE_ALL = (1 << 10), + WM_GIZMO_EVENT_HANDLE_ALL = (1 << 11), + + /** Don't use tool-tips for this gizmo (can be distracting). */ + WM_GIZMO_NO_TOOLTIP = (1 << 12), } eWM_GizmoFlag; /** diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 9aaaa0e2c81..0032a341610 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -388,7 +388,7 @@ void wm_add_default(Main *bmain, bContext *C) win->scene = CTX_data_scene(C); STRNCPY(win->view_layer_name, CTX_data_view_layer(C)->name); BKE_workspace_active_set(win->workspace_hook, workspace); - BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout); + BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout); screen->winid = win->winid; wm->winactive = win; diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 58ca3bf1b95..2af68956923 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -145,6 +145,16 @@ void WM_cursor_set(wmWindow *win, int curs) return; /* Can't set custom cursor before Window init */ } + if (curs == WM_CURSOR_DEFAULT && win->modalcursor) { + curs = win->modalcursor; + } + + if (win->cursor == curs) { + return; /* Cursor is already set */ + } + + win->cursor = curs; + if (curs == WM_CURSOR_NONE) { GHOST_SetCursorVisibility(win->ghostwin, 0); return; @@ -152,12 +162,6 @@ void WM_cursor_set(wmWindow *win, int curs) GHOST_SetCursorVisibility(win->ghostwin, 1); - if (curs == WM_CURSOR_DEFAULT && win->modalcursor) { - curs = win->modalcursor; - } - - win->cursor = curs; - if (curs < 0 || curs >= WM_CURSOR_NUM) { BLI_assert(!"Invalid cursor number"); return; diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 4cc9f4ee7d1..fa12d6cf974 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -574,13 +574,13 @@ void wm_draw_region_blend(ARegion *region, int view, bool blend) alpha = 1.0f; } - glUniform1i(GPU_shader_get_uniform_ensure(shader, "image"), 0); - glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_icon"), + glUniform1i(GPU_shader_get_uniform(shader, "image"), 0); + glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), rect_tex.xmin, rect_tex.ymin, rect_tex.xmax, rect_tex.ymax); - glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_geom"), + glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), rect_geo.xmin, rect_geo.ymin, rect_geo.xmax, diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index c7bda0bdae0..53d6df915d6 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -563,7 +563,7 @@ void wm_event_do_notifiers(bContext *C) static int wm_event_always_pass(const wmEvent *event) { /* some events we always pass on, to ensure proper communication */ - return ISTIMER(event->type) || (event->type == WINDEACTIVATE) || (event->type == EVT_FILESELECT); + return ISTIMER(event->type) || (event->type == WINDEACTIVATE); } /** \} */ @@ -602,6 +602,12 @@ static int wm_handler_ui_call(bContext *C, } } + /* Don't block file-select events. Those are triggered by a separate file browser window. + * See T75292. */ + if (event->type == EVT_FILESELECT) { + return WM_UI_HANDLER_CONTINUE; + } + /* we set context to where ui handler came from */ if (handler->context.area) { CTX_wm_area_set(C, handler->context.area); @@ -2584,7 +2590,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) { if (gz != NULL) { - if (U.flag & USER_TOOLTIPS) { + if ((U.flag & USER_TOOLTIPS) && (gz->flag & WM_GIZMO_NO_TOOLTIP) == 0) { WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init); } } @@ -2596,7 +2602,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, if (handle_keymap) { /* Handle highlight gizmo. */ - if (gz != NULL) { + if ((gz != NULL) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) { bool keymap_poll = false; wmGizmoGroup *gzgroup = gz->parent_gzgroup; wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap); @@ -4248,7 +4254,7 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g /* imperfect but probably usable... draw/enable drags to other windows */ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event) { - int mx = event->x, my = event->y; + int mval[2] = {event->x, event->y}; if (wm->windows.first == wm->windows.last) { return NULL; @@ -4257,7 +4263,8 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi /* in order to use window size and mouse position (pixels), we have to use a WM function */ /* check if outside, include top window bar... */ - if (mx < 0 || my < 0 || mx > WM_window_pixels_x(win) || my > WM_window_pixels_y(win) + 30) { + if (mval[0] < 0 || mval[1] < 0 || mval[0] > WM_window_pixels_x(win) || + mval[1] > WM_window_pixels_y(win) + 30) { wmWindow *owin; wmEventHandler *handler; @@ -4270,25 +4277,10 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi } } - /* to desktop space */ - mx += (int)(U.pixelsize * win->posx); - my += (int)(U.pixelsize * win->posy); - - /* check other windows to see if it has mouse inside */ - for (owin = wm->windows.first; owin; owin = owin->next) { - - if (owin != win) { - int posx = (int)(U.pixelsize * owin->posx); - int posy = (int)(U.pixelsize * owin->posy); - - if (mx - posx >= 0 && owin->posy >= 0 && mx - posx <= WM_window_pixels_x(owin) && - my - posy <= WM_window_pixels_y(owin)) { - event->x = mx - (int)(U.pixelsize * owin->posx); - event->y = my - (int)(U.pixelsize * owin->posy); - - return owin; - } - } + if (WM_window_find_under_cursor(wm, win, win, mval, &owin, mval)) { + event->x = mval[0]; + event->y = mval[1]; + return owin; } } return NULL; diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index cc81e4f2715..ed1b29d61ce 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -141,11 +141,37 @@ static void wm_history_file_free(RecentFile *recent); static void wm_history_file_update(void); static void wm_history_file_write(void); -/* To be able to read files without windows closing, opening, moving +/* -------------------------------------------------------------------- */ +/** \name Misc Utility Functions + * \{ */ + +void WM_file_tag_modified(void) +{ + wmWindowManager *wm = G_MAIN->wm.first; + if (wm->file_saved) { + wm->file_saved = 0; + /* notifier that data changed, for save-over warning or header */ + WM_main_add_notifier(NC_WM | ND_DATACHANGED, NULL); + } +} + +bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm) +{ + return !wm->file_saved || ED_image_should_save_modified(bmain); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Window Matching for File Reading + * \{ */ + +/** + * To be able to read files without windows closing, opening, moving * we try to prepare for worst case: * - active window gets active screen from file * - restoring the screens from non-active windows - * Best case is all screens match, in that case they get assigned to proper window + * Best case is all screens match, in that case they get assigned to proper window. */ static void wm_window_match_init(bContext *C, ListBase *wmlist) { @@ -355,6 +381,12 @@ static void wm_window_match_do(bContext *C, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Preferences Initialization & Versioning + * \{ */ + /* in case UserDef was read, we re-initialize all, and do versioning */ static void wm_init_userdef(Main *bmain) { @@ -389,6 +421,15 @@ static void wm_init_userdef(Main *bmain) # define BKE_READ_EXOTIC_OK_OTHER 1 /* other supported formats */ #endif +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Exotic File Formats + * + * Currently only supports '.blend' files, + * we could support registering other file formats and their loaders. + * \{ */ + /* intended to check for non-blender formats but for now it only reads blends */ static int wm_read_exotic(const char *name) { @@ -441,6 +482,12 @@ static int wm_read_exotic(const char *name) return retval; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Blend-File Shared Utilities + * \{ */ + void WM_file_autoexec_init(const char *filepath) { if (G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) { @@ -486,6 +533,24 @@ void wm_file_read_report(bContext *C, Main *bmain) /** * Logic shared between #WM_file_read & #wm_homefile_read, + * call before loading a file. + * \note In the case of #WM_file_read the file may fail to load. + * Change here shouldn't cause user-visible changes in that case. + */ +static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef)) +{ + if (use_data) { + BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE); + BLI_timer_on_file_load(); + } + + /* Always do this as both startup and preferences may have loaded in many font's + * at a different zoom level to the file being loaded. */ + UI_view2d_zoom_cache_reset(); +} + +/** + * Logic shared between #WM_file_read & #wm_homefile_read, * updates to make after reading a file. */ static void wm_file_read_post(bContext *C, @@ -510,12 +575,16 @@ static void wm_file_read_post(bContext *C, if (is_startup_file) { /* possible python hasn't been initialized */ if (CTX_py_init_get(C)) { - if (reset_app_template) { + bool reset_all = use_userdef; + if (use_userdef || reset_app_template) { /* Only run when we have a template path found. */ if (BKE_appdir_app_template_any()) { BPY_execute_string( C, (const char *[]){"bl_app_template_utils", NULL}, "bl_app_template_utils.reset()"); + reset_all = true; } + } + if (reset_all) { /* sync addons, these may have changed from the defaults */ BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()"); } @@ -601,21 +670,27 @@ static void wm_file_read_post(bContext *C, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Main Blend-File API + * \{ */ + bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) { /* assume automated tasks with background, don't write recent file list */ const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0); bool success = false; + const bool use_data = true; + const bool use_userdef = false; + /* so we can get the error message */ errno = 0; WM_cursor_wait(1); - BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE); - BLI_timer_on_file_load(); - - UI_view2d_zoom_cache_reset(); + wm_file_read_pre(C, use_data, use_userdef); /* first try to append data from exotic file formats... */ /* it throws error box when file doesn't exist and returns -1 */ @@ -675,8 +750,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } } - const bool use_data = true; - const bool use_userdef = false; wm_file_read_post(C, false, false, use_data, use_userdef, false); } #if 0 @@ -746,6 +819,12 @@ const char *WM_init_state_app_template_get(void) return wm_init_state_app_template.override ? wm_init_state_app_template.app_template : NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Startup & Preferences Blend-File API + * \{ */ + /** * Called on startup, (context entirely filled with NULLs) * or called for 'New File' both startup.blend and userpref.blend are checked. @@ -802,6 +881,23 @@ void wm_homefile_read(bContext *C, * or use app-template startup.blend which the user hasn't saved. */ bool is_factory_startup = true; + const char *app_template = NULL; + bool update_defaults = false; + + if (filepath_startup_override != NULL) { + /* pass */ + } + else if (app_template_override) { + /* This may be clearing the current template by setting to an empty string. */ + app_template = app_template_override; + } + else if (!use_factory_settings && U.app_template[0]) { + app_template = U.app_template; + } + + const bool reset_app_template = ((!app_template && U.app_template[0]) || + (app_template && !STREQ(app_template, U.app_template))); + /* options exclude eachother */ BLI_assert((use_factory_settings && filepath_startup_override) == 0); @@ -809,18 +905,30 @@ void wm_homefile_read(bContext *C, SET_FLAG_FROM_TEST(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_FLAG_SCRIPT_AUTOEXEC); } - if (use_data) { - BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE); - BLI_timer_on_file_load(); + if (use_userdef || reset_app_template) { +#ifdef WITH_PYTHON + /* This only runs once Blender has already started. */ + if (CTX_py_init_get(C)) { + /* This is restored by 'wm_file_read_post', disable before loading any preferences + * so an add-on can read their own preferences when un-registering, + * and use new preferences if/when re-registering, see T67577. + * + * Note that this fits into 'wm_file_read_pre' function but gets messy + * since we need to know if 'reset_app_template' is true. */ + BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.disable_all()"); + } +#endif /* WITH_PYTHON */ + } + + wm_file_read_pre(C, use_data, use_userdef); + if (use_data) { G.relbase_valid = 0; /* put aside screens to match with persistent windows later */ wm_window_match_init(C, &wmbase); } - UI_view2d_zoom_cache_reset(); - filepath_startup[0] = '\0'; filepath_userdef[0] = '\0'; app_template_system[0] = '\0'; @@ -861,28 +969,6 @@ void wm_homefile_read(bContext *C, } } - const char *app_template = NULL; - bool update_defaults = false; - bool reset_app_template = false; - - if (filepath_startup_override != NULL) { - /* pass */ - } - else if (app_template_override) { - /* This may be clearing the current template by setting to an empty string. */ - app_template = app_template_override; - } - else if (!use_factory_settings && U.app_template[0]) { - app_template = U.app_template; - } - - if ((!app_template && U.app_template[0]) || - (app_template && !STREQ(app_template, U.app_template))) { - /* Always load UI when switching to another template. */ - G.fileflags &= ~G_FILE_NO_UI; - reset_app_template = true; - } - if ((app_template != NULL) && (app_template[0] != '\0')) { if (!BKE_appdir_app_template_id_search( app_template, app_template_system, sizeof(app_template_system))) { @@ -1028,6 +1114,11 @@ void wm_homefile_read(bContext *C, * Screws up autosaves otherwise can remove this eventually, * only in a 2.53 and older, now its not written. */ G.fileflags &= ~G_FILE_RELATIVE_REMAP; + + if (reset_app_template) { + /* Always load UI when switching to another template. */ + G.fileflags &= ~G_FILE_NO_UI; + } } bmain = CTX_data_main(C); @@ -1035,7 +1126,6 @@ void wm_homefile_read(bContext *C, if (use_userdef) { /* check userdef before open window, keymaps etc */ wm_init_userdef(bmain); - reset_app_template = true; } if (use_data) { @@ -1070,7 +1160,7 @@ void wm_homefile_read(bContext *C, } /* -------------------------------------------------------------------- */ -/** \name WM History File API +/** \name Blend-File History API * \{ */ void wm_history_file_read(void) @@ -1199,7 +1289,7 @@ static void wm_history_file_update(void) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Save Main .blend File (internal) +/** \name Save Main Blend-File (internal) * \{ */ /* screen can be NULL */ @@ -1623,18 +1713,8 @@ void wm_open_init_use_scripts(wmOperator *op, bool use_prefs) /** \} */ -void WM_file_tag_modified(void) -{ - wmWindowManager *wm = G_MAIN->wm.first; - if (wm->file_saved) { - wm->file_saved = 0; - /* notifier that data changed, for save-over warning or header */ - WM_main_add_notifier(NC_WM | ND_DATACHANGED, NULL); - } -} - /* -------------------------------------------------------------------- */ -/** \name Preferences/startup save & load. +/** \name Startup File Save Operator * \{ */ /** @@ -1699,48 +1779,11 @@ void WM_OT_save_homefile(wmOperatorType *ot) ot->exec = wm_homefile_write_exec; } -static int wm_userpref_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) -{ - bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare"); - BLI_addtail(&U.autoexec_paths, path_cmp); - U.runtime.is_dirty = true; - return OPERATOR_FINISHED; -} - -void WM_OT_userpref_autoexec_path_add(wmOperatorType *ot) -{ - ot->name = "Add Autoexec Path"; - ot->idname = "WM_OT_userpref_autoexec_path_add"; - ot->description = "Add path to exclude from autoexecution"; - - ot->exec = wm_userpref_autoexec_add_exec; - - ot->flag = OPTYPE_INTERNAL; -} - -static int wm_userpref_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op) -{ - const int index = RNA_int_get(op->ptr, "index"); - bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index); - if (path_cmp) { - BLI_freelinkN(&U.autoexec_paths, path_cmp); - U.runtime.is_dirty = true; - } - return OPERATOR_FINISHED; -} - -void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot) -{ - ot->name = "Remove Autoexec Path"; - ot->idname = "WM_OT_userpref_autoexec_path_remove"; - ot->description = "Remove path to exclude from autoexecution"; - - ot->exec = wm_userpref_autoexec_remove_exec; - - ot->flag = OPTYPE_INTERNAL; +/** \} */ - RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); -} +/* -------------------------------------------------------------------- */ +/** \name Write Preferences Operator + * \{ */ /* Only save the prefs block. operator entry */ static int wm_userpref_write_exec(bContext *C, wmOperator *op) @@ -1765,6 +1808,12 @@ void WM_OT_save_userpref(wmOperatorType *ot) ot->exec = wm_userpref_write_exec; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Preferences Operator + * \{ */ + /** * When reading preferences, there are some exceptions for values which are reset. */ @@ -1828,10 +1877,6 @@ static void wm_userpref_update_when_changed(bContext *C, rna_struct_update_when_changed(C, bmain, &ptr_a, &ptr_b); -#ifdef WITH_PYTHON - BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()"); -#endif - WM_reinit_gizmomap_all(bmain); WM_keyconfig_reload(C); @@ -1897,6 +1942,12 @@ void WM_OT_read_factory_userpref(wmOperatorType *ot) ot->exec = wm_userpref_read_exec; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read File History Operator + * \{ */ + static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) { ED_file_read_bookmarks(); @@ -1917,6 +1968,14 @@ void WM_OT_read_history(wmOperatorType *ot) ot->flag = OPTYPE_INTERNAL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Startup & Preferences Operator + * + * Both #WM_OT_read_homefile & #WM_OT_read_factory_settings. + * \{ */ + static int wm_homefile_read_exec(bContext *C, wmOperator *op) { const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings")); @@ -2442,7 +2501,7 @@ void WM_OT_revert_mainfile(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Recover last session & auto-save. +/** \name Recover Last Session Operator * \{ */ void WM_recover_last_session(bContext *C, ReportList *reports) @@ -2486,6 +2545,12 @@ void WM_OT_recover_last_session(wmOperatorType *ot) ot->exec = wm_recover_last_session_exec; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Auto-Save Main .blend File Operator + * \{ */ + static int wm_recover_auto_save_exec(bContext *C, wmOperator *op) { char filepath[FILE_MAX]; @@ -2540,6 +2605,8 @@ void WM_OT_recover_auto_save(wmOperatorType *ot) /* -------------------------------------------------------------------- */ /** \name Save Main .blend File Operator + * + * Both #WM_OT_save_as_mainfile & #WM_OT_save_mainfile. * \{ */ static void wm_filepath_default(char *filepath) @@ -2766,7 +2833,7 @@ void WM_OT_save_mainfile(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Auto-execution of scripts warning popup +/** \name Auto Script Execution Warning Dialog * \{ */ static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void *UNUSED(arg)) @@ -2968,8 +3035,11 @@ void wm_test_autorun_warning(bContext *C) } } -/* Close File Dialog - *************************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Close File Dialog + * \{ */ static char save_images_when_file_is_closed = true; @@ -3235,9 +3305,4 @@ void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action) } } -bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm) -{ - return !wm->file_saved || ED_image_should_save_modified(bmain); -} - /** \} */ diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 9aa401722b7..6b2a74138c9 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -365,7 +365,7 @@ static void draw_filled_lasso(wmGesture *gt) IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_bind(state.shader); GPU_shader_uniform_vector( - state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red); + state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); immDrawPixelsTex(&state, rect.xmin, diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index fc3f0c87b69..001acc459c2 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -187,7 +187,7 @@ void WM_init_opengl(Main *bmain) GPU_init(); GPU_set_mipmap(bmain, true); GPU_set_linear_mipmap(true); - GPU_set_anisotropic(bmain, U.anisotropic_filter); + GPU_set_anisotropic(U.anisotropic_filter); GPU_pass_cache_init(); diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 5f2b492088e..d7102a1e8af 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1936,7 +1936,7 @@ void WM_keyconfig_update(wmWindowManager *wm) * During event handling this function is called to get the keymap from the final configuration. * \{ */ -wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap) +wmKeyMap *WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap) { wmKeyMap *km; diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 39811d67b9a..f99f47bc3ad 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -2059,13 +2059,14 @@ static void WM_OT_console_toggle(wmOperatorType *ot) * * \{ */ -wmPaintCursor *WM_paint_cursor_activate(wmWindowManager *wm, - short space_type, +wmPaintCursor *WM_paint_cursor_activate(short space_type, short region_type, bool (*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata) { + wmWindowManager *wm = G_MAIN->wm.first; + wmPaintCursor *pc = MEM_callocN(sizeof(wmPaintCursor), "paint cursor"); BLI_addtail(&wm->paintcursors, pc); @@ -2080,11 +2081,10 @@ wmPaintCursor *WM_paint_cursor_activate(wmWindowManager *wm, return pc; } -bool WM_paint_cursor_end(wmWindowManager *wm, wmPaintCursor *handle) +bool WM_paint_cursor_end(wmPaintCursor *handle) { - wmPaintCursor *pc; - - for (pc = wm->paintcursors.first; pc; pc = pc->next) { + wmWindowManager *wm = G_MAIN->wm.first; + for (wmPaintCursor *pc = wm->paintcursors.first; pc; pc = pc->next) { if (pc == (wmPaintCursor *)handle) { BLI_remlink(&wm->paintcursors, pc); MEM_freeN(pc); @@ -2759,7 +2759,7 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve /* add radial control paint cursor */ rc->cursor = WM_paint_cursor_activate( - wm, SPACE_TYPE_ANY, RGN_TYPE_ANY, op->type->poll, radial_control_paint_cursor, rc); + SPACE_TYPE_ANY, RGN_TYPE_ANY, op->type->poll, radial_control_paint_cursor, rc); WM_event_add_modal_handler(C, op); @@ -2793,7 +2793,7 @@ static void radial_control_cancel(bContext *C, wmOperator *op) ED_area_status_text(area, NULL); - WM_paint_cursor_end(wm, rc->cursor); + WM_paint_cursor_end(rc->cursor); /* restore original paint cursors */ wm->paintcursors = rc->orig_paintcursors; @@ -3778,8 +3778,6 @@ void wm_operatortypes_register(void) WM_operatortype_append(WM_OT_save_userpref); WM_operatortype_append(WM_OT_read_userpref); WM_operatortype_append(WM_OT_read_factory_userpref); - WM_operatortype_append(WM_OT_userpref_autoexec_path_add); - WM_operatortype_append(WM_OT_userpref_autoexec_path_remove); WM_operatortype_append(WM_OT_window_fullscreen_toggle); WM_operatortype_append(WM_OT_quit_blender); WM_operatortype_append(WM_OT_open_mainfile); diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index 8445fac0498..b75609fd28f 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -96,39 +96,7 @@ static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, UI_block_emboss_set(block, UI_EMBOSS); } -static void get_version_string(char *ver, const int max_length) -{ - /* Version number. */ - const char *version_cycle = NULL; - - 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 = STRINGIFY(BLENDER_VERSION_CHAR); - } - - const char *version_cycle_number = ""; - if (strlen(STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER))) { - version_cycle_number = " " STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER); - } - - BLI_snprintf(ver, - max_length, - "%d.%d.%d%s%s", - BLENDER_VERSION / 100, - BLENDER_VERSION % 100, - BLENDER_SUBVERSION, - version_cycle, - version_cycle_number); -} - +#ifndef WITH_HEADLESS static void wm_block_splash_image_roundcorners_add(ImBuf *ibuf) { uchar *rct = (uchar *)ibuf->rect; @@ -179,6 +147,7 @@ static void wm_block_splash_image_roundcorners_add(ImBuf *ibuf) } } } +#endif /* WITH_HEADLESS */ static ImBuf *wm_block_splash_image(int width, int *r_height) { @@ -219,6 +188,7 @@ static ImBuf *wm_block_splash_image(int width, int *r_height) return ibuf; #else + UNUSED_VARS(width, r_height); return NULL; #endif } @@ -249,9 +219,8 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE UI_but_func_set(but, wm_block_close, block, NULL); UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL); - char version_buf[256] = "\0"; - get_version_string(version_buf, sizeof(version_buf)); - wm_block_splash_add_label(block, version_buf, splash_width, splash_height - 13.0 * U.dpi_fac); + wm_block_splash_add_label( + block, BKE_blender_version_string(), splash_width, splash_height - 13.0 * U.dpi_fac); const int layout_margin_x = U.dpi_fac * 26; uiLayout *layout = UI_block_layout(block, @@ -329,9 +298,7 @@ static uiBlock *wm_block_create_about(bContext *C, ARegion *region, void *UNUSED uiItemL_ex(layout, "Blender", ICON_NONE, true, false); /* Version. */ - char str_buf[256] = "\0"; - get_version_string(str_buf, sizeof(str_buf)); - uiItemL(layout, str_buf, ICON_NONE); + uiItemL(layout, BKE_blender_version_string(), ICON_NONE); uiItemS_ex(layout, 3.0f); @@ -339,6 +306,7 @@ static uiBlock *wm_block_create_about(bContext *C, ARegion *region, void *UNUSED extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[]; + char str_buf[256] = "\0"; BLI_snprintf(str_buf, sizeof(str_buf), "Date: %s %s", build_commit_date, build_commit_time); uiItemL(layout, str_buf, ICON_NONE); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index fcb2be0a0bb..1ba22652157 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -326,7 +326,7 @@ wmWindow *wm_window_copy(Main *bmain, layout_new = duplicate_layout ? ED_workspace_layout_duplicate(bmain, workspace, layout_old, win_dst) : layout_old; - BKE_workspace_hook_layout_for_workspace_set(win_dst->workspace_hook, workspace, layout_new); + BKE_workspace_active_layout_set(win_dst->workspace_hook, workspace, layout_new); *win_dst->stereo3d_format = *win_src->stereo3d_format; @@ -1984,6 +1984,90 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Find Window Utility + * + * \{ */ +static void wm_window_desktop_pos_get(const wmWindow *win, + const int screen_pos[2], + int r_desk_pos[2]) +{ + /* To desktop space. */ + r_desk_pos[0] = screen_pos[0] + (int)(U.pixelsize * win->posx); + r_desk_pos[1] = screen_pos[1] + (int)(U.pixelsize * win->posy); +} + +static void wm_window_screen_pos_get(const wmWindow *win, + const int desktop_pos[2], + int r_scr_pos[2]) +{ + /* To window space. */ + r_scr_pos[0] = desktop_pos[0] - (int)(U.pixelsize * win->posx); + r_scr_pos[1] = desktop_pos[1] - (int)(U.pixelsize * win->posy); +} + +bool WM_window_find_under_cursor(const wmWindowManager *wm, + const wmWindow *win_ignore, + const wmWindow *win, + const int mval[2], + wmWindow **r_win, + int r_mval[2]) +{ + int desk_pos[2]; + wm_window_desktop_pos_get(win, mval, desk_pos); + + /* TODO: This should follow the order of the activated windows. + * The current solution is imperfect but usable in most cases. */ + LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) { + if (win_iter == win_ignore) { + continue; + } + + if (win_iter->windowstate == GHOST_kWindowStateMinimized) { + continue; + } + + int scr_pos[2]; + wm_window_screen_pos_get(win_iter, desk_pos, scr_pos); + + if (scr_pos[0] >= 0 && win_iter->posy >= 0 && scr_pos[0] <= WM_window_pixels_x(win_iter) && + scr_pos[1] <= WM_window_pixels_y(win_iter)) { + + *r_win = win_iter; + copy_v2_v2_int(r_mval, scr_pos); + return true; + } + } + + return false; +} + +void WM_window_pixel_sample_read(const wmWindowManager *wm, + const wmWindow *win, + const int pos[2], + float r_col[3]) +{ + bool setup_context = wm->windrawable != win; + + if (setup_context) { + GHOST_ActivateWindowDrawingContext(win->ghostwin); + GPU_context_active_set(win->gpuctx); + } + + glReadBuffer(GL_FRONT); + glReadPixels(pos[0], pos[1], 1, 1, GL_RGB, GL_FLOAT, r_col); + glReadBuffer(GL_BACK); + + if (setup_context) { + if (wm->windrawable) { + GHOST_ActivateWindowDrawingContext(wm->windrawable->ghostwin); + GPU_context_active_set(wm->windrawable->gpuctx); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Window Screen Shot Utility * * Include here since it can involve low level buffer switching. @@ -2359,7 +2443,7 @@ WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win) } void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout) { - BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout); + BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout); } /** diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index e081742b904..42eab35cdb9 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -45,8 +45,6 @@ void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action); bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm); void WM_OT_save_homefile(struct wmOperatorType *ot); -void WM_OT_userpref_autoexec_path_add(struct wmOperatorType *ot); -void WM_OT_userpref_autoexec_path_remove(struct wmOperatorType *ot); void WM_OT_save_userpref(struct wmOperatorType *ot); void WM_OT_read_userpref(struct wmOperatorType *ot); void WM_OT_read_factory_userpref(struct wmOperatorType *ot); diff --git a/source/blender/windowmanager/xr/intern/wm_xr.c b/source/blender/windowmanager/xr/intern/wm_xr.c index 69c9034d51f..90f30809136 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr.c +++ b/source/blender/windowmanager/xr/intern/wm_xr.c @@ -126,7 +126,12 @@ void wm_xr_exit(wmWindowManager *wm) bool wm_xr_events_handle(wmWindowManager *wm) { if (wm->xr.runtime && wm->xr.runtime->context) { - return GHOST_XrEventsHandle(wm->xr.runtime->context); + GHOST_XrEventsHandle(wm->xr.runtime->context); + + /* wm_window_process_events() uses the return value to determine if it can put the main thread + * to sleep for some milliseconds. We never want that to happen while the VR session runs on + * the main thread. So always return true. */ + return true; } return false; } |