diff options
Diffstat (limited to 'source/blender/blenkernel')
97 files changed, 2518 insertions, 1390 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 9d948dfd57b..229b5193e9c 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -40,7 +40,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 4 +#define BLENDER_FILE_SUBVERSION 5 /* 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 diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h index 2bff684948d..e835137bfa1 100644 --- a/source/blender/blenkernel/BKE_blendfile.h +++ b/source/blender/blenkernel/BKE_blendfile.h @@ -74,6 +74,7 @@ void BKE_blendfile_write_partial_begin(struct Main *bmain_src); bool BKE_blendfile_write_partial(struct Main *bmain_src, const char *filepath, const int write_flags, + const int remap_mode, struct ReportList *reports); void BKE_blendfile_write_partial_end(struct Main *bmain_src); diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index f4b56aa152f..4cf33640ebd 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -24,6 +24,8 @@ #include "BLI_compiler_compat.h" #include "BLI_ghash.h" #include "BLI_iterator.h" +#include "BLI_sys_types.h" + #include "DNA_listBase.h" #ifdef __cplusplus @@ -57,16 +59,11 @@ void BKE_collection_add_from_object(struct Main *bmain, void BKE_collection_free(struct Collection *collection); bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy); -struct Collection *BKE_collection_copy(struct Main *bmain, - struct Collection *parent, - struct Collection *collection); - struct Collection *BKE_collection_duplicate(struct Main *bmain, struct Collection *parent, struct Collection *collection, - const bool do_hierarchy, - const bool do_objects, - const bool do_obdata); + const uint duplicate_flags, + const uint duplicate_options); /* Master Collection for Scene */ diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h index 94b8d59b3db..0623e0e5395 100644 --- a/source/blender/blenkernel/BKE_colortools.h +++ b/source/blender/blenkernel/BKE_colortools.h @@ -37,6 +37,8 @@ struct Histogram; struct ImBuf; struct Scopes; struct rctf; +struct BlendWriter; +struct BlendDataReader; void BKE_curvemapping_set_defaults( struct CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy); @@ -100,6 +102,11 @@ void BKE_curvemapping_table_RGBA(const struct CurveMapping *cumap, float **array /* non-const, these modify the curve */ void BKE_curvemapping_premultiply(struct CurveMapping *cumap, int restore); +void BKE_curvemapping_blend_write(struct BlendWriter *writer, const struct CurveMapping *cumap); +void BKE_curvemapping_curves_blend_write(struct BlendWriter *writer, + const struct CurveMapping *cumap); +void BKE_curvemapping_blend_read(struct BlendDataReader *reader, struct CurveMapping *cumap); + void BKE_histogram_update_sample_line(struct Histogram *hist, struct ImBuf *ibuf, const struct ColorManagedViewSettings *view_settings, diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 8fe3bd77a26..8d7fe875c37 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -145,6 +145,11 @@ struct bConstraint *BKE_constraint_duplicate_ex(struct bConstraint *src, const int flag, const bool do_extern); +struct bConstraint *BKE_constraint_copy_for_pose(struct Object *ob, + struct bPoseChannel *pchan, + struct bConstraint *src); +struct bConstraint *BKE_constraint_copy_for_object(struct Object *ob, struct bConstraint *src); + void BKE_constraints_free(struct ListBase *list); void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user); void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern); diff --git a/source/blender/blenkernel/BKE_curveprofile.h b/source/blender/blenkernel/BKE_curveprofile.h index ecbaa365bac..877ab887138 100644 --- a/source/blender/blenkernel/BKE_curveprofile.h +++ b/source/blender/blenkernel/BKE_curveprofile.h @@ -28,6 +28,8 @@ extern "C" { #endif +struct BlendWriter; +struct BlendDataReader; struct CurveProfile; struct CurveProfilePoint; @@ -43,6 +45,16 @@ void BKE_curveprofile_copy_data(struct CurveProfile *target, const struct CurveP struct CurveProfile *BKE_curveprofile_copy(const struct CurveProfile *profile); +bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point, + const bool handle_1, + const bool snap, + const float delta[2]); + +bool BKE_curveprofile_move_point(struct CurveProfile *profile, + struct CurveProfilePoint *point, + const bool snap, + const float delta[2]); + bool BKE_curveprofile_remove_point(struct CurveProfile *profile, struct CurveProfilePoint *point); void BKE_curveprofile_remove_by_flag(struct CurveProfile *profile, const short flag); @@ -63,7 +75,12 @@ void BKE_curveprofile_create_samples(struct CurveProfile *profile, void BKE_curveprofile_initialize(struct CurveProfile *profile, short segments_len); /* Called for a complete update of the widget after modifications */ -void BKE_curveprofile_update(struct CurveProfile *profile, const bool rem_doubles); +enum { + PROF_UPDATE_NONE = 0, + PROF_UPDATE_REMOVE_DOUBLES = (1 << 0), + PROF_UPDATE_CLIP = (1 << 1), +}; +void BKE_curveprofile_update(struct CurveProfile *profile, const int update_flags); /* Need to find the total length of the curve to sample a portion of it */ float BKE_curveprofile_total_length(const struct CurveProfile *profile); @@ -78,6 +95,9 @@ void BKE_curveprofile_evaluate_length_portion(const struct CurveProfile *profile float *x_out, float *y_out); +void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct CurveProfile *profile); +void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_derived_node_tree.hh b/source/blender/blenkernel/BKE_derived_node_tree.hh index 009d9b747f9..84b36f675e0 100644 --- a/source/blender/blenkernel/BKE_derived_node_tree.hh +++ b/source/blender/blenkernel/BKE_derived_node_tree.hh @@ -32,7 +32,8 @@ #include "BKE_node_tree_ref.hh" -namespace BKE { +namespace blender { +namespace bke { class DSocket; class DInputSocket; @@ -42,7 +43,7 @@ class DParentNode; class DGroupInput; class DerivedNodeTree; -class DSocket : blender::NonCopyable, blender::NonMovable { +class DSocket : NonCopyable, NonMovable { protected: DNode *m_node; const SocketRef *m_socket_ref; @@ -66,6 +67,11 @@ class DSocket : blender::NonCopyable, blender::NonMovable { PointerRNA *rna() const; StringRefNull idname() const; StringRefNull name() const; + + const SocketRef &socket_ref() const; + bNodeSocket *bsocket() const; + + bool is_available() const; }; class DInputSocket : public DSocket { @@ -95,7 +101,7 @@ class DOutputSocket : public DSocket { Span<const DInputSocket *> linked_sockets() const; }; -class DGroupInput : blender::NonCopyable, blender::NonMovable { +class DGroupInput : NonCopyable, NonMovable { private: const InputSocketRef *m_socket_ref; DParentNode *m_parent; @@ -106,13 +112,14 @@ class DGroupInput : blender::NonCopyable, blender::NonMovable { public: const InputSocketRef &socket_ref() const; + bNodeSocket *bsocket() const; const DParentNode *parent() const; Span<const DInputSocket *> linked_sockets() const; uint id() const; StringRefNull name() const; }; -class DNode : blender::NonCopyable, blender::NonMovable { +class DNode : NonCopyable, NonMovable { private: const NodeRef *m_node_ref; DParentNode *m_parent; @@ -144,7 +151,7 @@ class DNode : blender::NonCopyable, blender::NonMovable { void destruct_with_sockets(); }; -class DParentNode : blender::NonCopyable, blender::NonMovable { +class DParentNode : NonCopyable, NonMovable { private: const NodeRef *m_node_ref; DParentNode *m_parent; @@ -160,7 +167,7 @@ class DParentNode : blender::NonCopyable, blender::NonMovable { using NodeTreeRefMap = Map<bNodeTree *, std::unique_ptr<const NodeTreeRef>>; -class DerivedNodeTree : blender::NonCopyable, blender::NonMovable { +class DerivedNodeTree : NonCopyable, NonMovable { private: LinearAllocator<> m_allocator; bNodeTree *m_btree; @@ -172,19 +179,22 @@ class DerivedNodeTree : blender::NonCopyable, blender::NonMovable { Vector<DInputSocket *> m_input_sockets; Vector<DOutputSocket *> m_output_sockets; - Map<std::string, Vector<DNode *>> m_nodes_by_idname; + Map<const bNodeType *, Vector<DNode *>> m_nodes_by_type; public: DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs); ~DerivedNodeTree(); Span<const DNode *> nodes() const; - Span<const DNode *> nodes_with_idname(StringRef idname) const; + Span<const DNode *> nodes_by_type(StringRefNull idname) const; + Span<const DNode *> nodes_by_type(const bNodeType *nodetype) const; Span<const DSocket *> sockets() const; Span<const DInputSocket *> input_sockets() const; Span<const DOutputSocket *> output_sockets() const; + Span<const DGroupInput *> group_inputs() const; + std::string to_dot() const; private: @@ -278,6 +288,21 @@ inline StringRefNull DSocket::name() const return m_socket_ref->name(); } +inline const SocketRef &DSocket::socket_ref() const +{ + return *m_socket_ref; +} + +inline bNodeSocket *DSocket::bsocket() const +{ + return m_socket_ref->bsocket(); +} + +inline bool DSocket::is_available() const +{ + return (m_socket_ref->bsocket()->flag & SOCK_UNAVAIL) == 0; +} + /* -------------------------------------------------------------------- * DInputSocket inline methods. */ @@ -325,6 +350,11 @@ inline const InputSocketRef &DGroupInput::socket_ref() const return *m_socket_ref; } +inline bNodeSocket *DGroupInput::bsocket() const +{ + return m_socket_ref->bsocket(); +} + inline const DParentNode *DGroupInput::parent() const { return m_parent; @@ -427,9 +457,15 @@ inline Span<const DNode *> DerivedNodeTree::nodes() const return m_nodes_by_id.as_span(); } -inline Span<const DNode *> DerivedNodeTree::nodes_with_idname(StringRef idname) const +inline Span<const DNode *> DerivedNodeTree::nodes_by_type(StringRefNull idname) const +{ + const bNodeType *nodetype = nodeTypeFind(idname.data()); + return this->nodes_by_type(nodetype); +} + +inline Span<const DNode *> DerivedNodeTree::nodes_by_type(const bNodeType *nodetype) const { - const Vector<DNode *> *nodes = m_nodes_by_idname.lookup_ptr(idname); + const Vector<DNode *> *nodes = m_nodes_by_type.lookup_ptr(nodetype); if (nodes == nullptr) { return {}; } @@ -438,6 +474,11 @@ inline Span<const DNode *> DerivedNodeTree::nodes_with_idname(StringRef idname) } } +inline Span<const DSocket *> DerivedNodeTree::sockets() const +{ + return m_sockets_by_id.as_span(); +} + inline Span<const DInputSocket *> DerivedNodeTree::input_sockets() const { return m_input_sockets.as_span(); @@ -448,6 +489,12 @@ inline Span<const DOutputSocket *> DerivedNodeTree::output_sockets() const return m_output_sockets.as_span(); } -} // namespace BKE +inline Span<const DGroupInput *> DerivedNodeTree::group_inputs() const +{ + return m_group_inputs.as_span(); +} + +} // namespace bke +} // namespace blender #endif /* __BKE_DERIVED_NODE_TREE_HH__ */ diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 6935b3aecce..0518ce8ffa3 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -130,6 +130,7 @@ void BKE_effectors_apply(struct ListBase *effectors, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, + float *wind_force, float *impulse); void BKE_effectors_free(struct ListBase *lb); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index f6cae6d8a9c..61c270202f1 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -169,7 +169,7 @@ enum { G_FILE_AUTOPACK = (1 << 0), G_FILE_COMPRESS = (1 << 1), - G_FILE_USERPREFS = (1 << 9), + // G_FILE_DEPRECATED_9 = (1 << 9), G_FILE_NO_UI = (1 << 10), /* Bits 11 to 22 (inclusive) are deprecated & need to be cleared */ @@ -177,19 +177,16 @@ enum { /** On read, use #FileGlobal.filename instead of the real location on-disk, * needed for recovering temp files so relative paths resolve */ G_FILE_RECOVER = (1 << 23), - /** On write, remap relative file paths to the new file location. */ - G_FILE_RELATIVE_REMAP = (1 << 24), - /** On write, make backup `.blend1`, `.blend2` ... files, when the users preference is enabled */ - G_FILE_HISTORY = (1 << 25), /** BMesh option to save as older mesh format */ /* #define G_FILE_MESH_COMPAT (1 << 26) */ - /** On write, restore paths after editing them (G_FILE_RELATIVE_REMAP) */ - G_FILE_SAVE_COPY = (1 << 27), /* #define G_FILE_GLSL_NO_ENV_LIGHTING (1 << 28) */ /* deprecated */ }; -/** Don't overwrite these flags when reading a file. */ -#define G_FILE_FLAG_ALL_RUNTIME (G_FILE_NO_UI | G_FILE_RELATIVE_REMAP | G_FILE_SAVE_COPY) +/** + * Run-time only #G.fileflags which are never read or written to/from Blend files. + * This means we can change the values without worrying about do-versions. + */ +#define G_FILE_FLAG_ALL_RUNTIME (G_FILE_NO_UI) /** ENDIAN_ORDER: indicates what endianness the platform where the file was written had. */ #if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 85ba8175143..cd434566e43 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -96,6 +96,7 @@ void BKE_gpencil_free_layers(struct ListBase *list); void BKE_gpencil_free(struct bGPdata *gpd, bool free_all); void BKE_gpencil_eval_delete(struct bGPdata *gpd_eval); void BKE_gpencil_free_layer_masks(struct bGPDlayer *gpl); +void BKE_gpencil_tag(struct bGPdata *gpd); void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd); void BKE_gpencil_batch_cache_free(struct bGPdata *gpd); diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index b26016aa26c..b79bbf3948f 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -98,6 +98,19 @@ bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist); float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d); +void BKE_gpencil_convert_mesh(struct Main *bmain, + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob_gp, + struct Object *ob_mesh, + const float angle, + const int thickness, + const float offset, + const float matrix[4][4], + const int frame_offset, + const bool use_seams, + const bool use_faces); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index 966d3a98234..ac5f4607838 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -20,12 +20,14 @@ * \ingroup bke */ +#include "BLI_compiler_attrs.h" #include "DNA_gpencil_modifier_types.h" /* needed for all enum typdefs */ #ifdef __cplusplus extern "C" { #endif +struct ARegionType; struct Depsgraph; struct GpencilModifierData; struct ID; @@ -255,11 +257,17 @@ typedef struct GpencilModifierTypeInfo { struct Object *ob, GreasePencilTexWalkFunc walk, void *userData); + + /* Register the panel types for the modifier's UI. */ + void (*panelRegister)(struct ARegionType *region_type); } GpencilModifierTypeInfo; +#define GPENCIL_MODIFIER_TYPE_PANEL_PREFIX "MOD_PT_gpencil_" + /* Initialize modifier's global data (type info and some common global storages). */ void BKE_gpencil_modifier_init(void); +void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname); const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type); struct GpencilModifierData *BKE_gpencil_modifier_new(int type); void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag); @@ -276,6 +284,8 @@ void BKE_gpencil_modifier_copydata(struct GpencilModifierData *md, void BKE_gpencil_modifier_copydata_ex(struct GpencilModifierData *md, struct GpencilModifierData *target, const int flag); +void BKE_gpencil_modifier_set_error(struct GpencilModifierData *md, const char *format, ...) + ATTR_PRINTF_FORMAT(2, 3); void BKE_gpencil_modifiers_foreach_ID_link(struct Object *ob, GreasePencilIDWalkFunc walk, void *userData); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 1272127daa0..dc01e8ea27b 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -110,9 +110,9 @@ bool IDP_InsertToGroup(struct IDProperty *group, void IDP_RemoveFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL(); void IDP_FreeFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL(); -IDProperty *IDP_GetPropertyFromGroup(struct IDProperty *prop, +IDProperty *IDP_GetPropertyFromGroup(const struct IDProperty *prop, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -IDProperty *IDP_GetPropertyTypeFromGroup(struct IDProperty *prop, +IDProperty *IDP_GetPropertyTypeFromGroup(const struct IDProperty *prop, const char *name, const char type) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 7f5a6e3e36a..bc72afdd08d 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -144,6 +144,16 @@ struct ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +/** + * Duplicate (a.k.a. deep copy) common processing options. + * See also eDupli_ID_Flags for options controlling what kind of IDs to duplicate. + */ +typedef enum eLibIDDuplicateFlags { + /** This call to a duplicate function is part of another call for some parent ID. + * Therefore, this sub-process should not clear `newid` pointers, nor handle remapping itself. */ + LIB_ID_DUPLICATE_IS_SUBPROCESS = 1 << 0, +} eLibIDDuplicateFlags; + /* lib_remap.c (keep here since they're general functions) */ /** * New freeing logic options. @@ -217,6 +227,10 @@ bool id_single_user(struct bContext *C, bool BKE_id_copy_is_allowed(const struct ID *id); bool BKE_id_copy(struct Main *bmain, const struct ID *id, struct ID **newid); bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag); +struct ID *BKE_id_copy_for_duplicate(struct Main *bmain, + struct ID *id, + const bool is_owner_id_liboverride, + const uint duplicate_flags); void BKE_lib_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b); void BKE_lib_id_swap_full(struct Main *bmain, struct ID *id_a, struct ID *id_b); @@ -253,6 +267,7 @@ void BKE_main_id_repair_duplicate_names_listbase(struct ListBase *lb); void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const struct ID *id, char separator_str); void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const struct ID *id, + const bool add_lib_hint, char separator_char); char *BKE_id_to_unique_string_key(const struct ID *id); diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index 786d0b5ba97..411df66fe36 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -108,9 +108,7 @@ bool BKE_lib_override_library_property_operation_operands_validate( bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *local); bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local); -bool BKE_lib_override_library_operations_create(struct Main *bmain, - struct ID *local, - const bool force_auto); +bool BKE_lib_override_library_operations_create(struct Main *bmain, struct ID *local); void BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto); void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property, diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 516148728d2..b7c70168a49 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -173,6 +173,7 @@ void BKE_main_unlock(struct Main *bmain); void BKE_main_relations_create(struct Main *bmain, const short flag); void BKE_main_relations_free(struct Main *bmain); +void BKE_main_relations_ID_remove(struct Main *bmain, struct ID *id); struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 46c6f68384e..7d989bfcf69 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -484,6 +484,7 @@ void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap, const struct MLoop *mloop); bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]); +bool BKE_mesh_center_median_from_polys(const struct Mesh *me, float r_cent[3]); bool BKE_mesh_center_bounds(const struct Mesh *me, float r_cent[3]); bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]); bool BKE_mesh_center_of_volume(const struct Mesh *me, float r_cent[3]); diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h index b63f9a9814b..24f95f7ed20 100644 --- a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h +++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h @@ -60,6 +60,7 @@ struct Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(struct Mesh *mesh, /* Data reprojection functions */ void BKE_mesh_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source); +void BKE_remesh_reproject_vertex_paint(struct Mesh *target, struct Mesh *source); void BKE_remesh_reproject_sculpt_face_sets(struct Mesh *target, struct Mesh *source); #ifdef __cplusplus diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h index fdddafcc71f..468ec6a44cd 100644 --- a/source/blender/blenkernel/BKE_mesh_runtime.h +++ b/source/blender/blenkernel/BKE_mesh_runtime.h @@ -49,6 +49,7 @@ void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh); const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh); bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh); bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh); +bool BKE_mesh_runtime_reset_edit_data(struct Mesh *mesh); void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh); void BKE_mesh_runtime_clear_cache(struct Mesh *mesh); diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 766ca78dc50..e16a9284425 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -48,25 +48,28 @@ typedef enum { /* Should not be used, only for None modifier type */ eModifierTypeType_None, - /* Modifier only does deformation, implies that modifier + /** + * Modifier only does deformation, implies that modifier * type should have a valid deformVerts function. OnlyDeform * style modifiers implicitly accept either mesh or CV * input but should still declare flags appropriately. */ eModifierTypeType_OnlyDeform, - /* Modifier adds geometry. */ + /** Modifier adds geometry. */ eModifierTypeType_Constructive, /* Modifier can add and remove geometry. */ eModifierTypeType_Nonconstructive, - /* both deformVerts & applyModifier are valid calls + /** + * Both deformVerts & applyModifier are valid calls * used for particles modifier that doesn't actually modify the object * unless it's a mesh and can be exploded -> curve can also emit particles */ eModifierTypeType_DeformOrConstruct, - /* Like eModifierTypeType_Nonconstructive, but does not affect the geometry + /** + * Like eModifierTypeType_Nonconstructive, but does not affect the geometry * of the object, rather some of its CustomData layers. * E.g. UVProject and WeightVG modifiers. */ eModifierTypeType_NonGeometrical, @@ -78,7 +81,8 @@ typedef enum { eModifierTypeFlag_SupportsMapping = (1 << 2), eModifierTypeFlag_SupportsEditmode = (1 << 3), - /* For modifiers that support editmode this determines if the + /** + * For modifiers that support editmode this determines if the * modifier should be enabled by default in editmode. This should * only be used by modifiers that are relatively speedy and * also generally used in editmode, otherwise let the user enable @@ -86,22 +90,25 @@ typedef enum { */ eModifierTypeFlag_EnableInEditmode = (1 << 4), - /* For modifiers that require original data and so cannot + /** + * For modifiers that require original data and so cannot * be placed after any non-deformative modifier. */ eModifierTypeFlag_RequiresOriginalData = (1 << 5), - /* For modifiers that support pointcache, - * so we can check to see if it has files we need to deal with. */ + /** + * For modifiers that support pointcache, + * so we can check to see if it has files we need to deal with. + */ eModifierTypeFlag_UsesPointCache = (1 << 6), - /* For physics modifiers, max one per type */ + /** For physics modifiers, max one per type */ eModifierTypeFlag_Single = (1 << 7), - /* Some modifier can't be added manually by user */ + /** Some modifier can't be added manually by user */ eModifierTypeFlag_NoUserAdd = (1 << 8), - /* For modifiers that use CD_PREVIEW_MCOL for preview. */ + /** For modifiers that use CD_PREVIEW_MCOL for preview. */ eModifierTypeFlag_UsesPreview = (1 << 9), eModifierTypeFlag_AcceptsVertexCosOnly = (1 << 10), @@ -169,7 +176,8 @@ typedef struct ModifierTypeInfo { /********************* Non-optional functions *********************/ - /* Copy instance data for this modifier type. Should copy all user + /** + * Copy instance data for this modifier type. Should copy all user * level settings to the target modifier. * * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more). @@ -178,7 +186,8 @@ typedef struct ModifierTypeInfo { /********************* Deform modifier functions *********************/ - /* Only for deform types, should apply the deformation + /** + * Only for deform types, should apply the deformation * to the given vertex array. If the deformer requires information from * the object it can obtain it from the mesh argument if non-NULL, * and otherwise the ob argument. @@ -189,15 +198,17 @@ typedef struct ModifierTypeInfo { float (*vertexCos)[3], int numVerts); - /* Like deformMatricesEM but called from object mode (for supporting modifiers in sculpt mode) */ + /** + * Like deformMatricesEM but called from object mode (for supporting modifiers in sculpt mode). + */ void (*deformMatrices)(struct ModifierData *md, const struct ModifierEvalContext *ctx, struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts); - - /* Like deformVerts but called during editmode (for supporting modifiers) + /** + * Like deformVerts but called during editmode (for supporting modifiers) */ void (*deformVertsEM)(struct ModifierData *md, const struct ModifierEvalContext *ctx, @@ -206,7 +217,7 @@ typedef struct ModifierTypeInfo { float (*vertexCos)[3], int numVerts); - /* Set deform matrix per vertex for crazyspace correction */ + /* Set deform matrix per vertex for crazy-space correction */ void (*deformMatricesEM)(struct ModifierData *md, const struct ModifierEvalContext *ctx, struct BMEditMesh *editData, @@ -217,7 +228,8 @@ typedef struct ModifierTypeInfo { /********************* Non-deform modifier functions *********************/ - /* For non-deform types: apply the modifier and return a mesh data-block. + /** + * 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 data-block rather than object->data, as it contains the mesh @@ -242,14 +254,16 @@ typedef struct ModifierTypeInfo { /********************* Optional functions *********************/ - /* Initialize new instance data for this modifier type, this function + /** + * Initialize new instance data for this modifier type, this function * should set modifier variables to their default values. * * This function is optional. */ void (*initData)(struct ModifierData *md); - /* Should add to passed \a r_cddata_masks the data types that this + /** + * Should add to passed \a r_cddata_masks the data types that this * modifier needs. If (mask & (1 << (layer type))) != 0, this modifier * needs that custom data layer. It can change required layers * depending on the modifier's settings. @@ -266,7 +280,8 @@ typedef struct ModifierTypeInfo { struct ModifierData *md, struct CustomData_MeshMasks *r_cddata_masks); - /* Free internal modifier data variables, this function should + /** + * Free internal modifier data variables, this function should * not free the md variable itself. * * This function is responsible for freeing the runtime data as well. @@ -275,7 +290,8 @@ typedef struct ModifierTypeInfo { */ void (*freeData)(struct ModifierData *md); - /* Return a boolean value indicating if this modifier is able to be + /** + * Return a boolean value indicating if this modifier is able to be * calculated based on the modifier data. This is *not* regarding the * md->flag, that is tested by the system, this is just if the data * validates (for example, a lattice will return false if the lattice @@ -285,29 +301,33 @@ typedef struct ModifierTypeInfo { */ bool (*isDisabled)(const struct Scene *scene, struct ModifierData *md, bool userRenderParams); - /* Add the appropriate relations to the dependency graph. + /** + * Add the appropriate relations to the dependency graph. * * This function is optional. */ void (*updateDepsgraph)(struct ModifierData *md, const ModifierUpdateDepsgraphContext *ctx); - /* Should return true if the modifier needs to be recalculated on time + /** + * Should return true if the modifier needs to be recalculated on time * changes. * * This function is optional (assumes false if not present). */ bool (*dependsOnTime)(struct ModifierData *md); - /* True when a deform modifier uses normals, the requiredDataMask + /** + * True when a deform modifier uses normals, the requiredDataMask * cant be used here because that refers to a normal layer whereas * in this case we need to know if the deform modifier uses normals. * * this is needed because applying 2 deform modifiers will give the * second modifier bogus normals. - * */ + */ bool (*dependsOnNormals)(struct ModifierData *md); - /* Should call the given walk function on with a pointer to each Object + /** + * Should call the given walk function on with a pointer to each Object * pointer that the modifier data stores. This is used for linking on file * load and for unlinking objects or forwarding object references. * @@ -318,7 +338,8 @@ typedef struct ModifierTypeInfo { ObjectWalkFunc walk, void *userData); - /* Should call the given walk function with a pointer to each ID + /** + * Should call the given walk function with a pointer to each ID * pointer (i.e. each data-block pointer) that the modifier data * stores. This is used for linking on file load and for * unlinking data-blocks or forwarding data-block references. @@ -331,7 +352,8 @@ typedef struct ModifierTypeInfo { IDWalkFunc walk, void *userData); - /* Should call the given walk function for each texture that the + /** + * Should call the given walk function for each texture that the * modifier data stores. This is used for finding all textures in * the context for the UI. * @@ -343,7 +365,8 @@ typedef struct ModifierTypeInfo { TexWalkFunc walk, void *userData); - /* Free given run-time data. + /** + * Free given run-time data. * * This data is coming from a modifier of the corresponding type, but actual * modifier data is not known here. @@ -355,10 +378,11 @@ typedef struct ModifierTypeInfo { */ void (*freeRuntimeData)(void *runtime_data); - /* Register the panel types for the modifier's UI. */ + /** Register the panel types for the modifier's UI. */ void (*panelRegister)(struct ARegionType *region_type); - /* Is called when the modifier is written to a file. The modifier data struct itself is written + /** + * Is called when the modifier is written to a file. The modifier data struct itself is written * already. * * This method should write any additional arrays and referenced structs that should be @@ -366,7 +390,8 @@ typedef struct ModifierTypeInfo { */ void (*blendWrite)(struct BlendWriter *writer, const struct ModifierData *md); - /* Is called when the modifier is read from a file. + /** + * Is called when the modifier is read from a file. * * It can be used to update pointers to arrays and other structs. Furthermore, fields that have * not been written (e.g. runtime data) can be reset. @@ -447,7 +472,8 @@ typedef struct CDMaskLink { struct CustomData_MeshMasks mask; } CDMaskLink; -/* Calculates and returns a linked list of CustomData_MeshMasks and modified +/** + * Calculates and returns a linked list of CustomData_MeshMasks and modified * final datamask, indicating the data required by each modifier in the stack * pointed to by md for correct evaluation, assuming the data indicated by * final_datamask is required at the end of the stack. @@ -473,7 +499,7 @@ typedef struct VirtualModifierData { struct ModifierData *BKE_modifiers_get_virtual_modifierlist(const struct Object *ob, struct VirtualModifierData *data); -/* ensure modifier correctness when changing ob->data */ +/** Ensure modifier correctness when changing ob->data. */ void BKE_modifiers_test_object(struct Object *ob); /* here for do_versions */ diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 536d04f8bd3..bdcbe2129c8 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -500,7 +500,7 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype); } \ ((void)0) -struct bNodeSocket *nodeFindSocket(struct bNode *node, int in_out, const char *identifier); +struct bNodeSocket *nodeFindSocket(const struct bNode *node, int in_out, const char *identifier); struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, diff --git a/source/blender/blenkernel/BKE_node_tree_ref.hh b/source/blender/blenkernel/BKE_node_tree_ref.hh index 043ef957af7..557eb44e5df 100644 --- a/source/blender/blenkernel/BKE_node_tree_ref.hh +++ b/source/blender/blenkernel/BKE_node_tree_ref.hh @@ -58,17 +58,8 @@ #include "RNA_access.h" -namespace BKE { - -using blender::Array; -using blender::IndexRange; -using blender::LinearAllocator; -using blender::Map; -using blender::MutableSpan; -using blender::Span; -using blender::StringRef; -using blender::StringRefNull; -using blender::Vector; +namespace blender { +namespace bke { class SocketRef; class InputSocketRef; @@ -76,7 +67,7 @@ class OutputSocketRef; class NodeRef; class NodeTreeRef; -class SocketRef : blender::NonCopyable, blender::NonMovable { +class SocketRef : NonCopyable, NonMovable { protected: NodeRef *m_node; bNodeSocket *m_bsocket; @@ -129,7 +120,7 @@ class OutputSocketRef final : public SocketRef { Span<const InputSocketRef *> directly_linked_sockets() const; }; -class NodeRef : blender::NonCopyable, blender::NonMovable { +class NodeRef : NonCopyable, NonMovable { private: NodeTreeRef *m_tree; bNode *m_bnode; @@ -164,7 +155,7 @@ class NodeRef : blender::NonCopyable, blender::NonMovable { bool is_group_output_node() const; }; -class NodeTreeRef : blender::NonCopyable, blender::NonMovable { +class NodeTreeRef : NonCopyable, NonMovable { private: LinearAllocator<> m_allocator; bNodeTree *m_btree; @@ -172,14 +163,15 @@ class NodeTreeRef : blender::NonCopyable, blender::NonMovable { Vector<SocketRef *> m_sockets_by_id; Vector<InputSocketRef *> m_input_sockets; Vector<OutputSocketRef *> m_output_sockets; - Map<std::string, Vector<NodeRef *>> m_nodes_by_idname; + Map<const bNodeType *, Vector<NodeRef *>> m_nodes_by_type; public: NodeTreeRef(bNodeTree *btree); ~NodeTreeRef(); Span<const NodeRef *> nodes() const; - Span<const NodeRef *> nodes_with_idname(StringRef idname) const; + Span<const NodeRef *> nodes_by_type(StringRefNull idname) const; + Span<const NodeRef *> nodes_by_type(const bNodeType *nodetype) const; Span<const SocketRef *> sockets() const; Span<const InputSocketRef *> input_sockets() const; @@ -412,9 +404,15 @@ inline Span<const NodeRef *> NodeTreeRef::nodes() const return m_nodes_by_id.as_span(); } -inline Span<const NodeRef *> NodeTreeRef::nodes_with_idname(StringRef idname) const +inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(StringRefNull idname) const { - const Vector<NodeRef *> *nodes = m_nodes_by_idname.lookup_ptr(idname); + const bNodeType *nodetype = nodeTypeFind(idname.data()); + return this->nodes_by_type(nodetype); +} + +inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(const bNodeType *nodetype) const +{ + const Vector<NodeRef *> *nodes = m_nodes_by_type.lookup_ptr(nodetype); if (nodes == nullptr) { return {}; } @@ -443,6 +441,7 @@ inline bNodeTree *NodeTreeRef::btree() const return m_btree; } -} // namespace BKE +} // namespace bke +} // namespace blender #endif /* __BKE_NODE_TREE_REF_HH__ */ diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 3710ec810ce..d830a35dda0 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -23,6 +23,7 @@ */ #include "BLI_compiler_attrs.h" +#include "BLI_sys_types.h" #include "DNA_object_enums.h" @@ -137,8 +138,9 @@ bool BKE_object_is_libdata(const struct Object *ob); bool BKE_object_obdata_is_libdata(const struct Object *ob); struct Object *BKE_object_duplicate(struct Main *bmain, - const struct Object *ob, - const int dupflag); + struct Object *ob, + const uint dupflag, + const uint duplicate_options); void BKE_object_obdata_size_init(struct Object *ob, const float scale); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 6e4f2efeeb8..78092884655 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -37,8 +37,8 @@ struct Brush; struct CurveMapping; struct Depsgraph; struct EnumPropertyItem; +struct EdgeSet; struct GHash; -struct GSet; struct GridPaintMask; struct ImagePool; struct MLoop; @@ -269,7 +269,7 @@ typedef struct SculptClothLengthConstraint { typedef struct SculptClothSimulation { SculptClothLengthConstraint *length_constraints; int tot_length_constraints; - struct GSet *created_length_constraints; + struct EdgeSet *created_length_constraints; int capacity_length_constraints; float *length_constraint_tweak; @@ -283,11 +283,27 @@ typedef struct SculptClothSimulation { } SculptClothSimulation; -typedef struct SculptLayerPersistentBase { +typedef struct SculptPersistentBase { float co[3]; float no[3]; float disp; -} SculptLayerPersistentBase; +} SculptPersistentBase; + +typedef struct SculptVertexInfo { + /* Idexed by vertex, stores and ID of its topologycally connected component. */ + int *connected_component; +} SculptVertexInfo; + +typedef struct SculptFakeNeighbors { + bool use_fake_neighbors; + + /* Max distance used to calculate neighborhood information. */ + float current_max_distance; + + /* Idexed by vertex, stores the vertex index of its fake neighbor if available. */ + int *fake_neighbor_index; + +} SculptFakeNeighbors; /* Session data (mode-specific) */ @@ -308,6 +324,7 @@ typedef struct SculptSession { int totvert, totpoly; struct KeyBlock *shapekey_active; + struct MPropCol *vcol; float *vmask; /* Mesh connectivity */ @@ -338,10 +355,10 @@ typedef struct SculptSession { bool show_face_sets; /* Painting on deformed mesh */ - bool deform_modifiers_active; /* object is deformed with some modifiers */ - float (*orig_cos)[3]; /* coords of undeformed mesh */ - float (*deform_cos)[3]; /* coords of deformed mesh but without stroke displacement */ - float (*deform_imats)[3][3]; /* crazyspace deformation matrices */ + bool deform_modifiers_active; /* Object is deformed with some modifiers. */ + float (*orig_cos)[3]; /* Coords of un-deformed mesh. */ + float (*deform_cos)[3]; /* Coords of deformed mesh but without stroke displacement. */ + float (*deform_imats)[3][3]; /* Crazy-space deformation matrices. */ /* Used to cache the render of the active texture */ unsigned int texcache_side, *texcache, texcache_actual; @@ -365,6 +382,7 @@ typedef struct SculptSession { /* TODO(jbakker): Replace rv3d adn v3d with ViewContext */ struct RegionView3D *rv3d; struct View3D *v3d; + struct Scene *scene; /* Dynamic mesh preview */ int *preview_vert_index_list; @@ -374,9 +392,12 @@ typedef struct SculptSession { float pose_origin[3]; SculptPoseIKChain *pose_ik_chain_preview; - /* Layer brush persistence between strokes */ + /* Mesh State Persistence */ /* This is freed with the PBVH, so it is always in sync with the mesh. */ - SculptLayerPersistentBase *layer_base; + SculptPersistentBase *persistent_base; + + SculptVertexInfo vertex_info; + SculptFakeNeighbors fake_neighbors; /* Transform operator */ float pivot_pos[3]; @@ -430,7 +451,8 @@ void BKE_sculptsession_bm_to_me_for_render(struct Object *object); void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph, struct Object *ob_orig, bool need_pmap, - bool need_mask); + bool need_mask, + bool need_colors); void BKE_sculpt_update_object_before_eval(struct Object *ob_eval); void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Object *ob_eval); diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 8fb6f140822..87875314aec 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -58,6 +58,10 @@ typedef struct { float (*co)[3]; } PBVHProxyNode; +typedef struct { + float (*color)[4]; +} PBVHColorBufferNode; + typedef enum { PBVH_Leaf = 1 << 0, @@ -75,6 +79,7 @@ typedef enum { PBVH_FullyUnmasked = 1 << 12, PBVH_UpdateTopology = 1 << 13, + PBVH_UpdateColor = 1 << 14, } PBVHNodeFlags; typedef struct PBVHFrustumPlanes { @@ -252,6 +257,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, void BKE_pbvh_node_mark_update(PBVHNode *node); void BKE_pbvh_node_mark_update_mask(PBVHNode *node); +void BKE_pbvh_node_mark_update_color(PBVHNode *node); void BKE_pbvh_node_mark_update_visibility(PBVHNode *node); void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node); void BKE_pbvh_node_mark_redraw(PBVHNode *node); @@ -352,6 +358,7 @@ typedef struct PBVHVertexIter { struct MVert *mverts; int totvert; const int *vert_indices; + struct MPropCol *vcol; float *vmask; /* bmesh */ @@ -368,6 +375,7 @@ typedef struct PBVHVertexIter { short *no; float *fno; float *mask; + float *col; bool visible; } PBVHVertexIter; @@ -419,7 +427,9 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi.no = vi.mvert->no; \ vi.index = vi.vert_indices[vi.i]; \ if (vi.vmask) \ - vi.mask = &vi.vmask[vi.vert_indices[vi.gx]]; \ + vi.mask = &vi.vmask[vi.index]; \ + if (vi.vcol) \ + vi.col = vi.vcol[vi.index].color; \ } \ else { \ if (!BLI_gsetIterator_done(&vi.bm_unique_verts)) { \ @@ -472,6 +482,9 @@ void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings, struct MVert *BKE_pbvh_get_verts(const PBVH *pbvh); +PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node); +void BKE_pbvh_node_color_buffer_free(PBVH *pbvh); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index a8c6fe4416f..8f9c53ffc05 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -132,7 +132,7 @@ typedef struct PTCacheID { struct PTCacheID *next, *prev; struct Scene *scene; - struct Object *ob; + struct ID *owner_id; void *calldata; unsigned int type, file_type; unsigned int stack_index; diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index fc7146b8cf4..91f241018ec 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -142,6 +142,8 @@ typedef struct ARegionType { void (*exit)(struct wmWindowManager *wm, struct ARegion *region); /* draw entirely, view changes should be handled here */ void (*draw)(const struct bContext *C, struct ARegion *region); + /* Handler to draw overlays. This handler is called every draw loop. */ + void (*draw_overlay)(const struct bContext *C, struct ARegion *region); /* optional, compute button layout before drawing for dynamic size */ void (*layout)(const struct bContext *C, struct ARegion *region); /* snap the size of the region (can be NULL for no snapping). */ @@ -211,7 +213,7 @@ typedef struct PanelType { char context[BKE_ST_MAXNAME]; /* for buttons window */ char category[BKE_ST_MAXNAME]; /* for category tabs */ char owner_id[BKE_ST_MAXNAME]; /* for work-spaces to selectively show. */ - char parent_id[BKE_ST_MAXNAME]; /* parent idname for subpanels */ + char parent_id[BKE_ST_MAXNAME]; /* parent idname for sub-panels */ short space_type; short region_type; /* For popovers, 0 for default. */ diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h index bdc782a606e..31e14c6c884 100644 --- a/source/blender/blenkernel/BKE_shader_fx.h +++ b/source/blender/blenkernel/BKE_shader_fx.h @@ -28,6 +28,7 @@ extern "C" { #endif +struct ARegionType; struct ID; struct ListBase; struct ModifierUpdateDepsgraphContext; @@ -157,11 +158,17 @@ typedef struct ShaderFxTypeInfo { struct Object *ob, ShaderFxIDWalkFunc walk, void *userData); + + /* Register the panel types for the effect's UI. */ + void (*panelRegister)(struct ARegionType *region_type); } ShaderFxTypeInfo; +#define SHADERFX_TYPE_PANEL_PREFIX "FX_PT_" + /* Initialize global data (type info and some common global storages). */ void BKE_shaderfx_init(void); +void BKE_shaderfxType_panel_id(ShaderFxType type, char *panel_id); const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type); struct ShaderFxData *BKE_shaderfx_new(int type); void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag); diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h index 8d2565c31f7..78e91d3ad2f 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.h +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -214,6 +214,12 @@ typedef struct SubdivCCG { /* Corresponds to MULTIRES_HIDDEN_MODIFIED. */ bool hidden; } dirty; + + /* Cached values, are not supposed to be accessed directly. */ + struct { + /* Indexed by face, indicates index of the first grid which corresponds to the face. */ + int *start_face_grid_index; + } cache_; } SubdivCCG; /* Create CCG representation of subdivision surface. @@ -307,6 +313,15 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index); +/* Get array which is indexed by face index and contains index of a first grid of the face. + * + * The "ensure" version allocates the mapping if it's not know yet and stores it in the subdiv_ccg + * descriptor. This function is NOT safe for threading. + * + * The "get" version simply returns cached array. */ +const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG *subdiv_ccg); +const int *BKE_subdiv_ccg_start_face_grid_index_get(const SubdivCCG *subdiv_ccg); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h index f462a7fab71..b32c3e315ff 100644 --- a/source/blender/blenkernel/BKE_undo_system.h +++ b/source/blender/blenkernel/BKE_undo_system.h @@ -120,7 +120,9 @@ typedef struct UndoType { /** * \note When freeing all steps, - * free from the last since #MemFileUndoType will merge with the next undo type in the list. */ + * free from the last since #BKE_UNDOSYS_TYPE_MEMFILE + * will merge with the next undo type in the list. + */ void (*step_free)(UndoStep *us); void (*step_foreach_ID_ref)(UndoStep *us, diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index b4e2cd772c9..8a5be6b9cb3 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1669,7 +1669,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, else { Mesh *me_orig = mesh_input; if (me_orig->id.tag & LIB_TAG_COPIED_ON_WRITE) { - BKE_mesh_runtime_ensure_edit_data(me_orig); + if (!BKE_mesh_runtime_ensure_edit_data(me_orig)) { + BKE_mesh_runtime_reset_edit_data(me_orig); + } me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts); } mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords( diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index c776f0d077d..b35d2183408 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -939,7 +939,7 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user) BKE_constraints_free_ex(&pchan->constraints, do_id_user); if (pchan->prop) { - IDP_FreeProperty(pchan->prop); + IDP_FreeProperty_ex(pchan->prop, do_id_user); pchan->prop = NULL; } diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index cbb34cbee30..841fdaa3b2c 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -399,6 +399,8 @@ void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid) if (ntree) { BKE_animdata_copy_id_action(bmain, &ntree->id, set_newid); } + /* Note that collections are not animatable currently, so no need to handle scenes' master + * collection here. */ } /* Merge copies of the data from the src AnimData into the destination AnimData */ diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c index e757e30e524..44b50ab96d3 100644 --- a/source/blender/blenkernel/intern/armature_deform.c +++ b/source/blender/blenkernel/intern/armature_deform.c @@ -349,8 +349,7 @@ static void armature_vert_task_with_dvert(const ArmatureUserdata *data, pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib); } } - /* if there are vertexgroups but not groups with bones - * (like for softbody groups) */ + /* If there are vertex-groups but not groups with bones (like for soft-body groups). */ if (deformed == 0 && use_envelope) { for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) { if (!(pchan->bone->flag & BONE_NO_DEFORM)) { diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index 4d27621a861..e950e94655a 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -72,9 +72,10 @@ void BKE_copybuffer_tag_ID(ID *id) */ bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *reports) { - const int write_flags = G_FILE_RELATIVE_REMAP; + const int write_flags = 0; + const eBLO_WritePathRemap remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE; - bool retval = BKE_blendfile_write_partial(bmain_src, filename, write_flags, reports); + bool retval = BKE_blendfile_write_partial(bmain_src, filename, write_flags, remap_mode, reports); BKE_blendfile_write_partial_end(bmain_src); @@ -99,7 +100,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, BKE_main_lib_objects_recalc_all(bmain_dst); IMB_colormanagement_check_file_config(bmain_dst); /* Append, rather than linking. */ - Library *lib = BLI_findstring(&bmain_dst->libraries, libname, offsetof(Library, filepath)); + Library *lib = BLI_findstring(&bmain_dst->libraries, libname, offsetof(Library, filepath_abs)); BKE_library_make_local(bmain_dst, lib, NULL, true, false); /* Important we unset, otherwise these object wont * link into other scenes from this blend file. @@ -154,7 +155,7 @@ int BKE_copybuffer_paste(bContext *C, IMB_colormanagement_check_file_config(bmain); /* append, rather than linking */ - lib = BLI_findstring(&bmain->libraries, libname, offsetof(Library, filepath)); + lib = BLI_findstring(&bmain->libraries, libname, offsetof(Library, filepath_abs)); BKE_library_make_local(bmain, lib, NULL, true, false); /* important we unset, otherwise these object wont diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index ab382d0e8ff..a6f84f3c3a4 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -109,7 +109,6 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev) static int counter = 0; char filename[FILE_MAX]; char numstr[32]; - int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */ /* Calculate current filename. */ counter++; @@ -118,7 +117,8 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev) BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter); BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), numstr); - /* success = */ /* UNUSED */ BLO_write_file(bmain, filename, fileflags, NULL, NULL); + /* success = */ /* UNUSED */ BLO_write_file( + bmain, filename, G.fileflags, &(const struct BlendFileWriteParams){0}, NULL); BLI_strncpy(mfu->filename, filename, sizeof(mfu->filename)); } diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index ef474022f19..ee60bf79611 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -646,7 +646,13 @@ bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports) Main *mainb = MEM_callocN(sizeof(Main), "empty main"); bool ok = false; - if (BLO_write_file(mainb, filepath, G_FILE_USERPREFS, reports, NULL)) { + if (BLO_write_file(mainb, + filepath, + 0, + &(const struct BlendFileWriteParams){ + .use_userdef = true, + }, + reports)) { ok = true; } @@ -768,7 +774,7 @@ WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepat bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports) { - int fileflags = G.fileflags & ~(G_FILE_NO_UI | G_FILE_HISTORY); + const int fileflags = G.fileflags & ~G_FILE_NO_UI; bool retval = false; BKE_blendfile_write_partial_begin(bmain); @@ -777,7 +783,8 @@ bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, Rep BKE_blendfile_write_partial_tag_ID(&workspace->id, true); } - if (BKE_blendfile_write_partial(bmain, filepath, fileflags, reports)) { + if (BKE_blendfile_write_partial( + bmain, filepath, fileflags, BLO_WRITE_PATH_REMAP_NONE, reports)) { retval = true; } @@ -829,11 +836,13 @@ static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain) } /** + * \param remap_mode: Choose the kind of path remapping or none #eBLO_WritePathRemap. * \return Success. */ bool BKE_blendfile_write_partial(Main *bmain_src, const char *filepath, const int write_flags, + const int remap_mode, ReportList *reports) { Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer"); @@ -875,12 +884,18 @@ bool BKE_blendfile_write_partial(Main *bmain_src, * This happens because id_sort_by_name does not take into account * string case or the library name, so the order is not strictly * defined for two linked data-blocks with the same name! */ - if (write_flags & G_FILE_RELATIVE_REMAP) { + if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) { path_list_backup = BKE_bpath_list_backup(bmain_dst, path_list_flag); } /* save the buffer */ - retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL); + retval = BLO_write_file(bmain_dst, + filepath, + write_flags, + &(const struct BlendFileWriteParams){ + .remap_mode = remap_mode, + }, + reports); if (path_list_backup) { BKE_bpath_list_restore(bmain_dst, path_list_flag, path_list_backup); diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 6197b9dbefd..d5064629451 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -218,7 +218,7 @@ static int rule_avoid_collision(BoidRule *rule, BoidValues *val, ParticleData *pa) { - const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT); + const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT; BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision *)rule; KDTreeNearest_3d *ptn = NULL; ParticleTarget *pt; @@ -854,7 +854,7 @@ static Object *boid_find_ground(BoidBrainData *bbd, float ground_co[3], float ground_nor[3]) { - const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT); + const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT; BoidParticle *bpa = pa->boid; if (bpa->data.mode == eBoidMode_Climbing) { @@ -1388,6 +1388,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa) bbd->part->effector_weights, &epoint, force, + NULL, NULL); if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index f0e23ddad41..10783c741b6 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -564,8 +564,8 @@ void BKE_bpath_traverse_id( * don't make sense to add directories to until the image has been saved * once to give it a meaningful value. */ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) && - ima->name[0]) { - if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) { + ima->filepath[0]) { + if (rewrite_path_fixed(ima->filepath, visit_cb, absbase, bpath_user_data)) { if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) { if (!BKE_image_has_packedfile(ima) && /* image may have been painted onto (and not saved, T44543) */ @@ -643,7 +643,7 @@ void BKE_bpath_traverse_id( case ID_SO: { bSound *sound = (bSound *)id; if (sound->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { - rewrite_path_fixed(sound->name, visit_cb, absbase, bpath_user_data); + rewrite_path_fixed(sound->filepath, visit_cb, absbase, bpath_user_data); } break; } @@ -655,15 +655,15 @@ void BKE_bpath_traverse_id( break; } case ID_TXT: - if (((Text *)id)->name) { - rewrite_path_alloc(&((Text *)id)->name, visit_cb, absbase, bpath_user_data); + if (((Text *)id)->filepath) { + rewrite_path_alloc(&((Text *)id)->filepath, visit_cb, absbase, bpath_user_data); } break; case ID_VF: { VFont *vfont = (VFont *)id; if (vfont->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { if (BKE_vfont_is_builtin(vfont) == false) { - rewrite_path_fixed(((VFont *)id)->name, visit_cb, absbase, bpath_user_data); + rewrite_path_fixed(((VFont *)id)->filepath, visit_cb, absbase, bpath_user_data); } } break; @@ -756,15 +756,15 @@ void BKE_bpath_traverse_id( Library *lib = (Library *)id; /* keep packedfile paths always relative to the blend */ if (lib->packedfile == NULL) { - if (rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) { - BKE_library_filepath_set(bmain, lib, lib->name); + if (rewrite_path_fixed(lib->filepath, visit_cb, absbase, bpath_user_data)) { + BKE_library_filepath_set(bmain, lib, lib->filepath); } } break; } case ID_MC: { MovieClip *clip = (MovieClip *)id; - rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data); + rewrite_path_fixed(clip->filepath, visit_cb, absbase, bpath_user_data); break; } case ID_CF: { diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 3241518cae5..a8f52593429 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -248,6 +248,7 @@ static void brush_defaults(Brush *brush) FROM_DEFAULT(crease_pinch_factor); FROM_DEFAULT(normal_radius_factor); FROM_DEFAULT(area_radius_factor); + FROM_DEFAULT(disconnected_distance_max); FROM_DEFAULT(sculpt_plane); FROM_DEFAULT(plane_offset); FROM_DEFAULT(clone.alpha); @@ -493,7 +494,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->preset_type = type; /* Set vertex mix factor. */ - brush->gpencil_settings->vertex_mode = GPPAINT_MODE_STROKE; + brush->gpencil_settings->vertex_mode = GPPAINT_MODE_BOTH; brush->gpencil_settings->vertex_factor = 1.0f; switch (type) { @@ -1185,6 +1186,11 @@ void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool r if (reset || brush_prev == NULL) { BKE_paint_brush_set(paint, deft_draw); } + else { + if (brush_prev != NULL) { + BKE_paint_brush_set(paint, brush_prev); + } + } } /* Create a set of grease pencil Vertex Paint presets. */ @@ -1227,6 +1233,11 @@ void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool if (reset || brush_prev == NULL) { BKE_paint_brush_set(vertexpaint, deft_vertex); } + else { + if (brush_prev != NULL) { + BKE_paint_brush_set(vertexpaint, brush_prev); + } + } } /* Create a set of grease pencil Sculpt Paint presets. */ @@ -1297,6 +1308,11 @@ void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool if (reset || brush_prev == NULL) { BKE_paint_brush_set(sculptpaint, deft_sculpt); } + else { + if (brush_prev != NULL) { + BKE_paint_brush_set(sculptpaint, brush_prev); + } + } } /* Create a set of grease pencil Weight Paint presets. */ @@ -1318,6 +1334,11 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool if (reset || brush_prev == NULL) { BKE_paint_brush_set(weightpaint, deft_weight); } + else { + if (brush_prev != NULL) { + BKE_paint_brush_set(weightpaint, brush_prev); + } + } } struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode) @@ -1538,7 +1559,7 @@ void BKE_brush_sculpt_reset(Brush *br) case SCULPT_TOOL_POSE: br->pose_smooth_iterations = 4; br->pose_ik_segments = 1; - br->flag2 |= BRUSH_POSE_IK_ANCHORED; + br->flag2 |= BRUSH_POSE_IK_ANCHORED | BRUSH_USE_CONNECTED_ONLY; br->flag &= ~BRUSH_ALPHA_PRESSURE; br->flag &= ~BRUSH_SPACE; br->flag &= ~BRUSH_SPACE_ATTEN; @@ -1570,6 +1591,24 @@ void BKE_brush_sculpt_reset(Brush *br) br->alpha = 1.0f; br->height = 0.05f; break; + case SCULPT_TOOL_PAINT: + br->hardness = 0.4f; + br->spacing = 10; + br->alpha = 0.6f; + br->flow = 1.0f; + br->tip_scale_x = 1.0f; + br->tip_roundness = 1.0f; + br->density = 1.0f; + br->flag &= ~BRUSH_SPACE_ATTEN; + zero_v3(br->rgb); + break; + case SCULPT_TOOL_SMEAR: + br->alpha = 1.0f; + br->spacing = 5; + br->flag &= ~BRUSH_ALPHA_PRESSURE; + br->flag &= ~BRUSH_SPACE_ATTEN; + br->curve_preset = BRUSH_CURVE_SPHERE; + break; default: break; } @@ -1629,14 +1668,15 @@ void BKE_brush_sculpt_reset(Brush *br) break; case SCULPT_TOOL_SIMPLIFY: + case SCULPT_TOOL_PAINT: case SCULPT_TOOL_MASK: case SCULPT_TOOL_DRAW_FACE_SETS: - br->add_col[0] = 0.750000; - br->add_col[1] = 0.750000; - br->add_col[2] = 0.750000; - br->sub_col[0] = 0.750000; - br->sub_col[1] = 0.750000; - br->sub_col[2] = 0.750000; + br->add_col[0] = 0.75f; + br->add_col[1] = 0.75f; + br->add_col[2] = 0.75f; + br->sub_col[0] = 0.75f; + br->sub_col[1] = 0.75f; + br->sub_col[2] = 0.75f; break; case SCULPT_TOOL_CLOTH: diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 6f63da18a22..080d61f1500 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -28,6 +28,7 @@ #include "BLI_threads.h" #include "BLT_translation.h" +#include "BKE_anim_data.h" #include "BKE_collection.h" #include "BKE_icons.h" #include "BKE_idprop.h" @@ -326,16 +327,16 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy) static Collection *collection_duplicate_recursive(Main *bmain, Collection *parent, Collection *collection_old, - const bool do_hierarchy, - const bool do_objects, - const bool do_obdata) + const eDupli_ID_Flags duplicate_flags, + const eLibIDDuplicateFlags duplicate_options) { Collection *collection_new; bool do_full_process = false; - const int object_dupflag = (do_obdata) ? U.dupflag : 0; const bool is_collection_master = (collection_old->flag & COLLECTION_IS_MASTER) != 0; const bool is_collection_liboverride = ID_IS_OVERRIDE_LIBRARY(collection_old); + const bool do_objects = (duplicate_flags & USER_DUP_OBJECT) != 0; + if (is_collection_master) { /* We never duplicate master collections here, but we can still deep-copy their objects and * collections. */ @@ -343,15 +344,9 @@ static Collection *collection_duplicate_recursive(Main *bmain, collection_new = collection_old; do_full_process = true; } - else if (!do_hierarchy || collection_old->id.newid == NULL) { - BKE_id_copy(bmain, &collection_old->id, (ID **)&collection_new); - - /* Copying add one user by default, need to get rid of that one. */ - id_us_min(&collection_new->id); - - if (do_hierarchy) { - ID_NEW_SET(collection_old, collection_new); - } + else if (collection_old->id.newid == NULL) { + collection_new = (Collection *)BKE_id_copy_for_duplicate( + bmain, (ID *)collection_old, is_collection_liboverride, duplicate_flags); do_full_process = true; } else { @@ -376,7 +371,7 @@ static Collection *collection_duplicate_recursive(Main *bmain, /* If we are not doing any kind of deep-copy, we can return immediately. * False do_full_process means collection_old had already been duplicated, * no need to redo some deep-copy on it. */ - if (!do_hierarchy || !do_full_process) { + if (!do_full_process) { return collection_new; } @@ -394,8 +389,8 @@ static Collection *collection_duplicate_recursive(Main *bmain, } if (ob_new == NULL) { - ob_new = BKE_object_duplicate(bmain, ob_old, object_dupflag); - ID_NEW_SET(ob_old, ob_new); + ob_new = BKE_object_duplicate( + bmain, ob_old, duplicate_flags, duplicate_options | LIB_ID_DUPLICATE_IS_SUBPROCESS); } collection_object_add(bmain, collection_new, ob_new, 0, true); @@ -413,7 +408,7 @@ static Collection *collection_duplicate_recursive(Main *bmain, } collection_duplicate_recursive( - bmain, collection_new, child_collection_old, do_hierarchy, do_objects, do_obdata); + bmain, collection_new, child_collection_old, duplicate_flags, duplicate_options); collection_child_remove(collection_new, child_collection_old); } @@ -421,56 +416,54 @@ static Collection *collection_duplicate_recursive(Main *bmain, } /** - * Makes a standard (aka shallow) ID copy of a Collection. - * - * Add a new collection in the same level as the old one, link any nested collections - * and finally link the objects to the new collection (as opposed to copying them). - */ -Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection) -{ - return BKE_collection_duplicate(bmain, parent, collection, false, false, false); -} - -/** - * Make either a shallow copy, or deeper duplicate of given collection. + * Make a deep copy (aka duplicate) of the given collection and all of its children, recursively. * - * If \a do_hierarchy and \a do_deep_copy are false, this is a regular (shallow) ID copy. - * - * \warning If any 'deep copy' behavior is enabled, - * this functions will clear all \a bmain id.idnew pointers. - * - * \param do_hierarchy: If true, it will recursively make shallow copies of children collections. - * \param do_objects: If true, it will also make duplicates of objects. - * This one does nothing if \a do_hierarchy is not set. - * \param do_obdata: If true, it will also make deep duplicates of objects, - * using behavior defined in user settings (#U.dupflag). - * This one does nothing if \a do_hierarchy and \a do_objects are not set. + * \warning This functions will clear all \a bmain #ID.idnew pointers, unless \a + * #LIB_ID_DUPLICATE_IS_SUBPROCESS duplicate option is passed on, in which case caller is + * responsible to reconstruct collection dependencies information's + * (i.e. call #BKE_main_collection_sync). */ Collection *BKE_collection_duplicate(Main *bmain, Collection *parent, Collection *collection, - const bool do_hierarchy, - const bool do_objects, - const bool do_obdata) + eDupli_ID_Flags duplicate_flags, + eLibIDDuplicateFlags duplicate_options) { - if (do_hierarchy) { + const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0; + + if (!is_subprocess) { BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); BKE_main_id_clear_newpoins(bmain); } Collection *collection_new = collection_duplicate_recursive( - bmain, parent, collection, do_hierarchy, do_objects, do_obdata); - - /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/ - BKE_libblock_relink_to_newid(&collection_new->id); + bmain, parent, collection, duplicate_flags, duplicate_options); + + if (!is_subprocess) { + /* `collection_duplicate_recursive` will also tag our 'root' collection, which is not required + * unless its duplication is a sub-process of another one. */ + collection_new->id.tag &= ~LIB_TAG_NEW; + + /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/ + BKE_libblock_relink_to_newid(&collection_new->id); + +#ifndef NDEBUG + /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */ + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + if (id_iter->tag & LIB_TAG_NEW) { + BLI_assert((id_iter->tag & LIB_TAG_NEW) == 0); + } + } + FOREACH_MAIN_ID_END; +#endif - if (do_hierarchy) { /* Cleanup. */ BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); BKE_main_id_clear_newpoins(bmain); - } - BKE_main_collection_sync(bmain); + BKE_main_collection_sync(bmain); + } return collection_new; } @@ -927,7 +920,7 @@ bool BKE_collection_object_remove(Main *bmain, /** * Remove object from all collections of scene - * \param scene_collection_skip: Don't remove base from this collection. + * \param collection_skip: Don't remove base from this collection. */ static bool scene_collections_object_remove( Main *bmain, Scene *scene, Object *ob, const bool free_us, Collection *collection_skip) @@ -1126,7 +1119,7 @@ static bool collection_find_instance_recursive(Collection *collection, { LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) { if (collection_object->ob != NULL && - /* Object from a given collection should never instanciate that collection either. */ + /* Object from a given collection should never instantiate that collection either. */ ELEM(collection_object->ob->instance_collection, instance_collection, collection)) { return true; } @@ -1153,7 +1146,7 @@ bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection) } } - /* Find possible objects in collection or its children, that would instanciate the given ancestor + /* Find possible objects in collection or its children, that would instantiate the given ancestor * collection (that would also make a fully invalid cycle of dependencies) .*/ return collection_find_instance_recursive(collection, new_ancestor); } diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 3da384a2745..4f4eb8f9f9d 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -44,6 +44,8 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" +#include "BLO_read_write.h" + /* ********************************* color curve ********************* */ /* ***************** operations on full struct ************* */ @@ -1238,6 +1240,32 @@ void BKE_curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int * } } +void BKE_curvemapping_blend_write(BlendWriter *writer, const CurveMapping *cumap) +{ + BLO_write_struct(writer, CurveMapping, cumap); + BKE_curvemapping_curves_blend_write(writer, cumap); +} + +void BKE_curvemapping_curves_blend_write(BlendWriter *writer, const CurveMapping *cumap) +{ + for (int a = 0; a < CM_TOT; a++) { + BLO_write_struct_array(writer, CurveMapPoint, cumap->cm[a].totpoint, cumap->cm[a].curve); + } +} + +/* cumap itself has been read already. */ +void BKE_curvemapping_blend_read(BlendDataReader *reader, CurveMapping *cumap) +{ + /* flag seems to be able to hang? Maybe old files... not bad to clear anyway */ + cumap->flag &= ~CUMA_PREMULLED; + + for (int a = 0; a < CM_TOT; a++) { + BLO_read_data_address(reader, &cumap->cm[a].curve); + cumap->cm[a].table = NULL; + cumap->cm[a].premultable = NULL; + } +} + /* ***************** Histogram **************** */ #define INV_255 (1.f / 255.f) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 050e8d434ae..06c28776840 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -5412,9 +5412,16 @@ static bConstraint *add_new_constraint_internal(const char *name, short type) /* Set up a generic constraint data-block. */ con->type = type; - con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; + con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; con->enforce = 1.0f; + /* Only open the main panel when constraints are created, not the sub-panels. */ + con->ui_expand_flag = (1 << 0); + if (ELEM(type, CONSTRAINT_TYPE_ACTION, CONSTRAINT_TYPE_SPLINEIK)) { + /* Expand the two sub-panels in the cases where the main panel barely has any properties. */ + con->ui_expand_flag |= (1 << 1) | (1 << 2); + } + /* Determine a basic name, and info */ if (cti) { /* initialize constraint data */ @@ -5441,18 +5448,11 @@ static bConstraint *add_new_constraint_internal(const char *name, short type) return con; } -/* if pchan is not NULL then assume we're adding a pose constraint */ -static bConstraint *add_new_constraint(Object *ob, - bPoseChannel *pchan, - const char *name, - short type) +/* Add a newly created constraint to the constraint list. */ +static void add_new_constraint_to_list(Object *ob, bPoseChannel *pchan, bConstraint *con) { - bConstraint *con; ListBase *list; - /* add the constraint */ - con = add_new_constraint_internal(name, type); - /* find the constraint stack - bone or object? */ list = (pchan) ? (&pchan->constraints) : (&ob->constraints); @@ -5474,6 +5474,20 @@ static bConstraint *add_new_constraint(Object *ob, /* make this constraint the active one */ BKE_constraints_active_set(list, con); } +} + +/* if pchan is not NULL then assume we're adding a pose constraint */ +static bConstraint *add_new_constraint(Object *ob, + bPoseChannel *pchan, + const char *name, + short type) +{ + bConstraint *con; + + /* add the constraint */ + con = add_new_constraint_internal(name, type); + + add_new_constraint_to_list(ob, pchan, con); /* set type+owner specific immutable settings */ /* TODO: does action constraint need anything here - i.e. spaceonce? */ @@ -5607,6 +5621,26 @@ bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const return dst; } +/* Add a copy of the given constraint for the given bone */ +bConstraint *BKE_constraint_copy_for_pose(Object *ob, bPoseChannel *pchan, bConstraint *src) +{ + if (pchan == NULL) { + return NULL; + } + + bConstraint *new_con = BKE_constraint_duplicate_ex(src, 0, !ID_IS_LINKED(ob)); + add_new_constraint_to_list(ob, pchan, new_con); + return new_con; +} + +/* Add a copy of the given constraint for the given object */ +bConstraint *BKE_constraint_copy_for_object(Object *ob, bConstraint *src) +{ + bConstraint *new_con = BKE_constraint_duplicate_ex(src, 0, !ID_IS_LINKED(ob)); + add_new_constraint_to_list(ob, NULL, new_con); + return new_con; +} + /* duplicate all of the constraints in a constraint stack */ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern) { diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index 4d685a511fd..e4f851819a8 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -252,7 +252,7 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me, } /** - * Returns an array of deform matrices for crazyspace correction, + * Returns an array of deform matrices for crazy-space correction, * and the number of modifiers left. */ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph, @@ -327,7 +327,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra } /** - * Crazyspace evaluation needs to have an object which has all the fields + * Crazy-space evaluation needs to have an object which has all the fields * evaluated, but the mesh data being at undeformed state. This way it can * re-apply modifiers and also have proper pointers to key data blocks. * @@ -455,8 +455,8 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, depsgraph, scene, object, deformmats, deformcos); if (totleft) { - /* there are deformation modifier which doesn't support deformation matrices - * calculation. Need additional crazyspace correction */ + /* There are deformation modifier which doesn't support deformation matrices calculation. + * Need additional crazy-space correction. */ Mesh *mesh = (Mesh *)object->data; Mesh *mesh_eval = NULL; diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 0b65f53708f..6b28297622c 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -4081,9 +4081,9 @@ void BKE_nurb_handle_calc( /** * Variant of #BKE_nurb_handle_calc() that allows calculating based on a different select flag. * - * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`, - * but may want to use a different one at times (if caller does not operate on - * selection). + * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. + * Usually #SELECT, but may want to use a different one at times + * (if caller does not operate on selection). */ void BKE_nurb_handle_calc_ex(BezTriple *bezt, BezTriple *prev, diff --git a/source/blender/blenkernel/intern/curveprofile.c b/source/blender/blenkernel/intern/curveprofile.c index a748dfbab3e..6919d4fa10f 100644 --- a/source/blender/blenkernel/intern/curveprofile.c +++ b/source/blender/blenkernel/intern/curveprofile.c @@ -41,6 +41,8 @@ #include "BKE_curveprofile.h" #include "BKE_fcurve.h" +#include "BLO_read_write.h" + void BKE_curveprofile_free_data(CurveProfile *profile) { MEM_SAFE_FREE(profile->path); @@ -63,6 +65,11 @@ void BKE_curveprofile_copy_data(CurveProfile *target, const CurveProfile *profil target->path = MEM_dupallocN(profile->path); target->table = MEM_dupallocN(profile->table); target->segments = MEM_dupallocN(profile->segments); + + /* Update the reference the points have to the profile. */ + for (int i = 0; i < target->path_len; i++) { + target->path[i].profile = target; + } } CurveProfile *BKE_curveprofile_copy(const CurveProfile *profile) @@ -76,6 +83,101 @@ CurveProfile *BKE_curveprofile_copy(const CurveProfile *profile) } /** + * Move a point's handle, accounting for the alignment of handles with the #HD_ALIGN type. + * + * \param handle_1: Whether to move the 1st or 2nd control point. + * \param delta: The *relative* change in the handle's position. + * \note Requires #BKE_curveprofile_update call after. + * \return Whether the handle moved from its start position. + */ +bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point, + const bool handle_1, + const bool snap, + const float delta[2]) +{ + short handle_type = (handle_1) ? point->h1 : point->h2; + float *handle_location = (handle_1) ? &point->h1_loc[0] : &point->h2_loc[0]; + + float start_position[2]; + copy_v2_v2(start_position, handle_location); + + /* Don't move the handle if it's not a free handle type. */ + if (!ELEM(handle_type, HD_FREE, HD_ALIGN)) { + return false; + } + + /* Move the handle. */ + handle_location[0] += delta ? delta[0] : 0.0f; + handle_location[1] += delta ? delta[1] : 0.0f; + if (snap) { + handle_location[0] = 0.125f * roundf(8.0f * handle_location[0]); + handle_location[1] = 0.125f * roundf(8.0f * handle_location[1]); + } + + /* Move the other handle if they are aligned. */ + if (handle_type == HD_ALIGN) { + short other_handle_type = (handle_1) ? point->h2 : point->h1; + if (other_handle_type == HD_ALIGN) { + float *other_handle_location = (handle_1) ? &point->h2_loc[0] : &point->h1_loc[0]; + other_handle_location[0] = 2.0f * point->x - handle_location[0]; + other_handle_location[1] = 2.0f * point->y - handle_location[1]; + } + } + + if (!equals_v2v2(handle_location, start_position)) { + return true; + } + return false; +} + +/** + * Moves a control point, accounting for clipping and snapping, and moving free handles. + * + * \param snap: Whether to snap the point to the grid + * \param delta: The *relative* change of the point's location. + * \return Whether the point moved from its start position. + * \note Requires #BKE_curveprofile_update call after. + */ +bool BKE_curveprofile_move_point(struct CurveProfile *profile, + struct CurveProfilePoint *point, + const bool snap, + const float delta[2]) +{ + float origx = point->x; + float origy = point->y; + + point->x += delta[0]; + point->y += delta[1]; + if (snap) { + point->x = 0.125f * roundf(8.0f * point->x); + point->y = 0.125f * roundf(8.0f * point->y); + } + + /* Clip here instead to test clipping here to stop handles from moving too. */ + if (profile->flag & PROF_USE_CLIP) { + point->x = max_ff(point->x, profile->clip_rect.xmin); + point->x = min_ff(point->x, profile->clip_rect.xmax); + point->y = max_ff(point->y, profile->clip_rect.ymin); + point->y = min_ff(point->y, profile->clip_rect.ymax); + } + + /* Also move free handles even when they aren't selected. */ + if (ELEM(point->h1, HD_FREE, HD_ALIGN)) { + point->h1_loc[0] += point->x - origx; + point->h1_loc[1] += point->y - origy; + } + if (ELEM(point->h2, HD_FREE, HD_ALIGN)) { + point->h2_loc[0] += point->x - origx; + point->h2_loc[1] += point->y - origy; + } + + if (point->x != origx || point->y != origy) { + return true; + } + return false; +} + +/** * Removes a specific point from the path of control points. * \note Requires #BKE_curveprofile_update call after. */ @@ -98,8 +200,10 @@ bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *poi uint i_delete = (uint)(point - profile->path); /* Copy the before and after the deleted point. */ - memcpy(pts, profile->path, i_delete); - memcpy(pts + i_delete, profile->path + i_delete + 1, (size_t)profile->path_len - i_delete - 1); + memcpy(pts, profile->path, sizeof(CurveProfilePoint) * i_delete); + memcpy(pts + i_delete, + profile->path + i_delete + 1, + sizeof(CurveProfilePoint) * (profile->path_len - i_delete - 1)); MEM_freeN(profile->path); profile->path = pts; @@ -178,12 +282,9 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float "profile path"); for (int i_new = 0, i_old = 0; i_new < profile->path_len; i_new++) { if (i_new != i_insert) { - /* Insert old points */ - new_pts[i_new].x = profile->path[i_old].x; - new_pts[i_new].y = profile->path[i_old].y; - new_pts[i_new].flag = profile->path[i_old].flag & ~PROF_SELECT; /* Deselect old points. */ - new_pts[i_new].h1 = profile->path[i_old].h1; - new_pts[i_new].h2 = profile->path[i_old].h2; + /* Insert old points. */ + memcpy(&new_pts[i_new], &profile->path[i_old], sizeof(CurveProfilePoint)); + new_pts[i_new].flag &= ~PROF_SELECT; /* Deselect old points. */ i_old++; } else { @@ -199,6 +300,8 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float else { new_pt->h1 = new_pt->h2 = HD_AUTO; } + /* Give new point a reference to the profile. */ + new_pt->profile = profile; } } @@ -210,35 +313,19 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float /** * Sets the handle type of the selected control points. - * \param type_1, type_2: Either HD_VECT or HD_AUTO. Handle types for the first and second handles. - * + * \param type_1, type_2: Handle type for the first handle. HD_VECT, HD_AUTO, HD_FREE, or HD_ALIGN. * \note Requires #BKE_curveprofile_update call after. */ void BKE_curveprofile_selected_handle_set(CurveProfile *profile, int type_1, int type_2) { for (int i = 0; i < profile->path_len; i++) { - if (profile->path[i].flag & PROF_SELECT) { - switch (type_1) { - case HD_AUTO: - profile->path[i].h1 = HD_AUTO; - break; - case HD_VECT: - profile->path[i].h1 = HD_VECT; - break; - default: - profile->path[i].h1 = HD_AUTO; - break; - } - switch (type_2) { - case HD_AUTO: - profile->path[i].h2 = HD_AUTO; - break; - case HD_VECT: - profile->path[i].h2 = HD_VECT; - break; - default: - profile->path[i].h1 = HD_AUTO; - break; + if (ELEM(profile->path[i].flag, PROF_SELECT, PROF_H1_SELECT, PROF_H2_SELECT)) { + profile->path[i].h1 = type_1; + profile->path[i].h2 = type_2; + + if (type_1 == HD_ALIGN && type_2 == HD_ALIGN) { + /* Align the handles. */ + BKE_curveprofile_move_handle(&profile->path[i], true, false, NULL); } } } @@ -259,11 +346,24 @@ void BKE_curveprofile_reverse(CurveProfile *profile) "profile path"); /* Mirror the new points across the y = x line */ for (int i = 0; i < profile->path_len; i++) { - new_pts[profile->path_len - i - 1].x = profile->path[i].y; - new_pts[profile->path_len - i - 1].y = profile->path[i].x; - new_pts[profile->path_len - i - 1].flag = profile->path[i].flag; - new_pts[profile->path_len - i - 1].h1 = profile->path[i].h1; - new_pts[profile->path_len - i - 1].h2 = profile->path[i].h2; + int i_reversed = profile->path_len - i - 1; + BLI_assert(i_reversed >= 0); + new_pts[i_reversed].x = profile->path[i].y; + new_pts[i_reversed].y = profile->path[i].x; + new_pts[i_reversed].flag = profile->path[i].flag; + new_pts[i_reversed].h1 = profile->path[i].h2; + new_pts[i_reversed].h2 = profile->path[i].h1; + new_pts[i_reversed].profile = profile; + + /* Mirror free handles, they can't be recalculated. */ + if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) { + new_pts[i_reversed].h1_loc[0] = profile->path[i].h2_loc[1]; + new_pts[i_reversed].h1_loc[1] = profile->path[i].h2_loc[0]; + } + if (ELEM(profile->path[i].h2, HD_FREE, HD_ALIGN)) { + new_pts[i_reversed].h2_loc[0] = profile->path[i].h1_loc[1]; + new_pts[i_reversed].h2_loc[1] = profile->path[i].h1_loc[0]; + } } /* Free the old points and use the new ones */ @@ -446,6 +546,13 @@ void BKE_curveprofile_reset(CurveProfile *profile) break; } + profile->flag &= ~PROF_DIRTY_PRESET; + + /* Ensure each point has a reference to the profile. */ + for (int i = 0; i < profile->path_len; i++) { + profile->path[i].profile = profile; + } + if (profile->table) { MEM_freeN(profile->table); profile->table = NULL; @@ -463,7 +570,7 @@ static bool is_curved_edge(BezTriple *bezt, int i) /** * Used to set bezier handle locations in the sample creation process. Reduced copy of - * #calchandleNurb_intern code in curve.c. + * #calchandleNurb_intern code in curve.c, mostly changed by removing the third dimension. */ static void calchandle_profile(BezTriple *bezt, const BezTriple *prev, const BezTriple *next) { @@ -598,7 +705,7 @@ static int sort_points_curvature(const void *in_a, const void *in_b) * this is true and there are only vector edges the straight edges will still be sampled. * \param r_samples: An array of points to put the sampled positions. Must have length n_segments. * \return r_samples: Fill the array with the sampled locations and if the point corresponds - * to a control point, its handle type + * to a control point, its handle type. */ void BKE_curveprofile_create_samples(CurveProfile *profile, int n_segments, @@ -619,21 +726,33 @@ void BKE_curveprofile_create_samples(CurveProfile *profile, for (i = 0; i < totpoints; i++) { bezt[i].vec[1][0] = profile->path[i].x; bezt[i].vec[1][1] = profile->path[i].y; - bezt[i].h1 = (profile->path[i].h1 == HD_VECT) ? HD_VECT : HD_AUTO; - bezt[i].h2 = (profile->path[i].h2 == HD_VECT) ? HD_VECT : HD_AUTO; - } - /* Give the first and last bezier points the same handle type as their neighbors. */ - if (totpoints > 2) { - bezt[0].h1 = bezt[0].h2 = bezt[1].h1; - bezt[totpoints - 1].h1 = bezt[totpoints - 1].h2 = bezt[totpoints - 2].h2; + bezt[i].h1 = profile->path[i].h1; + bezt[i].h2 = profile->path[i].h2; + /* Copy handle locations if the handle type is free. */ + if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) { + bezt[i].vec[0][0] = profile->path[i].h1_loc[0]; + bezt[i].vec[0][1] = profile->path[i].h1_loc[1]; + } + if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) { + bezt[i].vec[2][0] = profile->path[i].h2_loc[0]; + bezt[i].vec[2][1] = profile->path[i].h2_loc[1]; + } } - /* Get handle positions for the bezier points. */ + /* Get handle positions for the non-free bezier points. */ calchandle_profile(&bezt[0], NULL, &bezt[1]); for (i = 1; i < totpoints - 1; i++) { calchandle_profile(&bezt[i], &bezt[i - 1], &bezt[i + 1]); } calchandle_profile(&bezt[totpoints - 1], &bezt[totpoints - 2], NULL); + /* Copy the handle locations back to the control points. */ + for (i = 0; i < totpoints; i++) { + profile->path[i].h1_loc[0] = bezt[i].vec[0][0]; + profile->path[i].h1_loc[1] = bezt[i].vec[0][1]; + profile->path[i].h2_loc[0] = bezt[i].vec[2][0]; + profile->path[i].h2_loc[1] = bezt[i].vec[2][1]; + } + /* Create a list of edge indices with the most curved at the start, least curved at the end. */ curve_sorted = MEM_callocN(sizeof(CurvatureSortPoint) * totedges, "curve sorted"); for (i = 0; i < totedges; i++) { @@ -718,7 +837,7 @@ void BKE_curveprofile_create_samples(CurveProfile *profile, BLI_assert(j < n_segments); } - /* Do the sampling from bezier points, X values first, then Y values. */ + /* Sample from the bezier points. X then Y values. */ BKE_curve_forward_diff_bezier(bezt[i].vec[1][0], bezt[i].vec[2][0], bezt[i + 1].vec[0][0], @@ -738,7 +857,7 @@ void BKE_curveprofile_create_samples(CurveProfile *profile, BLI_assert(i_sample <= n_segments); } -#ifdef DEBUG_profile_TABLE +#ifdef DEBUG_PROFILE_TABLE printf("CURVEPROFILE CREATE SAMPLES\n"); printf("n_segments: %d\n", n_segments); printf("totedges: %d\n", totedges); @@ -755,6 +874,7 @@ void BKE_curveprofile_create_samples(CurveProfile *profile, } printf("\n"); #endif + MEM_freeN(bezt); MEM_freeN(curve_sorted); MEM_freeN(n_samples); @@ -825,8 +945,10 @@ void BKE_curveprofile_set_defaults(CurveProfile *profile) profile->path[0].x = 1.0f; profile->path[0].y = 0.0f; + profile->path[0].profile = profile; profile->path[1].x = 1.0f; profile->path[1].y = 1.0f; + profile->path[1].profile = profile; profile->changed_timestamp = 0; } @@ -850,13 +972,14 @@ struct CurveProfile *BKE_curveprofile_add(int preset) /** * Should be called after the widget is changed. Does profile and remove double checks and more * importantly, recreates the display / evaluation and segments tables. + * \param update_flags: Bitfield with fields defined in header file. Controls removing doubles and + * clipping. */ -void BKE_curveprofile_update(CurveProfile *profile, const bool remove_double) +void BKE_curveprofile_update(CurveProfile *profile, const int update_flags) { CurveProfilePoint *points = profile->path; rctf *clipr = &profile->clip_rect; float thresh; - float dx, dy; int i; profile->changed_timestamp++; @@ -864,11 +987,16 @@ void BKE_curveprofile_update(CurveProfile *profile, const bool remove_double) /* Clamp with the clipping rect in case something got past. */ if (profile->flag & PROF_USE_CLIP) { /* Move points inside the clip rectangle. */ - for (i = 0; i < profile->path_len; i++) { - points[i].x = max_ff(points[i].x, clipr->xmin); - points[i].x = min_ff(points[i].x, clipr->xmax); - points[i].y = max_ff(points[i].y, clipr->ymin); - points[i].y = min_ff(points[i].y, clipr->ymax); + if (update_flags & PROF_UPDATE_CLIP) { + for (i = 0; i < profile->path_len; i++) { + points[i].x = max_ff(points[i].x, clipr->xmin); + points[i].x = min_ff(points[i].x, clipr->xmax); + points[i].y = max_ff(points[i].y, clipr->ymin); + points[i].y = min_ff(points[i].y, clipr->ymax); + + /* Extra sanity assert to make sure the points have the right profile pointer. */ + BLI_assert(points[i].profile == profile); + } } /* Ensure zoom-level respects clipping. */ if (BLI_rctf_size_x(&profile->view_rect) > BLI_rctf_size_x(&profile->clip_rect)) { @@ -882,30 +1010,19 @@ void BKE_curveprofile_update(CurveProfile *profile, const bool remove_double) } /* Remove doubles with a threshold set at 1% of default range. */ - thresh = 0.01f * BLI_rctf_size_x(clipr); - if (remove_double && profile->path_len > 2) { + thresh = pow2f(0.01f * BLI_rctf_size_x(clipr)); + if (update_flags & PROF_UPDATE_REMOVE_DOUBLES && profile->path_len > 2) { for (i = 0; i < profile->path_len - 1; i++) { - dx = points[i].x - points[i + 1].x; - dy = points[i].y - points[i + 1].y; - if (sqrtf(dx * dx + dy * dy) < thresh) { + if (len_squared_v2v2(&points[i].x, &points[i + 1].x) < thresh) { if (i == 0) { - points[i + 1].flag |= HD_VECT; - if (points[i + 1].flag & PROF_SELECT) { - points[i].flag |= PROF_SELECT; - } + BKE_curveprofile_remove_point(profile, &points[1]); } else { - points[i].flag |= HD_VECT; - if (points[i].flag & PROF_SELECT) { - points[i + 1].flag |= PROF_SELECT; - } + BKE_curveprofile_remove_point(profile, &points[i]); } - break; /* Assumes 1 deletion per edit is ok. */ + break; /* Assumes 1 deletion per update call is ok. */ } } - if (i != profile->path_len - 1) { - BKE_curveprofile_remove_by_flag(profile, 2); - } } /* Create the high resolution table for drawing and some evaluation functions. */ @@ -925,10 +1042,13 @@ void BKE_curveprofile_update(CurveProfile *profile, const bool remove_double) */ void BKE_curveprofile_initialize(CurveProfile *profile, short segments_len) { + if (segments_len != profile->segments_len) { + profile->flag |= PROF_DIRTY_PRESET; + } profile->segments_len = segments_len; /* Calculate the higher resolution / segments tables for display and evaluation. */ - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); } /** @@ -1070,3 +1190,22 @@ void BKE_curveprofile_evaluate_length_portion(const CurveProfile *profile, *x_out = interpf(profile->table[i].x, profile->table[i + 1].x, lerp_factor); *y_out = interpf(profile->table[i].y, profile->table[i + 1].y, lerp_factor); } + +void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct CurveProfile *profile) +{ + BLO_write_struct(writer, CurveProfile, profile); + BLO_write_struct_array(writer, CurveProfilePoint, profile->path_len, profile->path); +} + +/* Expects that the curve profile itself has been read already. */ +void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile) +{ + BLO_read_data_address(reader, &profile->path); + profile->table = NULL; + profile->segments = NULL; + + /* Reset the points' pointers to the profile. */ + for (int i = 0; i < profile->path_len; i++) { + profile->path[i].profile = profile; + } +} diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 7dd4d1178ef..2be61239ac6 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -858,7 +858,6 @@ static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax) if (m->a < min->a) { min->a = m->a; } - if (m->r > max->r) { max->r = m->r; } @@ -1355,7 +1354,7 @@ static void layerCopyValue_propcol(const void *source, /* 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; + const float f = (m2->color[0] + m2->color[1] + m2->color[2]) / 3.0f; if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) { return; /* Do Nothing! */ } @@ -1363,29 +1362,29 @@ static void layerCopyValue_propcol(const void *source, return; /* Do Nothing! */ } } - copy_v3_v3(m2->col, m1->col); + copy_v3_v3(m2->color, m1->color); } else { /* Modes that support 'real' mix factor. */ if (mixmode == CDT_MIX_MIX) { - blend_color_mix_float(tmp_col, m2->col, m1->col); + blend_color_mix_float(tmp_col, m2->color, m1->color); } else if (mixmode == CDT_MIX_ADD) { - blend_color_add_float(tmp_col, m2->col, m1->col); + blend_color_add_float(tmp_col, m2->color, m1->color); } else if (mixmode == CDT_MIX_SUB) { - blend_color_sub_float(tmp_col, m2->col, m1->col); + blend_color_sub_float(tmp_col, m2->color, m1->color); } else if (mixmode == CDT_MIX_MUL) { - blend_color_mul_float(tmp_col, m2->col, m1->col); + blend_color_mul_float(tmp_col, m2->color, m1->color); } else { - memcpy(tmp_col, m1->col, sizeof(tmp_col)); + memcpy(tmp_col, m1->color, sizeof(tmp_col)); } - blend_color_interpolate_float(m2->col, m2->col, tmp_col, mixfactor); + blend_color_interpolate_float(m2->color, m2->color, tmp_col, mixfactor); - copy_v3_v3(m2->col, m1->col); + copy_v3_v3(m2->color, m1->color); } - m2->col[3] = m1->col[3]; + m2->color[3] = m1->color[3]; } static bool layerEqual_propcol(const void *data1, const void *data2) @@ -1394,7 +1393,7 @@ static bool layerEqual_propcol(const void *data1, const void *data2) float tot = 0; for (int i = 0; i < 4; i++) { - float c = (m1->col[i] - m2->col[i]); + float c = (m1->color[i] - m2->color[i]); tot += c * c; } @@ -1404,29 +1403,29 @@ static bool layerEqual_propcol(const void *data1, const void *data2) static void layerMultiply_propcol(void *data, float fac) { MPropCol *m = data; - mul_v4_fl(m->col, fac); + mul_v4_fl(m->color, fac); } static void layerAdd_propcol(void *data1, const void *data2) { MPropCol *m = data1; const MPropCol *m2 = data2; - add_v4_v4(m->col, m2->col); + add_v4_v4(m->color, m2->color); } 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); + minmax_v4v4_v4(min->color, max->color, m->color); } 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); + copy_v4_fl(min->color, FLT_MAX); + copy_v4_fl(max->color, FLT_MIN); } static void layerDefault_propcol(void *data, int count) @@ -1436,7 +1435,7 @@ static void layerDefault_propcol(void *data, int count) MPropCol *pcol = (MPropCol *)data; int i; for (i = 0; i < count; i++) { - copy_v4_v4(pcol[i].col, default_propcol.col); + copy_v4_v4(pcol[i].color, default_propcol.color); } } @@ -1450,14 +1449,14 @@ static void layerInterp_propcol( float weight = weights ? weights[i] : 1.0f; const MPropCol *src = sources[i]; if (sub_weights) { - madd_v4_v4fl(col, src->col, (*sub_weight) * weight); + madd_v4_v4fl(col, src->color, (*sub_weight) * weight); sub_weight++; } else { - madd_v4_v4fl(col, src->col, weight); + madd_v4_v4fl(col, src->color, weight); } } - copy_v4_v4(mc->col, col); + copy_v4_v4(mc->color, col); } static int layerMaxNum_propcol(void) @@ -1784,7 +1783,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(MPropCol), "MPropCol", 1, - N_("Col"), + N_("Color"), NULL, NULL, layerInterp_propcol, @@ -1871,7 +1870,7 @@ const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = { }; const CustomData_MeshMasks CD_MASK_MESH = { .vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK | - CD_MASK_GENERIC_DATA), + CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR), .emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA), .fmask = 0, .lmask = (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | @@ -1881,7 +1880,7 @@ const CustomData_MeshMasks CD_MASK_MESH = { }; const CustomData_MeshMasks CD_MASK_EDITMESH = { .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY | - CD_MASK_SHAPE_KEYINDEX | CD_MASK_GENERIC_DATA), + CD_MASK_SHAPE_KEYINDEX | CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR), .emask = (CD_MASK_GENERIC_DATA), .fmask = 0, .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | @@ -1890,7 +1889,7 @@ const CustomData_MeshMasks CD_MASK_EDITMESH = { }; const CustomData_MeshMasks CD_MASK_DERIVEDMESH = { .vmask = (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN | - CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_GENERIC_DATA), + CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR), .emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA), .fmask = (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT), .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | @@ -1901,7 +1900,8 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = { }; const CustomData_MeshMasks CD_MASK_BMESH = { .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY | - CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_GENERIC_DATA), + CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_GENERIC_DATA | + CD_MASK_PROP_COLOR), .emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA), .fmask = 0, .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | @@ -1925,7 +1925,7 @@ const CustomData_MeshMasks CD_MASK_EVERYTHING = { .vmask = (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | - CD_MASK_GENERIC_DATA), + CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR), .emask = (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA), .fmask = (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL | diff --git a/source/blender/blenkernel/intern/derived_node_tree.cc b/source/blender/blenkernel/intern/derived_node_tree.cc index 961fef958b7..b53457812ba 100644 --- a/source/blender/blenkernel/intern/derived_node_tree.cc +++ b/source/blender/blenkernel/intern/derived_node_tree.cc @@ -20,12 +20,13 @@ #define UNINITIALIZED_ID UINT32_MAX -namespace BKE { +namespace blender { +namespace bke { static const NodeTreeRef &get_tree_ref(NodeTreeRefMap &node_tree_refs, bNodeTree *btree) { - return *node_tree_refs.lookup_or_add_cb( - btree, [&]() { return blender::make_unique<NodeTreeRef>(btree); }); + return *node_tree_refs.lookup_or_add_cb(btree, + [&]() { return std::make_unique<NodeTreeRef>(btree); }); } DerivedNodeTree::DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs) : m_btree(btree) @@ -173,7 +174,7 @@ BLI_NOINLINE void DerivedNodeTree::relink_group_inputs(const NodeTreeRef &group_ Span<DNode *> nodes_by_id, DNode &group_node) { - Span<const NodeRef *> node_refs = group_ref.nodes_with_idname("NodeGroupInput"); + Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupInput"); if (node_refs.size() == 0) { return; } @@ -220,7 +221,7 @@ BLI_NOINLINE void DerivedNodeTree::relink_group_outputs(const NodeTreeRef &group Span<DNode *> nodes_by_id, DNode &group_node) { - Span<const NodeRef *> node_refs = group_ref.nodes_with_idname("NodeGroupOutput"); + Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupOutput"); if (node_refs.size() == 0) { return; } @@ -320,7 +321,8 @@ BLI_NOINLINE void DerivedNodeTree::store_in_this_and_init_ids( DNode *node = m_nodes_by_id[node_index]; node->m_id = node_index; - m_nodes_by_idname.lookup_or_add_default(node->idname()).append(node); + const bNodeType *nodetype = node->m_node_ref->bnode()->typeinfo; + m_nodes_by_type.lookup_or_add_default(nodetype).append(node); for (DInputSocket *socket : node->m_inputs) { socket->m_id = m_sockets_by_id.append_and_get_index(socket); @@ -356,19 +358,17 @@ DerivedNodeTree::~DerivedNodeTree() } } -namespace Dot = blender::DotExport; - -static Dot::Cluster *get_cluster_for_parent(Dot::DirectedGraph &graph, - Map<const DParentNode *, Dot::Cluster *> &clusters, +static dot::Cluster *get_cluster_for_parent(dot::DirectedGraph &graph, + Map<const DParentNode *, dot::Cluster *> &clusters, const DParentNode *parent) { if (parent == nullptr) { return nullptr; } return clusters.lookup_or_add_cb(parent, [&]() { - Dot::Cluster *parent_cluster = get_cluster_for_parent(graph, clusters, parent->parent()); + dot::Cluster *parent_cluster = get_cluster_for_parent(graph, clusters, parent->parent()); bNodeTree *btree = (bNodeTree *)parent->node_ref().bnode()->id; - Dot::Cluster *new_cluster = &graph.new_cluster(parent->node_ref().name() + " / " + + dot::Cluster *new_cluster = &graph.new_cluster(parent->node_ref().name() + " / " + StringRef(btree->id.name + 2)); new_cluster->set_parent_cluster(parent_cluster); return new_cluster; @@ -377,15 +377,15 @@ static Dot::Cluster *get_cluster_for_parent(Dot::DirectedGraph &graph, std::string DerivedNodeTree::to_dot() const { - Dot::DirectedGraph digraph; - digraph.set_rankdir(Dot::Attr_rankdir::LeftToRight); + dot::DirectedGraph digraph; + digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); - Map<const DNode *, Dot::NodeWithSocketsRef> dot_nodes; - Map<const DGroupInput *, Dot::NodeWithSocketsRef> dot_group_inputs; - Map<const DParentNode *, Dot::Cluster *> dot_clusters; + Map<const DNode *, dot::NodeWithSocketsRef> dot_nodes; + Map<const DGroupInput *, dot::NodeWithSocketsRef> dot_group_inputs; + Map<const DParentNode *, dot::Cluster *> dot_clusters; for (const DNode *node : m_nodes_by_id) { - Dot::Node &dot_node = digraph.new_node(""); + dot::Node &dot_node = digraph.new_node(""); dot_node.set_background_color("white"); Vector<std::string> input_names; @@ -398,37 +398,37 @@ std::string DerivedNodeTree::to_dot() const } dot_nodes.add_new(node, - Dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names)); + dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names)); - Dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, node->parent()); + dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, node->parent()); dot_node.set_parent_cluster(cluster); } for (const DGroupInput *group_input : m_group_inputs) { - Dot::Node &dot_node = digraph.new_node(""); + dot::Node &dot_node = digraph.new_node(""); dot_node.set_background_color("white"); std::string group_input_name = group_input->name(); dot_group_inputs.add_new( - group_input, Dot::NodeWithSocketsRef(dot_node, "Group Input", {}, {group_input_name})); + group_input, dot::NodeWithSocketsRef(dot_node, "Group Input", {}, {group_input_name})); - Dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, group_input->parent()); + dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, group_input->parent()); dot_node.set_parent_cluster(cluster); } for (const DNode *to_node : m_nodes_by_id) { - Dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(to_node); + dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(to_node); for (const DInputSocket *to_socket : to_node->inputs()) { for (const DOutputSocket *from_socket : to_socket->linked_sockets()) { const DNode *from_node = &from_socket->node(); - Dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(from_node); + dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(from_node); digraph.new_edge(from_dot_node.output(from_socket->index()), to_dot_node.input(to_socket->index())); } for (const DGroupInput *group_input : to_socket->linked_group_inputs()) { - Dot::NodeWithSocketsRef &from_dot_node = dot_group_inputs.lookup(group_input); + dot::NodeWithSocketsRef &from_dot_node = dot_group_inputs.lookup(group_input); digraph.new_edge(from_dot_node.output(0), to_dot_node.input(to_socket->index())); } @@ -439,4 +439,5 @@ std::string DerivedNodeTree::to_dot() const return digraph.to_dot_string(); } -} // namespace BKE +} // namespace bke +} // namespace blender diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index dae8a59fe43..2e1fa519284 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -5112,7 +5112,7 @@ static void dynamic_paint_prepare_effect_cb(void *__restrict userdata, EffectedPoint epoint; pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint); epoint.vel_to_sec = 1.0f; - BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL); + BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL, NULL); } /* if global gravity is enabled, add it too */ diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 3d5f9cad1c1..1a5b7685c0e 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -237,12 +237,13 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me) { BMesh *bm = em->bm; - /* We need to create clnors data if none exist yet, otherwise there is no way to edit them. - * Similar code to MESH_OT_customdata_custom_splitnormals_add operator, - * we want to keep same shading in case we were using autosmooth so far. + /* We need to create custom-loop-normals (CLNORS) data if none exist yet, + * otherwise there is no way to edit them. + * Similar code to #MESH_OT_customdata_custom_splitnormals_add operator, + * we want to keep same shading in case we were using auto-smooth so far. * Note: there is a problem here, which is that if someone starts a normal editing operation on - * previously autosmooth-ed mesh, and cancel that operation, generated clnors data remain, - * with related sharp edges (and hence autosmooth is 'lost'). + * previously auto-smooth-ed mesh, and cancel that operation, generated CLNORS data remain, + * with related sharp edges (and hence auto-smooth is 'lost'). * Not sure how critical this is, and how to fix that issue? */ if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) { if (me->flag & ME_AUTOSMOOTH) { diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index fe2c9ed51b8..235c834fde9 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -108,7 +108,8 @@ PartDeflect *BKE_partdeflect_new(int type) break; case PFIELD_WIND: pd->shape = PFIELD_SHAPE_PLANE; - pd->f_flow = 1.0f; /* realistic wind behavior */ + pd->f_flow = 1.0f; /* realistic wind behavior */ + pd->f_wind_factor = 1.0f; /* only act perpendicularly to a surface */ break; case PFIELD_TEXTURE: pd->f_size = 1.0f; @@ -428,7 +429,7 @@ static float eff_calc_visibility(ListBase *colliders, EffectorData *efd, EffectedPoint *point) { - const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT); + const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT; ListBase *colls = colliders; ColliderCache *col; float norm[3], len = 0.0; @@ -1072,7 +1073,8 @@ static void do_physical_effector(EffectorCache *eff, * scene = scene where it runs in, for time and stuff * lb = listbase with objects that take part in effecting * opco = global coord, as input - * force = force accumulator + * force = accumulator for force + * wind_force = accumulator for force only acting perpendicular to a surface * speed = actual current speed which can be altered * cur_time = "external" time in frames, is constant for static particles * loc_time = "local" time in frames, range <0-1> for the lifetime of particle @@ -1085,6 +1087,7 @@ void BKE_effectors_apply(ListBase *effectors, EffectorWeights *weights, EffectedPoint *point, float *force, + float *wind_force, float *impulse) { /* @@ -1120,22 +1123,27 @@ void BKE_effectors_apply(ListBase *effectors, if (efd.falloff > 0.0f) { efd.falloff *= eff_calc_visibility(colliders, eff, &efd, point); } - if (efd.falloff <= 0.0f) { - /* don't do anything */ - } - else if (eff->pd->forcefield == PFIELD_TEXTURE) { - do_texture_effector(eff, &efd, point, force); - } - else { - float temp1[3] = {0, 0, 0}, temp2[3]; - copy_v3_v3(temp1, force); + if (efd.falloff > 0.0f) { + float out_force[3] = {0, 0, 0}; - do_physical_effector(eff, &efd, point, force); + if (eff->pd->forcefield == PFIELD_TEXTURE) { + do_texture_effector(eff, &efd, point, out_force); + } + else { + do_physical_effector(eff, &efd, point, out_force); - /* for softbody backward compatibility */ - if (point->flag & PE_WIND_AS_SPEED && impulse) { - sub_v3_v3v3(temp2, force, temp1); - sub_v3_v3v3(impulse, impulse, temp2); + /* for softbody backward compatibility */ + if (point->flag & PE_WIND_AS_SPEED && impulse) { + sub_v3_v3v3(impulse, impulse, out_force); + } + } + + if (wind_force) { + madd_v3_v3fl(force, out_force, 1.0f - eff->pd->f_wind_factor); + madd_v3_v3fl(wind_force, out_force, eff->pd->f_wind_factor); + } + else { + add_v3_v3(force, out_force); } } } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index d4754615c7f..bc14f525c2c 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1063,9 +1063,9 @@ static BezTriple *cycle_offset_triple( /** * Variant of #calchandles_fcurve() that allows calculating based on a different select flag. * - * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`, - * but may want to use a different one at times (if caller does not operate on - * selection). + * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. + * Usually `SELECT`, but may want to use a different one at times + * (if caller does not operate on selection). */ void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag) { diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index 78a6cf28824..a0625918a62 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -484,14 +484,14 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) dtar->flag &= ~DTAR_FLAG_INVALID; } - /* try to get posechannel */ + /* Try to get pose-channel. */ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); - /* check if object or bone, and get transform matrix accordingly - * - "useEulers" code is used to prevent the problems associated with non-uniqueness - * of euler decomposition from matrices [#20870] - * - localspace is for [#21384], where parent results are not wanted - * but local-consts is for all the common "corrective-shapes-for-limbs" situations + /* Check if object or bone, and get transform matrix accordingly: + * - "use_eulers" code is used to prevent the problems associated with non-uniqueness + * of euler decomposition from matrices T20870. + * - "local-space" is for T21384, where parent results are not wanted + * but #DTAR_FLAG_LOCAL_CONSTS is for all the common "corrective-shapes-for-limbs" situations. */ if (pchan) { /* bone */ @@ -517,7 +517,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) } } else { - /* worldspace matrix */ + /* World-space matrix. */ mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); } } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index b75592836e0..98573ea98ec 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -3175,7 +3175,8 @@ static void update_effectors_task_cb(void *__restrict userdata, /* do effectors */ pd_point_from_loc(data->scene, voxel_center, vel, index, &epoint); - BKE_effectors_apply(data->effectors, NULL, mds->effector_weights, &epoint, retvel, NULL); + BKE_effectors_apply( + data->effectors, NULL, mds->effector_weights, &epoint, retvel, NULL, NULL); /* convert retvel to local space */ mag = len_v3(retvel); @@ -3793,8 +3794,8 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, int next_frame = scene_framenr + 1; int prev_frame = scene_framenr - 1; - /* Ensure positivity of previous frame. */ - CLAMP(prev_frame, mds->cache_frame_start, prev_frame); + /* Ensure positive of previous frame. */ + CLAMP_MIN(prev_frame, mds->cache_frame_start); int data_frame = scene_framenr, noise_frame = scene_framenr; int mesh_frame = scene_framenr, particles_frame = scene_framenr, guide_frame = scene_framenr; @@ -3808,6 +3809,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, bubble = mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE; floater = mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM; + bool with_resumable_cache = mds->flags & FLUID_DOMAIN_USE_RESUMABLE_CACHE; bool with_script, with_adaptive, with_noise, with_mesh, with_particles, with_guide; with_script = mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT; with_adaptive = mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN; @@ -3867,13 +3869,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, /* Cache mode specific settings. */ switch (mode) { - case FLUID_DOMAIN_CACHE_FINAL: - /* Just load the data that has already been baked */ - if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) { - read_cache = true; - bake_cache = false; - } - break; + case FLUID_DOMAIN_CACHE_ALL: case FLUID_DOMAIN_CACHE_MODULAR: /* Just load the data that has already been baked */ if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) { @@ -3901,10 +3897,10 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } /* Noise, mesh and particles can never be baked more than data. */ - CLAMP(noise_frame, noise_frame, data_frame); - CLAMP(mesh_frame, mesh_frame, data_frame); - CLAMP(particles_frame, particles_frame, data_frame); - CLAMP(guide_frame, guide_frame, mds->cache_frame_end); + CLAMP_MAX(noise_frame, data_frame); + CLAMP_MAX(mesh_frame, data_frame); + CLAMP_MAX(particles_frame, data_frame); + CLAMP_MAX(guide_frame, mds->cache_frame_end); /* Force to read cache as we're resuming the bake */ read_cache = true; @@ -3928,6 +3924,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, break; } + bool read_partial = false, read_all = false; /* Try to read from cache and keep track of read success. */ if (read_cache) { @@ -3936,20 +3933,16 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, has_config = manta_read_config(mds->fluid, mmd, mesh_frame); /* Update mesh data from file is faster than via Python (manta_read_mesh()). */ - has_mesh = manta_update_mesh_structures(mds->fluid, mmd, mesh_frame); + has_mesh = manta_read_mesh(mds->fluid, mmd, mesh_frame); } /* Read particles cache. */ if (with_liquid && with_particles) { has_config = manta_read_config(mds->fluid, mmd, particles_frame); - if (!baking_data && !baking_particles && next_particles) { - /* Update particle data from file is faster than via Python (manta_read_particles()). */ - has_particles = manta_update_particle_structures(mds->fluid, mmd, particles_frame); - } - else { - has_particles = manta_read_particles(mds->fluid, mmd, particles_frame); - } + read_partial = !baking_data && !baking_particles && next_particles; + read_all = !read_partial && with_resumable_cache; + has_particles = manta_read_particles(mds->fluid, mmd, particles_frame, read_all); } /* Read guide cache. */ @@ -3967,12 +3960,10 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, manta_needs_realloc(mds->fluid, mmd)) { BKE_fluid_reallocate_fluid(mds, mds->res, 1); } - if (!baking_data && !baking_noise && next_noise) { - has_noise = manta_update_noise_structures(mds->fluid, mmd, noise_frame); - } - else { - has_noise = manta_read_noise(mds->fluid, mmd, noise_frame); - } + + read_partial = !baking_data && !baking_noise && next_noise; + read_all = !read_partial && with_resumable_cache; + has_noise = manta_read_noise(mds->fluid, mmd, noise_frame, read_all); /* When using the adaptive domain, copy all data that was read to a new fluid object. */ if (with_adaptive && baking_noise) { @@ -3986,12 +3977,10 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, mds, o_res, mds->res, o_min, mds->res_min, o_max, o_shift, mds->shift); } } - if (!baking_data && !baking_noise && next_data && next_noise) { - /* Nothing to do here since we already loaded noise grids. */ - } - else { - has_data = manta_read_data(mds->fluid, mmd, data_frame); - } + + read_partial = !baking_data && !baking_noise && next_data && next_noise; + read_all = !read_partial && with_resumable_cache; + has_data = manta_read_data(mds->fluid, mmd, data_frame, read_all); } /* Read data cache only */ else { @@ -4002,28 +3991,17 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, if (has_config && manta_needs_realloc(mds->fluid, mmd)) { BKE_fluid_reallocate_fluid(mds, mds->res, 1); } - /* Read data cache */ - if (!baking_data && !baking_particles && !baking_mesh && next_data) { - has_data = manta_update_smoke_structures(mds->fluid, mmd, data_frame); - } - else { - has_data = manta_read_data(mds->fluid, mmd, data_frame); - } - } - if (with_liquid) { - if (!baking_data && !baking_particles && !baking_mesh && next_data) { - has_data = manta_update_liquid_structures(mds->fluid, mmd, data_frame); - } - else { - has_data = manta_read_data(mds->fluid, mmd, data_frame); - } } + + read_partial = !baking_data && !baking_particles && !baking_mesh && next_data; + read_all = !read_partial && with_resumable_cache; + has_data = manta_read_data(mds->fluid, mmd, data_frame, read_all); } } /* Cache mode specific settings */ switch (mode) { - case FLUID_DOMAIN_CACHE_FINAL: + case FLUID_DOMAIN_CACHE_ALL: case FLUID_DOMAIN_CACHE_MODULAR: if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) { bake_cache = false; @@ -4605,13 +4583,9 @@ void BKE_fluid_particles_set(FluidDomainSettings *settings, int value, bool clea void BKE_fluid_domain_type_set(Object *object, FluidDomainSettings *settings, int type) { - /* Set common values for liquid/smoke domain: cache type, - * border collision and viewport draw-type. */ + /* Set values for border collision: + * Liquids should have a closed domain, smoke domains should be open. */ if (type == FLUID_DOMAIN_TYPE_GAS) { - BKE_fluid_cachetype_mesh_set(settings, FLUID_DOMAIN_FILE_BIN_OBJECT); - BKE_fluid_cachetype_data_set(settings, FLUID_DOMAIN_FILE_UNI); - BKE_fluid_cachetype_particle_set(settings, FLUID_DOMAIN_FILE_UNI); - BKE_fluid_cachetype_noise_set(settings, FLUID_DOMAIN_FILE_UNI); BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_FRONT, 1); BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_BACK, 1); BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_RIGHT, 1); @@ -4621,10 +4595,6 @@ void BKE_fluid_domain_type_set(Object *object, FluidDomainSettings *settings, in object->dt = OB_WIRE; } else if (type == FLUID_DOMAIN_TYPE_LIQUID) { - BKE_fluid_cachetype_mesh_set(settings, FLUID_DOMAIN_FILE_BIN_OBJECT); - BKE_fluid_cachetype_data_set(settings, FLUID_DOMAIN_FILE_UNI); - BKE_fluid_cachetype_particle_set(settings, FLUID_DOMAIN_FILE_UNI); - BKE_fluid_cachetype_noise_set(settings, FLUID_DOMAIN_FILE_UNI); BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_FRONT, 0); BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_BACK, 0); BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_RIGHT, 0); @@ -4986,12 +4956,12 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) /* OpenVDB cache options */ #ifdef WITH_OPENVDB_BLOSC - mmd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC; + mmd->domain->openvdb_compression = VDB_COMPRESSION_BLOSC; #else - mmd->domain->openvdb_comp = VDB_COMPRESSION_ZIP; + mmd->domain->openvdb_compression = VDB_COMPRESSION_ZIP; #endif mmd->domain->clipping = 1e-6f; - mmd->domain->data_depth = 0; + mmd->domain->openvdb_data_depth = 0; } else if (mmd->type & MOD_FLUID_TYPE_FLOW) { if (mmd->flow) { @@ -5228,9 +5198,9 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd, } /* OpenVDB cache options */ - tmds->openvdb_comp = mds->openvdb_comp; + tmds->openvdb_compression = mds->openvdb_compression; tmds->clipping = mds->clipping; - tmds->data_depth = mds->data_depth; + tmds->openvdb_data_depth = mds->openvdb_data_depth; } else if (tmmd->flow) { FluidFlowSettings *tmfs = tmmd->flow; diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 5771eb053f7..dfa5ff6975f 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -78,7 +78,7 @@ static void vfont_init_data(ID *id) if (vfd) { vfont->data = vfd; - BLI_strncpy(vfont->name, FO_BUILTIN_NAME, sizeof(vfont->name)); + BLI_strncpy(vfont->filepath, FO_BUILTIN_NAME, sizeof(vfont->filepath)); } /* Free the packed file */ @@ -177,7 +177,7 @@ static int builtin_font_size = 0; bool BKE_vfont_is_builtin(struct VFont *vfont) { - return STREQ(vfont->name, FO_BUILTIN_NAME); + return STREQ(vfont->filepath, FO_BUILTIN_NAME); } void BKE_vfont_builtin_register(void *mem, int size) @@ -237,20 +237,20 @@ static VFontData *vfont_get_data(VFont *vfont) } } else { - pf = BKE_packedfile_new(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id)); + pf = BKE_packedfile_new(NULL, vfont->filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id)); if (vfont->temp_pf == NULL) { vfont->temp_pf = BKE_packedfile_new( - NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id)); + NULL, vfont->filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id)); } } if (!pf) { - CLOG_WARN(&LOG, "Font file doesn't exist: %s", vfont->name); + CLOG_WARN(&LOG, "Font file doesn't exist: %s", vfont->filepath); /* DON'T DO THIS * missing file shouldn't modify path! - campbell */ #if 0 - strcpy(vfont->name, FO_BUILTIN_NAME); + strcpy(vfont->filepath, FO_BUILTIN_NAME); #endif pf = get_builtin_packedfile(); } @@ -301,7 +301,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath) if (vfd->name[0] != '\0') { BLI_strncpy(vfont->id.name + 2, vfd->name, sizeof(vfont->id.name) - 2); } - BLI_strncpy(vfont->name, filepath, sizeof(vfont->name)); + BLI_strncpy(vfont->filepath, filepath, sizeof(vfont->filepath)); /* if autopack is on store the packedfile in de font structure */ if (!is_builtin && (G.fileflags & G_FILE_AUTOPACK)) { @@ -333,7 +333,7 @@ VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool * /* first search an identical filepath */ for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) { - BLI_strncpy(strtest, vfont->name, sizeof(vfont->name)); + BLI_strncpy(strtest, vfont->filepath, sizeof(vfont->filepath)); BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &vfont->id)); if (BLI_path_cmp(strtest, str) == 0) { diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index b460e6d6dc0..dece833c00f 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -289,6 +289,16 @@ void BKE_gpencil_eval_delete(bGPdata *gpd_eval) MEM_freeN(gpd_eval); } +/** + * Tag data-block for depsgraph update. + * Wrapper to avoid include Depsgraph tag functions in other modules. + * \param gpd: Grease pencil data-block. + */ +void BKE_gpencil_tag(bGPdata *gpd) +{ + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); +} + /* ************************************************** */ /* Container Creation */ @@ -417,7 +427,7 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti gpl_active = BKE_gpencil_layer_active_get(gpd); - /* add to datablock */ + /* Add to data-block. */ if (gpl_active == NULL) { BLI_addtail(&gpd->layers, gpl); } @@ -469,7 +479,9 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti return gpl; } -/* add a new gp-datablock */ +/** + * Add a new grease pencil data-block. + */ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) { bGPdata *gpd; @@ -496,7 +508,7 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */ gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */ - /* onion-skinning settings (datablock level) */ + /* Onion-skinning settings (data-block level) */ gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL); gpd->onion_flag |= GP_ONION_FADE; gpd->onion_mode = GP_ONION_MODE_RELATIVE; @@ -516,8 +528,8 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) /** * Populate stroke with point data from data buffers * - * \param array: Flat array of point data values. Each entry has GP_PRIM_DATABUF_SIZE values - * \param mat: 4x4 transform matrix to transform points into the right coordinate space + * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values. + * \param mat: 4x4 transform matrix to transform points into the right coordinate space. */ void BKE_gpencil_stroke_add_points(bGPDstroke *gps, const float *array, @@ -728,7 +740,9 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) return gpl_dst; } -/* Standard API to make a copy of GP datablock, separate from copying its data */ +/** + * Standard API to make a copy of GP data-block, separate from copying its data. + */ bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd) { bGPdata *gpd_copy; @@ -736,8 +750,11 @@ bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd) return gpd_copy; } -/* make a copy of a given gpencil datablock */ -/* XXX: Should this be deprecated? */ +/** + * Make a copy of a given gpencil data-block. + * + * XXX: Should this be deprecated? + */ bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy) { bGPdata *gpd_dst; @@ -1319,7 +1336,7 @@ int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *materi /** * Creates a new gpencil material and assigns it to object. * - * \param *r_index: value is set to zero based index of the new material if r_index is not NULL + * \param *r_index: value is set to zero based index of the new material if \a r_index is not NULL. */ Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index) { @@ -1491,9 +1508,9 @@ void BKE_gpencil_dvert_ensure(bGPDstroke *gps) * Get range of selected frames in layer. * Always the active frame is considered as selected, so if no more selected the range * will be equal to the current active frame. - * \param gpl: Layer - * \param r_initframe: Number of first selected frame - * \param r_endframe: Number of last selected frame + * \param gpl: Layer. + * \param r_initframe: Number of first selected frame. + * \param r_endframe: Number of last selected frame. */ void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe) { @@ -1514,11 +1531,11 @@ void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_e /** * Get Falloff factor base on frame range - * \param gpf: Frame - * \param actnum: Number of active frame in layer - * \param f_init: Number of first selected frame - * \param f_end: Number of last selected frame - * \param cur_falloff: Curve with falloff factors + * \param gpf: Frame. + * \param actnum: Number of active frame in layer. + * \param f_init: Number of first selected frame. + * \param f_end: Number of last selected frame. + * \param cur_falloff: Curve with falloff factors. */ float BKE_gpencil_multiframe_falloff_calc( bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff) @@ -1803,7 +1820,7 @@ bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size, ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); - if (ibuf->rect) { + if (ibuf && ibuf->rect) { int img_x = ibuf->x; int img_y = ibuf->y; @@ -1848,10 +1865,10 @@ bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size, /** * Helper to check if a layers is used as mask - * \param view_layer Actual view layer - * \param gpd Grease pencil datablock - * \param gpl_mask Actual Layer - * \return True if the layer is used as mask + * \param view_layer: Actual view layer. + * \param gpd: Grease pencil data-block. + * \param gpl_mask: Actual Layer. + * \return True if the layer is used as mask. */ static bool gpencil_is_layer_mask(ViewLayer *view_layer, bGPdata *gpd, bGPDlayer *gpl_mask) { @@ -1874,8 +1891,7 @@ static bool gpencil_is_layer_mask(ViewLayer *view_layer, bGPdata *gpd, bGPDlayer /** \name Iterators * * Iterate over all visible stroke of all visible layers inside a gpObject. - * Also take into account onion skining. - * + * Also take into account onion-skinning. * \{ */ void BKE_gpencil_visible_stroke_iter(ViewLayer *view_layer, @@ -2081,7 +2097,7 @@ void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_ev /* Assign pointers to the original stroke and points to the evaluated data. This must * be done before applying any modifier because at this moment the structure is equals, - * so we can assume the layer index is the same in both datablocks. + * so we can assume the layer index is the same in both data-blocks. * This data will be used by operators. */ bGPDlayer *gpl_eval = gpd_eval->layers.first; diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c index 8299943cc49..66e9e2184c1 100644 --- a/source/blender/blenkernel/intern/gpencil_curve.c +++ b/source/blender/blenkernel/intern/gpencil_curve.c @@ -386,7 +386,8 @@ static void gpencil_convert_spline(Main *bmain, BKE_gpencil_stroke_geometry_update(gps); } -/* Convert a curve object to grease pencil stroke. +/** + * Convert a curve object to grease pencil stroke. * * \param bmain: Main thread pointer * \param scene: Original scene. diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c index d200e4e3a15..542f80aa9b5 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.c +++ b/source/blender/blenkernel/intern/gpencil_geom.c @@ -32,15 +32,22 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" #include "BLI_math_vector.h" #include "BLI_polyfill_2d.h" +#include "BLT_translation.h" + #include "DNA_gpencil_types.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" +#include "BKE_main.h" +#include "BKE_material.h" #include "BKE_object.h" #include "DEG_depsgraph_query.h" @@ -1244,7 +1251,8 @@ bool BKE_gpencil_stroke_trim(bGPDstroke *gps) return false; } bool intersect = false; - int start, end; + int start = 0; + int end = 0; float point[3]; /* loop segments from start until we have an intersection */ for (int i = 0; i < gps->totpoints - 2; i++) { @@ -1500,7 +1508,9 @@ void BKE_gpencil_dissolve_points(bGPDframe *gpf, bGPDstroke *gps, const short ta } /* Merge by distance ------------------------------------- */ -/* Reduce a series of points when the distance is below a threshold. + +/** + * Reduce a series of points when the distance is below a threshold. * Special case for first and last points (both are keeped) for other points, * the merge point always is at first point. * \param gpf: Grease Pencil frame @@ -1580,6 +1590,398 @@ void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf, BKE_gpencil_stroke_geometry_update(gps); } +typedef struct GpEdge { + uint v1, v2; + /* Coordinates. */ + float v1_co[3], v2_co[3]; + /* Normals. */ + float n1[3], n2[3]; + /* Direction of the segment. */ + float vec[3]; + int flag; +} GpEdge; + +static int gpencil_next_edge( + GpEdge *gp_edges, int totedges, GpEdge *gped_init, const float threshold, const bool reverse) +{ + int edge = -1; + float last_angle = 999999.0f; + for (int i = 0; i < totedges; i++) { + GpEdge *gped = &gp_edges[i]; + if (gped->flag != 0) { + continue; + } + if (reverse) { + if (gped_init->v1 != gped->v2) { + continue; + } + } + else { + if (gped_init->v2 != gped->v1) { + continue; + } + } + /* Look for straight lines. */ + float angle = angle_v3v3(gped->vec, gped_init->vec); + if ((angle < threshold) && (angle <= last_angle)) { + edge = i; + last_angle = angle; + } + } + + return edge; +} + +static int gpencil_walk_edge(GHash *v_table, + GpEdge *gp_edges, + int totedges, + uint *stroke_array, + int init_idx, + const float angle, + const bool reverse) +{ + GpEdge *gped_init = &gp_edges[init_idx]; + int idx = 1; + int edge = 0; + while (edge > -1) { + edge = gpencil_next_edge(gp_edges, totedges, gped_init, angle, reverse); + if (edge > -1) { + GpEdge *gped = &gp_edges[edge]; + stroke_array[idx] = edge; + gped->flag = 1; + gped_init = &gp_edges[edge]; + idx++; + + /* Avoid to follow already visited vertice. */ + if (reverse) { + if (BLI_ghash_haskey(v_table, POINTER_FROM_INT(gped->v1))) { + edge = -1; + } + else { + BLI_ghash_insert(v_table, POINTER_FROM_INT(gped->v1), POINTER_FROM_INT(gped->v1)); + } + } + else { + if (BLI_ghash_haskey(v_table, POINTER_FROM_INT(gped->v2))) { + edge = -1; + } + else { + BLI_ghash_insert(v_table, POINTER_FROM_INT(gped->v2), POINTER_FROM_INT(gped->v2)); + } + } + } + } + + return idx; +} + +static void gpencil_generate_edgeloops(Object *ob, + bGPDframe *gpf_stroke, + const float angle, + const int thickness, + const float offset, + const float matrix[4][4], + const bool use_seams) +{ + Mesh *me = (Mesh *)ob->data; + if (me->totedge == 0) { + return; + } + + /* Arrays for all edge vertices (forward and backward) that form a edge loop. + * This is reused for each edgeloop to create gpencil stroke. */ + uint *stroke = MEM_callocN(sizeof(uint) * me->totedge * 2, __func__); + uint *stroke_fw = MEM_callocN(sizeof(uint) * me->totedge, __func__); + uint *stroke_bw = MEM_callocN(sizeof(uint) * me->totedge, __func__); + + /* Create array with all edges. */ + GpEdge *gp_edges = MEM_callocN(sizeof(GpEdge) * me->totedge, __func__); + GpEdge *gped = NULL; + for (int i = 0; i < me->totedge; i++) { + MEdge *ed = &me->medge[i]; + gped = &gp_edges[i]; + MVert *mv1 = &me->mvert[ed->v1]; + normal_short_to_float_v3(gped->n1, mv1->no); + + gped->v1 = ed->v1; + copy_v3_v3(gped->v1_co, mv1->co); + + MVert *mv2 = &me->mvert[ed->v2]; + normal_short_to_float_v3(gped->n2, mv2->no); + gped->v2 = ed->v2; + copy_v3_v3(gped->v2_co, mv2->co); + + sub_v3_v3v3(gped->vec, mv1->co, mv2->co); + + /* If use seams, mark as done if not a seam. */ + if ((use_seams) && ((ed->flag & ME_SEAM) == 0)) { + gped->flag = 1; + } + } + + /* Loop edges to find edgeloops */ + bool pending = true; + int e = 0; + while (pending) { + /* Clear arrays of stroke. */ + memset(stroke_fw, 0, sizeof(uint) * me->totedge); + memset(stroke_bw, 0, sizeof(uint) * me->totedge); + memset(stroke, 0, sizeof(uint) * me->totedge * 2); + + gped = &gp_edges[e]; + /* Look first unused edge. */ + if (gped->flag != 0) { + e++; + if (e == me->totedge) { + pending = false; + } + continue; + } + /* Add current edge to arrays. */ + stroke_fw[0] = e; + stroke_bw[0] = e; + gped->flag = 1; + + /* Hash used to avoid loop over same vertice. */ + GHash *v_table = BLI_ghash_int_new(__func__); + /* Look forward edges. */ + int totedges = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_fw, e, angle, false); + /* Look backward edges. */ + int totbw = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_bw, e, angle, true); + + BLI_ghash_free(v_table, NULL, NULL); + + /* Join both arrays. */ + int array_len = 0; + for (int i = totbw - 1; i > 0; i--) { + stroke[array_len] = stroke_bw[i]; + array_len++; + } + for (int i = 0; i < totedges; i++) { + stroke[array_len] = stroke_fw[i]; + array_len++; + } + + /* Create Stroke. */ + bGPDstroke *gps_stroke = BKE_gpencil_stroke_add( + gpf_stroke, 0, array_len + 1, thickness * thickness, false); + + /* Create first segment. */ + float fpt[3]; + uint v = stroke[0]; + gped = &gp_edges[v]; + bGPDspoint *pt = &gps_stroke->points[0]; + mul_v3_v3fl(fpt, gped->n1, offset); + add_v3_v3v3(&pt->x, gped->v1_co, fpt); + mul_m4_v3(matrix, &pt->x); + + pt->pressure = 1.0f; + pt->strength = 1.0f; + + pt = &gps_stroke->points[1]; + mul_v3_v3fl(fpt, gped->n2, offset); + add_v3_v3v3(&pt->x, gped->v2_co, fpt); + mul_m4_v3(matrix, &pt->x); + + pt->pressure = 1.0f; + pt->strength = 1.0f; + + /* Add next segments. */ + for (int i = 1; i < array_len; i++) { + v = stroke[i]; + gped = &gp_edges[v]; + + pt = &gps_stroke->points[i + 1]; + mul_v3_v3fl(fpt, gped->n2, offset); + add_v3_v3v3(&pt->x, gped->v2_co, fpt); + mul_m4_v3(matrix, &pt->x); + + pt->pressure = 1.0f; + pt->strength = 1.0f; + } + + BKE_gpencil_stroke_geometry_update(gps_stroke); + } + + /* Free memory. */ + MEM_SAFE_FREE(stroke); + MEM_SAFE_FREE(stroke_fw); + MEM_SAFE_FREE(stroke_bw); + MEM_SAFE_FREE(gp_edges); +} + +/* Helper: Add gpencil material using material as base. */ +static Material *gpencil_add_material(Main *bmain, + Object *ob_gp, + const char *name, + const float color[4], + const bool use_stroke, + const bool use_fill, + int *r_idx) +{ + Material *mat_gp = BKE_gpencil_object_material_new(bmain, ob_gp, name, r_idx); + MaterialGPencilStyle *gp_style = mat_gp->gp_style; + + /* Stroke color. */ + if (use_stroke) { + ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f); + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + } + else { + linearrgb_to_srgb_v4(gp_style->stroke_rgba, color); + gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; + } + + /* Fill color. */ + linearrgb_to_srgb_v4(gp_style->fill_rgba, color); + if (use_fill) { + gp_style->flag |= GP_MATERIAL_FILL_SHOW; + } + + /* Check at least one is enabled. */ + if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) && + ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) { + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + } + + return mat_gp; +} + +/** + * Convert a mesh object to grease pencil stroke. + * + * \param bmain: Main thread pointer. + * \param depsgraph: Original depsgraph. + * \param scene: Original scene. + * \param ob_gp: Grease pencil object to add strokes. + * \param ob_mesh: Mesh to convert. + * \param angle: Limit angle to consider a edgeloop ends. + * \param thickness: Thickness of the strokes. + * \param offset: Offset along the normals. + * \param matrix: Transformation matrix. + * \param frame_offset: Destination frame number offset. + * \param use_seams: Only export seam edges. + * \param use_faces: Export faces as filled strokes. + */ +void BKE_gpencil_convert_mesh(Main *bmain, + Depsgraph *depsgraph, + Scene *scene, + Object *ob_gp, + Object *ob_mesh, + const float angle, + const int thickness, + const float offset, + const float matrix[4][4], + const int frame_offset, + const bool use_seams, + const bool use_faces) +{ + if (ELEM(NULL, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) { + return; + } + + bGPdata *gpd = (bGPdata *)ob_gp->data; + + /* Use evaluated data to get mesh with all modifiers on top. */ + Object *ob_eval = (Object *)DEG_get_evaluated_object(depsgraph, ob_mesh); + Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); + MPoly *mp, *mpoly = me_eval->mpoly; + MLoop *mloop = me_eval->mloop; + int mpoly_len = me_eval->totpoly; + int i; + + /* If the object has enough materials means it was created in a previous step. */ + const bool create_mat = ((ob_gp->totcol > 0) && (ob_gp->totcol >= ob_mesh->totcol)) ? false : + true; + + /* Need at least an edge. */ + if (me_eval->totvert < 2) { + return; + } + + int r_idx; + const float default_colors[2][4] = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.7f, 0.7f, 0.7f, 1.0f}}; + /* Create stroke material. */ + if (create_mat) { + gpencil_add_material(bmain, ob_gp, "Stroke", default_colors[0], true, false, &r_idx); + } + /* Export faces as filled strokes. */ + if (use_faces) { + if (create_mat) { + /* Find a material slot with material assigned */ + bool material_found = false; + for (i = 0; i < ob_mesh->totcol; i++) { + Material *ma = BKE_object_material_get(ob_mesh, i + 1); + if (ma != NULL) { + material_found = true; + break; + } + } + + /* If no materials, create a simple fill. */ + if (!material_found) { + gpencil_add_material(bmain, ob_gp, "Fill", default_colors[1], false, true, &r_idx); + } + else { + /* Create all materials for fill. */ + for (i = 0; i < ob_mesh->totcol; i++) { + Material *ma = BKE_object_material_get(ob_mesh, i + 1); + if (ma == NULL) { + continue; + } + float color[4]; + copy_v3_v3(color, &ma->r); + color[3] = 1.0f; + gpencil_add_material(bmain, ob_gp, ma->id.name + 2, color, false, true, &r_idx); + } + } + } + + /* Read all polygons and create fill for each. */ + if (mpoly_len > 0) { + bGPDlayer *gpl_fill = BKE_gpencil_layer_named_get(gpd, DATA_("Fills")); + if (gpl_fill == NULL) { + gpl_fill = BKE_gpencil_layer_addnew(gpd, DATA_("Fills"), true); + } + bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( + gpl_fill, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); + for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) { + MLoop *ml = &mloop[mp->loopstart]; + /* Create fill stroke. */ + bGPDstroke *gps_fill = BKE_gpencil_stroke_add( + gpf_fill, mp->mat_nr + 1, mp->totloop, 10, false); + gps_fill->flag |= GP_STROKE_CYCLIC; + + /* Add points to strokes. */ + int j; + for (j = 0; j < mp->totloop; j++, ml++) { + MVert *mv = &me_eval->mvert[ml->v]; + + bGPDspoint *pt = &gps_fill->points[j]; + copy_v3_v3(&pt->x, mv->co); + mul_m4_v3(matrix, &pt->x); + pt->pressure = 1.0f; + pt->strength = 1.0f; + } + + BKE_gpencil_stroke_geometry_update(gps_fill); + } + } + } + + /* Create stroke from edges. */ + bGPDlayer *gpl_stroke = BKE_gpencil_layer_named_get(gpd, DATA_("Lines")); + if (gpl_stroke == NULL) { + gpl_stroke = BKE_gpencil_layer_addnew(gpd, DATA_("Lines"), true); + } + bGPDframe *gpf_stroke = BKE_gpencil_layer_frame_get( + gpl_stroke, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); + gpencil_generate_edgeloops(ob_eval, gpf_stroke, angle, thickness, offset, matrix, use_seams); + + /* Tag for recalculation */ + DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); +} + /* Apply Transforms */ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) { diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 2f8500bd1df..fa0cbb0ab5c 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -53,6 +53,9 @@ #include "MOD_gpencil_modifiertypes.h" +#include "CLG_log.h" + +static CLG_LogRef LOG = {"bke.gpencil_modifier"}; static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = {NULL}; /* *************************************************** */ @@ -275,8 +278,7 @@ void BKE_gpencil_stroke_simplify_fixed(bGPDstroke *gps) /* init lattice deform data */ void BKE_gpencil_lattice_init(Object *ob) { - GpencilModifierData *md; - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { if (md->type == eGpencilModifierType_Lattice) { LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; Object *latob = NULL; @@ -298,8 +300,7 @@ void BKE_gpencil_lattice_init(Object *ob) /* clear lattice deform data */ void BKE_gpencil_lattice_clear(Object *ob) { - GpencilModifierData *md; - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { if (md->type == eGpencilModifierType_Lattice) { LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; if ((mmd) && (mmd->cache_data)) { @@ -316,8 +317,7 @@ void BKE_gpencil_lattice_clear(Object *ob) /* check if exist geometry modifiers */ bool BKE_gpencil_has_geometry_modifiers(Object *ob) { - GpencilModifierData *md; - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if (mti && mti->generateStrokes) { @@ -330,8 +330,7 @@ bool BKE_gpencil_has_geometry_modifiers(Object *ob) /* check if exist time modifiers */ bool BKE_gpencil_has_time_modifiers(Object *ob) { - GpencilModifierData *md; - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if (mti && mti->remapTime) { @@ -344,8 +343,7 @@ bool BKE_gpencil_has_time_modifiers(Object *ob) /* Check if exist transform stroke modifiers (to rotate sculpt or edit). */ bool BKE_gpencil_has_transform_modifiers(Object *ob) { - GpencilModifierData *md; - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { /* Only if enabled in edit mode. */ if (!GPENCIL_MODIFIER_EDIT(md, true) && GPENCIL_MODIFIER_ACTIVE(md, false)) { if ((md->type == eGpencilModifierType_Armature) || (md->type == eGpencilModifierType_Hook) || @@ -362,12 +360,11 @@ bool BKE_gpencil_has_transform_modifiers(Object *ob) static int gpencil_time_modifier( Depsgraph *depsgraph, Scene *scene, Object *ob, bGPDlayer *gpl, int cfra, bool is_render) { - GpencilModifierData *md; bGPdata *gpd = ob->data; const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); int nfra = cfra; - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); @@ -428,9 +425,9 @@ GpencilModifierData *BKE_gpencil_modifier_new(int type) BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name)); md->type = type; - md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render | - eGpencilModifierMode_Expanded; + md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render; md->flag = eGpencilModifierFlag_OverrideLibrary_Local; + md->ui_expand_flag = 1; /* Only expand the parent panel at first. */ if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode) { md->mode |= eGpencilModifierMode_Editmode; @@ -508,7 +505,8 @@ bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md) const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type) { /* type unsigned, no need to check < 0 */ - if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') { + if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && type > 0 && + modifier_gpencil_types[type]->name[0] != '\0') { return modifier_gpencil_types[type]; } else { @@ -516,6 +514,17 @@ const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType } } +/** + * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback. + */ +void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type); + + strcpy(r_idname, GPENCIL_MODIFIER_TYPE_PANEL_PREFIX); + strcat(r_idname, mti->name); +} + void BKE_gpencil_modifier_copydata_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst) { @@ -553,6 +562,7 @@ void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md, target->mode = md->mode; target->flag = md->flag; + target->ui_expand_flag = md->ui_expand_flag; /* Expand the parent panel by default. */ if (mti->copyData) { mti->copyData(md, target); @@ -587,6 +597,26 @@ GpencilModifierData *BKE_gpencil_modifiers_findby_type(Object *ob, GpencilModifi return md; } +void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format, ...) +{ + char buffer[512]; + va_list ap; + const char *format = TIP_(_format); + + va_start(ap, _format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + buffer[sizeof(buffer) - 1] = '\0'; + + if (md->error) { + MEM_freeN(md->error); + } + + md->error = BLI_strdup(buffer); + + CLOG_STR_ERROR(&LOG, md->error); +} + void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc walk, void *userData) { GpencilModifierData *md = ob->greasepencil_modifiers.first; diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 669539ca574..c3c67b9ed51 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -732,14 +732,14 @@ void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop) IDP_FreeProperty(prop); } -IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, const char *name) +IDProperty *IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name) { BLI_assert(prop->type == IDP_GROUP); return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name)); } /** same as above but ensure type match */ -IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, const char type) +IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type) { IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name); return (idprop && idprop->type == type) ? idprop : NULL; diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index b4a3f249c63..bb793b58a1d 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -360,13 +360,7 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock) ima->rr = NULL; } - if (!G.background) { - /* Background mode doesn't use OpenGL, - * so we can avoid freeing GPU images and save some - * time by skipping mutex lock. - */ - GPU_free_image(ima); - } + GPU_free_image(ima); LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { tile->ok = IMA_OK; @@ -648,7 +642,7 @@ char BKE_image_alpha_mode_from_extension_ex(const char *filepath) void BKE_image_alpha_mode_from_extension(Image *image) { - image->alpha_mode = BKE_image_alpha_mode_from_extension_ex(image->name); + image->alpha_mode = BKE_image_alpha_mode_from_extension_ex(image->filepath); } Image *BKE_image_load(Main *bmain, const char *filepath) @@ -668,7 +662,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath) close(file); ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE); - STRNCPY(ima->name, filepath); + STRNCPY(ima->filepath, filepath); if (BLI_path_extension_check_array(filepath, imb_ext_movie)) { ima->source = IMA_SRC_MOVIE; @@ -694,7 +688,7 @@ Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exist /* first search an identical filepath */ for (ima = bmain->images.first; ima; ima = ima->id.next) { if (ima->source != IMA_SRC_VIEWER && ima->source != IMA_SRC_GENERATED) { - STRNCPY(strtest, ima->name); + STRNCPY(strtest, ima->filepath); BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &ima->id)); if (BLI_path_cmp(strtest, str) == 0) { @@ -830,7 +824,7 @@ Image *BKE_image_add_generated(Main *bmain, int view_id; const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - /* STRNCPY(ima->name, name); */ /* don't do this, this writes in ain invalid filepath! */ + /* STRNCPY(ima->filepath, name); */ /* don't do this, this writes in ain invalid filepath! */ ima->gen_x = width; ima->gen_y = height; ima->gen_type = gen_type; @@ -846,7 +840,7 @@ Image *BKE_image_add_generated(Main *bmain, for (view_id = 0; view_id < 2; view_id++) { ImBuf *ibuf; ibuf = add_ibuf_size( - width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings); + width, height, ima->filepath, depth, floatbuf, gen_type, color, &ima->colorspace_settings); int index = tiled ? 0 : IMA_NO_INDEX; int entry = tiled ? 1001 : 0; image_assign_ibuf(ima, ibuf, stereo3d ? view_id : index, entry); @@ -881,7 +875,7 @@ Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name) ima = image_alloc(bmain, name, IMA_SRC_FILE, IMA_TYPE_IMAGE); if (ima) { - STRNCPY(ima->name, ibuf->name); + STRNCPY(ima->filepath, ibuf->name); image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); ImageTile *tile = BKE_image_get_tile(ima, 0); tile->ok = IMA_OK_LOADED; @@ -981,9 +975,9 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) if (totfiles == 1) { ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file"); BLI_addtail(&ima->packedfiles, imapf); - imapf->packedfile = BKE_packedfile_new(reports, ima->name, basepath); + imapf->packedfile = BKE_packedfile_new(reports, ima->filepath, basepath); if (imapf->packedfile) { - STRNCPY(imapf->filepath, ima->name); + STRNCPY(imapf->filepath, ima->filepath); } else { BLI_freelinkN(&ima->packedfiles, imapf); @@ -1020,7 +1014,7 @@ void BKE_image_packfiles_from_mem(ReportList *reports, ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__); BLI_addtail(&ima->packedfiles, imapf); imapf->packedfile = BKE_packedfile_new_from_memory(data, data_len); - STRNCPY(imapf->filepath, ima->name); + STRNCPY(imapf->filepath, ima->filepath); } } @@ -3385,7 +3379,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) * Here we ensure original image path wouldn't be used when saving * generated image. */ - ima->name[0] = '\0'; + ima->filepath[0] = '\0'; } if (ima->source != IMA_SRC_TILED) { @@ -3643,7 +3637,7 @@ bool BKE_image_fill_tile(struct Image *ima, image_free_tile(ima, tile); ImBuf *tile_ibuf = add_ibuf_size( - width, height, ima->name, planes, is_float, gen_type, color, &ima->colorspace_settings); + width, height, ima->filepath, planes, is_float, gen_type, color, &ima->colorspace_settings); if (tile_ibuf != NULL) { image_assign_ibuf(ima, tile_ibuf, 0, tile->tile_number); @@ -3807,7 +3801,7 @@ bool BKE_image_is_openexr(struct Image *ima) { #ifdef WITH_OPENEXR if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) { - return BLI_path_extension_check(ima->name, ".exr"); + return BLI_path_extension_check(ima->filepath, ".exr"); } #else UNUSED_VARS(ima); @@ -4893,7 +4887,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) } ibuf = add_ibuf_size(ima->gen_x, ima->gen_y, - ima->name, + ima->filepath, ima->gen_depth, (ima->gen_flag & IMA_GEN_FLOAT) != 0, ima->gen_type, @@ -5300,11 +5294,11 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) BLI_strncpy(filepath, iv->filepath, FILE_MAX); } else { - BLI_strncpy(filepath, ima->name, FILE_MAX); + BLI_strncpy(filepath, ima->filepath, FILE_MAX); } } else { - BLI_strncpy(filepath, ima->name, FILE_MAX); + BLI_strncpy(filepath, ima->filepath, FILE_MAX); } if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) { @@ -5461,7 +5455,7 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int int BKE_image_sequence_guess_offset(Image *image) { - return BLI_path_sequence_decode(image->name, NULL, NULL, NULL); + return BLI_path_sequence_decode(image->filepath, NULL, NULL, NULL); } bool BKE_image_has_anim(Image *ima) @@ -5478,7 +5472,7 @@ bool BKE_image_has_filepath(Image *ima) { /* This could be improved to detect cases like //../../, currently path * remapping empty file paths empty. */ - return ima->name[0] != '\0'; + return ima->filepath[0] != '\0'; } /* Checks the image buffer changes with time (not keyframed values). */ @@ -5653,14 +5647,14 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; for (i = 0; i < 2; i++) { - image_add_view(ima, names[i], ima->name); + image_add_view(ima, names[i], ima->filepath); } return; } else { /* R_IMF_VIEWS_INDIVIDUAL */ char prefix[FILE_MAX] = {'\0'}; - char *name = ima->name; + char *name = ima->filepath; const char *ext = NULL; BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext); diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c index c034fe895a6..19eb3380b8e 100644 --- a/source/blender/blenkernel/intern/image_save.c +++ b/source/blender/blenkernel/intern/image_save.c @@ -73,7 +73,7 @@ static void image_save_post(ReportList *reports, if (opts->do_newpath) { BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name)); - BLI_strncpy(ima->name, filepath, sizeof(ima->name)); + BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath)); } ibuf->userflags &= ~IB_BITMAPDIRTY; @@ -106,7 +106,7 @@ static void image_save_post(ReportList *reports, /* only image path, never ibuf */ if (opts->relative) { const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id); - BLI_path_rel(ima->name, relbase); /* only after saving */ + BLI_path_rel(ima->filepath, relbase); /* only after saving */ } ColorManagedColorspaceSettings old_colorspace_settings; @@ -135,7 +135,7 @@ static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf) /** * \return success. - * \note ``ima->name`` and ``ibuf->name`` should end up the same. + * \note ``ima->filepath`` and ``ibuf->name`` should end up the same. * \note for multiview the first ``ibuf`` is important to get the settings. */ static bool image_save_single(ReportList *reports, diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index ab9b11f436a..7c09ae51344 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -114,7 +114,7 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = { * Also note that the id _must_ have a library - campbell */ static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id) { - const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath}; + const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs}; BKE_bpath_traverse_id(bmain, id, @@ -160,7 +160,7 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id) BKE_lib_libblock_session_uuid_renew(id); /* We need to tag this IDs and all of its users, conceptually new local ID and original linked - * ones are two completely different data-blocks that were virtually remaped, even though in + * ones are two completely different data-blocks that were virtually remapped, even though in * reality they remain the same data. For undo this info is critical now. */ DEG_id_tag_update_ex(bmain, id, ID_RECALC_COPY_ON_WRITE); ID *id_iter; @@ -225,7 +225,7 @@ void id_us_ensure_real(ID *id) CLOG_ERROR(&LOG, "ID user count error: %s (from '%s')", id->name, - id->lib ? id->lib->filepath : "[Main]"); + id->lib ? id->lib->filepath_abs : "[Main]"); BLI_assert(0); } id->us = limit + 1; @@ -283,7 +283,7 @@ void id_us_min(ID *id) CLOG_ERROR(&LOG, "ID user decrement error: %s (from '%s'): %d <= %d", id->name, - id->lib ? id->lib->filepath : "[Main]", + id->lib ? id->lib->filepath_abs : "[Main]", id->us, limit); if (GS(id->name) != ID_IP) { @@ -446,9 +446,9 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags) /** * Calls the appropriate make_local method for the block, unless test is set. * - * \note Always set ID->newid pointer in case it gets duplicated... + * \note Always set #ID.newid pointer in case it gets duplicated. * - * \param lib_local: Special flag used when making a whole library's content local, + * \param flags: Special flag used when making a whole library's content local, * it needs specific handling. * * \return true if the block can be made local. @@ -608,6 +608,49 @@ bool BKE_id_copy(Main *bmain, const ID *id, ID **newid) } /** + * Invokes the appropriate copy method for the block and returns the result in + * newid, unless test. Returns true if the block can be copied. + */ +ID *BKE_id_copy_for_duplicate(Main *bmain, + ID *id, + const bool is_owner_id_liboverride, + const eDupli_ID_Flags duplicate_flags) +{ + if (id == NULL) { + return NULL; + } + if (id->newid == NULL) { + if (!is_owner_id_liboverride || !ID_IS_LINKED(id)) { + ID *id_new; + BKE_id_copy(bmain, id, &id_new); + /* Copying add one user by default, need to get rid of that one. */ + id_us_min(id_new); + ID_NEW_SET(id, id_new); + + /* Shape keys are always copied with their owner ID, by default. */ + ID *key_new = (ID *)BKE_key_from_id(id_new); + ID *key = (ID *)BKE_key_from_id(id); + if (key != NULL) { + ID_NEW_SET(key, key_new); + } + + /* Note: embedded data (root nodetrees and master collections) should never be referenced by + * anything else, so we do not need to set their newid pointer and flag. */ + + if (duplicate_flags & USER_DUP_ACT) { + BKE_animdata_copy_id_action(bmain, id_new, true); + if (key_new != NULL) { + BKE_animdata_copy_id_action(bmain, key_new, true); + } + /* Note that actions of embedded data (root nodetrees and master collections) are handled + * by `BKE_animdata_copy_id_action` as well. */ + } + } + } + return id->newid; +} + +/** * Does a mere memory swap over the whole IDs data (including type-specific memory). * \note Most internal ID data itself is not swapped (only IDProperties are). */ @@ -636,6 +679,9 @@ static void id_swap(Main *bmain, ID *id_a, ID *id_b, const bool do_full_id) /* Exception: IDProperties. */ id_a->properties = id_b_back.properties; id_b->properties = id_a_back.properties; + /* Exception: recalc flags. */ + id_a->recalc = id_b_back.recalc; + id_b->recalc = id_a_back.recalc; } if (bmain != NULL) { @@ -1183,7 +1229,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori /* We may need our own flag to control that at some point, but for now 'no main' one should be * good enough. */ - if ((orig_flag & LIB_ID_CREATE_NO_MAIN) == 0 && id->override_library != NULL) { + if ((orig_flag & LIB_ID_CREATE_NO_MAIN) == 0 && ID_IS_OVERRIDE_LIBRARY(id)) { /* We do not want to copy existing override rules here, as they would break the proper * remapping between IDs. Proper overrides rules will be re-generated anyway. */ BKE_lib_override_library_copy(new_id, id, false); @@ -2129,13 +2175,18 @@ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separa */ void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const ID *id, + const bool add_lib_hint, char separator_char) { - name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_OVERRIDE_LIBRARY(id) ? 'O' : ' '; - name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' '); - name[2] = ' '; + int i = 0; + + if (add_lib_hint) { + name[i++] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_OVERRIDE_LIBRARY(id) ? 'O' : ' '; + } + name[i++] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' '); + name[i++] = ' '; - BKE_id_full_name_get(name + 3, id, separator_char); + BKE_id_full_name_get(name + i, id, separator_char); } /** diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index 6fce898fd1e..9d7671322ea 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -24,6 +24,7 @@ /* all types are needed here, in order to do memory operations */ #include "DNA_ID.h" +#include "DNA_key_types.h" #include "BLI_utildefines.h" @@ -32,6 +33,7 @@ #include "BKE_anim_data.h" #include "BKE_idprop.h" #include "BKE_idtype.h" +#include "BKE_key.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_lib_remap.h" @@ -148,6 +150,13 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i BKE_libblock_relink_ex(bmain, id, NULL, NULL, 0); } + if ((flag & LIB_ID_FREE_NO_MAIN) == 0) { + Key *key = BKE_key_from_id(id); + if (key != NULL) { + BKE_id_free_ex(bmain, &key->id, flag, use_flag_from_idtag); + } + } + BKE_libblock_free_datablock(id, flag); /* avoid notifying on removed data */ diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index d6f037f64a4..457d096f983 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -27,11 +27,15 @@ #include "MEM_guardedalloc.h" #include "DNA_ID.h" +#include "DNA_key_types.h" #include "DNA_object_types.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "BKE_armature.h" +#include "BKE_idtype.h" +#include "BKE_key.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_lib_remap.h" @@ -40,6 +44,7 @@ #include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BLI_utildefines.h" #include "RNA_access.h" @@ -113,7 +118,7 @@ IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id) /** Shalow or deep copy of a whole override from \a src_id to \a dst_id. */ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_full_copy) { - BLI_assert(src_id->override_library != NULL); + BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id)); if (dst_id->override_library != NULL) { if (src_id->override_library == NULL) { @@ -125,6 +130,7 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f } } else if (src_id->override_library == NULL) { + /* Virtual overrides of embedded data does not require any extra work. */ return; } else { @@ -198,6 +204,16 @@ static ID *lib_override_library_create_from(Main *bmain, ID *reference_id) BKE_lib_override_library_init(local_id, reference_id); + /* Note: From liboverride perspective (and RNA one), shape keys are considered as local embedded + * data-blocks, just like root node trees or master collections. Therefore, we never need to + * create overrides for them. We need a way to mark them as overrides though. */ + Key *reference_key; + if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + Key *local_key = BKE_key_from_id(local_id); + BLI_assert(local_key != NULL); + local_key->id.flag |= LIB_EMBEDDED_DATA_LIB_OVERRIDE; + } + return local_id; } @@ -212,6 +228,12 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, ID *local_id = lib_override_library_create_from(bmain, reference_id); if (do_tagged_remap) { + Key *reference_key, *local_key = NULL; + if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + local_key = BKE_key_from_id(local_id); + BLI_assert(local_key != NULL); + } + ID *other_id; FOREACH_MAIN_ID_BEGIN (bmain, other_id) { if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) { @@ -222,6 +244,13 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + if (reference_key != NULL) { + BKE_libblock_relink_ex(bmain, + other_id, + &reference_key->id, + &local_key->id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + } } } FOREACH_MAIN_ID_END; @@ -246,14 +275,15 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, bool BKE_lib_override_library_create_from_tag(Main *bmain) { ID *reference_id; - bool ret = true; + bool success = true; ListBase todo_ids = {NULL}; LinkData *todo_id_iter; /* Get all IDs we want to override. */ FOREACH_MAIN_ID_BEGIN (bmain, reference_id) { - if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) { + if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && + BKE_idtype_idcode_is_linkable(GS(reference_id->name))) { todo_id_iter = MEM_callocN(sizeof(*todo_id_iter), __func__); todo_id_iter->data = reference_id; BLI_addtail(&todo_ids, todo_id_iter); @@ -265,44 +295,77 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain) for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { reference_id = todo_id_iter->data; if ((reference_id->newid = lib_override_library_create_from(bmain, reference_id)) == NULL) { - ret = false; + success = false; + break; } - else { + /* We also tag the new IDs so that in next step we can remap their pointers too. */ + reference_id->newid->tag |= LIB_TAG_DOIT; + + Key *reference_key; + if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + reference_key->id.tag |= LIB_TAG_DOIT; + + Key *local_key = BKE_key_from_id(reference_id->newid); + BLI_assert(local_key != NULL); + reference_key->id.newid = &local_key->id; /* We also tag the new IDs so that in next step we can remap their pointers too. */ - reference_id->newid->tag |= LIB_TAG_DOIT; + local_key->id.tag |= LIB_TAG_DOIT; } } /* Only remap new local ID's pointers, we don't want to force our new overrides onto our whole * existing linked IDs usages. */ - for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { - ID *other_id; - reference_id = todo_id_iter->data; + if (success) { + for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { + ID *other_id; + reference_id = todo_id_iter->data; + ID *local_id = reference_id->newid; + + if (local_id == NULL) { + continue; + } - if (reference_id->newid == NULL) { - continue; - } + Key *reference_key, *local_key = NULL; + if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + local_key = BKE_key_from_id(reference_id->newid); + BLI_assert(local_key != NULL); + } - /* Still checking the whole Main, that way we can tag other local IDs as needing to be remapped - * to use newly created overriding IDs, if needed. */ - FOREACH_MAIN_ID_BEGIN (bmain, other_id) { - if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) { - ID *local_id = reference_id->newid; - /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap - * local IDs usages anyway... */ - BKE_libblock_relink_ex(bmain, - other_id, - reference_id, - local_id, - ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + /* Still checking the whole Main, that way we can tag other local IDs as needing to be + * remapped to use newly created overriding IDs, if needed. */ + FOREACH_MAIN_ID_BEGIN (bmain, other_id) { + if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) { + /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap + * local IDs usages anyway... */ + BKE_libblock_relink_ex(bmain, + other_id, + reference_id, + local_id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + if (reference_key != NULL) { + BKE_libblock_relink_ex(bmain, + other_id, + &reference_key->id, + &local_key->id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + } + } } + FOREACH_MAIN_ID_END; + } + } + else { + /* We need to cleanup potentially already created data. */ + for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { + reference_id = todo_id_iter->data; + BKE_id_delete(bmain, reference_id->newid); + reference_id->newid = NULL; } - FOREACH_MAIN_ID_END; } BLI_freelistN(&todo_ids); - return ret; + return success; } /* We only build override GHash on request. */ @@ -310,7 +373,8 @@ BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_mapping_ensure( IDOverrideLibrary *override) { if (override->runtime == NULL) { - override->runtime = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); + override->runtime = BLI_ghash_new( + BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__); for (IDOverrideLibraryProperty *op = override->properties.first; op != NULL; op = op->next) { BLI_ghash_insert(override->runtime, op->rna_path, op); } @@ -469,7 +533,8 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_ return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL; } - /* index == -1 means all indices, that is valid fallback in case we requested specific index. */ + /* index == -1 means all indices, that is valid fallback in case we requested specific index. + */ if (!strict && (subitem_locindex != subitem_defindex) && (opop = BLI_listbase_bytes_find( &override_property->operations, @@ -617,7 +682,7 @@ bool BKE_lib_override_library_property_operation_operands_validate( * \return true if status is OK, false otherwise. */ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local) { - BLI_assert(local->override_library != NULL); + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local)); ID *reference = local->override_library->reference; @@ -649,6 +714,7 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local) &rnaptr_local, &rnaptr_reference, NULL, + 0, local->override_library, RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, @@ -672,7 +738,7 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local) * \return true if status is OK, false otherwise. */ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) { - BLI_assert(local->override_library != NULL); + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local)); ID *reference = local->override_library->reference; @@ -712,6 +778,7 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) &rnaptr_local, &rnaptr_reference, NULL, + 0, local->override_library, RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL)) { @@ -735,9 +802,7 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) * Generating diff values and applying overrides are much cheaper. * * \return true if new overriding op was created, or some local data was reset. */ -bool BKE_lib_override_library_operations_create(Main *bmain, - ID *local, - const bool UNUSED(force_auto)) +bool BKE_lib_override_library_operations_create(Main *bmain, ID *local) { BLI_assert(local->override_library != NULL); const bool is_template = (local->override_library->reference == NULL); @@ -752,9 +817,9 @@ bool BKE_lib_override_library_operations_create(Main *bmain, } if (GS(local->name) == ID_OB) { - /* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would ensure - * this is valid, but in some situations (like hidden collections etc.) this won't be the - * case, so we need to take care of this ourselves. */ + /* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would + * ensure this is valid, but in some situations (like hidden collections etc.) this won't + * be the case, so we need to take care of this ourselves. */ Object *ob_local = (Object *)local; if (ob_local->data != NULL && ob_local->type == OB_ARMATURE && ob_local->pose != NULL && ob_local->pose->flag & POSE_RECALC) { @@ -771,6 +836,7 @@ bool BKE_lib_override_library_operations_create(Main *bmain, &rnaptr_local, &rnaptr_reference, NULL, + 0, local->override_library, RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, &report_flags); @@ -792,29 +858,51 @@ bool BKE_lib_override_library_operations_create(Main *bmain, return ret; } +static void lib_override_library_operations_create_cb(TaskPool *__restrict pool, void *taskdata) +{ + Main *bmain = BLI_task_pool_user_data(pool); + ID *id = taskdata; + + BKE_lib_override_library_operations_create(bmain, id); +} + /** Check all overrides from given \a bmain and create/update overriding operations as needed. */ void BKE_lib_override_library_main_operations_create(Main *bmain, const bool force_auto) { ID *id; +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_START_AVERAGED(BKE_lib_override_library_main_operations_create); +#endif + /* When force-auto is set, we also remove all unused existing override properties & operations. */ if (force_auto) { BKE_lib_override_library_main_tag(bmain, IDOVERRIDE_LIBRARY_TAG_UNUSED, true); } + TaskPool *task_pool = BLI_task_pool_create(bmain, TASK_PRIORITY_HIGH); + FOREACH_MAIN_ID_BEGIN (bmain, id) { - if ((ID_IS_OVERRIDE_LIBRARY(id) && force_auto) || + if ((ID_IS_OVERRIDE_LIBRARY_REAL(id) && force_auto) || (id->tag & LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH)) { - BKE_lib_override_library_operations_create(bmain, id, force_auto); + BLI_task_pool_push(task_pool, lib_override_library_operations_create_cb, id, false, NULL); id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH; } } FOREACH_MAIN_ID_END; + BLI_task_pool_work_and_wait(task_pool); + + BLI_task_pool_free(task_pool); + if (force_auto) { BKE_lib_override_library_main_unused_cleanup(bmain); } + +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_END_AVERAGED(BKE_lib_override_library_main_operations_create); +#endif } /** Set or clear given tag in all operations as unused in that override property data. */ @@ -869,7 +957,7 @@ void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, cons /** Remove all tagged-as-unused properties and operations from that ID override data. */ void BKE_lib_override_library_id_unused_cleanup(struct ID *local) { - if (local->override_library != NULL) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(local)) { LISTBASE_FOREACH_MUTABLE ( IDOverrideLibraryProperty *, op, &local->override_library->properties) { if (op->tag & IDOVERRIDE_LIBRARY_TAG_UNUSED) { @@ -902,7 +990,7 @@ void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain) /** Update given override from its reference (re-applying overridden properties). */ void BKE_lib_override_library_update(Main *bmain, ID *local) { - if (local->override_library == NULL || local->override_library->reference == NULL) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(local)) { return; } @@ -924,8 +1012,8 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) * So we work on temp copy of reference, and 'swap' its content with local. */ /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)! - * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will - * do, as inn-efficient as it is. :/ + * However, this is whole bunch of code work in itself, so for now plain stupid ID copy + * will do, as inn-efficient as it is. :/ * Actually, maybe not! Since we are swapping with original ID's local content, we want to * keep user-count in correct state when freeing tmp_id * (and that user-counts of IDs used by 'new' local data also remain correct). */ @@ -942,11 +1030,21 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) } /* This ID name is problematic, since it is an 'rna name property' it should not be editable or - * different from reference linked ID. But local ID names need to be unique in a given type list - * of Main, so we cannot always keep it identical, which is why we need this special manual - * handling here. */ + * different from reference linked ID. But local ID names need to be unique in a given type + * list of Main, so we cannot always keep it identical, which is why we need this special + * manual handling here. */ BLI_strncpy(tmp_id->name, local->name, sizeof(tmp_id->name)); + /* Those ugly loopback pointers again... Luckily we only need to deal with the shape keys here, + * collections' parents are fully runtime and reconstructed later. */ + Key *local_key = BKE_key_from_id(local); + Key *tmp_key = BKE_key_from_id(tmp_id); + if (local_key != NULL && tmp_key != NULL) { + /* This is some kind of hard-coded 'always enforced override'... */ + tmp_key->from = local_key->from; + tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE); + } + PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL; RNA_id_pointer_create(local, &rnaptr_src); RNA_id_pointer_create(tmp_id, &rnaptr_dst); @@ -978,9 +1076,9 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) local->tag |= LIB_TAG_OVERRIDE_LIBRARY_REFOK; /* Full rebuild of Depsgraph! */ - - /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */ - DEG_on_visible_update(bmain, true); + /* Note: this is really brute force, in theory updates from RNA should have handle this already, + * but for now let's play it safe. */ + DEG_relations_tag_update(bmain); } /** Update all overrides from given \a bmain. */ @@ -1028,17 +1126,16 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain, OverrideLibraryStorage *override_storage, ID *local) { - BLI_assert(local->override_library != NULL); - BLI_assert(override_storage != NULL); - const bool is_template = (local->override_library->reference == NULL); - - if (is_template) { + if (ID_IS_OVERRIDE_LIBRARY_TEMPLATE(local) || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(local)) { /* This is actually purely local data with an override template, nothing to do here! */ return NULL; } + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local)); + BLI_assert(override_storage != NULL); + /* Forcefully ensure we know about all needed override operations. */ - BKE_lib_override_library_operations_create(bmain, local, false); + BKE_lib_override_library_operations_create(bmain, local); ID *storage_id; #ifdef DEBUG_OVERRIDE_TIMEIT @@ -1046,8 +1143,8 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain, #endif /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy - * never-overridable data (like Mesh geometry etc.)? And also maybe avoid lib reference-counting - * completely (shallow copy...). */ + * never-overridable data (like Mesh geometry etc.)? And also maybe avoid lib + * reference-counting completely (shallow copy...). */ /* This would imply change in handling of user-count all over RNA * (and possibly all over Blender code). * Not impossible to do, but would rather see first is extra useless usual user handling is @@ -1080,7 +1177,7 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain, void BKE_lib_override_library_operations_store_end( OverrideLibraryStorage *UNUSED(override_storage), ID *local) { - BLI_assert(local->override_library != NULL); + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local)); /* Nothing else to do here really, we need to keep all temp override storage data-blocks in * memory until whole file is written anyway (otherwise we'd get mem pointers overlap...). */ @@ -1089,8 +1186,8 @@ void BKE_lib_override_library_operations_store_end( void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage) { - /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' - * copies of IDs without increasing usercount of used data-blocks. */ + /* We cannot just call BKE_main_free(override_storage), not until we have option to make + * 'ghost' copies of IDs without increasing usercount of used data-blocks. */ ID *id; FOREACH_MAIN_ID_BEGIN (override_storage, id) { diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 3026dd617b5..777a4fb9dfa 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -667,9 +667,10 @@ static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data) /* See: NEW_ID macro */ if (id->newid) { BKE_library_update_ID_link_user(id->newid, id, cb_flag); - *id_pointer = id->newid; + id = id->newid; + *id_pointer = id; } - else if (id->tag & LIB_TAG_NEW) { + if (id->tag & LIB_TAG_NEW) { id->tag &= ~LIB_TAG_NEW; BKE_libblock_relink_to_newid(id); } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 64ffea22363..48c98be626d 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -81,23 +81,23 @@ void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath) { /* in some cases this is used to update the absolute path from the * relative */ - if (lib->name != filepath) { - BLI_strncpy(lib->name, filepath, sizeof(lib->name)); + if (lib->filepath != filepath) { + BLI_strncpy(lib->filepath, filepath, sizeof(lib->filepath)); } - BLI_strncpy(lib->filepath, filepath, sizeof(lib->filepath)); + BLI_strncpy(lib->filepath_abs, filepath, sizeof(lib->filepath_abs)); - /* not essential but set filepath is an absolute copy of value which - * is more useful if its kept in sync */ - if (BLI_path_is_rel(lib->filepath)) { + /* Not essential but set `filepath_abs` is an absolute copy of value which + * is more useful if its kept in sync. */ + if (BLI_path_is_rel(lib->filepath_abs)) { /* note that the file may be unsaved, in this case, setting the - * filepath on an indirectly linked path is not allowed from the + * `filepath_abs` on an indirectly linked path is not allowed from the * outliner, and its not really supported but allow from here for now * since making local could cause this to be directly linked - campbell */ /* Never make paths relative to parent lib - reading code (blenloader) always set *all* - * lib->name relative to current main, not to their parent for indirectly linked ones. */ + * `lib->filepath` relative to current main, not to their parent for indirectly linked ones. */ const char *basepath = BKE_main_blendfile_path(bmain); - BLI_path_abs(lib->filepath, basepath); + BLI_path_abs(lib->filepath_abs, basepath); } } diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c index ea3bee8b2f6..4b577ccec2c 100644 --- a/source/blender/blenkernel/intern/main.c +++ b/source/blender/blenkernel/intern/main.c @@ -288,6 +288,29 @@ void BKE_main_relations_free(Main *bmain) } /** + * Remove an ID from the relations (the two entries for that ID, not the ID from entries in other + * IDs' relationships). + * + * Does not free any allocated memory. + * Allows to use those relations as a way to mark an ID as already processed, without requiring any + * additional tagging or GSet. + * Obviously, relations should be freed after use then, since this will make them fully invalid. + */ +void BKE_main_relations_ID_remove(Main *bmain, ID *id) +{ + if (bmain->relations) { + /* Note: we do not free the entries from the mempool, those will be dealt with when finally + * freeing the whole relations. */ + if (bmain->relations->id_used_to_user) { + BLI_ghash_remove(bmain->relations->id_used_to_user, id, NULL, NULL); + } + if (bmain->relations->id_user_to_used) { + BLI_ghash_remove(bmain->relations->id_user_to_used, id, NULL, NULL); + } + } +} + +/** * Create a GSet storing all IDs present in given \a bmain, by their pointers. * * \param gset: If not NULL, given GSet will be extended with IDs from given \a bmain, diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 433db26ded8..b298a6a2787 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -2112,7 +2112,7 @@ void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3]) * Higher level functions hiding most of the code needed around call to * #BKE_mesh_normals_loop_custom_from_vertices_set(). * - * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there + * \param r_custom_vertnors: is not const, since code will replace zero_v3 normals there * with automatically computed vectors. */ void BKE_mesh_set_custom_normals_from_vertices(Mesh *mesh, float (*r_custom_vertnors)[3]) @@ -2386,10 +2386,10 @@ float BKE_mesh_calc_poly_uv_area(const MPoly *mpoly, const MLoopUV *uv_array) * - The resulting volume will only be correct if the mesh is manifold and has consistent * face winding (non-contiguous face normals or holes in the mesh surface). */ -static float mesh_calc_poly_volume_centroid(const MPoly *mpoly, - const MLoop *loopstart, - const MVert *mvarray, - float r_cent[3]) +static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MPoly *mpoly, + const MLoop *loopstart, + const MVert *mvarray, + float r_cent[3]) { const float *v_pivot, *v_step1; float total_volume = 0.0f; @@ -2424,6 +2424,36 @@ static float mesh_calc_poly_volume_centroid(const MPoly *mpoly, } /** + * A version of mesh_calc_poly_volume_centroid that takes an initial reference center, + * use this to increase numeric stability as the quality of the result becomes + * very low quality as the value moves away from 0.0, see: T65986. + */ +static float mesh_calc_poly_volume_centroid_with_reference_center(const MPoly *mpoly, + const MLoop *loopstart, + const MVert *mvarray, + const float reference_center[3], + float r_cent[3]) +{ + /* See: mesh_calc_poly_volume_centroid for comments. */ + float v_pivot[3], v_step1[3]; + float total_volume = 0.0f; + zero_v3(r_cent); + sub_v3_v3v3(v_pivot, mvarray[loopstart[0].v].co, reference_center); + sub_v3_v3v3(v_step1, mvarray[loopstart[1].v].co, reference_center); + for (int i = 2; i < mpoly->totloop; i++) { + float v_step2[3]; + sub_v3_v3v3(v_step2, mvarray[loopstart[i].v].co, reference_center); + const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2); + total_volume += tetra_volume; + for (uint j = 0; j < 3; j++) { + r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]); + } + copy_v3_v3(v_step1, v_step2); + } + return total_volume; +} + +/** * \note * - Results won't be correct if polygon is non-planar. * - This has the advantage over #mesh_calc_poly_volume_centroid @@ -2536,10 +2566,35 @@ bool BKE_mesh_center_median(const Mesh *me, float r_cent[3]) if (me->totvert) { mul_v3_fl(r_cent, 1.0f / (float)me->totvert); } - return (me->totvert != 0); } +/** + * Calculate the center from polygons, + * use when we want to ignore vertex locations that don't have connected faces. + */ +bool BKE_mesh_center_median_from_polys(const Mesh *me, float r_cent[3]) +{ + int i = me->totpoly; + int tot = 0; + const MPoly *mpoly = me->mpoly; + const MLoop *mloop = me->mloop; + const MVert *mvert = me->mvert; + zero_v3(r_cent); + for (mpoly = me->mpoly; i--; mpoly++) { + int loopend = mpoly->loopstart + mpoly->totloop; + for (int j = mpoly->loopstart; j < loopend; j++) { + add_v3_v3(r_cent, mvert[mloop[j].v].co); + } + tot += mpoly->totloop; + } + /* otherwise we get NAN for 0 verts */ + if (me->totpoly) { + mul_v3_fl(r_cent, 1.0f / (float)tot); + } + return (me->totpoly != 0); +} + bool BKE_mesh_center_bounds(const Mesh *me, float r_cent[3]) { float min[3], max[3]; @@ -2595,12 +2650,16 @@ bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3]) float total_volume = 0.0f; float poly_cent[3]; + /* Use an initial center to avoid numeric instability of geometry far away from the center. */ + float init_cent[3]; + const bool init_cent_result = BKE_mesh_center_median_from_polys(me, init_cent); + zero_v3(r_cent); /* calculate a weighted average of polyhedron centroids */ for (mpoly = me->mpoly; i--; mpoly++) { - poly_volume = mesh_calc_poly_volume_centroid( - mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent); + poly_volume = mesh_calc_poly_volume_centroid_with_reference_center( + mpoly, me->mloop + mpoly->loopstart, me->mvert, init_cent, poly_cent); /* poly_cent is already volume-weighted, so no need to multiply by the volume */ add_v3_v3(r_cent, poly_cent); @@ -2616,9 +2675,10 @@ bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3]) /* this can happen for non-manifold objects, fallback to median */ if (UNLIKELY(!is_finite_v3(r_cent))) { - return BKE_mesh_center_median(me, r_cent); + copy_v3_v3(r_cent, init_cent); + return init_cent_result; } - + add_v3_v3(r_cent, init_cent); return (me->totpoly != 0); } diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c index 3daf9f2752e..010b306ec76 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c @@ -405,6 +405,37 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, Mesh *source) free_bvhtree_from_mesh(&bvhtree); } +void BKE_remesh_reproject_vertex_paint(Mesh *target, Mesh *source) +{ + BVHTreeFromMesh bvhtree = { + .nearest_callback = NULL, + }; + BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2); + + int tot_color_layer = CustomData_number_of_layers(&source->vdata, CD_PROP_COLOR); + + for (int layer_n = 0; layer_n < tot_color_layer; layer_n++) { + const char *layer_name = CustomData_get_layer_name(&source->vdata, CD_PROP_COLOR, layer_n); + CustomData_add_layer_named( + &target->vdata, CD_PROP_COLOR, CD_CALLOC, NULL, target->totvert, layer_name); + + MPropCol *target_color = CustomData_get_layer_n(&target->vdata, CD_PROP_COLOR, layer_n); + MVert *target_verts = CustomData_get_layer(&target->vdata, CD_MVERT); + MPropCol *source_color = CustomData_get_layer_n(&source->vdata, CD_PROP_COLOR, layer_n); + for (int i = 0; i < target->totvert; i++) { + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + BLI_bvhtree_find_nearest( + bvhtree.tree, target_verts[i].co, &nearest, bvhtree.nearest_callback, &bvhtree); + if (nearest.index != -1) { + copy_v4_v4(target_color[i].color, source_color[nearest.index].color); + } + } + } + free_bvhtree_from_mesh(&bvhtree); +} + struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh) { const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c index 8bce577897b..932423bc445 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.c +++ b/source/blender/blenkernel/intern/mesh_runtime.c @@ -203,26 +203,31 @@ bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh) return true; } +bool BKE_mesh_runtime_reset_edit_data(Mesh *mesh) +{ + EditMeshData *edit_data = mesh->runtime.edit_data; + if (edit_data == NULL) { + return false; + } + + MEM_SAFE_FREE(edit_data->polyCos); + MEM_SAFE_FREE(edit_data->polyNos); + MEM_SAFE_FREE(edit_data->vertexCos); + MEM_SAFE_FREE(edit_data->vertexNos); + + return true; +} + bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh) { if (mesh->runtime.edit_data == NULL) { return false; } + BKE_mesh_runtime_reset_edit_data(mesh); - if (mesh->runtime.edit_data->polyCos != NULL) { - MEM_freeN((void *)mesh->runtime.edit_data->polyCos); - } - if (mesh->runtime.edit_data->polyNos != NULL) { - MEM_freeN((void *)mesh->runtime.edit_data->polyNos); - } - if (mesh->runtime.edit_data->vertexCos != NULL) { - MEM_freeN((void *)mesh->runtime.edit_data->vertexCos); - } - if (mesh->runtime.edit_data->vertexNos != NULL) { - MEM_freeN((void *)mesh->runtime.edit_data->vertexNos); - } + MEM_freeN(mesh->runtime.edit_data); + mesh->runtime.edit_data = NULL; - MEM_SAFE_FREE(mesh->runtime.edit_data); return true; } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 7c77746ea1c..327e8bfca7a 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -141,7 +141,7 @@ ModifierData *BKE_modifier_new(int type) md->type = type; md->mode = eModifierMode_Realtime | eModifierMode_Render; md->flag = eModifierFlag_OverrideLibrary_Local; - md->ui_expand_flag = 1; /* Only open the main panel at the beginning, not the subpanels. */ + md->ui_expand_flag = 1; /* Only open the main panel at the beginning, not the sub-panels. */ if (mti->flags & eModifierTypeFlag_EnableInEditmode) { md->mode |= eModifierMode_Editmode; diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index fe7c2055aef..f0efc9b8c50 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -220,19 +220,19 @@ static void get_sequence_fname(const MovieClip *clip, const int framenr, char *n char head[FILE_MAX], tail[FILE_MAX]; int offset; - BLI_strncpy(name, clip->name, sizeof(clip->name)); + BLI_strncpy(name, clip->filepath, sizeof(clip->filepath)); BLI_path_sequence_decode(name, head, tail, &numlen); /* Movie-clips always points to first image from sequence, auto-guess offset for now. * Could be something smarter in the future. */ - offset = sequence_guess_offset(clip->name, strlen(head), numlen); + offset = sequence_guess_offset(clip->filepath, strlen(head), numlen); if (numlen) { BLI_path_sequence_encode( name, head, tail, numlen, offset + framenr - clip->start_frame + clip->frame_offset); } else { - BLI_strncpy(name, clip->name, sizeof(clip->name)); + BLI_strncpy(name, clip->filepath, sizeof(clip->filepath)); } BLI_path_abs(name, ID_BLEND_PATH_FROM_GLOBAL(&clip->id)); @@ -246,7 +246,7 @@ static void get_proxy_fname( char dir[FILE_MAX], clipdir[FILE_MAX], clipfile[FILE_MAX]; int proxynr = framenr - clip->start_frame + 1 + clip->frame_offset; - BLI_split_dirfile(clip->name, clipdir, clipfile, FILE_MAX, FILE_MAX); + BLI_split_dirfile(clip->filepath, clipdir, clipfile, FILE_MAX, FILE_MAX); if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) { BLI_strncpy(dir, clip->proxy.dir, sizeof(dir)); @@ -395,7 +395,7 @@ static void movieclip_open_anim_file(MovieClip *clip) char str[FILE_MAX]; if (!clip->anim) { - BLI_strncpy(str, clip->name, FILE_MAX); + BLI_strncpy(str, clip->filepath, FILE_MAX); BLI_path_abs(str, ID_BLEND_PATH_FROM_GLOBAL(&clip->id)); /* FIXME: make several stream accessible in image editor, too */ @@ -445,7 +445,7 @@ static void movieclip_calc_length(MovieClip *clip) unsigned short numlen; char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX]; - BLI_path_sequence_decode(clip->name, head, tail, &numlen); + BLI_path_sequence_decode(clip->filepath, head, tail, &numlen); if (numlen == 0) { /* there's no number group in file name, assume it's single framed sequence */ @@ -531,10 +531,10 @@ static int user_frame_to_cache_frame(MovieClip *clip, int framenr) unsigned short numlen; char head[FILE_MAX], tail[FILE_MAX]; - BLI_path_sequence_decode(clip->name, head, tail, &numlen); + BLI_path_sequence_decode(clip->filepath, head, tail, &numlen); /* see comment in get_sequence_fname */ - clip->cache->sequence_offset = sequence_guess_offset(clip->name, strlen(head), numlen); + clip->cache->sequence_offset = sequence_guess_offset(clip->filepath, strlen(head), numlen); } index += clip->cache->sequence_offset; @@ -674,7 +674,7 @@ static bool put_imbuf_cache( clip->cache->sequence_offset = -1; if (clip->source == MCLIP_SRC_SEQUENCE) { unsigned short numlen; - BLI_path_sequence_decode(clip->name, NULL, NULL, &numlen); + BLI_path_sequence_decode(clip->filepath, NULL, NULL, &numlen); clip->cache->is_still_sequence = (numlen == 0); } } @@ -758,7 +758,7 @@ static void detect_clip_source(Main *bmain, MovieClip *clip) ImBuf *ibuf; char name[FILE_MAX]; - BLI_strncpy(name, clip->name, sizeof(name)); + BLI_strncpy(name, clip->filepath, sizeof(name)); BLI_path_abs(name, BKE_main_blendfile_path(bmain)); ibuf = IMB_testiffname(name, IB_rect | IB_multilayer); @@ -795,7 +795,7 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name) /* create a short library name */ clip = movieclip_alloc(bmain, BLI_path_basename(name)); - BLI_strncpy(clip->name, name, sizeof(clip->name)); + BLI_strncpy(clip->filepath, name, sizeof(clip->filepath)); detect_clip_source(bmain, clip); @@ -821,7 +821,7 @@ MovieClip *BKE_movieclip_file_add_exists_ex(Main *bmain, const char *filepath, b /* first search an identical filepath */ for (clip = bmain->movieclips.first; clip; clip = clip->id.next) { - BLI_strncpy(strtest, clip->name, sizeof(clip->name)); + BLI_strncpy(strtest, clip->filepath, sizeof(clip->filepath)); BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &clip->id)); if (BLI_path_cmp(strtest, str) == 0) { @@ -1739,7 +1739,7 @@ void BKE_movieclip_filename_for_frame(MovieClip *clip, MovieClipUser *user, char } } else { - BLI_strncpy(name, clip->name, FILE_MAX); + BLI_strncpy(name, clip->filepath, FILE_MAX); BLI_path_abs(name, ID_BLEND_PATH_FROM_GLOBAL(&clip->id)); } } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 48c6727add5..b73f957535c 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -748,7 +748,7 @@ GHashIterator *nodeSocketTypeGetIterator(void) return BLI_ghashIterator_new(nodesockettypes_hash); } -struct bNodeSocket *nodeFindSocket(bNode *node, int in_out, const char *identifier) +struct bNodeSocket *nodeFindSocket(const bNode *node, int in_out, const char *identifier) { bNodeSocket *sock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first); for (; sock; sock = sock->next) { @@ -3216,7 +3216,7 @@ void BKE_node_clipboard_add_node(bNode *node) BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name)); if (ID_IS_LINKED(node->id)) { BLI_strncpy( - node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name)); + node_info->library_name, node->id->lib->filepath_abs, sizeof(node_info->library_name)); } else { node_info->library_name[0] = '\0'; diff --git a/source/blender/blenkernel/intern/node_tree_ref.cc b/source/blender/blenkernel/intern/node_tree_ref.cc index 517c1b85aff..6bd3e2d2e5a 100644 --- a/source/blender/blenkernel/intern/node_tree_ref.cc +++ b/source/blender/blenkernel/intern/node_tree_ref.cc @@ -18,7 +18,8 @@ #include "BLI_dot_export.hh" -namespace BKE { +namespace blender { +namespace bke { NodeTreeRef::NodeTreeRef(bNodeTree *btree) : m_btree(btree) { @@ -78,7 +79,8 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : m_btree(btree) } for (NodeRef *node : m_nodes_by_id) { - m_nodes_by_idname.lookup_or_add_default(node->idname()).append(node); + const bNodeType *nodetype = node->m_bnode->typeinfo; + m_nodes_by_type.lookup_or_add_default(nodetype).append(node); } } @@ -138,15 +140,13 @@ void NodeTreeRef::find_targets_skipping_reroutes(OutputSocketRef &socket, std::string NodeTreeRef::to_dot() const { - namespace Dot = blender::DotExport; + dot::DirectedGraph digraph; + digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); - Dot::DirectedGraph digraph; - digraph.set_rankdir(Dot::Attr_rankdir::LeftToRight); - - Map<const NodeRef *, Dot::NodeWithSocketsRef> dot_nodes; + Map<const NodeRef *, dot::NodeWithSocketsRef> dot_nodes; for (const NodeRef *node : m_nodes_by_id) { - Dot::Node &dot_node = digraph.new_node(""); + dot::Node &dot_node = digraph.new_node(""); dot_node.set_background_color("white"); Vector<std::string> input_names; @@ -159,13 +159,13 @@ std::string NodeTreeRef::to_dot() const } dot_nodes.add_new(node, - Dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names)); + dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names)); } for (const OutputSocketRef *from_socket : m_output_sockets) { for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) { - Dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(&from_socket->node()); - Dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(&to_socket->node()); + dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(&from_socket->node()); + dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(&to_socket->node()); digraph.new_edge(from_dot_node.output(from_socket->index()), to_dot_node.input(to_socket->index())); @@ -175,4 +175,5 @@ std::string NodeTreeRef::to_dot() const return digraph.to_dot_string(); } -} // namespace BKE +} // namespace bke +} // namespace blender diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 127c5243c7e..2ddbdd02883 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1758,300 +1758,171 @@ Object *BKE_object_copy(Main *bmain, const Object *ob) * \note Caller MUST free \a newid pointers itself (#BKE_main_id_clear_newpoins()) and call updates * of DEG too (#DAG_relations_tag_update()). */ -Object *BKE_object_duplicate(Main *bmain, const Object *ob, const int dupflag) +Object *BKE_object_duplicate(Main *bmain, + Object *ob, + const eDupli_ID_Flags dupflag, + const eLibIDDuplicateFlags duplicate_options) { + const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0; + + if (!is_subprocess) { + BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); + BKE_main_id_clear_newpoins(bmain); + } + Material ***matarar; - ID *id; - int a, didit; const bool is_object_liboverride = ID_IS_OVERRIDE_LIBRARY(ob); - Object *obn = BKE_object_copy(bmain, ob); + Object *obn; + BKE_id_copy(bmain, &ob->id, (ID **)&obn); + id_us_min(&obn->id); + if (is_subprocess) { + ID_NEW_SET(ob, obn); + } /* 0 == full linked. */ if (dupflag == 0) { return obn; } -#define ID_NEW_REMAP_US(a) \ - if ((a)->id.newid) { \ - (a) = (void *)(a)->id.newid; \ - (a)->id.us++; \ - } -#define ID_NEW_REMAP_US2(a) \ - if (((ID *)a)->newid) { \ - (a) = ((ID *)a)->newid; \ - ((ID *)a)->us++; \ - } - /* duplicates using userflags */ if (dupflag & USER_DUP_ACT) { BKE_animdata_copy_id_action(bmain, &obn->id, true); } if (dupflag & USER_DUP_MAT) { - for (a = 0; a < obn->totcol; a++) { - id = (ID *)obn->mat[a]; - if (id) { - if (is_object_liboverride && ID_IS_LINKED(id)) { - continue; - } - ID_NEW_REMAP_US(obn->mat[a]) - else - { - obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a])); - if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(bmain, &obn->mat[a]->id, true); - } - } - id_us_min(id); - } + for (int i = 0; i < obn->totcol; i++) { + BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], is_object_liboverride, dupflag); } } if (dupflag & USER_DUP_PSYS) { ParticleSystem *psys; for (psys = obn->particlesystem.first; psys; psys = psys->next) { - id = (ID *)psys->part; - if (id) { - if (is_object_liboverride && ID_IS_LINKED(id)) { - continue; - } - ID_NEW_REMAP_US(psys->part) - else - { - psys->part = ID_NEW_SET(psys->part, BKE_particlesettings_copy(bmain, psys->part)); - if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(bmain, &psys->part->id, true); - } - } - id_us_min(id); - } + BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, is_object_liboverride, dupflag); } } - id = obn->data; - didit = 0; + ID *id = obn->data; + ID *id_new = NULL; + const bool need_to_duplicate_obdata = (id != NULL) && (id->newid == NULL); - if (!is_object_liboverride || !ID_IS_LINKED(id)) { - switch (obn->type) { - case OB_MESH: - if (dupflag & USER_DUP_MESH) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_mesh_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_CURVE: - if (dupflag & USER_DUP_CURVE) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_SURF: - if (dupflag & USER_DUP_SURF) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_FONT: - if (dupflag & USER_DUP_FONT) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_MBALL: - if (dupflag & USER_DUP_MBALL) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_mball_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_LAMP: - if (dupflag & USER_DUP_LAMP) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_light_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_ARMATURE: - if (dupflag != 0) { - DEG_id_tag_update(&obn->id, ID_RECALC_GEOMETRY); - if (obn->pose) { - BKE_pose_tag_recalc(bmain, obn->pose); - } - if (dupflag & USER_DUP_ARM) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data)); - BKE_pose_rebuild(bmain, obn, obn->data, true); - didit = 1; - } - id_us_min(id); - } - } - break; - case OB_LATTICE: - if (dupflag != 0) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_lattice_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_CAMERA: - if (dupflag != 0) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_camera_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_LIGHTPROBE: - if (dupflag & USER_DUP_LIGHTPROBE) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_lightprobe_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_SPEAKER: - if (dupflag != 0) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_speaker_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_GPENCIL: - if (dupflag & USER_DUP_GPENCIL) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_HAIR: - if (dupflag & USER_DUP_HAIR) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_hair_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_POINTCLOUD: - if (dupflag & USER_DUP_POINTCLOUD) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_pointcloud_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_VOLUME: - if (dupflag & USER_DUP_VOLUME) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_volume_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - } - } - - /* Check if obdata is copied. */ - if (didit) { - Key *key = BKE_key_from_object(obn); - - Key *oldkey = BKE_key_from_object(ob); - if (oldkey != NULL) { - ID_NEW_SET(oldkey, key); - } - - if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(bmain, (ID *)obn->data, true); - if (key) { - BKE_animdata_copy_id_action(bmain, (ID *)key, true); + switch (obn->type) { + case OB_MESH: + if (dupflag & USER_DUP_MESH) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); } - } + break; + case OB_CURVE: + if (dupflag & USER_DUP_CURVE) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_SURF: + if (dupflag & USER_DUP_SURF) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_FONT: + if (dupflag & USER_DUP_FONT) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_MBALL: + if (dupflag & USER_DUP_MBALL) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_LAMP: + if (dupflag & USER_DUP_LAMP) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_ARMATURE: + if (dupflag & USER_DUP_ARM) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_LATTICE: + if (dupflag != 0) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_CAMERA: + if (dupflag != 0) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_LIGHTPROBE: + if (dupflag & USER_DUP_LIGHTPROBE) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_SPEAKER: + if (dupflag != 0) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_GPENCIL: + if (dupflag & USER_DUP_GPENCIL) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_HAIR: + if (dupflag & USER_DUP_HAIR) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_POINTCLOUD: + if (dupflag & USER_DUP_POINTCLOUD) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_VOLUME: + if (dupflag & USER_DUP_VOLUME) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + } + /* If obdata has been copied, we may also have to duplicate the materials assigned to it. */ + if (need_to_duplicate_obdata && id_new != NULL) { if (dupflag & USER_DUP_MAT) { matarar = BKE_object_material_array_p(obn); if (matarar) { - for (a = 0; a < obn->totcol; a++) { - id = (ID *)(*matarar)[a]; - if (id) { - if (is_object_liboverride && ID_IS_LINKED(id)) { - continue; - } - ID_NEW_REMAP_US((*matarar)[a]) - else - { - (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a])); - if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(bmain, &(*matarar)[a]->id, true); - } - } - id_us_min(id); - } + for (int i = 0; i < obn->totcol; i++) { + BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], is_object_liboverride, dupflag); } } } } -#undef ID_NEW_REMAP_US -#undef ID_NEW_REMAP_US2 + if (!is_subprocess) { + /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/ + BKE_libblock_relink_to_newid(&obn->id); + +#ifndef NDEBUG + /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */ + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + BLI_assert((id_iter->tag & LIB_TAG_NEW) == 0); + } + FOREACH_MAIN_ID_END; +#endif + + /* Cleanup. */ + BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); + BKE_main_id_clear_newpoins(bmain); + } + + if (obn->type == OB_ARMATURE) { + DEG_id_tag_update(&obn->id, ID_RECALC_GEOMETRY); + if (obn->pose) { + BKE_pose_tag_recalc(bmain, obn->pose); + } + // BKE_pose_rebuild(bmain, obn, obn->data, true); + } - if (ob->data != NULL) { + if (obn->data != NULL) { DEG_id_tag_update_ex(bmain, (ID *)obn->data, ID_RECALC_EDITORS); } @@ -2512,7 +2383,6 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]) } /** - * \param depsgraph: Used for dupli-frame time. * \return success if \a mat is set. */ static bool ob_parcurve(Object *ob, Object *par, float mat[4][4]) diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index c5ef5acb08b..d8c3e0bf714 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -183,7 +183,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o #endif /* Always compute UVs, vertex colors as orcos for render. */ cddata_masks.lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; - cddata_masks.vmask |= CD_MASK_ORCO; + cddata_masks.vmask |= CD_MASK_ORCO | CD_MASK_PROP_COLOR; } if (em) { makeDerivedMesh(depsgraph, scene, ob, em, &cddata_masks); /* was CD_MASK_BAREMESH */ diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index ff6aa09ec89..2cd5588ccb8 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -264,14 +264,16 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose) for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) { if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) && BKE_vfont_is_builtin(vfont) == false) { - vfont->packedfile = BKE_packedfile_new(reports, vfont->name, BKE_main_blendfile_path(bmain)); + vfont->packedfile = BKE_packedfile_new( + reports, vfont->filepath, BKE_main_blendfile_path(bmain)); tot++; } } for (sound = bmain->sounds.first; sound; sound = sound->id.next) { if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) { - sound->packedfile = BKE_packedfile_new(reports, sound->name, BKE_main_blendfile_path(bmain)); + sound->packedfile = BKE_packedfile_new( + reports, sound->filepath, BKE_main_blendfile_path(bmain)); tot++; } } @@ -566,14 +568,14 @@ int BKE_packedfile_unpack_vfont(Main *bmain, if (vfont != NULL) { unpack_generate_paths( - vfont->name, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname)); + vfont->filepath, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname)); newname = BKE_packedfile_unpack_to_file( reports, BKE_main_blendfile_path(bmain), absname, localname, vfont->packedfile, how); if (newname != NULL) { ret_value = RET_OK; BKE_packedfile_free(vfont->packedfile); vfont->packedfile = NULL; - BLI_strncpy(vfont->name, newname, sizeof(vfont->name)); + BLI_strncpy(vfont->filepath, newname, sizeof(vfont->filepath)); MEM_freeN(newname); } } @@ -592,11 +594,11 @@ int BKE_packedfile_unpack_sound(Main *bmain, if (sound != NULL) { unpack_generate_paths( - sound->name, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname)); + sound->filepath, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname)); newname = BKE_packedfile_unpack_to_file( reports, BKE_main_blendfile_path(bmain), absname, localname, sound->packedfile, how); if (newname != NULL) { - BLI_strncpy(sound->name, newname, sizeof(sound->name)); + BLI_strncpy(sound->filepath, newname, sizeof(sound->filepath)); MEM_freeN(newname); BKE_packedfile_free(sound->packedfile); @@ -644,7 +646,7 @@ int BKE_packedfile_unpack_image(Main *bmain, /* keep the new name in the image for non-pack specific reasons */ if (how != PF_REMOVE) { - BLI_strncpy(ima->name, newname, sizeof(imapf->filepath)); + BLI_strncpy(ima->filepath, newname, sizeof(imapf->filepath)); } MEM_freeN(newname); } @@ -701,12 +703,12 @@ int BKE_packedfile_unpack_all_libraries(Main *bmain, ReportList *reports) int ret_value = RET_ERROR; for (lib = bmain->libraries.first; lib; lib = lib->id.next) { - if (lib->packedfile && lib->name[0]) { + if (lib->packedfile && lib->filepath[0]) { newname = BKE_packedfile_unpack_to_file(reports, BKE_main_blendfile_path(bmain), - lib->filepath, - lib->filepath, + lib->filepath_abs, + lib->filepath_abs, lib->packedfile, PF_WRITE_ORIGINAL); if (newname != NULL) { @@ -731,19 +733,19 @@ void BKE_packedfile_pack_all_libraries(Main *bmain, ReportList *reports) /* test for relativenss */ for (lib = bmain->libraries.first; lib; lib = lib->id.next) { - if (!BLI_path_is_rel(lib->name)) { + if (!BLI_path_is_rel(lib->filepath)) { break; } } if (lib) { - BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->name); + BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->filepath); return; } for (lib = bmain->libraries.first; lib; lib = lib->id.next) { if (lib->packedfile == NULL) { - lib->packedfile = BKE_packedfile_new(reports, lib->name, BKE_main_blendfile_path(bmain)); + lib->packedfile = BKE_packedfile_new(reports, lib->filepath, BKE_main_blendfile_path(bmain)); } } } @@ -844,7 +846,7 @@ void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF } case ID_LI: { Library *li = (Library *)id; - BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->name); + BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->filepath); break; } default: diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index f26b478c680..b3ab856468c 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1310,7 +1310,7 @@ static void sculptsession_free_pbvh(Object *object) MEM_SAFE_FREE(ss->pmap); MEM_SAFE_FREE(ss->pmap_mem); - MEM_SAFE_FREE(ss->layer_base); + MEM_SAFE_FREE(ss->persistent_base); MEM_SAFE_FREE(ss->preview_vert_index_list); ss->preview_vert_index_count = 0; @@ -1368,6 +1368,9 @@ void BKE_sculptsession_free(Object *ob) MEM_SAFE_FREE(ss->preview_vert_index_list); + MEM_SAFE_FREE(ss->vertex_info.connected_component); + MEM_SAFE_FREE(ss->fake_neighbors.fake_neighbor_index); + if (ss->pose_ik_chain_preview) { for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) { MEM_SAFE_FREE(ss->pose_ik_chain_preview->segments[i].weights); @@ -1474,8 +1477,12 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) /** * \param need_mask: So that the evaluated mesh that is returned has mask data. */ -static void sculpt_update_object( - Depsgraph *depsgraph, Object *ob, Mesh *me_eval, bool need_pmap, bool need_mask) +static void sculpt_update_object(Depsgraph *depsgraph, + Object *ob, + Mesh *me_eval, + bool need_pmap, + bool need_mask, + bool need_colors) { Scene *scene = DEG_get_input_scene(depsgraph); Sculpt *sd = scene->toolsettings->sculpt; @@ -1490,6 +1497,8 @@ static void sculpt_update_object( ss->building_vp_handle = false; + ss->scene = scene; + if (need_mask) { if (mmd == NULL) { if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) { @@ -1503,6 +1512,16 @@ static void sculpt_update_object( } } + /* Add a color layer if a color tool is used. */ + Mesh *orig_me = BKE_object_get_original_mesh(ob); + if (need_colors) { + if (!CustomData_has_layer(&orig_me->vdata, CD_PROP_COLOR)) { + CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert); + BKE_mesh_update_customdata_pointers(orig_me, true); + DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY); + } + } + /* tessfaces aren't used and will become invalid */ BKE_mesh_tessface_clear(me); @@ -1535,6 +1554,7 @@ static void sculpt_update_object( ss->multires.modifier = NULL; ss->multires.level = 0; ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); + ss->vcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR); } /* Sculpt Face Sets. */ @@ -1663,13 +1683,11 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval) BLI_assert(me_eval != NULL); - sculpt_update_object(depsgraph, ob_orig, me_eval, false, false); + sculpt_update_object(depsgraph, ob_orig, me_eval, false, false, false); } -void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, - Object *ob_orig, - bool need_pmap, - bool need_mask) +void BKE_sculpt_update_object_for_edit( + Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool need_colors) { /* Update from sculpt operators and undo, to update sculpt session * and PBVH after edits. */ @@ -1679,7 +1697,7 @@ void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, BLI_assert(ob_orig == DEG_get_original_object(ob_orig)); - sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask); + sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask, need_colors); } int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index c201cb83c44..b589db33edb 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -2262,6 +2262,7 @@ static void do_path_effectors(ParticleSimulationData *sim, sim->psys->part->effector_weights, &epoint, force, + NULL, NULL); mul_v3_fl(force, @@ -4786,7 +4787,7 @@ void psys_get_dupli_texture(ParticleSystem *psys, int num; /* XXX: on checking '(psmd->dm != NULL)' - * This is incorrect but needed for metaball evaluation. + * This is incorrect but needed for meta-ball evaluation. * 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. * diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 606291a9ae0..d09f9a8eb09 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2243,8 +2243,13 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo /* add effectors */ pd_point_from_particle(efdata->sim, efdata->pa, state, &epoint); if (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR) { - BKE_effectors_apply( - sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse); + BKE_effectors_apply(sim->psys->effectors, + sim->colliders, + part->effector_weights, + &epoint, + force, + NULL, + impulse); } mul_v3_fl(force, efdata->ptex.field); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 19f28047b80..8d7dabf9859 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1325,6 +1325,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS), pbvh->face_sets_color_seed, pbvh->face_sets_color_default, + CustomData_get_layer(pbvh->vdata, CD_PROP_COLOR), update_flags); break; case PBVH_BMESH: @@ -1442,6 +1443,10 @@ void BKE_pbvh_update_vertex_data(PBVH *pbvh, int flag) pbvh_update_mask_redraw(pbvh, nodes, totnode, flag); } + if (flag & (PBVH_UpdateColor)) { + /* Do nothing */ + } + if (flag & (PBVH_UpdateVisibility)) { pbvh_update_visibility_redraw(pbvh, nodes, totnode, flag); } @@ -1729,6 +1734,11 @@ void BKE_pbvh_node_mark_update_mask(PBVHNode *node) node->flag |= PBVH_UpdateMask | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; } +void BKE_pbvh_node_mark_update_color(PBVHNode *node) +{ + node->flag |= PBVH_UpdateColor | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; +} + void BKE_pbvh_node_mark_update_visibility(PBVHNode *node) { node->flag |= PBVH_UpdateVisibility | PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | @@ -2905,6 +2915,26 @@ void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot) *r_tot = tot; } +PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node) +{ + + if (!node->color_buffer.color) { + node->color_buffer.color = MEM_callocN(node->uniq_verts * sizeof(float) * 4, "Color buffer"); + } + return &node->color_buffer; +} + +void BKE_pbvh_node_color_buffer_free(PBVH *pbvh) +{ + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); + for (int i = 0; i < totnode; i++) { + MEM_SAFE_FREE(nodes[i]->color_buffer.color); + } + MEM_SAFE_FREE(nodes); +} + void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int mode) { struct CCGElem **grids; @@ -2958,6 +2988,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi->mask = NULL; if (pbvh->type == PBVH_FACES) { vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK); + vi->vcol = CustomData_get_layer(pbvh->vdata, CD_PROP_COLOR); } } diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 7397f939894..6f8bae822ea 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -105,6 +105,9 @@ struct PBVHNode { float (*bm_orco)[3]; int (*bm_ortri)[3]; int bm_tot_ortri; + + /* Used to store the brush color during a stroke and composite it over the original color */ + PBVHColorBufferNode color_buffer; }; typedef enum { diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 836fe59d7bd..ab392e50053 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1062,7 +1062,7 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke FluidModifierData *mmd = (FluidModifierData *)smoke_v; FluidDomainSettings *mds = mmd->domain; - OpenVDBWriter_set_flags(writer, mds->openvdb_comp, (mds->data_depth == 16)); + OpenVDBWriter_set_flags(writer, mds->openvdb_compression, (mds->openvdb_data_depth == 16)); OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", mds->active_fields); OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", mds->res); @@ -1593,7 +1593,7 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) { memset(pid, 0, sizeof(PTCacheID)); - pid->ob = ob; + pid->owner_id = &ob->id; pid->calldata = sb; pid->type = PTCACHE_TYPE_SOFTBODY; pid->cache = sb->shared->pointcache; @@ -1632,7 +1632,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p { memset(pid, 0, sizeof(PTCacheID)); - pid->ob = ob; + pid->owner_id = &ob->id; pid->calldata = psys; pid->type = PTCACHE_TYPE_PARTICLES; pid->stack_index = psys->pointcache->index; @@ -1697,7 +1697,7 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl { memset(pid, 0, sizeof(PTCacheID)); - pid->ob = ob; + pid->owner_id = &ob->id; pid->calldata = clmd; pid->type = PTCACHE_TYPE_CLOTH; pid->stack_index = clmd->point_cache->index; @@ -1738,7 +1738,7 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidMo memset(pid, 0, sizeof(PTCacheID)); - pid->ob = ob; + pid->owner_id = &ob->id; pid->calldata = mmd; pid->type = PTCACHE_TYPE_SMOKE_DOMAIN; @@ -1788,7 +1788,7 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu memset(pid, 0, sizeof(PTCacheID)); - pid->ob = ob; + pid->owner_id = &ob->id; pid->calldata = surface; pid->type = PTCACHE_TYPE_DYNAMICPAINT; pid->cache = surface->pointcache; @@ -1829,7 +1829,7 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r memset(pid, 0, sizeof(PTCacheID)); - pid->ob = ob; + pid->owner_id = &ob->id; pid->calldata = rbw; pid->type = PTCACHE_TYPE_RIGIDBODY; pid->cache = rbw->shared->pointcache; @@ -2188,9 +2188,9 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext) static int ptcache_path(PTCacheID *pid, char *filename) { - Library *lib = (pid->ob) ? pid->ob->id.lib : NULL; + Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL; const char *blendfilename = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ? - lib->filepath : + lib->filepath_abs : BKE_main_blendfile_path_from_global(); size_t i; @@ -2246,7 +2246,7 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p newname += len; } if (pid->cache->name[0] == '\0' && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) { - idname = (pid->ob->id.name + 2); + idname = (pid->owner_id->name + 2); /* convert chars to hex so they are always a valid filename */ while ('\0' != *idname) { BLI_snprintf(newname, MAX_PTCACHE_FILE, "%02X", (unsigned int)(*idname++)); @@ -2263,7 +2263,8 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p if (do_ext) { if (pid->cache->index < 0) { - pid->cache->index = pid->stack_index = BKE_object_insert_ptcache(pid->ob); + BLI_assert(GS(pid->owner_id->name) == ID_OB); + pid->cache->index = pid->stack_index = BKE_object_insert_ptcache((Object *)pid->owner_id); } const char *ext = ptcache_file_extension(pid); @@ -2297,7 +2298,7 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra) #ifndef DURIAN_POINTCACHE_LIB_OK /* don't allow writing for linked objects */ - if (pid->ob->id.lib && mode == PTCACHE_FILE_WRITE) { + if (pid->owner_id->lib && mode == PTCACHE_FILE_WRITE) { return NULL; } #endif @@ -3508,7 +3509,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) #ifndef DURIAN_POINTCACHE_LIB_OK /* don't allow clearing for linked objects */ - if (pid->ob->id.lib) { + if (pid->owner_id->lib) { return; } #endif @@ -3688,7 +3689,6 @@ void BKE_ptcache_id_time( * is probably to interpolate results from two frames for that .. */ - /* ob= pid->ob; */ /* UNUSED */ cache = pid->cache; if (timescale) { @@ -4119,7 +4119,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) G.is_break = false; /* set caches to baking mode and figure out start frame */ - if (pid->ob) { + if (pid->owner_id) { /* cache/bake a single object */ cache = pid->cache; if ((cache->flag & PTCACHE_BAKED) == 0) { @@ -4136,7 +4136,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker) /* get all pids from the object and search for smoke low res */ ListBase pidlist2; PTCacheID *pid2; - BKE_ptcache_ids_from_object(&pidlist2, pid->ob, scene, MAX_DUPLI_RECUR); + BLI_assert(GS(pid->owner_id->name) == ID_OB); + BKE_ptcache_ids_from_object(&pidlist2, (Object *)pid->owner_id, scene, MAX_DUPLI_RECUR); for (pid2 = pidlist2.first; pid2; pid2 = pid2->next) { if (pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) { if (pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) { @@ -4425,7 +4426,7 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid) if ((cache->flag & PTCACHE_DISK_CACHE) == 0) { if (cache->index) { - BKE_object_delete_ptcache(pid->ob, cache->index); + BKE_object_delete_ptcache((Object *)pid->owner_id, cache->index); cache->index = -1; } } diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index c9911d2cf85..4752782eaeb 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -1348,9 +1348,10 @@ void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collectio /* ************************************** */ /* Utilities API */ -/* Get RigidBody world for the given scene, creating one if needed +/** + * Get RigidBody world for the given scene, creating one if needed * - * \param scene: Scene to find active Rigid Body world for + * \param scene: Scene to find active Rigid Body world for. */ RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) { @@ -1646,7 +1647,7 @@ static void rigidbody_update_sim_ob( /* Calculate net force of effectors, and apply to sim object: * - we use 'central force' since apply force requires a "relative position" * which we don't have... */ - BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL); + BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL, NULL); if (G.f & G_DEBUG) { printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 7cf424f53e0..b0faa555f29 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -822,48 +822,70 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) return sce_copy; } else { - BKE_id_copy_ex(bmain, (ID *)sce, (ID **)&sce_copy, LIB_ID_COPY_ACTIONS); + const eDupli_ID_Flags duplicate_flags = U.dupflag | USER_DUP_OBJECT; + + BKE_id_copy(bmain, (ID *)sce, (ID **)&sce_copy); id_us_min(&sce_copy->id); id_us_ensure_real(&sce_copy->id); + if (duplicate_flags & USER_DUP_ACT) { + BKE_animdata_copy_id_action(bmain, &sce_copy->id, true); + } + /* Extra actions, most notably SCE_FULL_COPY also duplicates several 'children' datablocks. */ if (type == SCE_COPY_FULL) { + /* Scene duplication is always root of duplication currently. */ + const bool is_subprocess = false; + + if (!is_subprocess) { + BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); + BKE_main_id_clear_newpoins(bmain); + } + /* Copy Freestyle LineStyle datablocks. */ LISTBASE_FOREACH (ViewLayer *, view_layer_dst, &sce_copy->view_layers) { LISTBASE_FOREACH ( FreestyleLineSet *, lineset, &view_layer_dst->freestyle_config.linesets) { - if (lineset->linestyle) { - if (is_scene_liboverride && ID_IS_LINKED(lineset->linestyle)) { - continue; - } - id_us_min(&lineset->linestyle->id); - BKE_id_copy_ex( - bmain, (ID *)lineset->linestyle, (ID **)&lineset->linestyle, LIB_ID_COPY_ACTIONS); - } + BKE_id_copy_for_duplicate( + bmain, &lineset->linestyle->id, is_scene_liboverride, duplicate_flags); } } /* Full copy of world (included animations) */ - if (sce_copy->world) { - if (!is_scene_liboverride || !ID_IS_LINKED(sce_copy->world)) { - id_us_min(&sce_copy->world->id); - BKE_id_copy_ex( - bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS); - } - } + BKE_id_copy_for_duplicate(bmain, &sce->world->id, is_scene_liboverride, duplicate_flags); /* Full copy of GreasePencil. */ - if (sce_copy->gpd) { - if (!is_scene_liboverride || !ID_IS_LINKED(sce_copy->gpd)) { - id_us_min(&sce_copy->gpd->id); - BKE_id_copy_ex(bmain, (ID *)sce_copy->gpd, (ID **)&sce_copy->gpd, LIB_ID_COPY_ACTIONS); - } - } + BKE_id_copy_for_duplicate(bmain, &sce->gpd->id, is_scene_liboverride, duplicate_flags); /* Deep-duplicate collections and objects (using preferences' settings for which sub-data to * duplicate along the object itself). */ - BKE_collection_duplicate(bmain, NULL, sce_copy->master_collection, true, true, true); + BKE_collection_duplicate(bmain, + NULL, + sce_copy->master_collection, + duplicate_flags, + LIB_ID_DUPLICATE_IS_SUBPROCESS); + + if (!is_subprocess) { + /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/ + BKE_libblock_relink_to_newid(&sce_copy->id); + +#ifndef NDEBUG + /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those + * flags. */ + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + BLI_assert((id_iter->tag & LIB_TAG_NEW) == 0); + } + FOREACH_MAIN_ID_END; +#endif + + /* Cleanup. */ + BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); + BKE_main_id_clear_newpoins(bmain); + + BKE_main_collection_sync(bmain); + } } else { /* Remove sequencer if not full copy */ @@ -2271,7 +2293,8 @@ static char *scene_undo_depsgraph_gen_key(Scene *scene, ViewLayer *view_layer, c size_t key_full_offset = BLI_strncpy_rlen(key_full, scene->id.name, MAX_ID_NAME); if (scene->id.lib != NULL) { - key_full_offset += BLI_strncpy_rlen(key_full + key_full_offset, scene->id.lib->name, FILE_MAX); + key_full_offset += BLI_strncpy_rlen( + key_full + key_full_offset, scene->id.lib->filepath, FILE_MAX); } key_full_offset += BLI_strncpy_rlen(key_full + key_full_offset, view_layer->name, MAX_NAME); BLI_assert(key_full_offset < MAX_ID_NAME + FILE_MAX + MAX_NAME); diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index bfc0d437994..c510b3a2dfb 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -393,6 +393,7 @@ static void panel_list_copy(ListBase *newlb, const ListBase *lb) Panel *panel = lb->first; for (; new_panel; new_panel = new_panel->next, panel = panel->next) { new_panel->activedata = NULL; + new_panel->runtime.custom_data_ptr = NULL; panel_list_copy(&new_panel->children, &panel->children); } } @@ -575,18 +576,25 @@ void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *) region_free_gizmomap_callback = callback; } -void BKE_area_region_panels_free(ListBase *lb) +static void area_region_panels_free_recursive(Panel *panel) { - Panel *panel, *panel_next; - for (panel = lb->first; panel; panel = panel_next) { - panel_next = panel->next; - if (panel->activedata) { - MEM_freeN(panel->activedata); - } - BKE_area_region_panels_free(&panel->children); + MEM_SAFE_FREE(panel->activedata); + + LISTBASE_FOREACH_MUTABLE (Panel *, child_panel, &panel->children) { + area_region_panels_free_recursive(child_panel); } - BLI_freelistN(lb); + MEM_freeN(panel); +} + +void BKE_area_region_panels_free(ListBase *lb) +{ + LISTBASE_FOREACH_MUTABLE (Panel *, panel, lb) { + /* Free custom data just for parent panels to avoid a double free. */ + MEM_SAFE_FREE(panel->runtime.custom_data_ptr); + area_region_panels_free_recursive(panel); + } + BLI_listbase_clear(lb); } /* not region itself */ diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 9fa43ed0a5f..de233a8d473 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -2810,7 +2810,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context, context->rectx, context->recty, ibuf1->rect_float, - ibuf2->rect_float, + NULL, out->rect_float); } else { @@ -2821,7 +2821,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context, context->rectx, context->recty, (unsigned char *)ibuf1->rect, - (unsigned char *)ibuf2->rect, + NULL, (unsigned char *)out->rect); } @@ -3821,7 +3821,7 @@ void BKE_sequencer_text_font_load(TextVars *data, const bool do_id_user) } char path[FILE_MAX]; - STRNCPY(path, data->text_font->name); + STRNCPY(path, data->text_font->filepath); BLI_assert(BLI_thread_is_main()); BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&data->text_font->id)); @@ -3895,7 +3895,7 @@ static ImBuf *do_text_effect(const SeqRenderData *context, data->text_blf_id = -1; if (data->text_font) { - data->text_blf_id = BLF_load(data->text_font->name); + data->text_blf_id = BLF_load(data->text_font->filepath); } } diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c index 75f7ed82165..604cbf476a8 100644 --- a/source/blender/blenkernel/intern/seqmodifier.c +++ b/source/blender/blenkernel/intern/seqmodifier.c @@ -1126,3 +1126,5 @@ int BKE_sequence_supports_modifiers(Sequence *seq) { return !ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD); } + +/** \} */ diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 90edebfaa97..297d60e5976 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -406,17 +406,18 @@ static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt) /* check for a data with the same filename */ switch (GS(ID_PT->name)) { case ID_SO: { - id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->name, offsetof(bSound, name)); + id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->filepath, offsetof(bSound, filepath)); if (id_restore == NULL) { - id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->name); + id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->filepath); (ID_PT)->newid = id_restore; /* reuse next time */ } break; } case ID_MC: { - id_restore = BLI_findstring(lb, ((MovieClip *)ID_PT)->name, offsetof(MovieClip, name)); + id_restore = BLI_findstring( + lb, ((MovieClip *)ID_PT)->filepath, offsetof(MovieClip, filepath)); if (id_restore == NULL) { - id_restore = BKE_movieclip_file_add(bmain, ((MovieClip *)ID_PT)->name); + id_restore = BKE_movieclip_file_add(bmain, ((MovieClip *)ID_PT)->filepath); (ID_PT)->newid = id_restore; /* reuse next time */ } break; @@ -842,30 +843,22 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq) } /* effects and meta: automatic start and end */ - if (seq->type & SEQ_TYPE_EFFECT) { - /* pointers */ - if (seq->seq2 == NULL) { - seq->seq2 = seq->seq1; - } - if (seq->seq3 == NULL) { - seq->seq3 = seq->seq1; - } - - /* effecten go from seq1 -> seq2: test */ - - /* we take the largest start and smallest end */ - - // seq->start = seq->startdisp = MAX2(seq->seq1->startdisp, seq->seq2->startdisp); - // seq->enddisp = MIN2(seq->seq1->enddisp, seq->seq2->enddisp); - if (seq->seq1) { - /* XXX These resets should not be necessary, but users used to be able to - * edit effect's length, leading to strange results. See [#29190] */ seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0; - seq->start = seq->startdisp = max_iii( - seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp); - seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp); + if (seq->seq3) { + seq->start = seq->startdisp = max_iii( + seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp); + seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp); + } + else if (seq->seq2) { + seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp); + seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp); + } + else { + seq->start = seq->startdisp = seq->seq1->startdisp; + seq->enddisp = seq->seq1->enddisp; + } /* we cant help if strips don't overlap, it wont give useful results. * but at least ensure 'len' is never negative which causes bad bugs elsewhere. */ if (seq->enddisp < seq->startdisp) { @@ -919,6 +912,7 @@ static void seq_multiview_name(Scene *scene, size_t r_size) { const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id); + BLI_assert(ext != NULL && suffix != NULL && prefix != NULL); BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext); } @@ -1188,7 +1182,7 @@ static void seqbase_unique_name(ListBase *seqbasep, SeqUniqueInfo *sui) Sequence *seq; for (seq = seqbasep->first; seq; seq = seq->next) { if ((sui->seq != seq) && STREQ(sui->name_dest, seq->name + 2)) { - /* SEQ_NAME_MAXSTR -4 for the number, -1 for \0, - 2 for prefix */ + /* SEQ_NAME_MAXSTR -4 for the number, -1 for \0, - 2 for r_prefix */ BLI_snprintf(sui->name_dest, sizeof(sui->name_dest), "%.*s.%03d", @@ -1783,6 +1777,33 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) } } +static bool seq_proxy_get_custom_file_fname(Sequence *seq, char *name, const int view_id) +{ + char fname[FILE_MAXFILE]; + char suffix[24]; + StripProxy *proxy = seq->strip->proxy; + + if (proxy == NULL) { + return false; + } + + BLI_join_dirfile(fname, PROXY_MAXFILE, proxy->dir, proxy->file); + BLI_path_abs(fname, BKE_main_blendfile_path_from_global()); + + if (view_id > 0) { + BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id); + /* TODO(sergey): This will actually append suffix after extension + * which is weird but how was originally coded in multiview branch. + */ + BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", fname, suffix); + } + else { + BLI_strncpy(name, fname, PROXY_MAXFILE); + } + + return true; +} + static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, @@ -1790,141 +1811,82 @@ static bool seq_proxy_get_fname(Editing *ed, char *name, const int view_id) { - int frameno; char dir[PROXY_MAXFILE]; - StripAnim *sanim; char suffix[24] = {'\0'}; - StripProxy *proxy = seq->strip->proxy; - if (!proxy) { + + if (proxy == NULL) { return false; } - /* MOVIE tracks (only exception: custom files) are now handled - * internally by ImBuf module for various reasons: proper time code - * support, quicker index build, using one file instead - * of a full directory of jpeg files, etc. Trying to support old - * and new method at once could lead to funny effects, if people - * have both, a directory full of jpeg files and proxy avis, so - * sorry folks, please rebuild your proxies... */ + /* Multiview suffix. */ + if (view_id > 0) { + BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id); + } - sanim = BLI_findlink(&seq->anims, view_id); + /* Per strip with Custom file situation is handled separately. */ + if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE && + ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE) { + if (seq_proxy_get_custom_file_fname(seq, name, view_id)) { + return true; + } + } if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) { - char fname[FILE_MAXFILE]; + /* Per project default. */ if (ed->proxy_dir[0] == 0) { BLI_strncpy(dir, "//BL_proxy", sizeof(dir)); } - else { + else { /* Per project with custom dir. */ BLI_strncpy(dir, ed->proxy_dir, sizeof(dir)); } - - if (sanim && sanim->anim) { - IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE); - } - else if (seq->type == SEQ_TYPE_IMAGE) { - fname[0] = 0; - } - else { - /* We could make a name here, except non-movie's don't generate proxies, - * cancel until other types of sequence strips are supported. */ - return false; - } - BLI_path_append(dir, sizeof(dir), fname); BLI_path_abs(name, BKE_main_blendfile_path_from_global()); } - else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) && - (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) { - BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); - } - else if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) { - BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); - } - else if (sanim && sanim->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) { - char fname[FILE_MAXFILE]; - BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); - IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE); - BLI_path_append(dir, sizeof(dir), fname); - } - else if (seq->type == SEQ_TYPE_IMAGE) { + else { + /* Pre strip with custom dir. */ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) { BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); } - else { + else { /* Per strip default. */ BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir); } } - else { - return false; - } - - if (view_id > 0) { - BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id); - } - - if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE && - ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE) { - char fname[FILE_MAXFILE]; - BLI_join_dirfile(fname, PROXY_MAXFILE, dir, proxy->file); - BLI_path_abs(fname, BKE_main_blendfile_path_from_global()); - if (suffix[0] != '\0') { - /* TODO(sergey): This will actually append suffix after extension - * which is weird but how was originally coded in multiview branch. - */ - BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", fname, suffix); - } - else { - BLI_strncpy(name, fname, PROXY_MAXFILE); - } - - return true; - } - - /* generate a separate proxy directory for each preview size */ + /* Proxy size number to be used in path. */ int proxy_size_number = BKE_sequencer_rendersize_to_scale_factor(render_size) * 100; - if (seq->type == SEQ_TYPE_IMAGE) { - BLI_snprintf(name, - PROXY_MAXFILE, - "%s/images/%d/%s_proxy%s", - dir, - proxy_size_number, - BKE_sequencer_give_stripelem(seq, cfra)->name, - suffix); - frameno = 1; - } - else { - frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs; - BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, proxy_size_number, suffix); - } - + BLI_snprintf(name, + PROXY_MAXFILE, + "%s/images/%d/%s_proxy%s", + dir, + proxy_size_number, + BKE_sequencer_give_stripelem(seq, cfra)->name, + suffix); BLI_path_abs(name, BKE_main_blendfile_path_from_global()); - BLI_path_frame(name, frameno, 0); - strcat(name, ".jpg"); return true; } +static bool seq_can_use_proxy(Sequence *seq, IMB_Proxy_Size psize) +{ + if (seq->strip->proxy == NULL) { + return false; + } + short size_flags = seq->strip->proxy->build_size_flags; + return (seq->flag & SEQ_USE_PROXY) != 0 && psize != IMB_PROXY_NONE && (size_flags & psize) != 0; +} + static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int cfra) { char name[PROXY_MAXFILE]; StripProxy *proxy = seq->strip->proxy; const eSpaceSeq_Proxy_RenderSize psize = context->preview_render_size; - const IMB_Proxy_Size psize_flag = seq_rendersize_to_proxysize(psize); - int size_flags; Editing *ed = context->scene->ed; StripAnim *sanim; - if (!(seq->flag & SEQ_USE_PROXY)) { - return NULL; - } - - size_flags = proxy->build_size_flags; - /* only use proxies, if they are enabled (even if present!) */ - if (psize_flag == IMB_PROXY_NONE || (size_flags & psize_flag) == 0) { + if (!seq_can_use_proxy(seq, seq_rendersize_to_proxysize(psize))) { return NULL; } @@ -2342,7 +2304,9 @@ MINLINE float color_balance_fl( x = 0.f; } - return powf(x, gamma) * mul; + x = powf(x, gamma) * mul; + CLAMP(x, FLT_MIN, FLT_MAX); + return x; } static void make_cb_table_float(float lift, float gain, float gamma, float *table, float mul) @@ -2977,9 +2941,9 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, case EARLY_DO_EFFECT: for (i = 0; i < 3; i++) { /* Speed effect requires time remapping of cfra for input(s). */ - if (input[1] && seq->type == SEQ_TYPE_SPEED) { + if (input[0] && seq->type == SEQ_TYPE_SPEED) { float target_frame = BKE_sequencer_speed_effect_target_frame_get(context, seq, cfra, i); - ibuf[i] = seq_render_strip(context, state, input[i], target_frame); + ibuf[i] = seq_render_strip(context, state, input[0], target_frame); } else { /* Other effects. */ if (input[i]) { @@ -2988,7 +2952,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, } } - if (ibuf[0] && ibuf[1]) { + if (ibuf[0] && (ibuf[1] || BKE_sequence_effect_get_num_inputs(seq->type) == 1)) { if (sh.multithreaded) { out = BKE_sequencer_effect_execute_threaded( &sh, context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]); @@ -3021,97 +2985,126 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, return out; } +/* Render individual view for multiview or single (default view) for monoview. */ +static ImBuf *seq_render_image_strip_view(const SeqRenderData *context, + Sequence *seq, + char *name, + char *prefix, + const char *ext, + int view_id) +{ + + ImBuf *ibuf = NULL; + + int flag = IB_rect | IB_metadata; + if (seq->alpha_mode == SEQ_ALPHA_PREMUL) { + flag |= IB_alphamode_premul; + } + + if (prefix[0] == '\0') { + ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name); + } + else { + char str[FILE_MAX]; + BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext); + seq_multiview_name(context->scene, view_id, prefix, ext, str, FILE_MAX); + ibuf = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name); + } + + if (ibuf == NULL) { + return NULL; + } + + /* We don't need both (speed reasons)! */ + if (ibuf->rect_float != NULL && ibuf->rect != NULL) { + imb_freerectImBuf(ibuf); + } + + /* All sequencer color is done in SRGB space, linear gives odd crossfades. */ + BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false); + + return ibuf; +} + +static bool seq_image_strip_is_multiview_render( + Scene *scene, Sequence *seq, int totfiles, char *name, char *r_prefix, const char *r_ext) +{ + if (totfiles > 1) { + BKE_scene_multiview_view_prefix_get(scene, name, r_prefix, &r_ext); + if (r_prefix[0] == '\0') { + return false; + } + } + else { + r_prefix[0] = '\0'; + } + + return (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0; +} + static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq, float UNUSED(nr), - float cfra) + float cfra, + bool *r_is_proxy_image) { - ImBuf *ibuf = NULL; char name[FILE_MAX]; - bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && - (context->scene->r.scemode & R_MULTIVIEW) != 0; - StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra); - int flag; + const char *ext = NULL; + char prefix[FILE_MAX]; + ImBuf *ibuf = NULL; - if (s_elem) { - BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name); - BLI_path_abs(name, BKE_main_blendfile_path_from_global()); + StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra); + if (s_elem == NULL) { + return NULL; } - flag = IB_rect | IB_metadata; - if (seq->alpha_mode == SEQ_ALPHA_PREMUL) { - flag |= IB_alphamode_premul; - } + BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name); + BLI_path_abs(name, BKE_main_blendfile_path_from_global()); - if (!s_elem) { - /* don't do anything */ + /* Try to get a proxy image. */ + ibuf = seq_proxy_fetch(context, seq, cfra); + if (ibuf != NULL) { + s_elem->orig_width = ibuf->x; + s_elem->orig_height = ibuf->y; + *r_is_proxy_image = true; + return ibuf; } - else if (is_multiview) { - const int totfiles = seq_num_files(context->scene, seq->views_format, true); - int totviews; - struct ImBuf **ibufs_arr; - char prefix[FILE_MAX]; - const char *ext = NULL; - if (totfiles > 1) { - BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext); - if (prefix[0] == '\0') { - goto monoview_image; - } - } - else { - prefix[0] = '\0'; - } + /* Proxy not found, render original. */ + const int totfiles = seq_num_files(context->scene, seq->views_format, true); + bool is_multiview_render = seq_image_strip_is_multiview_render( + context->scene, seq, totfiles, name, prefix, ext); - totviews = BKE_scene_multiview_num_views_get(&context->scene->r); - ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs"); + if (is_multiview_render) { + int totviews = BKE_scene_multiview_num_views_get(&context->scene->r); + ImBuf **ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs"); for (int view_id = 0; view_id < totfiles; view_id++) { + ibufs_arr[view_id] = seq_render_image_strip_view(context, seq, name, prefix, ext, view_id); + } - if (prefix[0] == '\0') { - ibufs_arr[view_id] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name); - } - else { - char str[FILE_MAX]; - seq_multiview_name(context->scene, view_id, prefix, ext, str, FILE_MAX); - ibufs_arr[view_id] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name); - } - - if (ibufs_arr[view_id]) { - /* we don't need both (speed reasons)! */ - if (ibufs_arr[view_id]->rect_float && ibufs_arr[view_id]->rect) { - imb_freerectImBuf(ibufs_arr[view_id]); - } - } + if (ibufs_arr[0] == NULL) { + return NULL; } - if (seq->views_format == R_IMF_VIEWS_STEREO_3D && ibufs_arr[0]) { + if (seq->views_format == R_IMF_VIEWS_STEREO_3D) { IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]); } for (int view_id = 0; view_id < totviews; view_id++) { - if (ibufs_arr[view_id]) { - SeqRenderData localcontext = *context; - localcontext.view_id = view_id; - - /* all sequencer color is done in SRGB space, linear gives odd crossfades */ - BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false); + SeqRenderData localcontext = *context; + localcontext.view_id = view_id; - if (view_id != context->view_id) { - ibufs_arr[view_id] = seq_render_preprocess_ibuf( - &localcontext, seq, ibufs_arr[view_id], cfra, clock(), true, false, false); - } + if (view_id != context->view_id) { + ibufs_arr[view_id] = seq_render_preprocess_ibuf( + &localcontext, seq, ibufs_arr[view_id], cfra, clock(), true, false, false); } } - /* return the original requested ImBuf */ + /* Return the original requested ImBuf. */ ibuf = ibufs_arr[context->view_id]; - if (ibuf) { - s_elem->orig_width = ibufs_arr[0]->x; - s_elem->orig_height = ibufs_arr[0]->y; - } - /* "remove" the others (decrease their refcount) */ + /* Remove the others (decrease their refcount). */ for (int view_id = 0; view_id < totviews; view_id++) { if (ibufs_arr[view_id] != ibuf) { IMB_freeImBuf(ibufs_arr[view_id]); @@ -3121,116 +3114,114 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context, MEM_freeN(ibufs_arr); } else { - monoview_image: - if ((ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) { - /* we don't need both (speed reasons)! */ - if (ibuf->rect_float && ibuf->rect) { - imb_freerectImBuf(ibuf); - } - - /* all sequencer color is done in SRGB space, linear gives odd crossfades */ - BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false); + ibuf = seq_render_image_strip_view(context, seq, name, prefix, ext, context->view_id); + } - s_elem->orig_width = ibuf->x; - s_elem->orig_height = ibuf->y; - } + if (ibuf == NULL) { + return NULL; } + s_elem->orig_width = ibuf->x; + s_elem->orig_height = ibuf->y; + return ibuf; } -static ImBuf *seq_render_movie_strip(const SeqRenderData *context, - Sequence *seq, - float nr, - float cfra) +/** + * Render individual view for multi-view or single (default view) for mono-view. + */ +static ImBuf *seq_render_movie_strip_view(const SeqRenderData *context, + Sequence *seq, + float nr, + StripAnim *sanim, + bool *r_is_proxy_image) { ImBuf *ibuf = NULL; - StripAnim *sanim; + IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size); - bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && - (context->scene->r.scemode & R_MULTIVIEW) != 0; + IMB_anim_set_preseek(sanim->anim, seq->anim_preseek); - IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size); + if (seq_can_use_proxy(seq, psize)) { + ibuf = IMB_anim_absolute(sanim->anim, + nr + seq->anim_startofs, + seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, + psize); + if (ibuf != NULL) { + *r_is_proxy_image = true; + } + } - if ((seq->flag & SEQ_USE_PROXY) == 0) { - psize = IMB_PROXY_NONE; + /* Fetching for requested proxy size failed, try fetching the original instead. */ + if (ibuf == NULL) { + ibuf = IMB_anim_absolute(sanim->anim, + nr + seq->anim_startofs, + seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, + IMB_PROXY_NONE); + } + if (ibuf == NULL) { + return NULL; } - /* load all the videos */ - seq_open_anim_file(context->scene, seq, false); - if (is_multiview) { - ImBuf **ibuf_arr; - const int totfiles = seq_num_files(context->scene, seq->views_format, true); - int totviews; - int ibuf_view_id; + BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false); - if (totfiles != BLI_listbase_count_at_most(&seq->anims, totfiles + 1)) { - goto monoview_movie; - } + /* We don't need both (speed reasons)! */ + if (ibuf->rect_float != NULL && ibuf->rect != NULL) { + imb_freerectImBuf(ibuf); + } + + return ibuf; +} + +static ImBuf *seq_render_movie_strip( + const SeqRenderData *context, Sequence *seq, float nr, float cfra, bool *r_is_proxy_image) +{ + /* Load all the videos. */ + seq_open_anim_file(context->scene, seq, false); + + ImBuf *ibuf = NULL; + StripAnim *sanim = seq->anims.first; + const int totfiles = seq_num_files(context->scene, seq->views_format, true); + bool is_multiview_render = (seq->flag & SEQ_USE_VIEWS) != 0 && + (context->scene->r.scemode & R_MULTIVIEW) != 0 && + BLI_listbase_count_at_most(&seq->anims, totfiles + 1) == totfiles; - totviews = BKE_scene_multiview_num_views_get(&context->scene->r); + if (is_multiview_render) { + ImBuf **ibuf_arr; + int totviews = BKE_scene_multiview_num_views_get(&context->scene->r); ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs"); + int ibuf_view_id; for (ibuf_view_id = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, ibuf_view_id++) { if (sanim->anim) { - IMB_anim_set_preseek(sanim->anim, seq->anim_preseek); - - ibuf_arr[ibuf_view_id] = IMB_anim_absolute(sanim->anim, - nr + seq->anim_startofs, - seq->strip->proxy ? seq->strip->proxy->tc : - IMB_TC_RECORD_RUN, - psize); - - /* fetching for requested proxy size failed, try fetching the original instead */ - if (!ibuf_arr[ibuf_view_id] && psize != IMB_PROXY_NONE) { - ibuf_arr[ibuf_view_id] = IMB_anim_absolute(sanim->anim, - nr + seq->anim_startofs, - seq->strip->proxy ? seq->strip->proxy->tc : - IMB_TC_RECORD_RUN, - IMB_PROXY_NONE); - } - if (ibuf_arr[ibuf_view_id]) { - /* we don't need both (speed reasons)! */ - if (ibuf_arr[ibuf_view_id]->rect_float && ibuf_arr[ibuf_view_id]->rect) { - imb_freerectImBuf(ibuf_arr[ibuf_view_id]); - } - } + ibuf_arr[ibuf_view_id] = seq_render_movie_strip_view( + context, seq, nr, sanim, r_is_proxy_image); } } if (seq->views_format == R_IMF_VIEWS_STEREO_3D) { - if (ibuf_arr[0]) { - IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); - } - else { - /* probably proxy hasn't been created yet */ + if (ibuf_arr[0] == NULL) { + /* Probably proxy hasn't been created yet. */ MEM_freeN(ibuf_arr); return NULL; } + + IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); } for (int view_id = 0; view_id < totviews; view_id++) { SeqRenderData localcontext = *context; localcontext.view_id = view_id; - if (ibuf_arr[view_id]) { - /* all sequencer color is done in SRGB space, linear gives odd crossfades */ - BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[view_id], false); - } if (view_id != context->view_id) { ibuf_arr[view_id] = seq_render_preprocess_ibuf( &localcontext, seq, ibuf_arr[view_id], cfra, clock(), true, false, false); } } - /* return the original requested ImBuf */ + /* Return the original requested ImBuf. */ ibuf = ibuf_arr[context->view_id]; - if (ibuf) { - seq->strip->stripdata->orig_width = ibuf->x; - seq->strip->stripdata->orig_height = ibuf->y; - } - /* "remove" the others (decrease their refcount) */ + /* Remove the others (decrease their refcount). */ for (int view_id = 0; view_id < totviews; view_id++) { if (ibuf_arr[view_id] != ibuf) { IMB_freeImBuf(ibuf_arr[view_id]); @@ -3240,44 +3231,39 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context, MEM_freeN(ibuf_arr); } else { - monoview_movie: - sanim = seq->anims.first; - if (sanim && sanim->anim) { - IMB_anim_set_preseek(sanim->anim, seq->anim_preseek); - - ibuf = IMB_anim_absolute(sanim->anim, - nr + seq->anim_startofs, - seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, - psize); - - /* fetching for requested proxy size failed, try fetching the original instead */ - if (!ibuf && psize != IMB_PROXY_NONE) { - ibuf = IMB_anim_absolute(sanim->anim, - nr + seq->anim_startofs, - seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, - IMB_PROXY_NONE); - } - if (ibuf) { - BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false); + ibuf = seq_render_movie_strip_view(context, seq, nr, sanim, r_is_proxy_image); + } - /* we don't need both (speed reasons)! */ - if (ibuf->rect_float && ibuf->rect) { - imb_freerectImBuf(ibuf); - } + if (ibuf == NULL) { + return NULL; + } - seq->strip->stripdata->orig_width = ibuf->x; - seq->strip->stripdata->orig_height = ibuf->y; - } - } + seq->strip->stripdata->orig_width = ibuf->x; + seq->strip->stripdata->orig_height = ibuf->y; + + return ibuf; +} + +static ImBuf *seq_get_movieclip_ibuf(Sequence *seq, MovieClipUser user) +{ + ImBuf *ibuf = NULL; + float tloc[2], tscale, tangle; + if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_STABILIZED) { + ibuf = BKE_movieclip_get_stable_ibuf(seq->clip, &user, tloc, &tscale, &tangle, 0); + } + else { + ibuf = BKE_movieclip_get_ibuf_flag(seq->clip, &user, seq->clip->flag, MOVIECLIP_CACHE_SKIP); } return ibuf; } -static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence *seq, float nr) +static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, + Sequence *seq, + float nr, + bool *r_is_proxy_image) { ImBuf *ibuf = NULL; MovieClipUser user; - float tloc[2], tscale, tangle; IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size); if (!seq->clip) { @@ -3288,8 +3274,6 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence BKE_movieclip_user_set_frame(&user, nr + seq->anim_startofs + seq->clip->start_frame); - user.render_flag |= MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER; - user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL; switch (psize) { case IMB_PROXY_NONE: @@ -3313,11 +3297,17 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence user.render_flag |= MCLIP_PROXY_RENDER_UNDISTORT; } - if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_STABILIZED) { - ibuf = BKE_movieclip_get_stable_ibuf(seq->clip, &user, tloc, &tscale, &tangle, 0); + /* Try to get a proxy image. */ + ibuf = seq_get_movieclip_ibuf(seq, user); + + if (ibuf != NULL && psize != IMB_PROXY_NONE) { + *r_is_proxy_image = true; } - else { - ibuf = BKE_movieclip_get_ibuf_flag(seq->clip, &user, seq->clip->flag, MOVIECLIP_CACHE_SKIP); + + /* If proxy is not found, grab full-size frame. */ + if (ibuf == NULL) { + user.render_flag |= MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER; + ibuf = seq_get_movieclip_ibuf(seq, user); } return ibuf; @@ -3695,7 +3685,8 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context, static ImBuf *do_render_strip_uncached(const SeqRenderData *context, SeqRenderState *state, Sequence *seq, - float cfra) + float cfra, + bool *r_is_proxy_image) { ImBuf *ibuf = NULL; float nr = BKE_sequencer_give_stripelem_index(seq, cfra); @@ -3747,17 +3738,17 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, } case SEQ_TYPE_IMAGE: { - ibuf = seq_render_image_strip(context, seq, nr, cfra); + ibuf = seq_render_image_strip(context, seq, nr, cfra, r_is_proxy_image); break; } case SEQ_TYPE_MOVIE: { - ibuf = seq_render_movie_strip(context, seq, nr, cfra); + ibuf = seq_render_movie_strip(context, seq, nr, cfra, r_is_proxy_image); break; } case SEQ_TYPE_MOVIECLIP: { - ibuf = seq_render_movieclip_strip(context, seq, nr); + ibuf = seq_render_movieclip_strip(context, seq, nr, r_is_proxy_image); if (ibuf) { /* duplicate frame so movie cache wouldn't be confused by sequencer's stuff */ @@ -3852,40 +3843,26 @@ static ImBuf *seq_render_strip(const SeqRenderData *context, clock_t begin = seq_estimate_render_cost_begin(); ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, false); + if (ibuf != NULL) { + return ibuf; + } + ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_RAW, false); if (ibuf == NULL) { - ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_RAW, false); - if (ibuf == NULL) { - /* MOVIECLIPs have their own proxy management */ - if (seq->type != SEQ_TYPE_MOVIECLIP) { - ibuf = seq_proxy_fetch(context, seq, cfra); - is_proxy_image = (ibuf != NULL); - } - - if (ibuf == NULL) { - ibuf = do_render_strip_uncached(context, state, seq, cfra); - } - - if (ibuf) { - if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) { - is_proxy_image = seq_rendersize_to_proxysize(context->preview_render_size) != - IMB_PROXY_NONE; - } - } - } - - if (ibuf) { - use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra); - } - - if (ibuf == NULL) { - ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect); - sequencer_imbuf_assign_spaces(context->scene, ibuf); - } + ibuf = do_render_strip_uncached(context, state, seq, cfra, &is_proxy_image); + } + if (ibuf) { + use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra); ibuf = seq_render_preprocess_ibuf( context, seq, ibuf, cfra, begin, use_preprocess, is_proxy_image, is_preprocessed); } + + if (ibuf == NULL) { + ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect); + sequencer_imbuf_assign_spaces(context->scene, ibuf); + } + return ibuf; } @@ -5052,7 +5029,7 @@ int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str) return 1; } -/* prefix + [" + escaped_name + "] + \0 */ +/* r_prefix + [" + escaped_name + "] + \0 */ #define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1) static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name) diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c index 0ad61de1ff2..2923298c5d5 100644 --- a/source/blender/blenkernel/intern/shader_fx.c +++ b/source/blender/blenkernel/intern/shader_fx.c @@ -82,8 +82,9 @@ ShaderFxData *BKE_shaderfx_new(int type) BLI_strncpy(fx->name, DATA_(fxi->name), sizeof(fx->name)); fx->type = type; - fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render | eShaderFxMode_Expanded; + fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render; fx->flag = eShaderFxFlag_OverrideLibrary_Local; + fx->ui_expand_flag = 1; /* Expand only the parent panel by default. */ if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode) { fx->mode |= eShaderFxMode_Editmode; @@ -156,7 +157,7 @@ bool BKE_shaderfx_depends_ontime(ShaderFxData *fx) const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type) { /* type unsigned, no need to check < 0 */ - if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') { + if (type < NUM_SHADER_FX_TYPES && type > 0 && shader_fx_types[type]->name[0] != '\0') { return shader_fx_types[type]; } else { @@ -164,6 +165,20 @@ const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type) } } +/** + * Get an effect's panel type, which was defined in the #panelRegister callback. + * + * \note ShaderFx panel types are assumed to be named with the struct name field concatenated to + * the defined prefix. + */ +void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type); + + strcpy(r_idname, SHADERFX_TYPE_PANEL_PREFIX); + strcat(r_idname, fxi->name); +} + void BKE_shaderfx_copydata_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst) { const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx_src->type); @@ -198,6 +213,7 @@ void BKE_shaderfx_copydata_ex(ShaderFxData *fx, ShaderFxData *target, const int target->mode = fx->mode; target->flag = fx->flag; + target->ui_expand_flag = fx->ui_expand_flag; if (fxi->copyData) { fxi->copyData(fx, target); diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 20a23ab8b38..eef848aff72 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -54,10 +54,6 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" -using blender::float3; -using blender::MutableSpan; -using blender::Span; - static void simulation_init_data(ID *id) { Simulation *simulation = (Simulation *)id; @@ -168,6 +164,9 @@ void *BKE_simulation_add(Main *bmain, const char *name) return simulation; } +namespace blender { +namespace bke { + static MutableSpan<float3> get_particle_positions(ParticleSimulationState *state) { return MutableSpan<float3>( @@ -197,7 +196,7 @@ static void copy_particle_state_to_cow(ParticleSimulationState *state_orig, state_cow->tot_particles = state_orig->tot_particles; } -void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation) +static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation) { int current_frame = scene->r.cfra; @@ -259,3 +258,11 @@ void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation * copy_particle_state_to_cow(state_orig, state_cow); } } + +} // namespace bke +} // namespace blender + +void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation) +{ + blender::bke::simulation_data_update(depsgraph, scene, simulation); +} diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 68d0822a223..9c7abbdf876 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -1479,7 +1479,8 @@ static void _scan_for_ext_spring_forces( mid_v3_v3v3(pos, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos); mid_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec); pd_point_from_soft(scene, pos, vel, -1, &epoint); - BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed); + BKE_effectors_apply( + effectors, NULL, sb->effector_weights, &epoint, force, NULL, speed); mul_v3_fl(speed, windfactor); add_v3_v3(vel, speed); @@ -2107,7 +2108,7 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, float eval_sb_fric_force_scale = sb_fric_force_scale(ob); pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint - bp, &epoint); - BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed); + BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, NULL, speed); /* apply forcefield*/ mul_v3_fl(force, fieldfactor * eval_sb_fric_force_scale); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index e8f31594cc0..a293bc55073 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -172,7 +172,7 @@ bSound *BKE_sound_new_file(Main *bmain, const char *filepath) BLI_path_abs(str, path); sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0); - BLI_strncpy(sound->name, filepath, FILE_MAX); + BLI_strncpy(sound->filepath, filepath, FILE_MAX); /* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */ sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock"); @@ -193,7 +193,7 @@ bSound *BKE_sound_new_file_exists_ex(Main *bmain, const char *filepath, bool *r_ /* first search an identical filepath */ for (sound = bmain->sounds.first; sound; sound = sound->id.next) { - BLI_strncpy(strtest, sound->name, sizeof(sound->name)); + BLI_strncpy(strtest, sound->filepath, sizeof(sound->filepath)); BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &sound->id)); if (BLI_path_cmp(strtest, str) == 0) { @@ -452,8 +452,8 @@ static void sound_load_audio(Main *bmain, bSound *sound, bool free_waveform) /* load sound */ PackedFile *pf = sound->packedfile; - /* don't modify soundact->sound->name, only change a copy */ - BLI_strncpy(fullpath, sound->name, sizeof(fullpath)); + /* don't modify soundact->sound->filepath, only change a copy */ + BLI_strncpy(fullpath, sound->filepath, sizeof(fullpath)); BLI_path_abs(fullpath, ID_BLEND_PATH(bmain, &sound->id)); /* but we need a packed file then */ diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index 4892e8d6ede..8455b60c894 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -1426,9 +1426,9 @@ void BKE_studiolight_init(void) BLI_addtail(&studiolights, sl); - /* go over the preset folder and add a studiolight for every image with its path */ - /* for portable installs (where USER and SYSTEM paths are the same), - * only go over LOCAL datafiles once */ + /* Go over the preset folder and add a studio-light for every image with its path. */ + /* For portable installs (where USER and SYSTEM paths are the same), + * only go over LOCAL data-files once. */ /* Also reserve icon space for it. */ if (!BKE_appdir_app_is_portable_install()) { studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index d5d5530c1ce..a1e218390c3 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -655,6 +655,7 @@ void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg) MEM_SAFE_FREE(adjacent_vertex->corner_coords); } MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices); + MEM_SAFE_FREE(subdiv_ccg->cache_.start_face_grid_index); MEM_freeN(subdiv_ccg); } @@ -1797,13 +1798,40 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index) { - // Subdiv *subdiv = subdiv_ccg->subdiv; /* UNUSED */ - // OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; /* UNUSED */ - SubdivCCGFace *face = subdiv_ccg->grid_faces[grid_index]; - - // const int face_grid_index = grid_index - face->start_grid_index; /* UNUSED */ + const SubdivCCGFace *face = subdiv_ccg->grid_faces[grid_index]; const int face_index = face - subdiv_ccg->faces; return face_index; } +const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG *subdiv_ccg) +{ + if (subdiv_ccg->cache_.start_face_grid_index == NULL) { + const Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + if (topology_refiner == NULL) { + return NULL; + } + + const int num_coarse_faces = topology_refiner->getNumFaces(topology_refiner); + + subdiv_ccg->cache_.start_face_grid_index = MEM_malloc_arrayN( + sizeof(int), num_coarse_faces, "start_face_grid_index"); + + int start_grid_index = 0; + for (int face_index = 0; face_index < num_coarse_faces; face_index++) { + const int num_face_grids = topology_refiner->getNumFaceVertices(topology_refiner, + face_index); + subdiv_ccg->cache_.start_face_grid_index[face_index] = start_grid_index; + start_grid_index += num_face_grids; + } + } + + return subdiv_ccg->cache_.start_face_grid_index; +} + +const int *BKE_subdiv_ccg_start_face_grid_index_get(const SubdivCCG *subdiv_ccg) +{ + return subdiv_ccg->cache_.start_face_grid_index; +} + /** \} */ diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index bce2266f3e9..5f85e1a1664 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -59,34 +59,6 @@ # include "BPY_extern.h" #endif -/* - * How Texts should work - * -- - * A text should relate to a file as follows - - * (Text *)->name should be the place where the - * file will or has been saved. - * - * (Text *)->flags has the following bits - * TXT_ISDIRTY - should always be set if the file in mem. differs from - * the file on disk, or if there is no file on disk. - * TXT_ISMEM - should always be set if the Text has not been mapped to - * a file, in which case (Text *)->name may be NULL or garbage. - * TXT_ISEXT - should always be set if the Text is not to be written into - * the .blend - * TXT_ISSCRIPT - should be set if the user has designated the text - * as a script. (NEW: this was unused, but now it is needed by - * space handler script links (see header_view3d.c, for example) - * - * ->>> see also: /makesdna/DNA_text_types.h - * - * Display - * -- - * - * The st->top determines at what line the top of the text is displayed. - * If the user moves the cursor the st containing that cursor should - * be popped ... other st's retain their own top location. - */ - /* -------------------------------------------------------------------- */ /** \name Prototypes * \{ */ @@ -110,9 +82,8 @@ static void text_init_data(ID *id) BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(text, id)); - text->name = NULL; + text->filepath = NULL; - text->nlines = 1; text->flags = TXT_ISDIRTY | TXT_ISMEM; if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0) { text->flags |= TXT_TABSTOSPACES; @@ -157,8 +128,8 @@ static void text_copy_data(Main *UNUSED(bmain), const Text *text_src = (Text *)id_src; /* File name can be NULL. */ - if (text_src->name) { - text_dst->name = BLI_strdup(text_src->name); + if (text_src->filepath) { + text_dst->filepath = BLI_strdup(text_src->filepath); } text_dst->flags |= TXT_ISDIRTY; @@ -190,7 +161,7 @@ static void text_free_data(ID *id) BKE_text_free_lines(text); - MEM_SAFE_FREE(text->name); + MEM_SAFE_FREE(text->filepath); #ifdef WITH_PYTHON BPY_text_free_code(text); #endif @@ -316,12 +287,12 @@ static void cleanup_textline(TextLine *tl) */ static void text_from_buf(Text *text, const unsigned char *buffer, const int len) { - int i, llen; + int i, llen, lines_count; BLI_assert(BLI_listbase_is_empty(&text->lines)); - text->nlines = 0; llen = 0; + lines_count = 0; for (i = 0; i < len; i++) { if (buffer[i] == '\n') { TextLine *tmp; @@ -339,7 +310,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len cleanup_textline(tmp); BLI_addtail(&text->lines, tmp); - text->nlines++; + lines_count += 1; llen = 0; continue; @@ -353,7 +324,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len * - file is empty. in this case new line is needed to start editing from. * - last character in buffer is \n. in this case new line is needed to * deal with newline at end of file. (see [#28087]) (sergey) */ - if (llen != 0 || text->nlines == 0 || buffer[len - 1] == '\n') { + if (llen != 0 || lines_count == 0 || buffer[len - 1] == '\n') { TextLine *tmp; tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline"); @@ -370,7 +341,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len cleanup_textline(tmp); BLI_addtail(&text->lines, tmp); - text->nlines++; + /* lines_count += 1; */ /* UNUSED */ } text->curl = text->sell = text->lines.first; @@ -384,11 +355,11 @@ bool BKE_text_reload(Text *text) char filepath_abs[FILE_MAX]; BLI_stat_t st; - if (!text->name) { + if (!text->filepath) { return false; } - BLI_strncpy(filepath_abs, text->name, FILE_MAX); + BLI_strncpy(filepath_abs, text->filepath, FILE_MAX); BLI_path_abs(filepath_abs, ID_BLEND_PATH_FROM_GLOBAL(&text->id)); buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len); @@ -444,8 +415,8 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const } if (is_internal == false) { - ta->name = MEM_mallocN(strlen(file) + 1, "text_name"); - strcpy(ta->name, file); + ta->filepath = MEM_mallocN(strlen(file) + 1, "text_name"); + strcpy(ta->filepath, file); } else { ta->flags |= TXT_ISMEM | TXT_ISDIRTY; @@ -503,11 +474,11 @@ int BKE_text_file_modified_check(Text *text) int result; char file[FILE_MAX]; - if (!text->name) { + if (!text->filepath) { return 0; } - BLI_strncpy(file, text->name, FILE_MAX); + BLI_strncpy(file, text->filepath, FILE_MAX); BLI_path_abs(file, ID_BLEND_PATH_FROM_GLOBAL(&text->id)); if (!BLI_exists(file)) { @@ -537,11 +508,11 @@ void BKE_text_file_modified_ignore(Text *text) int result; char file[FILE_MAX]; - if (!text->name) { + if (!text->filepath) { return; } - BLI_strncpy(file, text->name, FILE_MAX); + BLI_strncpy(file, text->filepath, FILE_MAX); BLI_path_abs(file, ID_BLEND_PATH_FROM_GLOBAL(&text->id)); if (!BLI_exists(file)) { @@ -738,6 +709,10 @@ bool txt_cursor_is_line_end(Text *text) /* -------------------------------------------------------------------- */ /** \name Cursor Movement Functions + * + * \note If the user moves the cursor the space containing that cursor should be popped + * See #txt_pop_first, #txt_pop_last + * Other space-types retain their own top location. * \{ */ void txt_move_up(Text *text, const bool sel) @@ -1309,6 +1284,8 @@ void txt_sel_set(Text *text, int startl, int startc, int endl, int endc) text->selc = BLI_str_utf8_offset_from_index(tol->line, endc); } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Buffer Conversion for Undo/Redo * @@ -2105,8 +2082,6 @@ static void txt_select_prefix(Text *text, const char *add, bool skip_blank_lines /** * Generic un-prefix operation, use for comment & indent. * - * \param r_line_index_mask: List of lines that are already at indent level 0, - * to store them later into the undo buffer. * \param require_all: When true, all non-empty lines must have this prefix. * Needed for comments where we might want to un-comment a block which contains some comments. * |