diff options
Diffstat (limited to 'source')
845 files changed, 30471 insertions, 14852 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. * diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh index 07155439170..25267bc65d6 100644 --- a/source/blender/blenlib/BLI_array.hh +++ b/source/blender/blenlib/BLI_array.hh @@ -27,8 +27,7 @@ * blender::Array should usually be used instead of blender::Vector whenever the number of elements * is known at construction time. Note however, that blender::Array will default construct all * elements when initialized with the size-constructor. For trivial types, this does nothing. In - * all other cases, this adds overhead. If this becomes a problem, a different constructor which - * does not do default construction can be added. + * all other cases, this adds overhead. * * A main benefit of using Array over Vector is that it expresses the intent of the developer * better. It indicates that the size of the data structure is not expected to change. Furthermore, @@ -130,6 +129,24 @@ class Array { uninitialized_fill_n(m_data, m_size, value); } + /** + * Create a new array with uninitialized elements. The caller is responsible for constructing the + * elements. Moving, copying or destructing an Array with uninitialized elements invokes + * undefined behavior. + * + * This should be used very rarely. Note, that the normal size-constructor also does not + * initialize the elements when T is trivially constructible. Therefore, it only makes sense to + * use this with non trivially constructible types. + * + * Usage: + * Array<std::string> my_strings(10, NoInitialization()); + */ + Array(uint size, NoInitialization) + { + m_size = size; + m_data = this->get_buffer_for_size(size); + } + Array(const Array &other) : m_allocator(other.m_allocator) { m_size = other.size(); diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh index 432459c9998..37f74edcf4c 100644 --- a/source/blender/blenlib/BLI_color.hh +++ b/source/blender/blenlib/BLI_color.hh @@ -28,6 +28,10 @@ struct Color4f { Color4f() = default; + Color4f(const float *rgba) : r(rgba[0]), g(rgba[1]), b(rgba[2]), a(rgba[3]) + { + } + Color4f(float r, float g, float b, float a) : r(r), g(g), b(b), a(a) { } diff --git a/source/blender/blenlib/BLI_dot_export.hh b/source/blender/blenlib/BLI_dot_export.hh index 67af4391a55..b496c00a75d 100644 --- a/source/blender/blenlib/BLI_dot_export.hh +++ b/source/blender/blenlib/BLI_dot_export.hh @@ -25,17 +25,17 @@ */ #include "BLI_map.hh" -#include "BLI_optional.hh" #include "BLI_set.hh" #include "BLI_utility_mixins.hh" #include "BLI_vector.hh" #include "BLI_dot_export_attribute_enums.hh" +#include <optional> #include <sstream> namespace blender { -namespace DotExport { +namespace dot { class Graph; class DirectedGraph; @@ -197,10 +197,10 @@ class DirectedGraph final : public Graph { class NodePort { private: Node *m_node; - Optional<std::string> m_port_name; + std::optional<std::string> m_port_name; public: - NodePort(Node &node, Optional<std::string> port_name = {}) + NodePort(Node &node, std::optional<std::string> port_name = {}) : m_node(&node), m_port_name(std::move(port_name)) { } @@ -283,7 +283,7 @@ class NodeWithSocketsRef { } }; -} // namespace DotExport +} // namespace dot } // namespace blender #endif /* __BLI_DOT_EXPORT_HH__ */ diff --git a/source/blender/blenlib/BLI_dot_export_attribute_enums.hh b/source/blender/blenlib/BLI_dot_export_attribute_enums.hh index 8fe1cda05f3..12019a49194 100644 --- a/source/blender/blenlib/BLI_dot_export_attribute_enums.hh +++ b/source/blender/blenlib/BLI_dot_export_attribute_enums.hh @@ -20,7 +20,7 @@ #include "BLI_string_ref.hh" namespace blender { -namespace DotExport { +namespace dot { enum class Attr_rankdir { LeftToRight, @@ -119,7 +119,7 @@ inline StringRef dirType_to_string(Attr_dirType value) return ""; } -} // namespace DotExport +} // namespace dot } // namespace blender #endif /* __BLI_DOT_EXPORT_ATTRIBUTE_ENUMS_HH__ */ diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh index 5490c953756..49e619ff1bc 100644 --- a/source/blender/blenlib/BLI_hash.hh +++ b/source/blender/blenlib/BLI_hash.hh @@ -23,7 +23,7 @@ * A specialization of `blender::DefaultHash<T>` provides a hash function for values of type T. * This hash function is used by default in hash table implementations in blenlib. * - * The actual hash function is in the `operator()` method of DefaultHash<T>. The following code + * The actual hash function is in the `operator()` method of `DefaultHash<T>`. The following code * computes the hash of some value using DefaultHash. * * T value = ...; @@ -32,17 +32,17 @@ * * Hash table implementations like blender::Set support heterogeneous key lookups. That means that * one can do a lookup with a key of type A in a hash table that stores keys of type B. This is - * commonly done when B is std::string, because the conversion from e.g. a StringRef to std::string - * can be costly and is unnecessary. To make this work, values of type A and B that compare equal - * have to have the same hash value. This is achieved by defining potentially multiple `operator()` - * in a specialization of DefaultHash. All those methods have to compute the same hash for values - * that compare equal. + * commonly done when B is std::string, because the conversion from e.g. a #StringRef to + * std::string can be costly and is unnecessary. To make this work, values of type A and B that + * compare equal have to have the same hash value. This is achieved by defining potentially + * multiple `operator()` in a specialization of #DefaultHash. All those methods have to compute the + * same hash for values that compare equal. * * The computed hash is an unsigned 32 bit integer. Ideally, the hash function would generate * uniformly random hash values for a set of keys. However, in many cases trivial hash functions * are faster and produce a good enough distribution. In general it is better when more information * is in the lower bits of the hash. By choosing a good probing strategy, the effects of a bad hash - * function are less noticable though. In this context a good probing strategy is one that takes + * function are less noticeable though. In this context a good probing strategy is one that takes * all bits of the hash into account eventually. One has to check on a case by case basis to see if * a better but more expensive or trivial hash function works better. * @@ -50,11 +50,11 @@ * * - When you want to provide a default hash function for your own custom type: Add a `hash` * member function to it. The function should return `uint32_t` and take no arguments. This - * method will be called by the default implementation of DefaultHash. It will automatically be + * method will be called by the default implementation of #DefaultHash. It will automatically be * used by hash table implementations. * * - When you want to provide a default hash function for a type that you cannot modify: Add a new - * specialization to the DefaultHash struct. This can be done by writing code like below in + * specialization to the #DefaultHash struct. This can be done by writing code like below in * either global or BLI namespace. * * template<> struct blender::DefaultHash<TheType> { @@ -86,9 +86,9 @@ namespace blender { /** - * If there is no other specialization of DefaultHash for a given type, try to call `hash()` on the - * value. If there is no such method, this will result in a compiler error. Usually that means that - * you have to implement a hash function using one of three strategies listed above. + * If there is no other specialization of #DefaultHash for a given type, try to call `hash()` on + * the value. If there is no such method, this will result in a compiler error. Usually that means + * that you have to implement a hash function using one of three strategies listed above. */ template<typename T> struct DefaultHash { uint32_t operator()(const T &value) const @@ -165,7 +165,7 @@ inline uint32_t hash_string(StringRef str) template<> struct DefaultHash<std::string> { /** - * Take a StringRef as parameter to support heterogeneous lookups in hash table implementations + * Take a #StringRef as parameter to support heterogeneous lookups in hash table implementations * when std::string is used as key. */ uint32_t operator()(StringRef value) const diff --git a/source/blender/blenlib/BLI_hash_tables.hh b/source/blender/blenlib/BLI_hash_tables.hh index c3b0b1f90e0..195811ebd71 100644 --- a/source/blender/blenlib/BLI_hash_tables.hh +++ b/source/blender/blenlib/BLI_hash_tables.hh @@ -39,7 +39,7 @@ namespace blender { /* -------------------------------------------------------------------- */ /** \name Constexpr Utility Functions * - * Those should eventually be deduplicated with functions in BLI_math_base.h. + * Those should eventually be de-duplicated with functions in BLI_math_base.h. * \{ */ inline constexpr int is_power_of_2_i_constexpr(int n) @@ -158,10 +158,10 @@ class LoadFactor { * two values of the key type are selected to indicate whether the slot is empty or removed. * * The classes below tell a slot implementation which special key values it can use. They can be - * used as KeyInfo in slot types like IntrusiveSetSlot and IntrusiveMapSlot. + * used as #KeyInfo in slot types like #IntrusiveSetSlot and #IntrusiveMapSlot. * - * A KeyInfo type has to implement a couple of static methods that are descriped in - * TemplatedKeyInfo. + * A #KeyInfo type has to implement a couple of static methods that are descried in + * #TemplatedKeyInfo. * * \{ */ diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh index 25192429a5d..e2b74931537 100644 --- a/source/blender/blenlib/BLI_index_range.hh +++ b/source/blender/blenlib/BLI_index_range.hh @@ -211,7 +211,7 @@ class IndexRange { } /** - * Returns a new range, that contains a subinterval of the current one. + * Returns a new range, that contains a sub-interval of the current one. */ IndexRange slice(uint start, uint size) const { diff --git a/source/blender/blenlib/BLI_listbase_wrapper.hh b/source/blender/blenlib/BLI_listbase_wrapper.hh index a77e2d66458..9cf7fc5c0e0 100644 --- a/source/blender/blenlib/BLI_listbase_wrapper.hh +++ b/source/blender/blenlib/BLI_listbase_wrapper.hh @@ -20,10 +20,10 @@ /** \file * \ingroup bli * - * `blender::ListBaseWrapper` is a typed wrapper for the ListBase struct. That makes it safer and + * `blender::ListBaseWrapper` is a typed wrapper for the #ListBase struct. That makes it safer and * more convenient to use in C++ in some cases. However, if you find yourself iterating over a * linked list a lot, consider to convert it into a vector for further processing. This improves - * performance and debugability. + * performance and debug-ability. */ #include "BLI_listbase.h" diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh index a4c3ee76ca1..688f334001f 100644 --- a/source/blender/blenlib/BLI_map.hh +++ b/source/blender/blenlib/BLI_map.hh @@ -67,13 +67,13 @@ * interface as blender::Map. This is useful for benchmarking. */ +#include <optional> #include <unordered_map> #include "BLI_array.hh" #include "BLI_hash.hh" #include "BLI_hash_tables.hh" #include "BLI_map_slots.hh" -#include "BLI_optional.hh" #include "BLI_probing_strategies.hh" namespace blender { @@ -98,7 +98,7 @@ template< */ uint32_t InlineBufferCapacity = (sizeof(Key) + sizeof(Value) < 100) ? 4 : 0, /** - * The strategy used to deal with collistions. They are defined in BLI_probing_strategies.hh. + * The strategy used to deal with collisions. They are defined in BLI_probing_strategies.hh. */ typename ProbingStrategy = DefaultProbingStrategy, /** @@ -392,7 +392,7 @@ class Map { * Get the value that is stored for the given key and remove it from the map. If the key is not * in the map, a value-less optional is returned. */ - Optional<Value> pop_try(const Key &key) + std::optional<Value> pop_try(const Key &key) { return this->pop_try_as(key); } @@ -400,7 +400,7 @@ class Map { /** * Same as `pop_try`, but accepts other key types that are supported by the hash function. */ - template<typename ForwardKey> Optional<Value> pop_try_as(const ForwardKey &key) + template<typename ForwardKey> std::optional<Value> pop_try_as(const ForwardKey &key) { return this->pop_try__impl(key, m_hash(key)); } @@ -641,7 +641,7 @@ class Map { */ template<typename FuncT> void foreach_item(const FuncT &func) const { - uint32_t size = this->size(); + uint32_t size = m_slots.size(); for (uint32_t i = 0; i < size; i++) { const Slot &slot = m_slots[i]; if (slot.is_occupied()) { @@ -1074,11 +1074,12 @@ class Map { MAP_SLOT_PROBING_END(); } - template<typename ForwardKey> Optional<Value> pop_try__impl(const ForwardKey &key, uint32_t hash) + template<typename ForwardKey> + std::optional<Value> pop_try__impl(const ForwardKey &key, uint32_t hash) { MAP_SLOT_PROBING_BEGIN (hash, slot) { if (slot.contains(key, m_is_equal, hash)) { - Optional<Value> value = std::move(*slot.value()); + std::optional<Value> value = std::move(*slot.value()); slot.remove(); m_removed_slots++; return value; diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 563bcad5d14..f51486c5e7b 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -190,6 +190,10 @@ float dist_squared_to_projected_aabb_simple(const float projmat[4][4], const float bbmin[3], const float bbmax[3]); +float closest_to_ray_v3(float r_close[3], + const float p[3], + const float ray_orig[3], + const float ray_dir[3]); float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]); double closest_to_line_v2_db(double r_close[2], const double p[2], diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index 81792e2101c..0c2cae6c606 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -204,14 +204,6 @@ template<typename T> void uninitialized_fill_n(T *dst, uint n, const T &value) } } -/** - * The same as std::unique_ptr. This can be removed when we start using C++14. - */ -template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args &&... args) -{ - return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); -} - template<typename T> struct DestructValueAtAddress { void operator()(T *ptr) { @@ -250,6 +242,13 @@ template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer { } }; +/** + * This can be used by container constructors. A parameter of this type should be used to indicate + * that the constructor does not construct the elements. + */ +class NoInitialization { +}; + } // namespace blender #endif /* __BLI_MEMORY_UTILS_HH__ */ diff --git a/source/blender/blenlib/BLI_optional.hh b/source/blender/blenlib/BLI_optional.hh deleted file mode 100644 index 2e6b66d0eac..00000000000 --- a/source/blender/blenlib/BLI_optional.hh +++ /dev/null @@ -1,189 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup bli - * - * Simple version of std::optional, which is only available since C++17. - */ - -#ifndef __BLI_OPTIONAL_HH__ -#define __BLI_OPTIONAL_HH__ - -#include "BLI_memory_utils.hh" -#include "BLI_utildefines.h" - -#include <algorithm> -#include <memory> - -namespace blender { - -template<typename T> class Optional { - private: - AlignedBuffer<sizeof(T), alignof(T)> m_storage; - bool m_set; - - public: - Optional() : m_set(false) - { - } - - ~Optional() - { - this->reset(); - } - - Optional(const T &value) : Optional() - { - this->set(value); - } - - Optional(T &&value) : Optional() - { - this->set(std::forward<T>(value)); - } - - Optional(const Optional &other) : Optional() - { - if (other.has_value()) { - this->set(other.value()); - } - } - - Optional(Optional &&other) : Optional() - { - if (other.has_value()) { - this->set(std::move(other.value())); - } - } - - Optional &operator=(const Optional &other) - { - if (this == &other) { - return *this; - } - if (other.has_value()) { - this->set(other.value()); - } - else { - this->reset(); - } - return *this; - } - - Optional &operator=(Optional &&other) - { - if (this == &other) { - return *this; - } - if (other.has_value()) { - this->set(std::move(other.value())); - } - else { - this->reset(); - } - return *this; - } - - bool has_value() const - { - return m_set; - } - - const T &value() const - { - BLI_assert(m_set); - return *this->value_ptr(); - } - - T &value() - { - BLI_assert(m_set); - return *this->value_ptr(); - } - - void set(const T &value) - { - if (m_set) { - this->value() = value; - } - else { - new ((void *)this->value_ptr()) T(value); - m_set = true; - } - } - - void set(T &&value) - { - if (m_set) { - this->value() = std::move(value); - } - else { - new ((void *)this->value_ptr()) T(std::move(value)); - m_set = true; - } - } - - void set_new(const T &value) - { - BLI_assert(!m_set); - new ((void *)this->value_ptr()) T(value); - m_set = true; - } - - void set_new(T &&value) - { - BLI_assert(!m_set); - new ((void *)this->value_ptr()) T(std::move(value)); - m_set = true; - } - - void reset() - { - if (m_set) { - this->value_ptr()->~T(); - m_set = false; - } - } - - T extract() - { - BLI_assert(m_set); - T value = std::move(this->value()); - this->reset(); - return value; - } - - T *operator->() - { - return this->value_ptr(); - } - - T &operator*() - { - return *this->value_ptr(); - } - - private: - T *value_ptr() const - { - return (T *)m_storage.ptr(); - } -}; - -} /* namespace blender */ - -#endif /* __BLI_OPTIONAL_HH__ */ diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh index d23aa96e434..c3dec147ac6 100644 --- a/source/blender/blenlib/BLI_set.hh +++ b/source/blender/blenlib/BLI_set.hh @@ -30,7 +30,7 @@ * Every slot is in one of three states: empty, occupied or removed. If a slot is occupied, it * contains an instance of the key type. * - * Benchmarking and comparing hash tables is hard, because many factors influence the result. The + * Bench-marking and comparing hash tables is hard, because many factors influence the result. The * performance of a hash table depends on the combination of the hash function, probing strategy, * max load factor, key type, slot type and the data distribution. This implementation is designed * to be relatively fast by default in all cases. However, it also offers many customization @@ -49,21 +49,21 @@ * - Small buffer optimization is enabled by default, if the key is not too large. * - The methods `add_new` and `remove_contained` should be used instead of `add` and `remove` * whenever appropriate. Assumptions and intention are described better this way. - * - Lookups can be performed using types other than Key without conversion. For that use the - * methods ending with `_as`. The template parameters Hash and IsEqual have to support the other + * - Look-ups can be performed using types other than Key without conversion. For that use the + * methods ending with `_as`. The template parameters Hash and #IsEqual have to support the other * key type. This can greatly improve performance when the set contains strings. - * - The default constructor is cheap, even when a large InlineBufferCapacity is used. A large + * - The default constructor is cheap, even when a large #InlineBufferCapacity is used. A large * slot array will only be initialized when the first key is added. * - The `print_stats` method can be used to get information about the distribution of keys and * memory usage of the set. * - The method names don't follow the std::unordered_set names in many cases. Searching for such * names in this file will usually let you discover the new name. - * - There is a StdUnorderedSetWrapper class, that wraps std::unordered_set and gives it the same - * interface as blender::Set. This is useful for benchmarking. + * - There is a #StdUnorderedSetWrapper class, that wraps std::unordered_set and gives it the same + * interface as blender::Set. This is useful for bench-marking. * * Possible Improvements: - * - Use a branchless loop over slots in grow function (measured ~10% performance improvement when - * the distribution of occupied slots is suffiently random). + * - Use a branch-less loop over slots in grow function (measured ~10% performance improvement when + * the distribution of occupied slots is sufficiently random). * - Support max load factor customization. * - Improve performance with large data sets through software prefetching. I got fairly * significant improvements in simple tests (~30% faster). It still needs to be investigated how diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh index bb8479efe95..62755de19af 100644 --- a/source/blender/blenlib/BLI_string_ref.hh +++ b/source/blender/blenlib/BLI_string_ref.hh @@ -89,7 +89,7 @@ class StringRefBase { } /** - * Implicitely convert to std::string. This is convenient in most cases, but you have to be a bit + * Implicitly convert to std::string. This is convenient in most cases, but you have to be a bit * careful not to convert to std::string accidentally. */ operator std::string() const diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index 25e3d2f969b..c5f65d54288 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -107,7 +107,7 @@ class Vector { #endif /** - * Be a friend with other vector instanciations. This is necessary to implement some memory + * Be a friend with other vector instantiations. This is necessary to implement some memory * management logic. */ template<typename OtherT, uint OtherInlineBufferCapacity, typename OtherAllocator> @@ -147,7 +147,7 @@ class Vector { } /** - * Create a vector that contains copys of the values in the initialized list. + * Create a vector that contains copies of the values in the initialized list. * * This allows you to write code like: * Vector<int> vec = {3, 4, 5}; @@ -611,7 +611,7 @@ class Vector { } /** - * Finds the first occurence of the value, removes it and copies the last element to the hole in + * Finds the first occurrence of the value, removes it and copies the last element to the hole in * the vector. This takes O(n) time. */ void remove_first_occurrence_and_reorder(const T &value) diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 69df0505dfe..2630eb6bbd0 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -225,7 +225,6 @@ set(SRC BLI_memory_utils.hh BLI_mempool.h BLI_noise.h - BLI_optional.hh BLI_path_util.h BLI_polyfill_2d.h BLI_polyfill_2d_beautify.h diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index da67baf0ead..9d1981b3392 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -769,7 +769,7 @@ static void non_recursive_bvh_div_nodes_task_cb(void *__restrict userdata, * This functions builds an optimal implicit tree from the given leafs. * Where optimal stands for: * - The resulting tree will have the smallest number of branches; - * - At most only one branch will have NULL childs; + * - At most only one branch will have NULL children; * - All leafs will be stored at level N or N+1. * * This function creates an implicit tree on branches_array, @@ -777,7 +777,7 @@ static void non_recursive_bvh_div_nodes_task_cb(void *__restrict userdata, * * The tree is built per depth levels. First branches at depth 1.. then branches at depth 2.. etc.. * The reason is that we can build level N+1 from level N without any data dependencies.. - * thus it allows to use multithread building. + * thus it allows to use multi-thread building. * * To archive this is necessary to find how much leafs are accessible from a certain branch, * #BVHBuildHelper, #implicit_needed_branches and #implicit_leafs_index diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c index 4e0cd3a78dc..08ccff695c1 100644 --- a/source/blender/blenlib/intern/delaunay_2d.c +++ b/source/blender/blenlib/intern/delaunay_2d.c @@ -405,7 +405,8 @@ static CDTEdge *add_vert_to_symedge_edge(CDT_state *cdt, CDTVert *v, SymEdge *se return e; } -/* Connect the verts of se1 and se2, assuming that currently those two SymEdges are on +/** + * Connect the verts of se1 and se2, assuming that currently those two #SymEdges are on * the outer boundary (have face == outer_face) of two components that are isolated from * each other. */ @@ -479,7 +480,7 @@ static CDTEdge *split_edge(CDT_state *cdt, SymEdge *se, double lambda) * the deleted edge will be the one that was e's face. * There will be now an unused face, marked by setting its deleted flag, * and an unused #CDTEdge, marked by setting the next and rot pointers of - * its SymEdges to NULL. + * its #SymEdge(s) to NULL. * <pre> * . v2 . * / \ / \ @@ -1017,7 +1018,9 @@ static void initial_triangulation(CDT_state *cdt) MEM_freeN(sites); } -/** Use LinkNode linked list as stack of SymEdges, allocating from cdt->listpool. */ +/** + * Use #LinkNode linked list as stack of #SymEdges, allocating from `cdt->listpool` . + */ typedef LinkNode *Stack; BLI_INLINE void push(Stack *stack, SymEdge *se, CDT_state *cdt) @@ -1153,22 +1156,22 @@ static double tri_orient(const SymEdge *t) * in the path we will take to insert an edge constraint. * Each such point will either be * (a) a vertex or - * (b) a fraction lambda (0 < lambda < 1) along some SymEdge.] + * (b) a fraction lambda (0 < lambda < 1) along some #SymEdge.] * * In general, lambda=0 indicates case a and lambda != 0 indicates case be. * The 'in' edge gives the destination attachment point of a diagonal from the previous crossing, * and the 'out' edge gives the origin attachment point of a diagonal to the next crossing. * But in some cases, 'in' and 'out' are undefined or not needed, and will be NULL. * - * For case (a), 'vert' will be the vertex, and lambda will be 0, and 'in' will be the SymEdge from - * 'vert' that has as face the one that you go through to get to this vertex. If you go exactly - * along an edge then we set 'in' to NULL, since it won't be needed. The first crossing will have - * 'in' = NULL. We set 'out' to the SymEdge that has the face we go though to get to the next - * crossing, or, if the next crossing is a case (a), then it is the edge that goes to that next - * vertex. 'out' wlll be NULL for the last one. + * For case (a), 'vert' will be the vertex, and lambda will be 0, and 'in' will be the #SymEdge + * from 'vert' that has as face the one that you go through to get to this vertex. If you go + * exactly along an edge then we set 'in' to NULL, since it won't be needed. The first crossing + * will have 'in' = NULL. We set 'out' to the #SymEdge that has the face we go though to get to the + * next crossing, or, if the next crossing is a case (a), then it is the edge that goes to that + * next vertex. 'out' wlll be NULL for the last one. * * For case (b), vert will be NULL at first, and later filled in with the created split vertex, - * and 'in' will be the SymEdge that we go through, and lambda will be between 0 and 1, + * and 'in' will be the #SymEdge that we go through, and lambda will be between 0 and 1, * the fraction from in's vert to in->next's vert to put the split vertex. * 'out' is not needed in this case, since the attachment point will be the sym of the first * half of the split edge. @@ -1231,8 +1234,8 @@ static void fill_crossdata_for_through_vert(CDTVert *v, /** * As part of finding crossings, we found a case where orient tests say that the next crossing - * is on the SymEdge t, while intersecting with the ray from curco to v2. - * Find the intersection point and fill in the CrossData for that point. + * is on the #SymEdge t, while intersecting with the ray from \a curco to \a v2. + * Find the intersection point and fill in the #CrossData for that point. * It may turn out that when doing the intersection, we get an answer that says that * this case is better handled as through-vertex case instead, so we may do that. * In the latter case, we want to avoid a situation where the current crossing is on an edge @@ -1442,12 +1445,12 @@ static bool get_next_crossing_from_vert(CDT_state *cdt, } /** - * As part of finding the crossings of a ray to v2, find the next crossing after 'cd', assuming + * As part of finding the crossings of a ray to 'v2', find the next crossing after 'cd', assuming * 'cd' represents a crossing that goes through a an edge, not at either end of that edge. * - * We have the triangle vb-va-vc, where va and vb are the split edge and vc is the third vertex on - * that new side of the edge (should be closer to v2). The next crossing should be through vc or - * intersecting vb-vc or va-vc. + * We have the triangle 'vb-va-vc', where va and vb are the split edge and 'vc' is the third vertex + * on that new side of the edge (should be closer to v2). The next crossing should be through 'vc' + * or intersecting 'vb-vc' or 'va-vc'. */ static void get_next_crossing_from_edge(CDT_state *cdt, CrossData *cd, diff --git a/source/blender/blenlib/intern/dot_export.cc b/source/blender/blenlib/intern/dot_export.cc index a2cf843c473..ff39265d681 100644 --- a/source/blender/blenlib/intern/dot_export.cc +++ b/source/blender/blenlib/intern/dot_export.cc @@ -19,7 +19,7 @@ #include "BLI_dot_export.hh" namespace blender { -namespace DotExport { +namespace dot { /* Graph Building ************************************************/ @@ -237,7 +237,7 @@ void NodePort::to_dot_string(std::stringstream &ss) const { m_node->export__as_id(ss); if (m_port_name.has_value()) { - ss << ":" << m_port_name.value(); + ss << ":" << *m_port_name; } } @@ -301,5 +301,5 @@ NodeWithSocketsRef::NodeWithSocketsRef(Node &node, m_node->set_shape(Attr_shape::Rectangle); } -} // namespace DotExport +} // namespace dot } // namespace blender diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c index 556c0a65fc5..56529581dd3 100644 --- a/source/blender/blenlib/intern/edgehash.c +++ b/source/blender/blenlib/intern/edgehash.c @@ -376,7 +376,7 @@ bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value) * Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found. * * \param v0, v1: The key to remove. - * \param valfreefp: Optional callback to free the value. + * \param free_value: Optional callback to free the value. * \return true if \a key was removed from \a eh. */ bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_value) diff --git a/source/blender/blenlib/intern/math_bits_inline.c b/source/blender/blenlib/intern/math_bits_inline.c index 8f8f257f1e7..e7a7b17e1e4 100644 --- a/source/blender/blenlib/intern/math_bits_inline.c +++ b/source/blender/blenlib/intern/math_bits_inline.c @@ -63,7 +63,7 @@ MINLINE unsigned int bitscan_reverse_uint(unsigned int a) #ifdef _MSC_VER unsigned long clz; _BitScanReverse(&clz, a); - return clz; + return 31 - clz; #else return (unsigned int)__builtin_clz(a); #endif diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index e7c1fc8c2d9..d3dc4729617 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -3248,19 +3248,27 @@ bool isect_ray_aabb_v3_simple(const float orig[3], } } -/* find closest point to p on line through (l1, l2) and return lambda, - * where (0 <= lambda <= 1) when cp is in the line segment (l1, l2) +float closest_to_ray_v3(float r_close[3], + const float p[3], + const float ray_orig[3], + const float ray_dir[3]) +{ + float h[3], lambda; + sub_v3_v3v3(h, p, ray_orig); + lambda = dot_v3v3(ray_dir, h) / dot_v3v3(ray_dir, ray_dir); + madd_v3_v3v3fl(r_close, ray_orig, ray_dir, lambda); + return lambda; +} + +/** + * Find closest point to p on line through (l1, l2) and return lambda, + * where (0 <= lambda <= 1) when cp is in the line segment (l1, l2). */ float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]) { - float h[3], u[3], lambda; + float u[3]; sub_v3_v3v3(u, l2, l1); - sub_v3_v3v3(h, p, l1); - lambda = dot_v3v3(u, h) / dot_v3v3(u, u); - r_close[0] = l1[0] + u[0] * lambda; - r_close[1] = l1[1] + u[1] * lambda; - r_close[2] = l1[2] + u[2] * lambda; - return lambda; + return closest_to_ray_v3(r_close, p, l1, u); } float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]) diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 9e398239bc7..92cfd09f191 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -2388,6 +2388,22 @@ void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], con mat3_polar_decompose(A, U_A, P_A); mat3_polar_decompose(B, U_B, P_B); + /* Quaternions cannot represent an axis flip. If such a singularity is detected, choose a + * different decomposition of the matrix that still satisfies A = U_A * P_A but which has a + * positive determinant and thus no axis flips. This resolves T77154. + * + * Note that a flip of two axes is just a rotation of 180 degrees around the third axis, and + * three flipped axes are just an 180 degree rotation + a single axis flip. It is thus sufficient + * to solve this problem for single axis flips. */ + if (determinant_m3_array(U_A) < 0) { + mul_m3_fl(U_A, -1.0f); + mul_m3_fl(P_A, -1.0f); + } + if (determinant_m3_array(U_B) < 0) { + mul_m3_fl(U_B, -1.0f); + mul_m3_fl(P_B, -1.0f); + } + mat3_to_quat(quat_A, U_A); mat3_to_quat(quat_B, U_B); interp_qt_qtqt(quat, quat_A, quat_B, t); diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index a91cdabe3ab..a2f7cc24dd3 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -543,8 +543,8 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q * * \param q: input quaternion. * \param axis: twist axis in [0,1,2] - * \param r_swing[out]: if not NULL, receives the swing quaternion. - * \param r_twist[out]: if not NULL, receives the twist quaternion. + * \param r_swing: if not NULL, receives the swing quaternion. + * \param r_twist: if not NULL, receives the twist quaternion. * \returns twist angle. */ float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]) @@ -2127,7 +2127,7 @@ void mul_v3m3_dq(float co[3], float mat[3][3], DualQuat *dq) co[1] = (co[1] + t[1]) * len2; co[2] = (co[2] + t[2]) * len2; - /* compute crazyspace correction mat */ + /* Compute crazy-space correction matrix. */ if (mat) { if (dq->scale_weight) { copy_m3_m4(scalemat, dq->scale); diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index fbfb258693b..f2217b1cd1a 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -529,7 +529,7 @@ void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t * Return the text file data with: * - Newlines replaced with '\0'. - * - Optionally trim whitespace, replacing trailing ' ' & '\t' with '\0'. + * - Optionally trim white-space, replacing trailing <space> & <tab> with '\0'. * * This is an alternative to using #BLI_file_read_as_lines, * allowing us to loop over lines without converting it into a linked list diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 8495caa91b5..e4908eb7257 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -48,6 +48,18 @@ struct wmWindowManager; typedef struct BlendHandle BlendHandle; +typedef struct WorkspaceConfigFileData { + struct Main *main; /* has to be freed when done reading file data */ + + struct ListBase workspaces; +} WorkspaceConfigFileData; + +/* -------------------------------------------------------------------- */ +/** \name BLO Read File API + * + * \see #BLO_write_file for file writing. + * \{ */ + typedef enum eBlenFileType { BLENFILETYPE_BLEND = 1, /* BLENFILETYPE_PUB = 2, */ /* UNUSED */ @@ -69,12 +81,6 @@ typedef struct BlendFileData { eBlenFileType type; } BlendFileData; -typedef struct WorkspaceConfigFileData { - struct Main *main; /* has to be freed when done reading file data */ - - struct ListBase workspaces; -} WorkspaceConfigFileData; - struct BlendFileReadParams { uint skip_flags : 3; /* eBLOReadSkip */ uint is_startup : 1; @@ -108,6 +114,12 @@ BlendFileData *BLO_read_from_memfile(struct Main *oldmain, void BLO_blendfiledata_free(BlendFileData *bfd); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BLO Blend File Handle API + * \{ */ + BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct ReportList *reports); BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize); @@ -119,7 +131,7 @@ struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh); void BLO_blendhandle_close(BlendHandle *bh); -/***/ +/** \} */ #define BLO_GROUP_MAX 32 #define BLO_EMBEDDED_STARTUP_BLEND "<startup.blend>" diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h index d83abf7f9ed..8fe04e764f9 100644 --- a/source/blender/blenloader/BLO_writefile.h +++ b/source/blender/blenloader/BLO_writefile.h @@ -30,14 +30,48 @@ struct Main; struct MemFile; struct ReportList; +/* -------------------------------------------------------------------- */ +/** \name BLO Write File API + * + * \see #BLO_read_from_file for file reading. + * \{ */ + +/** + * Adjust paths when saving (kept unless #BlendFileWriteParams.use_save_as_copy is set). + */ +typedef enum eBLO_WritePathRemap { + /** No path manipulation. */ + BLO_WRITE_PATH_REMAP_NONE = 0, + /** Remap existing relative paths (default). */ + BLO_WRITE_PATH_REMAP_RELATIVE = 1, + /** Remap paths making all paths relative to the new location. */ + BLO_WRITE_PATH_REMAP_RELATIVE_ALL = 2, + /** Make all paths absolute. */ + BLO_WRITE_PATH_REMAP_ABSOLUTE = 3, +} eBLO_WritePathRemap; + +/** Similar to #BlendFileReadParams. */ +struct BlendFileWriteParams { + eBLO_WritePathRemap remap_mode; + /** Save `.blend1`, `.blend2`... etc. */ + uint use_save_versions : 1; + /** On write, restore paths after editing them (see #BLO_WRITE_PATH_REMAP_RELATIVE). */ + uint use_save_as_copy : 1; + uint use_userdef : 1; + const struct BlendThumbnail *thumb; +}; + extern bool BLO_write_file(struct Main *mainvar, const char *filepath, - int write_flags, - struct ReportList *reports, - const struct BlendThumbnail *thumb); + const int write_flags, + const struct BlendFileWriteParams *params, + struct ReportList *reports); + extern bool BLO_write_file_mem(struct Main *mainvar, struct MemFile *compare, struct MemFile *current, int write_flags); +/** \} */ + #endif diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c index 33c5e3ac197..0a5d8d332aa 100644 --- a/source/blender/blenloader/intern/blend_validate.c +++ b/source/blender/blenloader/intern/blend_validate.c @@ -70,7 +70,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) RPT_ERROR, "ID %s is in local database while being linked from library %s!", id->name, - id->lib->name); + id->lib->filepath); } } } @@ -82,15 +82,15 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) continue; } - BKE_library_filepath_set(bmain, curlib, curlib->name); - BlendHandle *bh = BLO_blendhandle_from_file(curlib->filepath, reports); + BKE_library_filepath_set(bmain, curlib, curlib->filepath); + BlendHandle *bh = BLO_blendhandle_from_file(curlib->filepath_abs, reports); if (bh == NULL) { BKE_reportf(reports, RPT_ERROR, "Library ID %s not found at expected path %s!", curlib->id.name, - curlib->filepath); + curlib->filepath_abs); continue; } @@ -107,7 +107,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) RPT_ERROR, "Library ID %s in library %s, this should not happen!", id->name, - curlib->name); + curlib->filepath); continue; } @@ -120,7 +120,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) RPT_ERROR, "ID %s has NULL lib pointer while being in library %s!", id->name, - curlib->name); + curlib->filepath); continue; } if (id->lib != curlib) { @@ -143,7 +143,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) RPT_ERROR, "ID %s not found in library %s anymore!", id->name, - id->lib->name); + id->lib->filepath); continue; } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d7c8dbabcea..9a5f6ac6bbc 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -121,6 +121,7 @@ #include "BKE_colortools.h" #include "BKE_constraint.h" #include "BKE_curve.h" +#include "BKE_curveprofile.h" #include "BKE_effect.h" #include "BKE_fcurve_driver.h" #include "BKE_fluid.h" @@ -261,10 +262,10 @@ static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const static BHead *find_bhead_from_idname(FileData *fd, const char *idname); #ifdef USE_COLLECTION_COMPAT_28 -static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc); +static void expand_scene_collection(BlendExpander *expander, SceneCollection *sc); #endif static void direct_link_animdata(BlendDataReader *reader, AnimData *adt); -static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt); +static void lib_link_animdata(BlendLibReader *reader, ID *id, AnimData *adt); typedef struct BHeadN { struct BHeadN *next, *prev; @@ -313,7 +314,7 @@ void blo_reportf_wrap(ReportList *reports, ReportType type, const char *format, /* for reporting linking messages */ static const char *library_parent_filepath(Library *lib) { - return lib->parent ? lib->parent->filepath : "<direct>"; + return lib->parent ? lib->parent->filepath_abs : "<direct>"; } /* -------------------------------------------------------------------- */ @@ -676,7 +677,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab // printf("blo_find_main: converted to %s\n", name1); for (m = mainlist->first; m; m = m->next) { - const char *libname = (m->curlib) ? m->curlib->filepath : m->name; + const char *libname = (m->curlib) ? m->curlib->filepath_abs : m->name; if (BLI_path_cmp(name1, libname) == 0) { if (G.debug & G_DEBUG) { @@ -699,8 +700,8 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab /* Matches direct_link_library(). */ id_us_ensure_real(&lib->id); - BLI_strncpy(lib->name, filepath, sizeof(lib->name)); - BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath)); + BLI_strncpy(lib->filepath, filepath, sizeof(lib->filepath)); + BLI_strncpy(lib->filepath_abs, name1, sizeof(lib->filepath_abs)); m->curlib = lib; @@ -2454,7 +2455,7 @@ static void link_glob_list(FileData *fd, ListBase *lb) /* for glob data */ * \{ */ static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader); -static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd); +static void IDP_LibLinkProperty(IDProperty *prop, BlendLibReader *reader); static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader) { @@ -2590,7 +2591,7 @@ static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, } } -static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd) +static void IDP_LibLinkProperty(IDProperty *prop, BlendLibReader *reader) { if (!prop) { return; @@ -2599,7 +2600,7 @@ static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd) switch (prop->type) { case IDP_ID: /* PointerProperty */ { - void *newaddr = newlibadr(fd, NULL, IDP_Id(prop)); + void *newaddr = BLO_read_get_new_id_address(reader, NULL, IDP_Id(prop)); if (IDP_Id(prop) && !newaddr && G.debug) { printf("Error while loading \"%s\". Data not found in file!\n", prop->name); } @@ -2610,14 +2611,14 @@ static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd) { IDProperty *idp_array = IDP_IDPArray(prop); for (int i = 0; i < prop->len; i++) { - IDP_LibLinkProperty(&(idp_array[i]), fd); + IDP_LibLinkProperty(&(idp_array[i]), reader); } break; } case IDP_GROUP: /* PointerProperty */ { LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { - IDP_LibLinkProperty(loop, fd); + IDP_LibLinkProperty(loop, reader); } break; } @@ -2657,45 +2658,46 @@ static PreviewImage *direct_link_preview_image(BlendDataReader *reader, PreviewI /** \name Read ID * \{ */ -static void lib_link_id(FileData *fd, Main *bmain, ID *id); -static void lib_link_nodetree(FileData *fd, Main *bmain, bNodeTree *ntree); -static void lib_link_collection(FileData *fd, Main *bmain, Collection *collection); +static void lib_link_id(BlendLibReader *reader, ID *id); +static void lib_link_nodetree(BlendLibReader *reader, bNodeTree *ntree); +static void lib_link_collection(BlendLibReader *reader, Collection *collection); -static void lib_link_id_embedded_id(FileData *fd, Main *bmain, ID *id) +static void lib_link_id_embedded_id(BlendLibReader *reader, ID *id) { + /* Handle 'private IDs'. */ bNodeTree *nodetree = ntreeFromID(id); if (nodetree != NULL) { - lib_link_id(fd, bmain, &nodetree->id); - lib_link_nodetree(fd, bmain, nodetree); + lib_link_id(reader, &nodetree->id); + lib_link_nodetree(reader, nodetree); } if (GS(id->name) == ID_SCE) { Scene *scene = (Scene *)id; if (scene->master_collection != NULL) { - lib_link_id(fd, bmain, &scene->master_collection->id); - lib_link_collection(fd, bmain, scene->master_collection); + lib_link_id(reader, &scene->master_collection->id); + lib_link_collection(reader, scene->master_collection); } } } -static void lib_link_id(FileData *fd, Main *bmain, ID *id) +static void lib_link_id(BlendLibReader *reader, ID *id) { /* Note: WM IDProperties are never written to file, hence they should always be NULL here. */ BLI_assert((GS(id->name) != ID_WM) || id->properties == NULL); - IDP_LibLinkProperty(id->properties, fd); + IDP_LibLinkProperty(id->properties, reader); AnimData *adt = BKE_animdata_from_id(id); if (adt != NULL) { - lib_link_animdata(fd, id, adt); + lib_link_animdata(reader, id, adt); } if (id->override_library) { - id->override_library->reference = newlibadr(fd, id->lib, id->override_library->reference); - id->override_library->storage = newlibadr(fd, id->lib, id->override_library->storage); + BLO_read_id_address(reader, id->lib, &id->override_library->reference); + BLO_read_id_address(reader, id->lib, &id->override_library->storage); } - lib_link_id_embedded_id(fd, bmain, id); + lib_link_id_embedded_id(reader, id); } static void direct_link_id_override_property_operation_cb(BlendDataReader *reader, void *data) @@ -2890,58 +2892,23 @@ static void direct_link_id_common( /** \} */ /* -------------------------------------------------------------------- */ -/** \name Read CurveMapping - * \{ */ - -/* cuma itself has been read! */ -static void direct_link_curvemapping(BlendDataReader *reader, CurveMapping *cumap) -{ - int a; - - /* flag seems to be able to hang? Maybe old files... not bad to clear anyway */ - cumap->flag &= ~CUMA_PREMULLED; - - for (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; - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Read CurveProfile - * \{ */ - -static void direct_link_curveprofile(BlendDataReader *reader, CurveProfile *profile) -{ - BLO_read_data_address(reader, &profile->path); - profile->table = NULL; - profile->segments = NULL; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Read ID: Brush * \{ */ /* library brush linking after fileread */ -static void lib_link_brush(FileData *fd, Main *UNUSED(bmain), Brush *brush) +static void lib_link_brush(BlendLibReader *reader, Brush *brush) { /* brush->(mask_)mtex.obj is ignored on purpose? */ - brush->mtex.tex = newlibadr(fd, brush->id.lib, brush->mtex.tex); - brush->mask_mtex.tex = newlibadr(fd, brush->id.lib, brush->mask_mtex.tex); - brush->clone.image = newlibadr(fd, brush->id.lib, brush->clone.image); - brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush); - brush->paint_curve = newlibadr(fd, brush->id.lib, brush->paint_curve); + BLO_read_id_address(reader, brush->id.lib, &brush->mtex.tex); + BLO_read_id_address(reader, brush->id.lib, &brush->mask_mtex.tex); + BLO_read_id_address(reader, brush->id.lib, &brush->clone.image); + BLO_read_id_address(reader, brush->id.lib, &brush->toggle_brush); + BLO_read_id_address(reader, brush->id.lib, &brush->paint_curve); /* link default grease pencil palette */ if (brush->gpencil_settings != NULL) { if (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) { - brush->gpencil_settings->material = newlibadr( - fd, brush->id.lib, brush->gpencil_settings->material); + BLO_read_id_address(reader, brush->id.lib, &brush->gpencil_settings->material); if (!brush->gpencil_settings->material) { brush->gpencil_settings->flag &= ~GP_BRUSH_MATERIAL_PINNED; @@ -2963,7 +2930,7 @@ static void direct_link_brush(BlendDataReader *reader, Brush *brush) BLO_read_data_address(reader, &brush->gradient); if (brush->curve) { - direct_link_curvemapping(reader, brush->curve); + BKE_curvemapping_blend_read(reader, brush->curve); } else { BKE_brush_curve_preset(brush, CURVE_PRESET_SHARP); @@ -2984,39 +2951,39 @@ static void direct_link_brush(BlendDataReader *reader, Brush *brush) BLO_read_data_address(reader, &brush->gpencil_settings->curve_rand_value); if (brush->gpencil_settings->curve_sensitivity) { - direct_link_curvemapping(reader, brush->gpencil_settings->curve_sensitivity); + BKE_curvemapping_blend_read(reader, brush->gpencil_settings->curve_sensitivity); } if (brush->gpencil_settings->curve_strength) { - direct_link_curvemapping(reader, brush->gpencil_settings->curve_strength); + BKE_curvemapping_blend_read(reader, brush->gpencil_settings->curve_strength); } if (brush->gpencil_settings->curve_jitter) { - direct_link_curvemapping(reader, brush->gpencil_settings->curve_jitter); + BKE_curvemapping_blend_read(reader, brush->gpencil_settings->curve_jitter); } if (brush->gpencil_settings->curve_rand_pressure) { - direct_link_curvemapping(reader, brush->gpencil_settings->curve_rand_pressure); + BKE_curvemapping_blend_read(reader, brush->gpencil_settings->curve_rand_pressure); } if (brush->gpencil_settings->curve_rand_strength) { - direct_link_curvemapping(reader, brush->gpencil_settings->curve_rand_strength); + BKE_curvemapping_blend_read(reader, brush->gpencil_settings->curve_rand_strength); } if (brush->gpencil_settings->curve_rand_uv) { - direct_link_curvemapping(reader, brush->gpencil_settings->curve_rand_uv); + BKE_curvemapping_blend_read(reader, brush->gpencil_settings->curve_rand_uv); } if (brush->gpencil_settings->curve_rand_hue) { - direct_link_curvemapping(reader, brush->gpencil_settings->curve_rand_hue); + BKE_curvemapping_blend_read(reader, brush->gpencil_settings->curve_rand_hue); } if (brush->gpencil_settings->curve_rand_saturation) { - direct_link_curvemapping(reader, brush->gpencil_settings->curve_rand_saturation); + BKE_curvemapping_blend_read(reader, brush->gpencil_settings->curve_rand_saturation); } if (brush->gpencil_settings->curve_rand_value) { - direct_link_curvemapping(reader, brush->gpencil_settings->curve_rand_value); + BKE_curvemapping_blend_read(reader, brush->gpencil_settings->curve_rand_value); } } @@ -3030,7 +2997,7 @@ static void direct_link_brush(BlendDataReader *reader, Brush *brush) /** \name Read ID: Palette * \{ */ -static void lib_link_palette(FileData *UNUSED(fd), Main *UNUSED(bmain), Palette *UNUSED(palette)) +static void lib_link_palette(BlendLibReader *UNUSED(reader), Palette *UNUSED(palette)) { } @@ -3041,7 +3008,7 @@ static void direct_link_palette(BlendDataReader *reader, Palette *palette) BLO_read_list(reader, &palette->colors); } -static void lib_link_paint_curve(FileData *UNUSED(fd), Main *UNUSED(bmain), PaintCurve *UNUSED(pc)) +static void lib_link_paint_curve(BlendLibReader *UNUSED(reader), PaintCurve *UNUSED(pc)) { } @@ -3080,11 +3047,11 @@ static PackedFile *direct_link_packedfile(BlendDataReader *reader, PackedFile *o * \{ */ // XXX deprecated - old animation system -static void lib_link_ipo(FileData *fd, Main *UNUSED(bmain), Ipo *ipo) +static void lib_link_ipo(BlendLibReader *reader, Ipo *ipo) { LISTBASE_FOREACH (IpoCurve *, icu, &ipo->curve) { if (icu->driver) { - icu->driver->ob = newlibadr(fd, ipo->id.lib, icu->driver->ob); + BLO_read_id_address(reader, ipo->id.lib, &icu->driver->ob); } } } @@ -3104,17 +3071,17 @@ static void direct_link_ipo(BlendDataReader *reader, Ipo *ipo) } // XXX deprecated - old animation system -static void lib_link_nlastrips(FileData *fd, ID *id, ListBase *striplist) +static void lib_link_nlastrips(BlendLibReader *reader, ID *id, ListBase *striplist) { bActionStrip *strip; bActionModifier *amod; for (strip = striplist->first; strip; strip = strip->next) { - strip->object = newlibadr(fd, id->lib, strip->object); - strip->act = newlibadr(fd, id->lib, strip->act); - strip->ipo = newlibadr(fd, id->lib, strip->ipo); + BLO_read_id_address(reader, id->lib, &strip->object); + BLO_read_id_address(reader, id->lib, &strip->act); + BLO_read_id_address(reader, id->lib, &strip->ipo); for (amod = strip->modifiers.first; amod; amod = amod->next) { - amod->ob = newlibadr(fd, id->lib, amod->ob); + BLO_read_id_address(reader, id->lib, &amod->ob); } } } @@ -3132,12 +3099,12 @@ static void direct_link_nlastrips(BlendDataReader *reader, ListBase *strips) } // XXX deprecated - old animation system -static void lib_link_constraint_channels(FileData *fd, ID *id, ListBase *chanbase) +static void lib_link_constraint_channels(BlendLibReader *reader, ID *id, ListBase *chanbase) { bConstraintChannel *chan; for (chan = chanbase->first; chan; chan = chan->next) { - chan->ipo = newlibadr(fd, id->lib, chan->ipo); + BLO_read_id_address(reader, id->lib, &chan->ipo); } } @@ -3147,7 +3114,7 @@ static void lib_link_constraint_channels(FileData *fd, ID *id, ListBase *chanbas /** \name Read ID: Action * \{ */ -static void lib_link_fmodifiers(FileData *fd, ID *id, ListBase *list) +static void lib_link_fmodifiers(BlendLibReader *reader, ID *id, ListBase *list) { FModifier *fcm; @@ -3156,7 +3123,7 @@ static void lib_link_fmodifiers(FileData *fd, ID *id, ListBase *list) switch (fcm->type) { case FMODIFIER_TYPE_PYTHON: { FMod_Python *data = (FMod_Python *)fcm->data; - data->script = newlibadr(fd, id->lib, data->script); + BLO_read_id_address(reader, id->lib, &data->script); break; } @@ -3164,7 +3131,7 @@ static void lib_link_fmodifiers(FileData *fd, ID *id, ListBase *list) } } -static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list) +static void lib_link_fcurves(BlendLibReader *reader, ID *id, ListBase *list) { FCurve *fcu; @@ -3183,7 +3150,7 @@ static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list) DRIVER_TARGETS_LOOPER_BEGIN (dvar) { /* only relink if still used */ if (tarIndex < dvar->num_targets) { - dtar->id = newlibadr(fd, id->lib, dtar->id); + BLO_read_id_address(reader, id->lib, &dtar->id); } else { dtar->id = NULL; @@ -3194,7 +3161,7 @@ static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list) } /* modifiers */ - lib_link_fmodifiers(fd, id, &fcu->modifiers); + lib_link_fmodifiers(reader, id, &fcu->modifiers); } } @@ -3294,20 +3261,20 @@ static void direct_link_fcurves(BlendDataReader *reader, ListBase *list) } } -static void lib_link_action(FileData *fd, Main *UNUSED(bmain), bAction *act) +static void lib_link_action(BlendLibReader *reader, bAction *act) { // XXX deprecated - old animation system <<< LISTBASE_FOREACH (bActionChannel *, chan, &act->chanbase) { - chan->ipo = newlibadr(fd, act->id.lib, chan->ipo); - lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels); + BLO_read_id_address(reader, act->id.lib, &chan->ipo); + lib_link_constraint_channels(reader, &act->id, &chan->constraintChannels); } // >>> XXX deprecated - old animation system - lib_link_fcurves(fd, &act->id, &act->curves); + lib_link_fcurves(reader, &act->id, &act->curves); LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { if (marker->camera) { - marker->camera = newlibadr(fd, act->id.lib, marker->camera); + BLO_read_id_address(reader, act->id.lib, &marker->camera); } } } @@ -3338,29 +3305,29 @@ static void direct_link_action(BlendDataReader *reader, bAction *act) } } -static void lib_link_nladata_strips(FileData *fd, ID *id, ListBase *list) +static void lib_link_nladata_strips(BlendLibReader *reader, ID *id, ListBase *list) { NlaStrip *strip; for (strip = list->first; strip; strip = strip->next) { /* check strip's children */ - lib_link_nladata_strips(fd, id, &strip->strips); + lib_link_nladata_strips(reader, id, &strip->strips); /* check strip's F-Curves */ - lib_link_fcurves(fd, id, &strip->fcurves); + lib_link_fcurves(reader, id, &strip->fcurves); /* reassign the counted-reference to action */ - strip->act = newlibadr(fd, id->lib, strip->act); + BLO_read_id_address(reader, id->lib, &strip->act); } } -static void lib_link_nladata(FileData *fd, ID *id, ListBase *list) +static void lib_link_nladata(BlendLibReader *reader, ID *id, ListBase *list) { NlaTrack *nlt; /* we only care about the NLA strips inside the tracks */ for (nlt = list->first; nlt; nlt = nlt->next) { - lib_link_nladata_strips(fd, id, &nlt->strips); + lib_link_nladata_strips(reader, id, &nlt->strips); } } @@ -3402,7 +3369,7 @@ static void direct_link_nladata(BlendDataReader *reader, ListBase *list) /* ------- */ -static void lib_link_keyingsets(FileData *fd, ID *id, ListBase *list) +static void lib_link_keyingsets(BlendLibReader *reader, ID *id, ListBase *list) { KeyingSet *ks; KS_Path *ksp; @@ -3410,7 +3377,7 @@ static void lib_link_keyingsets(FileData *fd, ID *id, ListBase *list) /* here, we're only interested in the ID pointer stored in some of the paths */ for (ks = list->first; ks; ks = ks->next) { for (ksp = ks->paths.first; ksp; ksp = ksp->next) { - ksp->id = newlibadr(fd, id->lib, ksp->id); + BLO_read_id_address(reader, id->lib, &ksp->id); } } } @@ -3435,23 +3402,23 @@ static void direct_link_keyingsets(BlendDataReader *reader, ListBase *list) /* ------- */ -static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt) +static void lib_link_animdata(BlendLibReader *reader, ID *id, AnimData *adt) { if (adt == NULL) { return; } /* link action data */ - adt->action = newlibadr(fd, id->lib, adt->action); - adt->tmpact = newlibadr(fd, id->lib, adt->tmpact); + BLO_read_id_address(reader, id->lib, &adt->action); + BLO_read_id_address(reader, id->lib, &adt->tmpact); /* link drivers */ - lib_link_fcurves(fd, id, &adt->drivers); + lib_link_fcurves(reader, id, &adt->drivers); /* overrides don't have lib-link for now, so no need to do anything */ /* link NLA-data */ - lib_link_nladata(fd, id, &adt->nla_tracks); + lib_link_nladata(reader, id, &adt->nla_tracks); } static void direct_link_animdata(BlendDataReader *reader, AnimData *adt) @@ -3489,9 +3456,7 @@ static void direct_link_animdata(BlendDataReader *reader, AnimData *adt) /** \name Read ID: CacheFiles * \{ */ -static void lib_link_cachefiles(FileData *UNUSED(fd), - Main *UNUSED(bmain), - CacheFile *UNUSED(cache_file)) +static void lib_link_cachefiles(BlendLibReader *UNUSED(reader), CacheFile *UNUSED(cache_file)) { } @@ -3513,26 +3478,26 @@ static void direct_link_cachefile(BlendDataReader *reader, CacheFile *cache_file /** \name Read ID: WorkSpace * \{ */ -static void lib_link_workspaces(FileData *fd, Main *bmain, WorkSpace *workspace) +static void lib_link_workspaces(BlendLibReader *reader, WorkSpace *workspace) { ID *id = (ID *)workspace; LISTBASE_FOREACH_MUTABLE (WorkSpaceLayout *, layout, &workspace->layouts) { - layout->screen = newlibadr(fd, id->lib, layout->screen); + BLO_read_id_address(reader, id->lib, &layout->screen); if (layout->screen) { if (ID_IS_LINKED(id)) { layout->screen->winid = 0; if (layout->screen->temp) { /* delete temp layouts when appending */ - BKE_workspace_layout_remove(bmain, workspace, layout); + BKE_workspace_layout_remove(reader->main, workspace, layout); } } } else { /* If we're reading a layout without screen stored, it's useless and we shouldn't keep it * around. */ - BKE_workspace_layout_remove(bmain, workspace, layout); + BKE_workspace_layout_remove(reader->main, workspace, layout); } } } @@ -3569,10 +3534,13 @@ static void direct_link_workspace(BlendDataReader *reader, WorkSpace *workspace, id_us_ensure_real(&workspace->id); } -static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook *hook, ID *id) +static void lib_link_workspace_instance_hook(BlendLibReader *reader, + WorkSpaceInstanceHook *hook, + ID *id) { WorkSpace *workspace = BKE_workspace_active_get(hook); - BKE_workspace_active_set(hook, newlibadr(fd, id->lib, workspace)); + BLO_read_id_address(reader, id->lib, &workspace); + BKE_workspace_active_set(hook, workspace); } /** \} */ @@ -3581,19 +3549,19 @@ static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook /** \name Read ID: Node Tree * \{ */ -static void lib_link_node_socket(FileData *fd, Library *lib, bNodeSocket *sock) +static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSocket *sock) { - IDP_LibLinkProperty(sock->prop, fd); + IDP_LibLinkProperty(sock->prop, reader); switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { bNodeSocketValueObject *default_value = sock->default_value; - default_value->value = newlibadr(fd, lib, default_value->value); + BLO_read_id_address(reader, lib, &default_value->value); break; } case SOCK_IMAGE: { bNodeSocketValueImage *default_value = sock->default_value; - default_value->value = newlibadr(fd, lib, default_value->value); + BLO_read_id_address(reader, lib, &default_value->value); break; } case SOCK_FLOAT: @@ -3613,33 +3581,33 @@ static void lib_link_node_socket(FileData *fd, Library *lib, bNodeSocket *sock) } } -static void lib_link_node_sockets(FileData *fd, Library *lib, ListBase *sockets) +static void lib_link_node_sockets(BlendLibReader *reader, Library *lib, ListBase *sockets) { LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { - lib_link_node_socket(fd, lib, sock); + lib_link_node_socket(reader, lib, sock); } } /* Single node tree (also used for material/scene trees), ntree is not NULL */ -static void lib_link_ntree(FileData *fd, Library *lib, bNodeTree *ntree) +static void lib_link_ntree(BlendLibReader *reader, Library *lib, bNodeTree *ntree) { ntree->id.lib = lib; - ntree->gpd = newlibadr(fd, lib, ntree->gpd); + BLO_read_id_address(reader, lib, &ntree->gpd); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - IDP_LibLinkProperty(node->prop, fd); + IDP_LibLinkProperty(node->prop, reader); - node->id = newlibadr(fd, lib, node->id); + BLO_read_id_address(reader, lib, &node->id); - lib_link_node_sockets(fd, lib, &node->inputs); - lib_link_node_sockets(fd, lib, &node->outputs); + lib_link_node_sockets(reader, lib, &node->inputs); + lib_link_node_sockets(reader, lib, &node->outputs); } - lib_link_node_sockets(fd, lib, &ntree->inputs); - lib_link_node_sockets(fd, lib, &ntree->outputs); + lib_link_node_sockets(reader, lib, &ntree->inputs); + lib_link_node_sockets(reader, lib, &ntree->outputs); /* Set node->typeinfo pointers. This is done in lib linking, after the * first versioning that can change types still without functions that @@ -3649,7 +3617,7 @@ static void lib_link_ntree(FileData *fd, Library *lib, bNodeTree *ntree) /* For nodes with static socket layout, add/remove sockets as needed * to match the static layout. */ - if (fd->memfile == NULL) { + if (reader->fd->memfile == NULL) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { node_verify_socket_templates(ntree, node); } @@ -3657,9 +3625,9 @@ static void lib_link_ntree(FileData *fd, Library *lib, bNodeTree *ntree) } /* library ntree linking after fileread */ -static void lib_link_nodetree(FileData *fd, Main *UNUSED(bmain), bNodeTree *ntree) +static void lib_link_nodetree(BlendLibReader *reader, bNodeTree *ntree) { - lib_link_ntree(fd, ntree->id.lib, ntree); + lib_link_ntree(reader, ntree->id.lib, ntree); } static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) @@ -3729,7 +3697,7 @@ static void direct_link_nodetree(BlendDataReader *reader, bNodeTree *ntree) case CMP_NODE_HUECORRECT: case TEX_NODE_CURVE_RGB: case TEX_NODE_CURVE_TIME: { - direct_link_curvemapping(reader, node->storage); + BKE_curvemapping_blend_read(reader, node->storage); break; } case SH_NODE_SCRIPT: { @@ -3845,7 +3813,7 @@ static void direct_link_nodetree(BlendDataReader *reader, bNodeTree *ntree) /* temp struct used to transport needed info to lib_link_constraint_cb() */ typedef struct tConstraintLinkData { - FileData *fd; + BlendLibReader *reader; ID *id; } tConstraintLinkData; /* callback function used to relink constraint ID-links */ @@ -3855,10 +3823,10 @@ static void lib_link_constraint_cb(bConstraint *UNUSED(con), void *userdata) { tConstraintLinkData *cld = (tConstraintLinkData *)userdata; - *idpoin = newlibadr(cld->fd, cld->id->lib, *idpoin); + BLO_read_id_address(cld->reader, cld->id->lib, idpoin); } -static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) +static void lib_link_constraints(BlendLibReader *reader, ID *id, ListBase *conlist) { tConstraintLinkData cld; bConstraint *con; @@ -3871,7 +3839,7 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) con->type = CONSTRAINT_TYPE_NULL; } /* own ipo, all constraints have it */ - con->ipo = newlibadr(fd, id->lib, con->ipo); // XXX deprecated - old animation system + BLO_read_id_address(reader, id->lib, &con->ipo); // XXX deprecated - old animation system /* If linking from a library, clear 'local' library override flag. */ if (id->lib != NULL) { @@ -3880,7 +3848,7 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) } /* relink all ID-blocks used by the constraints */ - cld.fd = fd; + cld.reader = reader; cld.id = id; BKE_constraints_id_loop(conlist, lib_link_constraint_cb, &cld); @@ -3943,7 +3911,7 @@ static void direct_link_constraints(BlendDataReader *reader, ListBase *lb) } } -static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) +static void lib_link_pose(BlendLibReader *reader, Object *ob, bPose *pose) { bArmature *arm = ob->data; @@ -3954,7 +3922,7 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) /* always rebuild to match proxy or lib changes, but on Undo */ bool rebuild = false; - if (fd->memfile == NULL) { + if (reader->fd->memfile == NULL) { if (ob->proxy || ob->id.lib != arm->id.lib) { rebuild = true; } @@ -3976,13 +3944,13 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) } LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { - lib_link_constraints(fd, (ID *)ob, &pchan->constraints); + lib_link_constraints(reader, (ID *)ob, &pchan->constraints); pchan->bone = BKE_armature_find_bone_name(arm, pchan->name); - IDP_LibLinkProperty(pchan->prop, fd); + IDP_LibLinkProperty(pchan->prop, reader); - pchan->custom = newlibadr(fd, arm->id.lib, pchan->custom); + BLO_read_id_address(reader, arm->id.lib, &pchan->custom); if (UNLIKELY(pchan->bone == NULL)) { rebuild = true; } @@ -3995,24 +3963,24 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) if (rebuild) { DEG_id_tag_update_ex( - bmain, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - BKE_pose_tag_recalc(bmain, pose); + reader->main, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + BKE_pose_tag_recalc(reader->main, pose); } } -static void lib_link_bones(FileData *fd, Bone *bone) +static void lib_link_bones(BlendLibReader *reader, Bone *bone) { - IDP_LibLinkProperty(bone->prop, fd); + IDP_LibLinkProperty(bone->prop, reader); LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) { - lib_link_bones(fd, curbone); + lib_link_bones(reader, curbone); } } -static void lib_link_armature(FileData *fd, Main *UNUSED(bmain), bArmature *arm) +static void lib_link_armature(BlendLibReader *reader, bArmature *arm) { LISTBASE_FOREACH (Bone *, curbone, &arm->bonebase) { - lib_link_bones(fd, curbone); + lib_link_bones(reader, curbone); } } @@ -4065,16 +4033,16 @@ static void direct_link_armature(BlendDataReader *reader, bArmature *arm) /** \name Read ID: Camera * \{ */ -static void lib_link_camera(FileData *fd, Main *UNUSED(bmain), Camera *ca) +static void lib_link_camera(BlendLibReader *reader, Camera *ca) { - ca->ipo = newlibadr(fd, ca->id.lib, ca->ipo); /* deprecated, for versioning */ + BLO_read_id_address(reader, ca->id.lib, &ca->ipo); /* deprecated, for versioning */ - ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob); /* deprecated, for versioning */ - ca->dof.focus_object = newlibadr(fd, ca->id.lib, ca->dof.focus_object); + BLO_read_id_address(reader, ca->id.lib, &ca->dof_ob); /* deprecated, for versioning */ + BLO_read_id_address(reader, ca->id.lib, &ca->dof.focus_object); LISTBASE_FOREACH (CameraBGImage *, bgpic, &ca->bg_images) { - bgpic->ima = newlibadr(fd, ca->id.lib, bgpic->ima); - bgpic->clip = newlibadr(fd, ca->id.lib, bgpic->clip); + BLO_read_id_address(reader, ca->id.lib, &bgpic->ima); + BLO_read_id_address(reader, ca->id.lib, &bgpic->clip); } } @@ -4097,9 +4065,9 @@ static void direct_link_camera(BlendDataReader *reader, Camera *ca) /** \name Read ID: Light * \{ */ -static void lib_link_light(FileData *fd, Main *UNUSED(bmain), Light *la) +static void lib_link_light(BlendLibReader *reader, Light *la) { - la->ipo = newlibadr(fd, la->id.lib, la->ipo); // XXX deprecated - old animation system + BLO_read_id_address(reader, la->id.lib, &la->ipo); // XXX deprecated - old animation system } static void direct_link_light(BlendDataReader *reader, Light *la) @@ -4109,7 +4077,7 @@ static void direct_link_light(BlendDataReader *reader, Light *la) BLO_read_data_address(reader, &la->curfalloff); if (la->curfalloff) { - direct_link_curvemapping(reader, la->curfalloff); + BKE_curvemapping_blend_read(reader, la->curfalloff); } la->preview = direct_link_preview_image(reader, la->preview); @@ -4131,12 +4099,12 @@ void blo_do_versions_key_uidgen(Key *key) } } -static void lib_link_key(FileData *fd, Main *UNUSED(bmain), Key *key) +static void lib_link_key(BlendLibReader *reader, Key *key) { BLI_assert((key->id.tag & LIB_TAG_EXTERN) == 0); - key->ipo = newlibadr(fd, key->id.lib, key->ipo); // XXX deprecated - old animation system - key->from = newlibadr(fd, key->id.lib, key->from); + BLO_read_id_address(reader, key->id.lib, &key->ipo); // XXX deprecated - old animation system + BLO_read_id_address(reader, key->id.lib, &key->from); } static void switch_endian_keyblock(Key *key, KeyBlock *kb) @@ -4194,13 +4162,13 @@ static void direct_link_key(BlendDataReader *reader, Key *key) /** \name Read ID: Meta Ball * \{ */ -static void lib_link_mball(FileData *fd, Main *UNUSED(bmain), MetaBall *mb) +static void lib_link_mball(BlendLibReader *reader, MetaBall *mb) { for (int a = 0; a < mb->totcol; a++) { - mb->mat[a] = newlibadr(fd, mb->id.lib, mb->mat[a]); + BLO_read_id_address(reader, mb->id.lib, &mb->mat[a]); } - mb->ipo = newlibadr(fd, mb->id.lib, mb->ipo); // XXX deprecated - old animation system + BLO_read_id_address(reader, mb->id.lib, &mb->ipo); // XXX deprecated - old animation system } static void direct_link_mball(BlendDataReader *reader, MetaBall *mb) @@ -4227,9 +4195,9 @@ static void direct_link_mball(BlendDataReader *reader, MetaBall *mb) /** \name Read ID: World * \{ */ -static void lib_link_world(FileData *fd, Main *UNUSED(bmain), World *wrld) +static void lib_link_world(BlendLibReader *reader, World *wrld) { - wrld->ipo = newlibadr(fd, wrld->id.lib, wrld->ipo); // XXX deprecated - old animation system + BLO_read_id_address(reader, wrld->id.lib, &wrld->ipo); // XXX deprecated - old animation system } static void direct_link_world(BlendDataReader *reader, World *wrld) @@ -4247,7 +4215,7 @@ static void direct_link_world(BlendDataReader *reader, World *wrld) /** \name Read ID: VFont * \{ */ -static void lib_link_vfont(FileData *UNUSED(fd), Main *UNUSED(bmain), VFont *UNUSED(vf)) +static void lib_link_vfont(BlendLibReader *UNUSED(reader), VFont *UNUSED(vf)) { } @@ -4264,7 +4232,7 @@ static void direct_link_vfont(BlendDataReader *reader, VFont *vf) /** \name Read ID: Text * \{ */ -static void lib_link_text(FileData *UNUSED(fd), Main *UNUSED(bmain), Text *UNUSED(text)) +static void lib_link_text(BlendLibReader *UNUSED(reader), Text *UNUSED(text)) { } @@ -4272,7 +4240,7 @@ static void direct_link_text(BlendDataReader *reader, Text *text) { TextLine *ln; - BLO_read_data_address(reader, &text->name); + BLO_read_data_address(reader, &text->filepath); text->compiled = NULL; @@ -4309,7 +4277,7 @@ static void direct_link_text(BlendDataReader *reader, Text *text) /** \name Read ID: Image * \{ */ -static void lib_link_image(FileData *UNUSED(fd), Main *UNUSED(bmain), Image *UNUSED(ima)) +static void lib_link_image(BlendLibReader *UNUSED(reader), Image *UNUSED(ima)) { } @@ -4388,22 +4356,22 @@ static void direct_link_image(BlendDataReader *reader, Image *ima) /** \name Read ID: Curve * \{ */ -static void lib_link_curve(FileData *fd, Main *UNUSED(bmain), Curve *cu) +static void lib_link_curve(BlendLibReader *reader, Curve *cu) { for (int a = 0; a < cu->totcol; a++) { - cu->mat[a] = newlibadr(fd, cu->id.lib, cu->mat[a]); + BLO_read_id_address(reader, cu->id.lib, &cu->mat[a]); } - cu->bevobj = newlibadr(fd, cu->id.lib, cu->bevobj); - cu->taperobj = newlibadr(fd, cu->id.lib, cu->taperobj); - cu->textoncurve = newlibadr(fd, cu->id.lib, cu->textoncurve); - cu->vfont = newlibadr(fd, cu->id.lib, cu->vfont); - cu->vfontb = newlibadr(fd, cu->id.lib, cu->vfontb); - cu->vfonti = newlibadr(fd, cu->id.lib, cu->vfonti); - cu->vfontbi = newlibadr(fd, cu->id.lib, cu->vfontbi); + BLO_read_id_address(reader, cu->id.lib, &cu->bevobj); + BLO_read_id_address(reader, cu->id.lib, &cu->taperobj); + BLO_read_id_address(reader, cu->id.lib, &cu->textoncurve); + BLO_read_id_address(reader, cu->id.lib, &cu->vfont); + BLO_read_id_address(reader, cu->id.lib, &cu->vfontb); + BLO_read_id_address(reader, cu->id.lib, &cu->vfonti); + BLO_read_id_address(reader, cu->id.lib, &cu->vfontbi); - cu->ipo = newlibadr(fd, cu->id.lib, cu->ipo); // XXX deprecated - old animation system - cu->key = newlibadr(fd, cu->id.lib, cu->key); + BLO_read_id_address(reader, cu->id.lib, &cu->ipo); // XXX deprecated - old animation system + BLO_read_id_address(reader, cu->id.lib, &cu->key); } static void switch_endian_knots(Nurb *nu) @@ -4482,10 +4450,10 @@ static void direct_link_curve(BlendDataReader *reader, Curve *cu) /** \name Read ID: Texture * \{ */ -static void lib_link_texture(FileData *fd, Main *UNUSED(bmain), Tex *tex) +static void lib_link_texture(BlendLibReader *reader, Tex *tex) { - tex->ima = newlibadr(fd, tex->id.lib, tex->ima); - tex->ipo = newlibadr(fd, tex->id.lib, tex->ipo); // XXX deprecated - old animation system + BLO_read_id_address(reader, tex->id.lib, &tex->ima); + BLO_read_id_address(reader, tex->id.lib, &tex->ipo); // XXX deprecated - old animation system } static void direct_link_texture(BlendDataReader *reader, Tex *tex) @@ -4507,18 +4475,18 @@ static void direct_link_texture(BlendDataReader *reader, Tex *tex) /** \name Read ID: Material * \{ */ -static void lib_link_material(FileData *fd, Main *UNUSED(bmain), Material *ma) +static void lib_link_material(BlendLibReader *reader, Material *ma) { - ma->ipo = newlibadr(fd, ma->id.lib, ma->ipo); // XXX deprecated - old animation system + BLO_read_id_address(reader, ma->id.lib, &ma->ipo); // XXX deprecated - old animation system /* relink grease pencil settings */ if (ma->gp_style != NULL) { MaterialGPencilStyle *gp_style = ma->gp_style; if (gp_style->sima != NULL) { - gp_style->sima = newlibadr(fd, ma->id.lib, gp_style->sima); + BLO_read_id_address(reader, ma->id.lib, &gp_style->sima); } if (gp_style->ima != NULL) { - gp_style->ima = newlibadr(fd, ma->id.lib, gp_style->ima); + BLO_read_id_address(reader, ma->id.lib, &gp_style->ima); } } } @@ -4629,31 +4597,31 @@ static void direct_link_pointcache_list(BlendDataReader *reader, } } -static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd) +static void lib_link_partdeflect(BlendLibReader *reader, ID *id, PartDeflect *pd) { if (pd && pd->tex) { - pd->tex = newlibadr(fd, id->lib, pd->tex); + BLO_read_id_address(reader, id->lib, &pd->tex); } if (pd && pd->f_source) { - pd->f_source = newlibadr(fd, id->lib, pd->f_source); + BLO_read_id_address(reader, id->lib, &pd->f_source); } } -static void lib_link_particlesettings(FileData *fd, Main *UNUSED(bmain), ParticleSettings *part) +static void lib_link_particlesettings(BlendLibReader *reader, ParticleSettings *part) { - part->ipo = newlibadr(fd, part->id.lib, part->ipo); // XXX deprecated - old animation system + BLO_read_id_address(reader, part->id.lib, &part->ipo); // XXX deprecated - old animation system - part->instance_object = newlibadr(fd, part->id.lib, part->instance_object); - part->instance_collection = newlibadr(fd, part->id.lib, part->instance_collection); - part->force_group = newlibadr(fd, part->id.lib, part->force_group); - part->bb_ob = newlibadr(fd, part->id.lib, part->bb_ob); - part->collision_group = newlibadr(fd, part->id.lib, part->collision_group); + BLO_read_id_address(reader, part->id.lib, &part->instance_object); + BLO_read_id_address(reader, part->id.lib, &part->instance_collection); + BLO_read_id_address(reader, part->id.lib, &part->force_group); + BLO_read_id_address(reader, part->id.lib, &part->bb_ob); + BLO_read_id_address(reader, part->id.lib, &part->collision_group); - lib_link_partdeflect(fd, &part->id, part->pd); - lib_link_partdeflect(fd, &part->id, part->pd2); + lib_link_partdeflect(reader, &part->id, part->pd); + lib_link_partdeflect(reader, &part->id, part->pd2); if (part->effector_weights) { - part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group); + BLO_read_id_address(reader, part->id.lib, &part->effector_weights->group); } else { part->effector_weights = BKE_effector_add_weights(part->force_group); @@ -4661,7 +4629,7 @@ static void lib_link_particlesettings(FileData *fd, Main *UNUSED(bmain), Particl if (part->instance_weights.first && part->instance_collection) { LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) { - dw->ob = newlibadr(fd, part->id.lib, dw->ob); + BLO_read_id_address(reader, part->id.lib, &dw->ob); } } else { @@ -4678,12 +4646,12 @@ static void lib_link_particlesettings(FileData *fd, Main *UNUSED(bmain), Particl case eBoidRuleType_Goal: case eBoidRuleType_Avoid: { BoidRuleGoalAvoid *brga = (BoidRuleGoalAvoid *)rule; - brga->ob = newlibadr(fd, part->id.lib, brga->ob); + BLO_read_id_address(reader, part->id.lib, &brga->ob); break; } case eBoidRuleType_FollowLeader: { BoidRuleFollowLeader *brfl = (BoidRuleFollowLeader *)rule; - brfl->ob = newlibadr(fd, part->id.lib, brfl->ob); + BLO_read_id_address(reader, part->id.lib, &brfl->ob); break; } } @@ -4694,8 +4662,8 @@ static void lib_link_particlesettings(FileData *fd, Main *UNUSED(bmain), Particl for (int a = 0; a < MAX_MTEX; a++) { MTex *mtex = part->mtex[a]; if (mtex) { - mtex->tex = newlibadr(fd, part->id.lib, mtex->tex); - mtex->object = newlibadr(fd, part->id.lib, mtex->object); + BLO_read_id_address(reader, part->id.lib, &mtex->tex); + BLO_read_id_address(reader, part->id.lib, &mtex->object); } } } @@ -4721,15 +4689,15 @@ static void direct_link_particlesettings(BlendDataReader *reader, ParticleSettin BLO_read_data_address(reader, &part->clumpcurve); if (part->clumpcurve) { - direct_link_curvemapping(reader, part->clumpcurve); + BKE_curvemapping_blend_read(reader, part->clumpcurve); } BLO_read_data_address(reader, &part->roughcurve); if (part->roughcurve) { - direct_link_curvemapping(reader, part->roughcurve); + BKE_curvemapping_blend_read(reader, part->roughcurve); } BLO_read_data_address(reader, &part->twistcurve); if (part->twistcurve) { - direct_link_curvemapping(reader, part->twistcurve); + BKE_curvemapping_blend_read(reader, part->twistcurve); } BLO_read_data_address(reader, &part->effector_weights); @@ -4760,30 +4728,33 @@ static void direct_link_particlesettings(BlendDataReader *reader, ParticleSettin CLAMP(part->trail_count, 1, 100000); } -static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase *particles) +static void lib_link_particlesystems(BlendLibReader *reader, + Object *ob, + ID *id, + ListBase *particles) { ParticleSystem *psys, *psysnext; for (psys = particles->first; psys; psys = psysnext) { psysnext = psys->next; - psys->part = newlibadr(fd, id->lib, psys->part); + BLO_read_id_address(reader, id->lib, &psys->part); if (psys->part) { ParticleTarget *pt = psys->targets.first; for (; pt; pt = pt->next) { - pt->ob = newlibadr(fd, id->lib, pt->ob); + BLO_read_id_address(reader, id->lib, &pt->ob); } - psys->parent = newlibadr(fd, id->lib, psys->parent); - psys->target_ob = newlibadr(fd, id->lib, psys->target_ob); + BLO_read_id_address(reader, id->lib, &psys->parent); + BLO_read_id_address(reader, id->lib, &psys->target_ob); if (psys->clmd) { /* XXX - from reading existing code this seems correct but intended usage of * pointcache /w cloth should be added in 'ParticleSystem' - campbell */ psys->clmd->point_cache = psys->pointcache; psys->clmd->ptcaches.first = psys->clmd->ptcaches.last = NULL; - psys->clmd->coll_parms->group = newlibadr(fd, id->lib, psys->clmd->coll_parms->group); + BLO_read_id_address(reader, id->lib, &psys->clmd->coll_parms->group); psys->clmd->modifier.error = NULL; } } @@ -4894,21 +4865,21 @@ static void direct_link_particlesystems(BlendDataReader *reader, ListBase *parti /** \name Read ID: Mesh * \{ */ -static void lib_link_mesh(FileData *fd, Main *UNUSED(bmain), Mesh *me) +static void lib_link_mesh(BlendLibReader *reader, Mesh *me) { /* this check added for python created meshes */ if (me->mat) { for (int i = 0; i < me->totcol; i++) { - me->mat[i] = newlibadr(fd, me->id.lib, me->mat[i]); + BLO_read_id_address(reader, me->id.lib, &me->mat[i]); } } else { me->totcol = 0; } - me->ipo = newlibadr(fd, me->id.lib, me->ipo); // XXX: deprecated: old anim sys - me->key = newlibadr(fd, me->id.lib, me->key); - me->texcomesh = newlibadr(fd, me->id.lib, me->texcomesh); + BLO_read_id_address(reader, me->id.lib, &me->ipo); // XXX: deprecated: old anim sys + BLO_read_id_address(reader, me->id.lib, &me->key); + BLO_read_id_address(reader, me->id.lib, &me->texcomesh); } static void direct_link_dverts(BlendDataReader *reader, int count, MDeformVert *mdverts) @@ -5123,10 +5094,10 @@ static void direct_link_mesh(BlendDataReader *reader, Mesh *mesh) /** \name Read ID: Lattice * \{ */ -static void lib_link_latt(FileData *fd, Main *UNUSED(bmain), Lattice *lt) +static void lib_link_latt(BlendLibReader *reader, Lattice *lt) { - lt->ipo = newlibadr(fd, lt->id.lib, lt->ipo); // XXX deprecated - old animation system - lt->key = newlibadr(fd, lt->id.lib, lt->key); + BLO_read_id_address(reader, lt->id.lib, <->ipo); // XXX deprecated - old animation system + BLO_read_id_address(reader, lt->id.lib, <->key); } static void direct_link_latt(BlendDataReader *reader, Lattice *lt) @@ -5151,17 +5122,17 @@ static void direct_link_latt(BlendDataReader *reader, Lattice *lt) static void lib_link_modifiers_common(void *userData, Object *ob, ID **idpoin, int cb_flag) { - FileData *fd = userData; + BlendLibReader *reader = userData; - *idpoin = newlibadr(fd, ob->id.lib, *idpoin); + BLO_read_id_address(reader, ob->id.lib, idpoin); if (*idpoin != NULL && (cb_flag & IDWALK_CB_USER) != 0) { id_us_plus_no_lib(*idpoin); } } -static void lib_link_modifiers(FileData *fd, Object *ob) +static void lib_link_modifiers(BlendLibReader *reader, Object *ob) { - BKE_modifiers_foreach_ID_link(ob, lib_link_modifiers_common, fd); + BKE_modifiers_foreach_ID_link(ob, lib_link_modifiers_common, reader); /* If linking from a library, clear 'local' library override flag. */ if (ob->id.lib != NULL) { @@ -5171,9 +5142,9 @@ static void lib_link_modifiers(FileData *fd, Object *ob) } } -static void lib_link_gpencil_modifiers(FileData *fd, Object *ob) +static void lib_link_gpencil_modifiers(BlendLibReader *reader, Object *ob) { - BKE_gpencil_modifiers_foreach_ID_link(ob, lib_link_modifiers_common, fd); + BKE_gpencil_modifiers_foreach_ID_link(ob, lib_link_modifiers_common, reader); /* If linking from a library, clear 'local' library override flag. */ if (ob->id.lib != NULL) { @@ -5184,9 +5155,9 @@ static void lib_link_gpencil_modifiers(FileData *fd, Object *ob) } } -static void lib_link_shaderfxs(FileData *fd, Object *ob) +static void lib_link_shaderfxs(BlendLibReader *reader, Object *ob) { - BKE_shaderfx_foreach_ID_link(ob, lib_link_modifiers_common, fd); + BKE_shaderfx_foreach_ID_link(ob, lib_link_modifiers_common, reader); /* If linking from a library, clear 'local' library override flag. */ if (ob->id.lib != NULL) { @@ -5196,28 +5167,28 @@ static void lib_link_shaderfxs(FileData *fd, Object *ob) } } -static void lib_link_object(FileData *fd, Main *bmain, Object *ob) +static void lib_link_object(BlendLibReader *reader, Object *ob) { bool warn = false; int a; // XXX deprecated - old animation system <<< - ob->ipo = newlibadr(fd, ob->id.lib, ob->ipo); - ob->action = newlibadr(fd, ob->id.lib, ob->action); + BLO_read_id_address(reader, ob->id.lib, &ob->ipo); + BLO_read_id_address(reader, ob->id.lib, &ob->action); // >>> XXX deprecated - old animation system - ob->parent = newlibadr(fd, ob->id.lib, ob->parent); - ob->track = newlibadr(fd, ob->id.lib, ob->track); - ob->poselib = newlibadr(fd, ob->id.lib, ob->poselib); + BLO_read_id_address(reader, ob->id.lib, &ob->parent); + BLO_read_id_address(reader, ob->id.lib, &ob->track); + BLO_read_id_address(reader, ob->id.lib, &ob->poselib); /* 2.8x drops support for non-empty dupli instances. */ if (ob->type == OB_EMPTY) { - ob->instance_collection = newlibadr(fd, ob->id.lib, ob->instance_collection); + BLO_read_id_address(reader, ob->id.lib, &ob->instance_collection); } else { if (ob->instance_collection != NULL) { - ID *id = newlibadr(fd, ob->id.lib, ob->instance_collection); - blo_reportf_wrap(fd->reports, + ID *id = BLO_read_get_new_id_address(reader, ob->id.lib, &ob->instance_collection->id); + blo_reportf_wrap(reader->fd->reports, RPT_WARNING, TIP_("Non-Empty object '%s' cannot duplicate collection '%s' " "anymore in Blender 2.80, removed instancing"), @@ -5228,7 +5199,7 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob) ob->transflag &= ~OB_DUPLICOLLECTION; } - ob->proxy = newlibadr(fd, ob->id.lib, ob->proxy); + BLO_read_id_address(reader, ob->id.lib, &ob->proxy); if (ob->proxy) { /* paranoia check, actually a proxy_from pointer should never be written... */ if (ob->proxy->id.lib == NULL) { @@ -5236,7 +5207,7 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob) ob->proxy = NULL; if (ob->id.lib) { - printf("Proxy lost from object %s lib %s\n", ob->id.name + 2, ob->id.lib->name); + printf("Proxy lost from object %s lib %s\n", ob->id.name + 2, ob->id.lib->filepath); } else { printf("Proxy lost from object %s lib <NONE>\n", ob->id.name + 2); @@ -5247,14 +5218,14 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob) ob->proxy->proxy_from = ob; } } - ob->proxy_group = newlibadr(fd, ob->id.lib, ob->proxy_group); + BLO_read_id_address(reader, ob->id.lib, &ob->proxy_group); void *poin = ob->data; - ob->data = newlibadr(fd, ob->id.lib, ob->data); + BLO_read_id_address(reader, ob->id.lib, &ob->data); if (ob->data == NULL && poin != NULL) { if (ob->id.lib) { - printf("Can't find obdata of %s lib %s\n", ob->id.name + 2, ob->id.lib->name); + printf("Can't find obdata of %s lib %s\n", ob->id.name + 2, ob->id.lib->filepath); } else { printf("Object %s lost data.\n", ob->id.name + 2); @@ -5279,7 +5250,7 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob) } } for (a = 0; a < ob->totcol; a++) { - ob->mat[a] = newlibadr(fd, ob->id.lib, ob->mat[a]); + BLO_read_id_address(reader, ob->id.lib, &ob->mat[a]); } /* When the object is local and the data is library its possible @@ -5289,26 +5260,26 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob) /* Only expand so as not to loose any object materials that might be set. */ if (totcol_data && (*totcol_data > ob->totcol)) { /* printf("'%s' %d -> %d\n", ob->id.name, ob->totcol, *totcol_data); */ - BKE_object_material_resize(bmain, ob, *totcol_data, false); + BKE_object_material_resize(reader->main, ob, *totcol_data, false); } } - ob->gpd = newlibadr(fd, ob->id.lib, ob->gpd); + BLO_read_id_address(reader, ob->id.lib, &ob->gpd); /* if id.us==0 a new base will be created later on */ /* WARNING! Also check expand_object(), should reflect the stuff below. */ - lib_link_pose(fd, bmain, ob, ob->pose); - lib_link_constraints(fd, &ob->id, &ob->constraints); + lib_link_pose(reader, ob, ob->pose); + lib_link_constraints(reader, &ob->id, &ob->constraints); // XXX deprecated - old animation system <<< - lib_link_constraint_channels(fd, &ob->id, &ob->constraintChannels); - lib_link_nlastrips(fd, &ob->id, &ob->nlastrips); + lib_link_constraint_channels(reader, &ob->id, &ob->constraintChannels); + lib_link_nlastrips(reader, &ob->id, &ob->nlastrips); // >>> XXX deprecated - old animation system LISTBASE_FOREACH (PartEff *, paf, &ob->effect) { if (paf->type == EFF_PARTICLE) { - paf->group = newlibadr(fd, ob->id.lib, paf->group); + BLO_read_id_address(reader, ob->id.lib, &paf->group); } } @@ -5317,8 +5288,8 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob) ob, eModifierType_Fluidsim); if (fluidmd && fluidmd->fss) { - fluidmd->fss->ipo = newlibadr( - fd, ob->id.lib, fluidmd->fss->ipo); // XXX deprecated - old animation system + BLO_read_id_address( + reader, ob->id.lib, &fluidmd->fss->ipo); // XXX deprecated - old animation system } } @@ -5340,30 +5311,29 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob) /* texture field */ if (ob->pd) { - lib_link_partdeflect(fd, &ob->id, ob->pd); + lib_link_partdeflect(reader, &ob->id, ob->pd); } if (ob->soft) { - ob->soft->collision_group = newlibadr(fd, ob->id.lib, ob->soft->collision_group); + BLO_read_id_address(reader, ob->id.lib, &ob->soft->collision_group); - ob->soft->effector_weights->group = newlibadr( - fd, ob->id.lib, ob->soft->effector_weights->group); + BLO_read_id_address(reader, ob->id.lib, &ob->soft->effector_weights->group); } - lib_link_particlesystems(fd, ob, &ob->id, &ob->particlesystem); - lib_link_modifiers(fd, ob); - lib_link_gpencil_modifiers(fd, ob); - lib_link_shaderfxs(fd, ob); + lib_link_particlesystems(reader, ob, &ob->id, &ob->particlesystem); + lib_link_modifiers(reader, ob); + lib_link_gpencil_modifiers(reader, ob); + lib_link_shaderfxs(reader, ob); if (ob->rigidbody_constraint) { - ob->rigidbody_constraint->ob1 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob1); - ob->rigidbody_constraint->ob2 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob2); + BLO_read_id_address(reader, ob->id.lib, &ob->rigidbody_constraint->ob1); + BLO_read_id_address(reader, ob->id.lib, &ob->rigidbody_constraint->ob2); } { LodLevel *level; for (level = ob->lodlevels.first; level; level = level->next) { - level->source = newlibadr(fd, ob->id.lib, level->source); + BLO_read_id_address(reader, ob->id.lib, &level->source); if (!level->source && level == ob->lodlevels.first) { level->source = ob; @@ -5372,7 +5342,7 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob) } if (warn) { - BKE_report(fd->reports, RPT_WARNING, "Warning in console"); + BKE_report(reader->fd->reports, RPT_WARNING, "Warning in console"); } } @@ -5599,16 +5569,6 @@ static void direct_link_modifiers(BlendDataReader *reader, ListBase *lb, Object if (is_allocated) { /* All the fields has been properly allocated. */ } - else if (md->type == eModifierType_Subsurf) { - SubsurfModifierData *smd = (SubsurfModifierData *)md; - - smd->emCache = smd->mCache = NULL; - } - else if (md->type == eModifierType_Armature) { - ArmatureModifierData *amd = (ArmatureModifierData *)md; - - amd->vert_coords_prev = NULL; - } else if (md->type == eModifierType_Cloth) { ClothModifierData *clmd = (ClothModifierData *)md; @@ -5748,148 +5708,6 @@ static void direct_link_modifiers(BlendDataReader *reader, ListBase *lb, Object BLO_read_data_address(reader, &pmd->brush->vel_ramp); } } - else if (md->type == eModifierType_Collision) { - CollisionModifierData *collmd = (CollisionModifierData *)md; -#if 0 - // TODO: CollisionModifier should use pointcache - // + have proper reset events before enabling this - collmd->x = newdataadr(fd, collmd->x); - collmd->xnew = newdataadr(fd, collmd->xnew); - collmd->mfaces = newdataadr(fd, collmd->mfaces); - - collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x"); - collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew"); - collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v"); -#endif - - collmd->x = NULL; - collmd->xnew = NULL; - collmd->current_x = NULL; - collmd->current_xnew = NULL; - collmd->current_v = NULL; - collmd->time_x = collmd->time_xnew = -1000; - collmd->mvert_num = 0; - collmd->tri_num = 0; - collmd->is_static = false; - collmd->bvhtree = NULL; - collmd->tri = NULL; - } - else if (md->type == eModifierType_Surface) { - SurfaceModifierData *surmd = (SurfaceModifierData *)md; - - surmd->mesh = NULL; - surmd->bvhtree = NULL; - surmd->x = NULL; - surmd->v = NULL; - surmd->numverts = 0; - } - else if (md->type == eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData *)md; - BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar); - - BLO_read_data_address(reader, &hmd->curfalloff); - if (hmd->curfalloff) { - direct_link_curvemapping(reader, hmd->curfalloff); - } - } - else if (md->type == eModifierType_ParticleSystem) { - ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; - - psmd->mesh_final = NULL; - psmd->mesh_original = NULL; - BLO_read_data_address(reader, &psmd->psys); - psmd->flag &= ~eParticleSystemFlag_psys_updated; - psmd->flag |= eParticleSystemFlag_file_loaded; - } - else if (md->type == eModifierType_Explode) { - ExplodeModifierData *psmd = (ExplodeModifierData *)md; - - psmd->facepa = NULL; - } - else if (md->type == eModifierType_MeshDeform) { - MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; - - BLO_read_data_address(reader, &mmd->bindinfluences); - BLO_read_int32_array(reader, mmd->totvert + 1, &mmd->bindoffsets); - BLO_read_float3_array(reader, mmd->totcagevert, &mmd->bindcagecos); - BLO_read_data_address(reader, &mmd->dyngrid); - BLO_read_data_address(reader, &mmd->dyninfluences); - BLO_read_int32_array(reader, mmd->totvert, &mmd->dynverts); - - BLO_read_float_array(reader, mmd->totvert, &mmd->bindweights); - BLO_read_float3_array(reader, mmd->totcagevert, &mmd->bindcos); - } - else if (md->type == eModifierType_Ocean) { - OceanModifierData *omd = (OceanModifierData *)md; - omd->oceancache = NULL; - omd->ocean = NULL; - } - else if (md->type == eModifierType_Warp) { - WarpModifierData *tmd = (WarpModifierData *)md; - - BLO_read_data_address(reader, &tmd->curfalloff); - if (tmd->curfalloff) { - direct_link_curvemapping(reader, tmd->curfalloff); - } - } - else if (md->type == eModifierType_WeightVGEdit) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; - - BLO_read_data_address(reader, &wmd->cmap_curve); - if (wmd->cmap_curve) { - direct_link_curvemapping(reader, wmd->cmap_curve); - } - } - else if (md->type == eModifierType_CorrectiveSmooth) { - CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; - - if (csmd->bind_coords) { - BLO_read_float3_array(reader, csmd->bind_coords_num, (float **)&csmd->bind_coords); - } - - /* runtime only */ - csmd->delta_cache.deltas = NULL; - csmd->delta_cache.totverts = 0; - } - else if (md->type == eModifierType_MeshSequenceCache) { - MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md; - msmcd->reader = NULL; - msmcd->reader_object_path[0] = '\0'; - } - else if (md->type == eModifierType_SurfaceDeform) { - SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; - - BLO_read_data_address(reader, &smd->verts); - - if (smd->verts) { - for (int i = 0; i < smd->numverts; i++) { - BLO_read_data_address(reader, &smd->verts[i].binds); - - if (smd->verts[i].binds) { - for (int j = 0; j < smd->verts[i].numbinds; j++) { - BLO_read_uint32_array( - reader, smd->verts[i].binds[j].numverts, &smd->verts[i].binds[j].vert_inds); - - if (smd->verts[i].binds[j].mode == MOD_SDEF_MODE_CENTROID || - smd->verts[i].binds[j].mode == MOD_SDEF_MODE_LOOPTRI) { - BLO_read_float3_array(reader, 1, &smd->verts[i].binds[j].vert_weights); - } - else { - BLO_read_float_array( - reader, smd->verts[i].binds[j].numverts, &smd->verts[i].binds[j].vert_weights); - } - } - } - } - } - } - else if (md->type == eModifierType_Bevel) { - BevelModifierData *bmd = (BevelModifierData *)md; - BLO_read_data_address(reader, &bmd->custom_profile); - if (bmd->custom_profile) { - direct_link_curveprofile(reader, bmd->custom_profile); - } - } if (mti->blendRead != NULL) { mti->blendRead(reader, md); @@ -5920,7 +5738,7 @@ static void direct_link_gpencil_modifiers(BlendDataReader *reader, ListBase *lb) BLO_read_data_address(reader, &hmd->curfalloff); if (hmd->curfalloff) { - direct_link_curvemapping(reader, hmd->curfalloff); + BKE_curvemapping_blend_read(reader, hmd->curfalloff); } } else if (md->type == eGpencilModifierType_Noise) { @@ -5928,7 +5746,7 @@ static void direct_link_gpencil_modifiers(BlendDataReader *reader, ListBase *lb) BLO_read_data_address(reader, &gpmd->curve_intensity); if (gpmd->curve_intensity) { - direct_link_curvemapping(reader, gpmd->curve_intensity); + BKE_curvemapping_blend_read(reader, gpmd->curve_intensity); /* initialize the curve. Maybe this could be moved to modififer logic */ BKE_curvemapping_initialize(gpmd->curve_intensity); } @@ -5938,7 +5756,7 @@ static void direct_link_gpencil_modifiers(BlendDataReader *reader, ListBase *lb) BLO_read_data_address(reader, &gpmd->curve_thickness); if (gpmd->curve_thickness) { - direct_link_curvemapping(reader, gpmd->curve_thickness); + BKE_curvemapping_blend_read(reader, gpmd->curve_thickness); BKE_curvemapping_initialize(gpmd->curve_thickness); } } @@ -5947,7 +5765,7 @@ static void direct_link_gpencil_modifiers(BlendDataReader *reader, ListBase *lb) BLO_read_data_address(reader, &gpmd->colorband); BLO_read_data_address(reader, &gpmd->curve_intensity); if (gpmd->curve_intensity) { - direct_link_curvemapping(reader, gpmd->curve_intensity); + BKE_curvemapping_blend_read(reader, gpmd->curve_intensity); BKE_curvemapping_initialize(gpmd->curve_intensity); } } @@ -5955,7 +5773,7 @@ static void direct_link_gpencil_modifiers(BlendDataReader *reader, ListBase *lb) SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md; BLO_read_data_address(reader, &gpmd->curve_intensity); if (gpmd->curve_intensity) { - direct_link_curvemapping(reader, gpmd->curve_intensity); + BKE_curvemapping_blend_read(reader, gpmd->curve_intensity); BKE_curvemapping_initialize(gpmd->curve_intensity); } } @@ -5963,7 +5781,7 @@ static void direct_link_gpencil_modifiers(BlendDataReader *reader, ListBase *lb) ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md; BLO_read_data_address(reader, &gpmd->curve_intensity); if (gpmd->curve_intensity) { - direct_link_curvemapping(reader, gpmd->curve_intensity); + BKE_curvemapping_blend_read(reader, gpmd->curve_intensity); BKE_curvemapping_initialize(gpmd->curve_intensity); } } @@ -5971,7 +5789,7 @@ static void direct_link_gpencil_modifiers(BlendDataReader *reader, ListBase *lb) OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; BLO_read_data_address(reader, &gpmd->curve_intensity); if (gpmd->curve_intensity) { - direct_link_curvemapping(reader, gpmd->curve_intensity); + BKE_curvemapping_blend_read(reader, gpmd->curve_intensity); BKE_curvemapping_initialize(gpmd->curve_intensity); } } @@ -6205,7 +6023,7 @@ static void direct_link_view_settings(BlendDataReader *reader, BLO_read_data_address(reader, &view_settings->curve_mapping); if (view_settings->curve_mapping) { - direct_link_curvemapping(reader, view_settings->curve_mapping); + BKE_curvemapping_blend_read(reader, view_settings->curve_mapping); } } @@ -6252,39 +6070,39 @@ static void direct_link_view_layer(BlendDataReader *reader, ViewLayer *view_laye view_layer->object_bases_hash = NULL; } -static void lib_link_layer_collection(FileData *fd, +static void lib_link_layer_collection(BlendLibReader *reader, Library *lib, LayerCollection *layer_collection, bool master) { /* Master collection is not a real data-lock. */ if (!master) { - layer_collection->collection = newlibadr(fd, lib, layer_collection->collection); + BLO_read_id_address(reader, lib, &layer_collection->collection); } for (LayerCollection *layer_collection_nested = layer_collection->layer_collections.first; layer_collection_nested != NULL; layer_collection_nested = layer_collection_nested->next) { - lib_link_layer_collection(fd, lib, layer_collection_nested, false); + lib_link_layer_collection(reader, lib, layer_collection_nested, false); } } -static void lib_link_view_layer(FileData *fd, Library *lib, ViewLayer *view_layer) +static void lib_link_view_layer(BlendLibReader *reader, Library *lib, ViewLayer *view_layer) { LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) { - fmc->script = newlibadr(fd, lib, fmc->script); + BLO_read_id_address(reader, lib, &fmc->script); } LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { - fls->linestyle = newlibadr(fd, lib, fls->linestyle); - fls->group = newlibadr(fd, lib, fls->group); + BLO_read_id_address(reader, lib, &fls->linestyle); + BLO_read_id_address(reader, lib, &fls->group); } for (Base *base = view_layer->object_bases.first, *base_next = NULL; base; base = base_next) { base_next = base->next; /* we only bump the use count for the collection objects */ - base->object = newlibadr(fd, lib, base->object); + BLO_read_id_address(reader, lib, &base->object); if (base->object == NULL) { /* Free in case linked object got lost. */ @@ -6298,12 +6116,12 @@ static void lib_link_view_layer(FileData *fd, Library *lib, ViewLayer *view_laye for (LayerCollection *layer_collection = view_layer->layer_collections.first; layer_collection != NULL; layer_collection = layer_collection->next) { - lib_link_layer_collection(fd, lib, layer_collection, true); + lib_link_layer_collection(reader, lib, layer_collection, true); } - view_layer->mat_override = newlibadr(fd, lib, view_layer->mat_override); + BLO_read_id_address(reader, lib, &view_layer->mat_override); - IDP_LibLinkProperty(view_layer->id_properties, fd); + IDP_LibLinkProperty(view_layer->id_properties, reader); } /** \} */ @@ -6323,15 +6141,15 @@ static void direct_link_scene_collection(BlendDataReader *reader, SceneCollectio } } -static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollection *sc) +static void lib_link_scene_collection(BlendLibReader *reader, Library *lib, SceneCollection *sc) { LISTBASE_FOREACH (LinkData *, link, &sc->objects) { - link->data = newlibadr(fd, lib, link->data); + BLO_read_id_address(reader, lib, &link->data); BLI_assert(link->data); } LISTBASE_FOREACH (SceneCollection *, nsc, &sc->scene_collections) { - lib_link_scene_collection(fd, lib, nsc); + lib_link_scene_collection(reader, lib, nsc); } } #endif @@ -6362,11 +6180,11 @@ static void direct_link_collection(BlendDataReader *reader, Collection *collecti #endif } -static void lib_link_collection_data(FileData *fd, Library *lib, Collection *collection) +static void lib_link_collection_data(BlendLibReader *reader, Library *lib, Collection *collection) { for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) { cob_next = cob->next; - cob->ob = newlibadr(fd, lib, cob->ob); + BLO_read_id_address(reader, lib, &cob->ob); if (cob->ob == NULL) { BLI_freelinkN(&collection->gobject, cob); @@ -6374,23 +6192,23 @@ static void lib_link_collection_data(FileData *fd, Library *lib, Collection *col } for (CollectionChild *child = collection->children.first; child != NULL; child = child->next) { - child->collection = newlibadr(fd, lib, child->collection); + BLO_read_id_address(reader, lib, &child->collection); } } -static void lib_link_collection(FileData *fd, Main *UNUSED(bmain), Collection *collection) +static void lib_link_collection(BlendLibReader *reader, Collection *collection) { #ifdef USE_COLLECTION_COMPAT_28 if (collection->collection) { - lib_link_scene_collection(fd, collection->id.lib, collection->collection); + lib_link_scene_collection(reader, collection->id.lib, collection->collection); } if (collection->view_layer) { - lib_link_view_layer(fd, collection->id.lib, collection->view_layer); + lib_link_view_layer(reader, collection->id.lib, collection->view_layer); } #endif - lib_link_collection_data(fd, collection->id.lib, collection); + lib_link_collection_data(reader, collection->id.lib, collection); } /** \} */ @@ -6411,29 +6229,29 @@ static void composite_patch(bNodeTree *ntree, Scene *scene) } } -static void link_paint(FileData *fd, Scene *sce, Paint *p) +static void link_paint(BlendLibReader *reader, Scene *sce, Paint *p) { if (p) { - p->brush = newlibadr(fd, sce->id.lib, p->brush); + BLO_read_id_address(reader, sce->id.lib, &p->brush); for (int i = 0; i < p->tool_slots_len; i++) { if (p->tool_slots[i].brush != NULL) { - p->tool_slots[i].brush = newlibadr(fd, sce->id.lib, p->tool_slots[i].brush); + BLO_read_id_address(reader, sce->id.lib, &p->tool_slots[i].brush); } } - p->palette = newlibadr(fd, sce->id.lib, p->palette); + BLO_read_id_address(reader, sce->id.lib, &p->palette); p->paint_cursor = NULL; BKE_paint_runtime_init(sce->toolsettings, p); } } -static void lib_link_sequence_modifiers(FileData *fd, Scene *scene, ListBase *lb) +static void lib_link_sequence_modifiers(BlendLibReader *reader, Scene *scene, ListBase *lb) { SequenceModifierData *smd; for (smd = lb->first; smd; smd = smd->next) { if (smd->mask_id) { - smd->mask_id = newlibadr(fd, scene->id.lib, smd->mask_id); + BLO_read_id_address(reader, scene->id.lib, &smd->mask_id); } } } @@ -6514,76 +6332,72 @@ static bool scene_validate_setscene__liblink(Scene *sce, const int totscene) } #endif -static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce) +static void lib_link_scene(BlendLibReader *reader, Scene *sce) { - lib_link_keyingsets(fd, &sce->id, &sce->keyingsets); + lib_link_keyingsets(reader, &sce->id, &sce->keyingsets); - sce->camera = newlibadr(fd, sce->id.lib, sce->camera); - sce->world = newlibadr(fd, sce->id.lib, sce->world); - sce->set = newlibadr(fd, sce->id.lib, sce->set); - sce->gpd = newlibadr(fd, sce->id.lib, sce->gpd); + BLO_read_id_address(reader, sce->id.lib, &sce->camera); + BLO_read_id_address(reader, sce->id.lib, &sce->world); + BLO_read_id_address(reader, sce->id.lib, &sce->set); + BLO_read_id_address(reader, sce->id.lib, &sce->gpd); - link_paint(fd, sce, &sce->toolsettings->imapaint.paint); + link_paint(reader, sce, &sce->toolsettings->imapaint.paint); if (sce->toolsettings->sculpt) { - link_paint(fd, sce, &sce->toolsettings->sculpt->paint); + link_paint(reader, sce, &sce->toolsettings->sculpt->paint); } if (sce->toolsettings->vpaint) { - link_paint(fd, sce, &sce->toolsettings->vpaint->paint); + link_paint(reader, sce, &sce->toolsettings->vpaint->paint); } if (sce->toolsettings->wpaint) { - link_paint(fd, sce, &sce->toolsettings->wpaint->paint); + link_paint(reader, sce, &sce->toolsettings->wpaint->paint); } if (sce->toolsettings->uvsculpt) { - link_paint(fd, sce, &sce->toolsettings->uvsculpt->paint); + link_paint(reader, sce, &sce->toolsettings->uvsculpt->paint); } if (sce->toolsettings->gp_paint) { - link_paint(fd, sce, &sce->toolsettings->gp_paint->paint); + link_paint(reader, sce, &sce->toolsettings->gp_paint->paint); } if (sce->toolsettings->gp_vertexpaint) { - link_paint(fd, sce, &sce->toolsettings->gp_vertexpaint->paint); + link_paint(reader, sce, &sce->toolsettings->gp_vertexpaint->paint); } if (sce->toolsettings->gp_sculptpaint) { - link_paint(fd, sce, &sce->toolsettings->gp_sculptpaint->paint); + link_paint(reader, sce, &sce->toolsettings->gp_sculptpaint->paint); } if (sce->toolsettings->gp_weightpaint) { - link_paint(fd, sce, &sce->toolsettings->gp_weightpaint->paint); + link_paint(reader, sce, &sce->toolsettings->gp_weightpaint->paint); } if (sce->toolsettings->sculpt) { - sce->toolsettings->sculpt->gravity_object = newlibadr( - fd, sce->id.lib, sce->toolsettings->sculpt->gravity_object); + BLO_read_id_address(reader, sce->id.lib, &sce->toolsettings->sculpt->gravity_object); } if (sce->toolsettings->imapaint.stencil) { - sce->toolsettings->imapaint.stencil = newlibadr( - fd, sce->id.lib, sce->toolsettings->imapaint.stencil); + BLO_read_id_address(reader, sce->id.lib, &sce->toolsettings->imapaint.stencil); } if (sce->toolsettings->imapaint.clone) { - sce->toolsettings->imapaint.clone = newlibadr( - fd, sce->id.lib, sce->toolsettings->imapaint.clone); + BLO_read_id_address(reader, sce->id.lib, &sce->toolsettings->imapaint.clone); } if (sce->toolsettings->imapaint.canvas) { - sce->toolsettings->imapaint.canvas = newlibadr( - fd, sce->id.lib, sce->toolsettings->imapaint.canvas); + BLO_read_id_address(reader, sce->id.lib, &sce->toolsettings->imapaint.canvas); } - sce->toolsettings->particle.shape_object = newlibadr( - fd, sce->id.lib, sce->toolsettings->particle.shape_object); + BLO_read_id_address(reader, sce->id.lib, &sce->toolsettings->particle.shape_object); - sce->toolsettings->gp_sculpt.guide.reference_object = newlibadr( - fd, sce->id.lib, sce->toolsettings->gp_sculpt.guide.reference_object); + BLO_read_id_address(reader, sce->id.lib, &sce->toolsettings->gp_sculpt.guide.reference_object); for (Base *base_legacy_next, *base_legacy = sce->base.first; base_legacy; base_legacy = base_legacy_next) { base_legacy_next = base_legacy->next; - base_legacy->object = newlibadr(fd, sce->id.lib, base_legacy->object); + BLO_read_id_address(reader, sce->id.lib, &base_legacy->object); if (base_legacy->object == NULL) { - blo_reportf_wrap( - fd->reports, RPT_WARNING, TIP_("LIB: object lost from scene: '%s'"), sce->id.name + 2); + blo_reportf_wrap(reader->fd->reports, + RPT_WARNING, + TIP_("LIB: object lost from scene: '%s'"), + sce->id.name + 2); BLI_remlink(&sce->base, base_legacy); if (base_legacy == sce->basact) { sce->basact = NULL; @@ -6594,24 +6408,25 @@ static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce) Sequence *seq; SEQ_BEGIN (sce->ed, seq) { - IDP_LibLinkProperty(seq->prop, fd); + IDP_LibLinkProperty(seq->prop, reader); if (seq->ipo) { - seq->ipo = newlibadr(fd, sce->id.lib, seq->ipo); // XXX deprecated - old animation system + BLO_read_id_address( + reader, sce->id.lib, &seq->ipo); // XXX deprecated - old animation system } seq->scene_sound = NULL; if (seq->scene) { - seq->scene = newlibadr(fd, sce->id.lib, seq->scene); + BLO_read_id_address(reader, sce->id.lib, &seq->scene); seq->scene_sound = NULL; } if (seq->clip) { - seq->clip = newlibadr(fd, sce->id.lib, seq->clip); + BLO_read_id_address(reader, sce->id.lib, &seq->clip); } if (seq->mask) { - seq->mask = newlibadr(fd, sce->id.lib, seq->mask); + BLO_read_id_address(reader, sce->id.lib, &seq->mask); } if (seq->scene_camera) { - seq->scene_camera = newlibadr(fd, sce->id.lib, seq->scene_camera); + BLO_read_id_address(reader, sce->id.lib, &seq->scene_camera); } if (seq->sound) { seq->scene_sound = NULL; @@ -6619,7 +6434,7 @@ static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce) seq->type = SEQ_TYPE_SOUND_RAM; } else { - seq->sound = newlibadr(fd, sce->id.lib, seq->sound); + BLO_read_id_address(reader, sce->id.lib, &seq->sound); } if (seq->sound) { id_us_plus_no_lib((ID *)seq->sound); @@ -6628,17 +6443,17 @@ static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce) } if (seq->type == SEQ_TYPE_TEXT) { TextVars *t = seq->effectdata; - t->text_font = newlibadr(fd, sce->id.lib, t->text_font); + BLO_read_id_address(reader, sce->id.lib, &t->text_font); } BLI_listbase_clear(&seq->anims); - lib_link_sequence_modifiers(fd, sce, &seq->modifiers); + lib_link_sequence_modifiers(reader, sce, &seq->modifiers); } SEQ_END; LISTBASE_FOREACH (TimeMarker *, marker, &sce->markers) { if (marker->camera) { - marker->camera = newlibadr(fd, sce->id.lib, marker->camera); + BLO_read_id_address(reader, sce->id.lib, &marker->camera); } } @@ -6646,13 +6461,13 @@ static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce) if (sce->rigidbody_world) { RigidBodyWorld *rbw = sce->rigidbody_world; if (rbw->group) { - rbw->group = newlibadr(fd, sce->id.lib, rbw->group); + BLO_read_id_address(reader, sce->id.lib, &rbw->group); } if (rbw->constraints) { - rbw->constraints = newlibadr(fd, sce->id.lib, rbw->constraints); + BLO_read_id_address(reader, sce->id.lib, &rbw->constraints); } if (rbw->effector_weights) { - rbw->effector_weights->group = newlibadr(fd, sce->id.lib, rbw->effector_weights->group); + BLO_read_id_address(reader, sce->id.lib, &rbw->effector_weights->group); } } @@ -6661,30 +6476,30 @@ static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce) } LISTBASE_FOREACH (SceneRenderLayer *, srl, &sce->r.layers) { - srl->mat_override = newlibadr(fd, sce->id.lib, srl->mat_override); + BLO_read_id_address(reader, sce->id.lib, &srl->mat_override); LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &srl->freestyleConfig.modules) { - fmc->script = newlibadr(fd, sce->id.lib, fmc->script); + BLO_read_id_address(reader, sce->id.lib, &fmc->script); } LISTBASE_FOREACH (FreestyleLineSet *, fls, &srl->freestyleConfig.linesets) { - fls->linestyle = newlibadr(fd, sce->id.lib, fls->linestyle); - fls->group = newlibadr(fd, sce->id.lib, fls->group); + BLO_read_id_address(reader, sce->id.lib, &fls->linestyle); + BLO_read_id_address(reader, sce->id.lib, &fls->group); } } /* Motion Tracking */ - sce->clip = newlibadr(fd, sce->id.lib, sce->clip); + BLO_read_id_address(reader, sce->id.lib, &sce->clip); #ifdef USE_COLLECTION_COMPAT_28 if (sce->collection) { - lib_link_scene_collection(fd, sce->id.lib, sce->collection); + lib_link_scene_collection(reader, sce->id.lib, sce->collection); } #endif LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) { - lib_link_view_layer(fd, sce->id.lib, view_layer); + lib_link_view_layer(reader, sce->id.lib, view_layer); } if (sce->r.bake.cage_object) { - sce->r.bake.cage_object = newlibadr(fd, sce->id.lib, sce->r.bake.cage_object); + BLO_read_id_address(reader, sce->id.lib, &sce->r.bake.cage_object); } #ifdef USE_SETSCENE_CHECK @@ -6734,7 +6549,7 @@ static void direct_link_paint(BlendDataReader *reader, const Scene *scene, Paint BLO_read_data_address(reader, &p->cavity_curve); if (p->cavity_curve) { - direct_link_curvemapping(reader, p->cavity_curve); + BKE_curvemapping_blend_read(reader, p->cavity_curve); } else { BKE_paint_cavity_curve_preset(p, CURVE_PRESET_LINE); @@ -6776,12 +6591,12 @@ static void direct_link_sequence_modifiers(BlendDataReader *reader, ListBase *lb if (smd->type == seqModifierType_Curves) { CurvesModifierData *cmd = (CurvesModifierData *)smd; - direct_link_curvemapping(reader, &cmd->curve_mapping); + BKE_curvemapping_blend_read(reader, &cmd->curve_mapping); } else if (smd->type == seqModifierType_HueCorrect) { HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd; - direct_link_curvemapping(reader, &hcmd->curve_mapping); + BKE_curvemapping_blend_read(reader, &hcmd->curve_mapping); } } } @@ -6844,23 +6659,23 @@ static void direct_link_scene(BlendDataReader *reader, Scene *sce) /* relink grease pencil interpolation curves */ BLO_read_data_address(reader, &sce->toolsettings->gp_interpolate.custom_ipo); if (sce->toolsettings->gp_interpolate.custom_ipo) { - direct_link_curvemapping(reader, sce->toolsettings->gp_interpolate.custom_ipo); + BKE_curvemapping_blend_read(reader, sce->toolsettings->gp_interpolate.custom_ipo); } /* relink grease pencil multiframe falloff curve */ BLO_read_data_address(reader, &sce->toolsettings->gp_sculpt.cur_falloff); if (sce->toolsettings->gp_sculpt.cur_falloff) { - direct_link_curvemapping(reader, sce->toolsettings->gp_sculpt.cur_falloff); + BKE_curvemapping_blend_read(reader, sce->toolsettings->gp_sculpt.cur_falloff); } /* relink grease pencil primitive curve */ BLO_read_data_address(reader, &sce->toolsettings->gp_sculpt.cur_primitive); if (sce->toolsettings->gp_sculpt.cur_primitive) { - direct_link_curvemapping(reader, sce->toolsettings->gp_sculpt.cur_primitive); + BKE_curvemapping_blend_read(reader, sce->toolsettings->gp_sculpt.cur_primitive); } /* Relink toolsettings curve profile */ BLO_read_data_address(reader, &sce->toolsettings->custom_bevel_profile_preset); if (sce->toolsettings->custom_bevel_profile_preset) { - direct_link_curveprofile(reader, sce->toolsettings->custom_bevel_profile_preset); + BKE_curveprofile_blend_read(reader, sce->toolsettings->custom_bevel_profile_preset); } } @@ -7059,7 +6874,7 @@ static void direct_link_scene(BlendDataReader *reader, Scene *sce) sce->preview = direct_link_preview_image(reader, sce->preview); - direct_link_curvemapping(reader, &sce->r.mblur_shutter_curve); + BKE_curvemapping_blend_read(reader, &sce->r.mblur_shutter_curve); #ifdef USE_COLLECTION_COMPAT_28 /* this runs before the very first doversion */ @@ -7106,18 +6921,18 @@ static void direct_link_scene(BlendDataReader *reader, Scene *sce) * \{ */ /* relink's grease pencil data's refs */ -static void lib_link_gpencil(FileData *fd, Main *UNUSED(bmain), bGPdata *gpd) +static void lib_link_gpencil(BlendLibReader *reader, bGPdata *gpd) { /* Relink all data-lock linked by GP data-lock */ /* Layers */ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* Layer -> Parent References */ - gpl->parent = newlibadr(fd, gpd->id.lib, gpl->parent); + BLO_read_id_address(reader, gpd->id.lib, &gpl->parent); } /* materials */ for (int a = 0; a < gpd->totcol; a++) { - gpd->mat[a] = newlibadr(fd, gpd->id.lib, gpd->mat[a]); + BLO_read_id_address(reader, gpd->id.lib, &gpd->mat[a]); } } @@ -7209,6 +7024,7 @@ static void direct_link_panel_list(BlendDataReader *reader, ListBase *lb) panel->runtime_flag = 0; panel->activedata = NULL; panel->type = NULL; + panel->runtime.custom_data_ptr = NULL; direct_link_panel_list(reader, &panel->children); } } @@ -7524,9 +7340,9 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) BLO_read_data_address(reader, &area->v4); } -static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) +static void lib_link_area(BlendLibReader *reader, ID *parent_id, ScrArea *area) { - area->full = newlibadr(fd, parent_id->lib, area->full); + BLO_read_id_address(reader, parent_id->lib, &area->full); memset(&area->runtime, 0x0, sizeof(area->runtime)); @@ -7535,11 +7351,11 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) case SPACE_VIEW3D: { View3D *v3d = (View3D *)sl; - v3d->camera = newlibadr(fd, parent_id->lib, v3d->camera); - v3d->ob_center = newlibadr(fd, parent_id->lib, v3d->ob_center); + BLO_read_id_address(reader, parent_id->lib, &v3d->camera); + BLO_read_id_address(reader, parent_id->lib, &v3d->ob_center); if (v3d->localvd) { - v3d->localvd->camera = newlibadr(fd, parent_id->lib, v3d->localvd->camera); + BLO_read_id_address(reader, parent_id->lib, &v3d->localvd->camera); } break; } @@ -7548,14 +7364,14 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) bDopeSheet *ads = sipo->ads; if (ads) { - ads->source = newlibadr(fd, parent_id->lib, ads->source); - ads->filter_grp = newlibadr(fd, parent_id->lib, ads->filter_grp); + BLO_read_id_address(reader, parent_id->lib, &ads->source); + BLO_read_id_address(reader, parent_id->lib, &ads->filter_grp); } break; } case SPACE_PROPERTIES: { SpaceProperties *sbuts = (SpaceProperties *)sl; - sbuts->pinid = newlibadr(fd, parent_id->lib, sbuts->pinid); + BLO_read_id_address(reader, parent_id->lib, &sbuts->pinid); if (sbuts->pinid == NULL) { sbuts->flag &= ~SB_PIN_CONTEXT; } @@ -7568,23 +7384,23 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) bDopeSheet *ads = &saction->ads; if (ads) { - ads->source = newlibadr(fd, parent_id->lib, ads->source); - ads->filter_grp = newlibadr(fd, parent_id->lib, ads->filter_grp); + BLO_read_id_address(reader, parent_id->lib, &ads->source); + BLO_read_id_address(reader, parent_id->lib, &ads->filter_grp); } - saction->action = newlibadr(fd, parent_id->lib, saction->action); + BLO_read_id_address(reader, parent_id->lib, &saction->action); break; } case SPACE_IMAGE: { SpaceImage *sima = (SpaceImage *)sl; - sima->image = newlibadr(fd, parent_id->lib, sima->image); - sima->mask_info.mask = newlibadr(fd, parent_id->lib, sima->mask_info.mask); + BLO_read_id_address(reader, parent_id->lib, &sima->image); + BLO_read_id_address(reader, parent_id->lib, &sima->mask_info.mask); /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data * so fingers crossed this works fine! */ - sima->gpd = newlibadr(fd, parent_id->lib, sima->gpd); + BLO_read_id_address(reader, parent_id->lib, &sima->gpd); break; } case SPACE_SEQ: { @@ -7593,7 +7409,7 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data * so fingers crossed this works fine! */ - sseq->gpd = newlibadr(fd, parent_id->lib, sseq->gpd); + BLO_read_id_address(reader, parent_id->lib, &sseq->gpd); break; } case SPACE_NLA: { @@ -7601,22 +7417,22 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) bDopeSheet *ads = snla->ads; if (ads) { - ads->source = newlibadr(fd, parent_id->lib, ads->source); - ads->filter_grp = newlibadr(fd, parent_id->lib, ads->filter_grp); + BLO_read_id_address(reader, parent_id->lib, &ads->source); + BLO_read_id_address(reader, parent_id->lib, &ads->filter_grp); } break; } case SPACE_TEXT: { SpaceText *st = (SpaceText *)sl; - st->text = newlibadr(fd, parent_id->lib, st->text); + BLO_read_id_address(reader, parent_id->lib, &st->text); break; } case SPACE_SCRIPT: { SpaceScript *scpt = (SpaceScript *)sl; /*scpt->script = NULL; - 2.45 set to null, better re-run the script */ if (scpt->script) { - scpt->script = newlibadr(fd, parent_id->lib, scpt->script); + BLO_read_id_address(reader, parent_id->lib, &scpt->script); if (scpt->script) { SCRIPT_SET_NULL(scpt->script); } @@ -7625,7 +7441,7 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) } case SPACE_OUTLINER: { SpaceOutliner *so = (SpaceOutliner *)sl; - so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id); + BLO_read_id_address(reader, NULL, &so->search_tse.id); if (so->treestore) { TreeStoreElem *tselem; @@ -7633,7 +7449,7 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) BLI_mempool_iternew(so->treestore, &iter); while ((tselem = BLI_mempool_iterstep(&iter))) { - tselem->id = newlibadr(fd, NULL, tselem->id); + BLO_read_id_address(reader, NULL, &tselem->id); } if (so->treehash) { /* rebuild hash table, because it depends on ids too */ @@ -7645,14 +7461,18 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) case SPACE_NODE: { SpaceNode *snode = (SpaceNode *)sl; bNodeTreePath *path, *path_next; - bNodeTree *ntree; /* node tree can be stored locally in id too, link this first */ - snode->id = newlibadr(fd, parent_id->lib, snode->id); - snode->from = newlibadr(fd, parent_id->lib, snode->from); + BLO_read_id_address(reader, parent_id->lib, &snode->id); + BLO_read_id_address(reader, parent_id->lib, &snode->from); - ntree = snode->id ? ntreeFromID(snode->id) : NULL; - snode->nodetree = ntree ? ntree : newlibadr(fd, parent_id->lib, snode->nodetree); + bNodeTree *ntree = snode->id ? ntreeFromID(snode->id) : NULL; + if (ntree) { + snode->nodetree = ntree; + } + else { + BLO_read_id_address(reader, parent_id->lib, &snode->nodetree); + } for (path = snode->treepath.first; path; path = path->next) { if (path == snode->treepath.first) { @@ -7660,7 +7480,7 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) path->nodetree = snode->nodetree; } else { - path->nodetree = newlibadr(fd, parent_id->lib, path->nodetree); + BLO_read_id_address(reader, parent_id->lib, &path->nodetree); } if (!path->nodetree) { @@ -7689,8 +7509,8 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area) } case SPACE_CLIP: { SpaceClip *sclip = (SpaceClip *)sl; - sclip->clip = newlibadr(fd, parent_id->lib, sclip->clip); - sclip->mask_info.mask = newlibadr(fd, parent_id->lib, sclip->mask_info.mask); + BLO_read_id_address(reader, parent_id->lib, &sclip->clip); + BLO_read_id_address(reader, parent_id->lib, &sclip->mask_info.mask); break; } default: @@ -7738,10 +7558,9 @@ static void direct_link_wm_xr_data(BlendDataReader *reader, wmXrData *xr_data) direct_link_view3dshading(reader, &xr_data->session_settings.shading); } -static void lib_link_wm_xr_data(FileData *fd, ID *parent_id, wmXrData *xr_data) +static void lib_link_wm_xr_data(BlendLibReader *reader, ID *parent_id, wmXrData *xr_data) { - xr_data->session_settings.base_pose_object = newlibadr( - fd, parent_id->lib, xr_data->session_settings.base_pose_object); + BLO_read_id_address(reader, parent_id->lib, &xr_data->session_settings.base_pose_object); } /** \} */ @@ -7827,21 +7646,21 @@ static void direct_link_windowmanager(BlendDataReader *reader, wmWindowManager * wm->is_interface_locked = 0; } -static void lib_link_windowmanager(FileData *fd, Main *UNUSED(bmain), wmWindowManager *wm) +static void lib_link_windowmanager(BlendLibReader *reader, wmWindowManager *wm) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { if (win->workspace_hook) { /* NULL for old files */ - lib_link_workspace_instance_hook(fd, win->workspace_hook, &wm->id); + lib_link_workspace_instance_hook(reader, win->workspace_hook, &wm->id); } - win->scene = newlibadr(fd, wm->id.lib, win->scene); + BLO_read_id_address(reader, wm->id.lib, &win->scene); /* deprecated, but needed for versioning (will be NULL'ed then) */ - win->screen = newlibadr(fd, NULL, win->screen); + BLO_read_id_address(reader, NULL, &win->screen); LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { - lib_link_area(fd, &wm->id, area); + lib_link_area(reader, &wm->id, area); } - lib_link_wm_xr_data(fd, &wm->id, &wm->xr); + lib_link_wm_xr_data(reader, &wm->id, &wm->xr); } } @@ -7853,17 +7672,17 @@ static void lib_link_windowmanager(FileData *fd, Main *UNUSED(bmain), wmWindowMa /* note: file read without screens option G_FILE_NO_UI; * check lib pointers in call below */ -static void lib_link_screen(FileData *fd, Main *UNUSED(bmain), bScreen *screen) +static void lib_link_screen(BlendLibReader *reader, bScreen *screen) { /* deprecated, but needed for versioning (will be NULL'ed then) */ - screen->scene = newlibadr(fd, screen->id.lib, screen->scene); + BLO_read_id_address(reader, screen->id.lib, &screen->scene); screen->animtimer = NULL; /* saved in rare cases */ screen->tool_tip = NULL; screen->scrubbing = false; LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - lib_link_area(fd, &screen->id, area); + lib_link_area(reader, &screen->id, area); } } @@ -8399,12 +8218,12 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) /* check if the library was already read */ for (newmain = fd->mainlist->first; newmain; newmain = newmain->next) { if (newmain->curlib) { - if (BLI_path_cmp(newmain->curlib->filepath, lib->filepath) == 0) { + if (BLI_path_cmp(newmain->curlib->filepath_abs, lib->filepath_abs) == 0) { blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("Library '%s', '%s' had multiple instances, save and reload!"), - lib->name, - lib->filepath); + lib->filepath, + lib->filepath_abs); change_link_placeholder_to_real_ID_pointer(fd->mainlist, fd, lib, newmain->curlib); /* change_link_placeholder_to_real_ID_pointer_fd(fd, lib, newmain->curlib); */ @@ -8426,12 +8245,12 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) } } - /* make sure we have full path in lib->filepath */ - BLI_strncpy(lib->filepath, lib->name, sizeof(lib->name)); - BLI_path_normalize(fd->relabase, lib->filepath); + /* Make sure we have full path in lib->filepath_abs */ + BLI_strncpy(lib->filepath_abs, lib->filepath, sizeof(lib->filepath)); + BLI_path_normalize(fd->relabase, lib->filepath_abs); - // printf("direct_link_library: name %s\n", lib->name); // printf("direct_link_library: filepath %s\n", lib->filepath); + // printf("direct_link_library: filepath_abs %s\n", lib->filepath_abs); BlendDataReader reader = {fd}; lib->packedfile = direct_link_packedfile(&reader, lib->packedfile); @@ -8446,7 +8265,7 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) id_us_ensure_real(&lib->id); } -static void lib_link_library(FileData *UNUSED(fd), Main *UNUSED(bmain), Library *UNUSED(lib)) +static void lib_link_library(BlendLibReader *UNUSED(reader), Library *UNUSED(lib)) { } @@ -8463,8 +8282,8 @@ static void fix_relpaths_library(const char *basepath, Main *main) * it absolute. This can happen when appending an object with a relative * link into an unsaved blend file. See [#27405]. * The remap relative option will make it relative again on save - campbell */ - if (BLI_path_is_rel(lib->name)) { - BLI_strncpy(lib->name, lib->filepath, sizeof(lib->name)); + if (BLI_path_is_rel(lib->filepath)) { + BLI_strncpy(lib->filepath, lib->filepath_abs, sizeof(lib->filepath)); } } } @@ -8473,9 +8292,9 @@ static void fix_relpaths_library(const char *basepath, Main *main) /* Libraries store both relative and abs paths, recreate relative paths, * relative to the blend file since indirectly linked libs will be * relative to their direct linked library. */ - if (BLI_path_is_rel(lib->name)) { /* if this is relative to begin with? */ - BLI_strncpy(lib->name, lib->filepath, sizeof(lib->name)); - BLI_path_rel(lib->name, basepath); + if (BLI_path_is_rel(lib->filepath)) { /* if this is relative to begin with? */ + BLI_strncpy(lib->filepath, lib->filepath_abs, sizeof(lib->filepath)); + BLI_path_rel(lib->filepath, basepath); } } } @@ -8487,9 +8306,9 @@ static void fix_relpaths_library(const char *basepath, Main *main) /** \name Read ID: Light Probe * \{ */ -static void lib_link_lightprobe(FileData *fd, Main *UNUSED(bmain), LightProbe *prb) +static void lib_link_lightprobe(BlendLibReader *reader, LightProbe *prb) { - prb->visibility_grp = newlibadr(fd, prb->id.lib, prb->visibility_grp); + BLO_read_id_address(reader, prb->id.lib, &prb->visibility_grp); } static void direct_link_lightprobe(BlendDataReader *reader, LightProbe *prb) @@ -8504,9 +8323,9 @@ static void direct_link_lightprobe(BlendDataReader *reader, LightProbe *prb) /** \name Read ID: Speaker * \{ */ -static void lib_link_speaker(FileData *fd, Main *UNUSED(bmain), Speaker *spk) +static void lib_link_speaker(BlendLibReader *reader, Speaker *spk) { - spk->sound = newlibadr(fd, spk->id.lib, spk->sound); + BLO_read_id_address(reader, spk->id.lib, &spk->sound); } static void direct_link_speaker(BlendDataReader *reader, Speaker *spk) @@ -8556,9 +8375,10 @@ static void direct_link_sound(BlendDataReader *reader, bSound *sound) sound->newpackedfile = direct_link_packedfile(reader, sound->newpackedfile); } -static void lib_link_sound(FileData *fd, Main *UNUSED(bmain), bSound *sound) +static void lib_link_sound(BlendLibReader *reader, bSound *sound) { - sound->ipo = newlibadr(fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system + BLO_read_id_address( + reader, sound->id.lib, &sound->ipo); // XXX deprecated - old animation system } /** \} */ @@ -8650,36 +8470,38 @@ static void direct_link_movieclip(BlendDataReader *reader, MovieClip *clip) } } -static void lib_link_movieTracks(FileData *fd, MovieClip *clip, ListBase *tracksbase) +static void lib_link_movieTracks(BlendLibReader *reader, MovieClip *clip, ListBase *tracksbase) { MovieTrackingTrack *track; for (track = tracksbase->first; track; track = track->next) { - track->gpd = newlibadr(fd, clip->id.lib, track->gpd); + BLO_read_id_address(reader, clip->id.lib, &track->gpd); } } -static void lib_link_moviePlaneTracks(FileData *fd, MovieClip *clip, ListBase *tracksbase) +static void lib_link_moviePlaneTracks(BlendLibReader *reader, + MovieClip *clip, + ListBase *tracksbase) { MovieTrackingPlaneTrack *plane_track; for (plane_track = tracksbase->first; plane_track; plane_track = plane_track->next) { - plane_track->image = newlibadr(fd, clip->id.lib, plane_track->image); + BLO_read_id_address(reader, clip->id.lib, &plane_track->image); } } -static void lib_link_movieclip(FileData *fd, Main *UNUSED(bmain), MovieClip *clip) +static void lib_link_movieclip(BlendLibReader *reader, MovieClip *clip) { MovieTracking *tracking = &clip->tracking; - clip->gpd = newlibadr(fd, clip->id.lib, clip->gpd); + BLO_read_id_address(reader, clip->id.lib, &clip->gpd); - lib_link_movieTracks(fd, clip, &tracking->tracks); - lib_link_moviePlaneTracks(fd, clip, &tracking->plane_tracks); + lib_link_movieTracks(reader, clip, &tracking->tracks); + lib_link_moviePlaneTracks(reader, clip, &tracking->plane_tracks); LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) { - lib_link_movieTracks(fd, clip, &object->tracks); - lib_link_moviePlaneTracks(fd, clip, &object->plane_tracks); + lib_link_movieTracks(reader, clip, &object->tracks); + lib_link_moviePlaneTracks(reader, clip, &object->plane_tracks); } } @@ -8747,12 +8569,12 @@ static void direct_link_mask(BlendDataReader *reader, Mask *mask) } } -static void lib_link_mask_parent(FileData *fd, Mask *mask, MaskParent *parent) +static void lib_link_mask_parent(BlendLibReader *reader, Mask *mask, MaskParent *parent) { - parent->id = newlibadr(fd, mask->id.lib, parent->id); + BLO_read_id_address(reader, mask->id.lib, &parent->id); } -static void lib_link_mask(FileData *fd, Main *UNUSED(bmain), Mask *mask) +static void lib_link_mask(BlendLibReader *reader, Mask *mask) { LISTBASE_FOREACH (MaskLayer *, masklay, &mask->masklayers) { MaskSpline *spline; @@ -8764,10 +8586,10 @@ static void lib_link_mask(FileData *fd, Main *UNUSED(bmain), Mask *mask) for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; - lib_link_mask_parent(fd, mask, &point->parent); + lib_link_mask_parent(reader, mask, &point->parent); } - lib_link_mask_parent(fd, mask, &spline->parent); + lib_link_mask_parent(reader, mask, &spline->parent); spline = spline->next; } @@ -8780,7 +8602,7 @@ static void lib_link_mask(FileData *fd, Main *UNUSED(bmain), Mask *mask) /** \name Read ID: Line Style * \{ */ -static void lib_link_linestyle(FileData *fd, Main *UNUSED(bmain), FreestyleLineStyle *linestyle) +static void lib_link_linestyle(BlendLibReader *reader, FreestyleLineStyle *linestyle) { LineStyleModifier *m; @@ -8789,7 +8611,7 @@ static void lib_link_linestyle(FileData *fd, Main *UNUSED(bmain), FreestyleLineS case LS_MODIFIER_DISTANCE_FROM_OBJECT: { LineStyleColorModifier_DistanceFromObject *cm = (LineStyleColorModifier_DistanceFromObject *)m; - cm->target = newlibadr(fd, linestyle->id.lib, cm->target); + BLO_read_id_address(reader, linestyle->id.lib, &cm->target); break; } } @@ -8799,7 +8621,7 @@ static void lib_link_linestyle(FileData *fd, Main *UNUSED(bmain), FreestyleLineS case LS_MODIFIER_DISTANCE_FROM_OBJECT: { LineStyleAlphaModifier_DistanceFromObject *am = (LineStyleAlphaModifier_DistanceFromObject *)m; - am->target = newlibadr(fd, linestyle->id.lib, am->target); + BLO_read_id_address(reader, linestyle->id.lib, &am->target); break; } } @@ -8809,7 +8631,7 @@ static void lib_link_linestyle(FileData *fd, Main *UNUSED(bmain), FreestyleLineS case LS_MODIFIER_DISTANCE_FROM_OBJECT: { LineStyleThicknessModifier_DistanceFromObject *tm = (LineStyleThicknessModifier_DistanceFromObject *)m; - tm->target = newlibadr(fd, linestyle->id.lib, tm->target); + BLO_read_id_address(reader, linestyle->id.lib, &tm->target); break; } } @@ -8817,8 +8639,8 @@ static void lib_link_linestyle(FileData *fd, Main *UNUSED(bmain), FreestyleLineS for (int a = 0; a < MAX_MTEX; a++) { MTex *mtex = linestyle->mtex[a]; if (mtex) { - mtex->tex = newlibadr(fd, linestyle->id.lib, mtex->tex); - mtex->object = newlibadr(fd, linestyle->id.lib, mtex->object); + BLO_read_id_address(reader, linestyle->id.lib, &mtex->tex); + BLO_read_id_address(reader, linestyle->id.lib, &mtex->object); } } } @@ -8879,51 +8701,51 @@ static void direct_link_linestyle_alpha_modifier(BlendDataReader *reader, case LS_MODIFIER_ALONG_STROKE: { LineStyleAlphaModifier_AlongStroke *m = (LineStyleAlphaModifier_AlongStroke *)modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_DISTANCE_FROM_CAMERA: { LineStyleAlphaModifier_DistanceFromCamera *m = (LineStyleAlphaModifier_DistanceFromCamera *) modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_DISTANCE_FROM_OBJECT: { LineStyleAlphaModifier_DistanceFromObject *m = (LineStyleAlphaModifier_DistanceFromObject *) modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_MATERIAL: { LineStyleAlphaModifier_Material *m = (LineStyleAlphaModifier_Material *)modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_TANGENT: { LineStyleAlphaModifier_Tangent *m = (LineStyleAlphaModifier_Tangent *)modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_NOISE: { LineStyleAlphaModifier_Noise *m = (LineStyleAlphaModifier_Noise *)modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_CREASE_ANGLE: { LineStyleAlphaModifier_CreaseAngle *m = (LineStyleAlphaModifier_CreaseAngle *)modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_CURVATURE_3D: { LineStyleAlphaModifier_Curvature_3D *m = (LineStyleAlphaModifier_Curvature_3D *)modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } } @@ -8937,47 +8759,47 @@ static void direct_link_linestyle_thickness_modifier(BlendDataReader *reader, LineStyleThicknessModifier_AlongStroke *m = (LineStyleThicknessModifier_AlongStroke *) modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_DISTANCE_FROM_CAMERA: { LineStyleThicknessModifier_DistanceFromCamera *m = (LineStyleThicknessModifier_DistanceFromCamera *)modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_DISTANCE_FROM_OBJECT: { LineStyleThicknessModifier_DistanceFromObject *m = (LineStyleThicknessModifier_DistanceFromObject *)modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_MATERIAL: { LineStyleThicknessModifier_Material *m = (LineStyleThicknessModifier_Material *)modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_TANGENT: { LineStyleThicknessModifier_Tangent *m = (LineStyleThicknessModifier_Tangent *)modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_CREASE_ANGLE: { LineStyleThicknessModifier_CreaseAngle *m = (LineStyleThicknessModifier_CreaseAngle *) modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } case LS_MODIFIER_CURVATURE_3D: { LineStyleThicknessModifier_Curvature_3D *m = (LineStyleThicknessModifier_Curvature_3D *) modifier; BLO_read_data_address(reader, &m->curve); - direct_link_curvemapping(reader, m->curve); + BKE_curvemapping_blend_read(reader, m->curve); break; } } @@ -9022,10 +8844,10 @@ static void direct_link_linestyle(BlendDataReader *reader, FreestyleLineStyle *l /** \name Read ID: Hair * \{ */ -static void lib_link_hair(FileData *fd, Main *UNUSED(main), Hair *hair) +static void lib_link_hair(BlendLibReader *reader, Hair *hair) { for (int a = 0; a < hair->totcol; a++) { - hair->mat[a] = newlibadr(fd, hair->id.lib, hair->mat[a]); + BLO_read_id_address(reader, hair->id.lib, &hair->mat[a]); } } @@ -9049,10 +8871,10 @@ static void direct_link_hair(BlendDataReader *reader, Hair *hair) /** \name Read ID: Point Cloud * \{ */ -static void lib_link_pointcloud(FileData *fd, Main *UNUSED(main), PointCloud *pointcloud) +static void lib_link_pointcloud(BlendLibReader *reader, PointCloud *pointcloud) { for (int a = 0; a < pointcloud->totcol; a++) { - pointcloud->mat[a] = newlibadr(fd, pointcloud->id.lib, pointcloud->mat[a]); + BLO_read_id_address(reader, pointcloud->id.lib, &pointcloud->mat[a]); } } @@ -9075,10 +8897,10 @@ static void direct_link_pointcloud(BlendDataReader *reader, PointCloud *pointclo /** \name Read ID: Volume * \{ */ -static void lib_link_volume(FileData *fd, Main *UNUSED(main), Volume *volume) +static void lib_link_volume(BlendLibReader *reader, Volume *volume) { for (int a = 0; a < volume->totcol; a++) { - volume->mat[a] = newlibadr(fd, volume->id.lib, volume->mat[a]); + BLO_read_id_address(reader, volume->id.lib, &volume->mat[a]); } } @@ -9104,9 +8926,7 @@ static void direct_link_volume(BlendDataReader *reader, Volume *volume) /** \name Read ID: Simulation * \{ */ -static void lib_link_simulation(FileData *UNUSED(fd), - Main *UNUSED(main), - Simulation *UNUSED(simulation)) +static void lib_link_simulation(BlendLibReader *UNUSED(reader), Simulation *UNUSED(simulation)) { } @@ -9491,7 +9311,7 @@ static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID DEBUG_PRINTF("UNDO: restore linked datablock %s\n", id->name); DEBUG_PRINTF(" from %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", - main->curlib ? main->curlib->name : "<NULL>"); + main->curlib ? main->curlib->filepath : "<NULL>"); ID *id_old = BKE_libblock_find_name(main, GS(id->name), id->name + 2); if (id_old != NULL) { @@ -9940,8 +9760,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) static void do_versions_after_linking(Main *main, ReportList *reports) { - // printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name, - // main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile); + // printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->filepath : + // main->name, main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile); /* Don't allow versioning to create new data-blocks. */ main->is_locked_for_linking = true; @@ -9966,6 +9786,8 @@ static void lib_link_all(FileData *fd, Main *bmain) { const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; + BlendLibReader reader = {fd, bmain}; + ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { if ((id->tag & LIB_TAG_NEED_LINK) == 0) { @@ -9986,7 +9808,7 @@ static void lib_link_all(FileData *fd, Main *bmain) continue; } - lib_link_id(fd, bmain, id); + lib_link_id(&reader, id); /* Note: ID types are processed in reverse order as defined by INDEX_ID_XXX enums in DNA_ID.h. * This ensures handling of most dependencies in proper order, as elsewhere in code. @@ -9994,129 +9816,129 @@ static void lib_link_all(FileData *fd, Main *bmain) * whether something is wrong then. */ switch (GS(id->name)) { case ID_MSK: - lib_link_mask(fd, bmain, (Mask *)id); + lib_link_mask(&reader, (Mask *)id); break; case ID_WM: - lib_link_windowmanager(fd, bmain, (wmWindowManager *)id); + lib_link_windowmanager(&reader, (wmWindowManager *)id); break; case ID_WS: /* Could we skip WS in undo case? */ - lib_link_workspaces(fd, bmain, (WorkSpace *)id); + lib_link_workspaces(&reader, (WorkSpace *)id); break; case ID_SCE: - lib_link_scene(fd, bmain, (Scene *)id); + lib_link_scene(&reader, (Scene *)id); break; case ID_LS: - lib_link_linestyle(fd, bmain, (FreestyleLineStyle *)id); + lib_link_linestyle(&reader, (FreestyleLineStyle *)id); break; case ID_OB: - lib_link_object(fd, bmain, (Object *)id); + lib_link_object(&reader, (Object *)id); break; case ID_SCR: /* DO NOT skip screens here, * 3D viewport may contains pointers to other ID data (like bgpic)! See T41411. */ - lib_link_screen(fd, bmain, (bScreen *)id); + lib_link_screen(&reader, (bScreen *)id); break; case ID_MC: - lib_link_movieclip(fd, bmain, (MovieClip *)id); + lib_link_movieclip(&reader, (MovieClip *)id); break; case ID_WO: - lib_link_world(fd, bmain, (World *)id); + lib_link_world(&reader, (World *)id); break; case ID_LP: - lib_link_lightprobe(fd, bmain, (LightProbe *)id); + lib_link_lightprobe(&reader, (LightProbe *)id); break; case ID_SPK: - lib_link_speaker(fd, bmain, (Speaker *)id); + lib_link_speaker(&reader, (Speaker *)id); break; case ID_PA: - lib_link_particlesettings(fd, bmain, (ParticleSettings *)id); + lib_link_particlesettings(&reader, (ParticleSettings *)id); break; case ID_PC: - lib_link_paint_curve(fd, bmain, (PaintCurve *)id); + lib_link_paint_curve(&reader, (PaintCurve *)id); break; case ID_BR: - lib_link_brush(fd, bmain, (Brush *)id); + lib_link_brush(&reader, (Brush *)id); break; case ID_GR: - lib_link_collection(fd, bmain, (Collection *)id); + lib_link_collection(&reader, (Collection *)id); break; case ID_SO: - lib_link_sound(fd, bmain, (bSound *)id); + lib_link_sound(&reader, (bSound *)id); break; case ID_TXT: - lib_link_text(fd, bmain, (Text *)id); + lib_link_text(&reader, (Text *)id); break; case ID_CA: - lib_link_camera(fd, bmain, (Camera *)id); + lib_link_camera(&reader, (Camera *)id); break; case ID_LA: - lib_link_light(fd, bmain, (Light *)id); + lib_link_light(&reader, (Light *)id); break; case ID_LT: - lib_link_latt(fd, bmain, (Lattice *)id); + lib_link_latt(&reader, (Lattice *)id); break; case ID_MB: - lib_link_mball(fd, bmain, (MetaBall *)id); + lib_link_mball(&reader, (MetaBall *)id); break; case ID_CU: - lib_link_curve(fd, bmain, (Curve *)id); + lib_link_curve(&reader, (Curve *)id); break; case ID_ME: - lib_link_mesh(fd, bmain, (Mesh *)id); + lib_link_mesh(&reader, (Mesh *)id); break; case ID_CF: - lib_link_cachefiles(fd, bmain, (CacheFile *)id); + lib_link_cachefiles(&reader, (CacheFile *)id); break; case ID_AR: - lib_link_armature(fd, bmain, (bArmature *)id); + lib_link_armature(&reader, (bArmature *)id); break; case ID_VF: - lib_link_vfont(fd, bmain, (VFont *)id); + lib_link_vfont(&reader, (VFont *)id); break; case ID_HA: - lib_link_hair(fd, bmain, (Hair *)id); + lib_link_hair(&reader, (Hair *)id); break; case ID_PT: - lib_link_pointcloud(fd, bmain, (PointCloud *)id); + lib_link_pointcloud(&reader, (PointCloud *)id); break; case ID_VO: - lib_link_volume(fd, bmain, (Volume *)id); + lib_link_volume(&reader, (Volume *)id); break; case ID_MA: - lib_link_material(fd, bmain, (Material *)id); + lib_link_material(&reader, (Material *)id); break; case ID_TE: - lib_link_texture(fd, bmain, (Tex *)id); + lib_link_texture(&reader, (Tex *)id); break; case ID_IM: - lib_link_image(fd, bmain, (Image *)id); + lib_link_image(&reader, (Image *)id); break; case ID_NT: /* Has to be done after node users (scene/materials/...), this will verify group nodes. */ - lib_link_nodetree(fd, bmain, (bNodeTree *)id); + lib_link_nodetree(&reader, (bNodeTree *)id); break; case ID_GD: - lib_link_gpencil(fd, bmain, (bGPdata *)id); + lib_link_gpencil(&reader, (bGPdata *)id); break; case ID_PAL: - lib_link_palette(fd, bmain, (Palette *)id); + lib_link_palette(&reader, (Palette *)id); break; case ID_KE: - lib_link_key(fd, bmain, (Key *)id); + lib_link_key(&reader, (Key *)id); break; case ID_AC: - lib_link_action(fd, bmain, (bAction *)id); + lib_link_action(&reader, (bAction *)id); break; case ID_SIM: - lib_link_simulation(fd, bmain, (Simulation *)id); + lib_link_simulation(&reader, (Simulation *)id); break; case ID_IP: /* XXX deprecated... still needs to be maintained for version patches still. */ - lib_link_ipo(fd, bmain, (Ipo *)id); + lib_link_ipo(&reader, (Ipo *)id); break; case ID_LI: - lib_link_library(fd, bmain, (Library *)id); /* Only init users. */ + lib_link_library(&reader, (Library *)id); /* Only init users. */ break; } @@ -10591,7 +10413,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) } Library *lib = read_struct(fd, bheadlib, "Library"); - Main *libmain = blo_find_main(fd, lib->name, fd->relabase); + Main *libmain = blo_find_main(fd, lib->filepath, fd->relabase); if (libmain->curlib == NULL) { const char *idname = blo_bhead_id_name(fd, bhead); @@ -10600,7 +10422,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) RPT_WARNING, TIP_("LIB: Data refers to main .blend file: '%s' from %s"), idname, - mainvar->curlib->filepath); + mainvar->curlib->filepath_abs); return; } @@ -10611,7 +10433,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) * library it belongs to, so that it will be read later. */ read_libblock(fd, libmain, bhead, LIB_TAG_INDIRECT, false, NULL); // commented because this can print way too much - // if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name); + // if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->filepath); /* for outliner dependency only */ libmain->curlib->parent = mainvar->curlib; @@ -10648,7 +10470,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) /* Commented because this can print way too much. */ #if 0 if (G.debug & G_DEBUG) { - printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name); + printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->filepath); } #endif } @@ -10686,26 +10508,26 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) static BLOExpandDoitCallback expand_doit; // XXX deprecated - old animation system -static void expand_ipo(FileData *fd, Main *mainvar, Ipo *ipo) +static void expand_ipo(BlendExpander *expander, Ipo *ipo) { IpoCurve *icu; for (icu = ipo->curve.first; icu; icu = icu->next) { if (icu->driver) { - expand_doit(fd, mainvar, icu->driver->ob); + BLO_expand(expander, icu->driver->ob); } } } // XXX deprecated - old animation system -static void expand_constraint_channels(FileData *fd, Main *mainvar, ListBase *chanbase) +static void expand_constraint_channels(BlendExpander *expander, ListBase *chanbase) { bConstraintChannel *chan; for (chan = chanbase->first; chan; chan = chan->next) { - expand_doit(fd, mainvar, chan->ipo); + BLO_expand(expander, chan->ipo); } } -static void expand_fmodifiers(FileData *fd, Main *mainvar, ListBase *list) +static void expand_fmodifiers(BlendExpander *expander, ListBase *list) { FModifier *fcm; @@ -10715,7 +10537,7 @@ static void expand_fmodifiers(FileData *fd, Main *mainvar, ListBase *list) case FMODIFIER_TYPE_PYTHON: { FMod_Python *data = (FMod_Python *)fcm->data; - expand_doit(fd, mainvar, data->script); + BLO_expand(expander, data->script); break; } @@ -10723,7 +10545,7 @@ static void expand_fmodifiers(FileData *fd, Main *mainvar, ListBase *list) } } -static void expand_fcurves(FileData *fd, Main *mainvar, ListBase *list) +static void expand_fcurves(BlendExpander *expander, ListBase *list) { FCurve *fcu; @@ -10736,54 +10558,54 @@ static void expand_fcurves(FileData *fd, Main *mainvar, ListBase *list) for (dvar = driver->variables.first; dvar; dvar = dvar->next) { DRIVER_TARGETS_LOOPER_BEGIN (dvar) { // TODO: only expand those that are going to get used? - expand_doit(fd, mainvar, dtar->id); + BLO_expand(expander, dtar->id); } DRIVER_TARGETS_LOOPER_END; } } /* F-Curve Modifiers */ - expand_fmodifiers(fd, mainvar, &fcu->modifiers); + expand_fmodifiers(expander, &fcu->modifiers); } } -static void expand_animdata_nlastrips(FileData *fd, Main *mainvar, ListBase *list) +static void expand_animdata_nlastrips(BlendExpander *expander, ListBase *list) { NlaStrip *strip; for (strip = list->first; strip; strip = strip->next) { /* check child strips */ - expand_animdata_nlastrips(fd, mainvar, &strip->strips); + expand_animdata_nlastrips(expander, &strip->strips); /* check F-Curves */ - expand_fcurves(fd, mainvar, &strip->fcurves); + expand_fcurves(expander, &strip->fcurves); /* check F-Modifiers */ - expand_fmodifiers(fd, mainvar, &strip->modifiers); + expand_fmodifiers(expander, &strip->modifiers); /* relink referenced action */ - expand_doit(fd, mainvar, strip->act); + BLO_expand(expander, strip->act); } } -static void expand_animdata(FileData *fd, Main *mainvar, AnimData *adt) +static void expand_animdata(BlendExpander *expander, AnimData *adt) { NlaTrack *nlt; /* own action */ - expand_doit(fd, mainvar, adt->action); - expand_doit(fd, mainvar, adt->tmpact); + BLO_expand(expander, adt->action); + BLO_expand(expander, adt->tmpact); /* drivers - assume that these F-Curves have driver data to be in this list... */ - expand_fcurves(fd, mainvar, &adt->drivers); + expand_fcurves(expander, &adt->drivers); /* nla-data - referenced actions */ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - expand_animdata_nlastrips(fd, mainvar, &nlt->strips); + expand_animdata_nlastrips(expander, &nlt->strips); } } -static void expand_idprops(FileData *fd, Main *mainvar, IDProperty *prop) +static void expand_idprops(BlendExpander *expander, IDProperty *prop) { if (!prop) { return; @@ -10791,84 +10613,84 @@ static void expand_idprops(FileData *fd, Main *mainvar, IDProperty *prop) switch (prop->type) { case IDP_ID: - expand_doit(fd, mainvar, IDP_Id(prop)); + BLO_expand(expander, IDP_Id(prop)); break; case IDP_IDPARRAY: { IDProperty *idp_array = IDP_IDPArray(prop); for (int i = 0; i < prop->len; i++) { - expand_idprops(fd, mainvar, &idp_array[i]); + expand_idprops(expander, &idp_array[i]); } break; } case IDP_GROUP: LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { - expand_idprops(fd, mainvar, loop); + expand_idprops(expander, loop); } break; } } -static void expand_id(FileData *fd, Main *mainvar, ID *id); -static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree); -static void expand_collection(FileData *fd, Main *mainvar, Collection *collection); +static void expand_id(BlendExpander *expander, ID *id); +static void expand_nodetree(BlendExpander *expander, bNodeTree *ntree); +static void expand_collection(BlendExpander *expander, Collection *collection); -static void expand_id_embedded_id(FileData *fd, Main *mainvar, ID *id) +static void expand_id_embedded_id(BlendExpander *expander, ID *id) { /* Handle 'private IDs'. */ bNodeTree *nodetree = ntreeFromID(id); if (nodetree != NULL) { - expand_id(fd, mainvar, &nodetree->id); - expand_nodetree(fd, mainvar, nodetree); + expand_id(expander, &nodetree->id); + expand_nodetree(expander, nodetree); } if (GS(id->name) == ID_SCE) { Scene *scene = (Scene *)id; if (scene->master_collection != NULL) { - expand_id(fd, mainvar, &scene->master_collection->id); - expand_collection(fd, mainvar, scene->master_collection); + expand_id(expander, &scene->master_collection->id); + expand_collection(expander, scene->master_collection); } } } -static void expand_id(FileData *fd, Main *mainvar, ID *id) +static void expand_id(BlendExpander *expander, ID *id) { - expand_idprops(fd, mainvar, id->properties); + expand_idprops(expander, id->properties); if (id->override_library) { - expand_doit(fd, mainvar, id->override_library->reference); - expand_doit(fd, mainvar, id->override_library->storage); + BLO_expand(expander, id->override_library->reference); + BLO_expand(expander, id->override_library->storage); } AnimData *adt = BKE_animdata_from_id(id); if (adt != NULL) { - expand_animdata(fd, mainvar, adt); + expand_animdata(expander, adt); } - expand_id_embedded_id(fd, mainvar, id); + expand_id_embedded_id(expander, id); } -static void expand_action(FileData *fd, Main *mainvar, bAction *act) +static void expand_action(BlendExpander *expander, bAction *act) { bActionChannel *chan; // XXX deprecated - old animation system -------------- for (chan = act->chanbase.first; chan; chan = chan->next) { - expand_doit(fd, mainvar, chan->ipo); - expand_constraint_channels(fd, mainvar, &chan->constraintChannels); + BLO_expand(expander, chan->ipo); + expand_constraint_channels(expander, &chan->constraintChannels); } // --------------------------------------------------- /* F-Curves in Action */ - expand_fcurves(fd, mainvar, &act->curves); + expand_fcurves(expander, &act->curves); LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { if (marker->camera) { - expand_doit(fd, mainvar, marker->camera); + BLO_expand(expander, marker->camera); } } } -static void expand_keyingsets(FileData *fd, Main *mainvar, ListBase *list) +static void expand_keyingsets(BlendExpander *expander, ListBase *list) { KeyingSet *ks; KS_Path *ksp; @@ -10876,39 +10698,39 @@ static void expand_keyingsets(FileData *fd, Main *mainvar, ListBase *list) /* expand the ID-pointers in KeyingSets's paths */ for (ks = list->first; ks; ks = ks->next) { for (ksp = ks->paths.first; ksp; ksp = ksp->next) { - expand_doit(fd, mainvar, ksp->id); + BLO_expand(expander, ksp->id); } } } -static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSettings *part) +static void expand_particlesettings(BlendExpander *expander, ParticleSettings *part) { int a; - expand_doit(fd, mainvar, part->instance_object); - expand_doit(fd, mainvar, part->instance_collection); - expand_doit(fd, mainvar, part->force_group); - expand_doit(fd, mainvar, part->bb_ob); - expand_doit(fd, mainvar, part->collision_group); + BLO_expand(expander, part->instance_object); + BLO_expand(expander, part->instance_collection); + BLO_expand(expander, part->force_group); + BLO_expand(expander, part->bb_ob); + BLO_expand(expander, part->collision_group); for (a = 0; a < MAX_MTEX; a++) { if (part->mtex[a]) { - expand_doit(fd, mainvar, part->mtex[a]->tex); - expand_doit(fd, mainvar, part->mtex[a]->object); + BLO_expand(expander, part->mtex[a]->tex); + BLO_expand(expander, part->mtex[a]->object); } } if (part->effector_weights) { - expand_doit(fd, mainvar, part->effector_weights->group); + BLO_expand(expander, part->effector_weights->group); } if (part->pd) { - expand_doit(fd, mainvar, part->pd->tex); - expand_doit(fd, mainvar, part->pd->f_source); + BLO_expand(expander, part->pd->tex); + BLO_expand(expander, part->pd->f_source); } if (part->pd2) { - expand_doit(fd, mainvar, part->pd2->tex); - expand_doit(fd, mainvar, part->pd2->f_source); + BLO_expand(expander, part->pd2->tex); + BLO_expand(expander, part->pd2->f_source); } if (part->boids) { @@ -10919,58 +10741,58 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting for (rule = state->rules.first; rule; rule = rule->next) { if (rule->type == eBoidRuleType_Avoid) { BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule; - expand_doit(fd, mainvar, gabr->ob); + BLO_expand(expander, gabr->ob); } else if (rule->type == eBoidRuleType_FollowLeader) { BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule; - expand_doit(fd, mainvar, flbr->ob); + BLO_expand(expander, flbr->ob); } } } } LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) { - expand_doit(fd, mainvar, dw->ob); + BLO_expand(expander, dw->ob); } } -static void expand_collection(FileData *fd, Main *mainvar, Collection *collection) +static void expand_collection(BlendExpander *expander, Collection *collection) { LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - expand_doit(fd, mainvar, cob->ob); + BLO_expand(expander, cob->ob); } LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - expand_doit(fd, mainvar, child->collection); + BLO_expand(expander, child->collection); } #ifdef USE_COLLECTION_COMPAT_28 if (collection->collection != NULL) { - expand_scene_collection(fd, mainvar, collection->collection); + expand_scene_collection(expander, collection->collection); } #endif } -static void expand_key(FileData *fd, Main *mainvar, Key *key) +static void expand_key(BlendExpander *expander, Key *key) { - expand_doit(fd, mainvar, key->ipo); // XXX deprecated - old animation system + BLO_expand(expander, key->ipo); // XXX deprecated - old animation system } -static void expand_node_socket(FileData *fd, Main *mainvar, bNodeSocket *sock) +static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock) { - expand_idprops(fd, mainvar, sock->prop); + expand_idprops(expander, sock->prop); if (sock->default_value != NULL) { switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { bNodeSocketValueObject *default_value = sock->default_value; - expand_doit(fd, mainvar, default_value->value); + BLO_expand(expander, default_value->value); break; } case SOCK_IMAGE: { bNodeSocketValueImage *default_value = sock->default_value; - expand_doit(fd, mainvar, default_value->value); + BLO_expand(expander, default_value->value); break; } case SOCK_FLOAT: @@ -10991,155 +10813,145 @@ static void expand_node_socket(FileData *fd, Main *mainvar, bNodeSocket *sock) } } -static void expand_node_sockets(FileData *fd, Main *mainvar, ListBase *sockets) +static void expand_node_sockets(BlendExpander *expander, ListBase *sockets) { LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { - expand_node_socket(fd, mainvar, sock); + expand_node_socket(expander, sock); } } -static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree) +static void expand_nodetree(BlendExpander *expander, bNodeTree *ntree) { bNode *node; if (ntree->gpd) { - expand_doit(fd, mainvar, ntree->gpd); + BLO_expand(expander, ntree->gpd); } for (node = ntree->nodes.first; node; node = node->next) { if (node->id && node->type != CMP_NODE_R_LAYERS) { - expand_doit(fd, mainvar, node->id); + BLO_expand(expander, node->id); } - expand_idprops(fd, mainvar, node->prop); + expand_idprops(expander, node->prop); - expand_node_sockets(fd, mainvar, &node->inputs); - expand_node_sockets(fd, mainvar, &node->outputs); + expand_node_sockets(expander, &node->inputs); + expand_node_sockets(expander, &node->outputs); } - expand_node_sockets(fd, mainvar, &ntree->inputs); - expand_node_sockets(fd, mainvar, &ntree->outputs); + expand_node_sockets(expander, &ntree->inputs); + expand_node_sockets(expander, &ntree->outputs); } -static void expand_texture(FileData *fd, Main *mainvar, Tex *tex) +static void expand_texture(BlendExpander *expander, Tex *tex) { - expand_doit(fd, mainvar, tex->ima); - expand_doit(fd, mainvar, tex->ipo); // XXX deprecated - old animation system + BLO_expand(expander, tex->ima); + BLO_expand(expander, tex->ipo); // XXX deprecated - old animation system } -static void expand_brush(FileData *fd, Main *mainvar, Brush *brush) +static void expand_brush(BlendExpander *expander, Brush *brush) { - expand_doit(fd, mainvar, brush->mtex.tex); - expand_doit(fd, mainvar, brush->mask_mtex.tex); - expand_doit(fd, mainvar, brush->clone.image); - expand_doit(fd, mainvar, brush->paint_curve); + BLO_expand(expander, brush->mtex.tex); + BLO_expand(expander, brush->mask_mtex.tex); + BLO_expand(expander, brush->clone.image); + BLO_expand(expander, brush->paint_curve); if (brush->gpencil_settings != NULL) { - expand_doit(fd, mainvar, brush->gpencil_settings->material); + BLO_expand(expander, brush->gpencil_settings->material); } } -static void expand_material(FileData *fd, Main *mainvar, Material *ma) +static void expand_material(BlendExpander *expander, Material *ma) { - expand_doit(fd, mainvar, ma->ipo); // XXX deprecated - old animation system + BLO_expand(expander, ma->ipo); // XXX deprecated - old animation system if (ma->gp_style) { MaterialGPencilStyle *gp_style = ma->gp_style; - expand_doit(fd, mainvar, gp_style->sima); - expand_doit(fd, mainvar, gp_style->ima); + BLO_expand(expander, gp_style->sima); + BLO_expand(expander, gp_style->ima); } } -static void expand_light(FileData *fd, Main *mainvar, Light *la) +static void expand_light(BlendExpander *expander, Light *la) { - expand_doit(fd, mainvar, la->ipo); // XXX deprecated - old animation system + BLO_expand(expander, la->ipo); // XXX deprecated - old animation system } -static void expand_lattice(FileData *fd, Main *mainvar, Lattice *lt) +static void expand_lattice(BlendExpander *expander, Lattice *lt) { - expand_doit(fd, mainvar, lt->ipo); // XXX deprecated - old animation system - expand_doit(fd, mainvar, lt->key); + BLO_expand(expander, lt->ipo); // XXX deprecated - old animation system + BLO_expand(expander, lt->key); } -static void expand_world(FileData *fd, Main *mainvar, World *wrld) +static void expand_world(BlendExpander *expander, World *wrld) { - expand_doit(fd, mainvar, wrld->ipo); // XXX deprecated - old animation system + BLO_expand(expander, wrld->ipo); // XXX deprecated - old animation system } -static void expand_mball(FileData *fd, Main *mainvar, MetaBall *mb) +static void expand_mball(BlendExpander *expander, MetaBall *mb) { int a; for (a = 0; a < mb->totcol; a++) { - expand_doit(fd, mainvar, mb->mat[a]); + BLO_expand(expander, mb->mat[a]); } } -static void expand_curve(FileData *fd, Main *mainvar, Curve *cu) +static void expand_curve(BlendExpander *expander, Curve *cu) { int a; for (a = 0; a < cu->totcol; a++) { - expand_doit(fd, mainvar, cu->mat[a]); + BLO_expand(expander, cu->mat[a]); } - expand_doit(fd, mainvar, cu->vfont); - expand_doit(fd, mainvar, cu->vfontb); - expand_doit(fd, mainvar, cu->vfonti); - expand_doit(fd, mainvar, cu->vfontbi); - expand_doit(fd, mainvar, cu->key); - expand_doit(fd, mainvar, cu->ipo); // XXX deprecated - old animation system - expand_doit(fd, mainvar, cu->bevobj); - expand_doit(fd, mainvar, cu->taperobj); - expand_doit(fd, mainvar, cu->textoncurve); + BLO_expand(expander, cu->vfont); + BLO_expand(expander, cu->vfontb); + BLO_expand(expander, cu->vfonti); + BLO_expand(expander, cu->vfontbi); + BLO_expand(expander, cu->key); + BLO_expand(expander, cu->ipo); // XXX deprecated - old animation system + BLO_expand(expander, cu->bevobj); + BLO_expand(expander, cu->taperobj); + BLO_expand(expander, cu->textoncurve); } -static void expand_mesh(FileData *fd, Main *mainvar, Mesh *me) +static void expand_mesh(BlendExpander *expander, Mesh *me) { int a; for (a = 0; a < me->totcol; a++) { - expand_doit(fd, mainvar, me->mat[a]); + BLO_expand(expander, me->mat[a]); } - expand_doit(fd, mainvar, me->key); - expand_doit(fd, mainvar, me->texcomesh); + BLO_expand(expander, me->key); + BLO_expand(expander, me->texcomesh); } -/* temp struct used to transport needed info to expand_constraint_cb() */ -typedef struct tConstraintExpandData { - FileData *fd; - Main *mainvar; -} tConstraintExpandData; /* callback function used to expand constraint ID-links */ static void expand_constraint_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *userdata) { - tConstraintExpandData *ced = (tConstraintExpandData *)userdata; - expand_doit(ced->fd, ced->mainvar, *idpoin); + BlendExpander *expander = userdata; + BLO_expand(expander, *idpoin); } -static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb) +static void expand_constraints(BlendExpander *expander, ListBase *lb) { - tConstraintExpandData ced; bConstraint *curcon; - /* relink all ID-blocks used by the constraints */ - ced.fd = fd; - ced.mainvar = mainvar; - - BKE_constraints_id_loop(lb, expand_constraint_cb, &ced); + BKE_constraints_id_loop(lb, expand_constraint_cb, expander); /* deprecated manual expansion stuff */ for (curcon = lb->first; curcon; curcon = curcon->next) { if (curcon->ipo) { - expand_doit(fd, mainvar, curcon->ipo); // XXX deprecated - old animation system + BLO_expand(expander, curcon->ipo); // XXX deprecated - old animation system } } } -static void expand_pose(FileData *fd, Main *mainvar, bPose *pose) +static void expand_pose(BlendExpander *expander, bPose *pose) { bPoseChannel *chan; @@ -11148,25 +10960,25 @@ static void expand_pose(FileData *fd, Main *mainvar, bPose *pose) } for (chan = pose->chanbase.first; chan; chan = chan->next) { - expand_constraints(fd, mainvar, &chan->constraints); - expand_idprops(fd, mainvar, chan->prop); - expand_doit(fd, mainvar, chan->custom); + expand_constraints(expander, &chan->constraints); + expand_idprops(expander, chan->prop); + BLO_expand(expander, chan->custom); } } -static void expand_bones(FileData *fd, Main *mainvar, Bone *bone) +static void expand_bones(BlendExpander *expander, Bone *bone) { - expand_idprops(fd, mainvar, bone->prop); + expand_idprops(expander, bone->prop); LISTBASE_FOREACH (Bone *, curBone, &bone->childbase) { - expand_bones(fd, mainvar, curBone); + expand_bones(expander, curBone); } } -static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm) +static void expand_armature(BlendExpander *expander, bArmature *arm) { LISTBASE_FOREACH (Bone *, curBone, &arm->bonebase) { - expand_bones(fd, mainvar, curBone); + expand_bones(expander, curBone); } } @@ -11175,298 +10987,268 @@ static void expand_object_expandModifiers(void *userData, ID **idpoin, int UNUSED(cb_flag)) { - struct { - FileData *fd; - Main *mainvar; - } *data = userData; - - FileData *fd = data->fd; - Main *mainvar = data->mainvar; - - expand_doit(fd, mainvar, *idpoin); + BlendExpander *expander = userData; + BLO_expand(expander, *idpoin); } -static void expand_object(FileData *fd, Main *mainvar, Object *ob) +static void expand_object(BlendExpander *expander, Object *ob) { ParticleSystem *psys; bActionStrip *strip; PartEff *paf; int a; - expand_doit(fd, mainvar, ob->data); + BLO_expand(expander, ob->data); /* expand_object_expandModifier() */ if (ob->modifiers.first) { - struct { - FileData *fd; - Main *mainvar; - } data; - data.fd = fd; - data.mainvar = mainvar; - - BKE_modifiers_foreach_ID_link(ob, expand_object_expandModifiers, (void *)&data); + BKE_modifiers_foreach_ID_link(ob, expand_object_expandModifiers, expander); } /* expand_object_expandModifier() */ if (ob->greasepencil_modifiers.first) { - struct { - FileData *fd; - Main *mainvar; - } data; - data.fd = fd; - data.mainvar = mainvar; - - BKE_gpencil_modifiers_foreach_ID_link(ob, expand_object_expandModifiers, (void *)&data); + BKE_gpencil_modifiers_foreach_ID_link(ob, expand_object_expandModifiers, expander); } /* expand_object_expandShaderFx() */ if (ob->shader_fx.first) { - struct { - FileData *fd; - Main *mainvar; - } data; - data.fd = fd; - data.mainvar = mainvar; - - BKE_shaderfx_foreach_ID_link(ob, expand_object_expandModifiers, (void *)&data); + BKE_shaderfx_foreach_ID_link(ob, expand_object_expandModifiers, expander); } - expand_pose(fd, mainvar, ob->pose); - expand_doit(fd, mainvar, ob->poselib); - expand_constraints(fd, mainvar, &ob->constraints); + expand_pose(expander, ob->pose); + BLO_expand(expander, ob->poselib); + expand_constraints(expander, &ob->constraints); - expand_doit(fd, mainvar, ob->gpd); + BLO_expand(expander, ob->gpd); // XXX deprecated - old animation system (for version patching only) - expand_doit(fd, mainvar, ob->ipo); - expand_doit(fd, mainvar, ob->action); + BLO_expand(expander, ob->ipo); + BLO_expand(expander, ob->action); - expand_constraint_channels(fd, mainvar, &ob->constraintChannels); + expand_constraint_channels(expander, &ob->constraintChannels); for (strip = ob->nlastrips.first; strip; strip = strip->next) { - expand_doit(fd, mainvar, strip->object); - expand_doit(fd, mainvar, strip->act); - expand_doit(fd, mainvar, strip->ipo); + BLO_expand(expander, strip->object); + BLO_expand(expander, strip->act); + BLO_expand(expander, strip->ipo); } // XXX deprecated - old animation system (for version patching only) for (a = 0; a < ob->totcol; a++) { - expand_doit(fd, mainvar, ob->mat[a]); + BLO_expand(expander, ob->mat[a]); } paf = blo_do_version_give_parteff_245(ob); if (paf && paf->group) { - expand_doit(fd, mainvar, paf->group); + BLO_expand(expander, paf->group); } if (ob->instance_collection) { - expand_doit(fd, mainvar, ob->instance_collection); + BLO_expand(expander, ob->instance_collection); } if (ob->proxy) { - expand_doit(fd, mainvar, ob->proxy); + BLO_expand(expander, ob->proxy); } if (ob->proxy_group) { - expand_doit(fd, mainvar, ob->proxy_group); + BLO_expand(expander, ob->proxy_group); } for (psys = ob->particlesystem.first; psys; psys = psys->next) { - expand_doit(fd, mainvar, psys->part); + BLO_expand(expander, psys->part); } if (ob->pd) { - expand_doit(fd, mainvar, ob->pd->tex); - expand_doit(fd, mainvar, ob->pd->f_source); + BLO_expand(expander, ob->pd->tex); + BLO_expand(expander, ob->pd->f_source); } if (ob->soft) { - expand_doit(fd, mainvar, ob->soft->collision_group); + BLO_expand(expander, ob->soft->collision_group); if (ob->soft->effector_weights) { - expand_doit(fd, mainvar, ob->soft->effector_weights->group); + BLO_expand(expander, ob->soft->effector_weights->group); } } if (ob->rigidbody_constraint) { - expand_doit(fd, mainvar, ob->rigidbody_constraint->ob1); - expand_doit(fd, mainvar, ob->rigidbody_constraint->ob2); + BLO_expand(expander, ob->rigidbody_constraint->ob1); + BLO_expand(expander, ob->rigidbody_constraint->ob2); } if (ob->currentlod) { LodLevel *level; for (level = ob->lodlevels.first; level; level = level->next) { - expand_doit(fd, mainvar, level->source); + BLO_expand(expander, level->source); } } } #ifdef USE_COLLECTION_COMPAT_28 -static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc) +static void expand_scene_collection(BlendExpander *expander, SceneCollection *sc) { LISTBASE_FOREACH (LinkData *, link, &sc->objects) { - expand_doit(fd, mainvar, link->data); + BLO_expand(expander, link->data); } LISTBASE_FOREACH (SceneCollection *, nsc, &sc->scene_collections) { - expand_scene_collection(fd, mainvar, nsc); + expand_scene_collection(expander, nsc); } } #endif -static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) +static void expand_scene(BlendExpander *expander, Scene *sce) { SceneRenderLayer *srl; FreestyleModuleConfig *module; FreestyleLineSet *lineset; LISTBASE_FOREACH (Base *, base_legacy, &sce->base) { - expand_doit(fd, mainvar, base_legacy->object); + BLO_expand(expander, base_legacy->object); } - expand_doit(fd, mainvar, sce->camera); - expand_doit(fd, mainvar, sce->world); + BLO_expand(expander, sce->camera); + BLO_expand(expander, sce->world); - expand_keyingsets(fd, mainvar, &sce->keyingsets); + expand_keyingsets(expander, &sce->keyingsets); if (sce->set) { - expand_doit(fd, mainvar, sce->set); + BLO_expand(expander, sce->set); } for (srl = sce->r.layers.first; srl; srl = srl->next) { - expand_doit(fd, mainvar, srl->mat_override); + BLO_expand(expander, srl->mat_override); for (module = srl->freestyleConfig.modules.first; module; module = module->next) { if (module->script) { - expand_doit(fd, mainvar, module->script); + BLO_expand(expander, module->script); } } for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { if (lineset->group) { - expand_doit(fd, mainvar, lineset->group); + BLO_expand(expander, lineset->group); } - expand_doit(fd, mainvar, lineset->linestyle); + BLO_expand(expander, lineset->linestyle); } } LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) { - expand_idprops(fd, mainvar, view_layer->id_properties); + expand_idprops(expander, view_layer->id_properties); for (module = view_layer->freestyle_config.modules.first; module; module = module->next) { if (module->script) { - expand_doit(fd, mainvar, module->script); + BLO_expand(expander, module->script); } } for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) { if (lineset->group) { - expand_doit(fd, mainvar, lineset->group); + BLO_expand(expander, lineset->group); } - expand_doit(fd, mainvar, lineset->linestyle); + BLO_expand(expander, lineset->linestyle); } } if (sce->gpd) { - expand_doit(fd, mainvar, sce->gpd); + BLO_expand(expander, sce->gpd); } if (sce->ed) { Sequence *seq; SEQ_BEGIN (sce->ed, seq) { - expand_idprops(fd, mainvar, seq->prop); + expand_idprops(expander, seq->prop); if (seq->scene) { - expand_doit(fd, mainvar, seq->scene); + BLO_expand(expander, seq->scene); } if (seq->scene_camera) { - expand_doit(fd, mainvar, seq->scene_camera); + BLO_expand(expander, seq->scene_camera); } if (seq->clip) { - expand_doit(fd, mainvar, seq->clip); + BLO_expand(expander, seq->clip); } if (seq->mask) { - expand_doit(fd, mainvar, seq->mask); + BLO_expand(expander, seq->mask); } if (seq->sound) { - expand_doit(fd, mainvar, seq->sound); + BLO_expand(expander, seq->sound); } if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) { TextVars *data = seq->effectdata; - expand_doit(fd, mainvar, data->text_font); + BLO_expand(expander, data->text_font); } } SEQ_END; } if (sce->rigidbody_world) { - expand_doit(fd, mainvar, sce->rigidbody_world->group); - expand_doit(fd, mainvar, sce->rigidbody_world->constraints); + BLO_expand(expander, sce->rigidbody_world->group); + BLO_expand(expander, sce->rigidbody_world->constraints); } LISTBASE_FOREACH (TimeMarker *, marker, &sce->markers) { if (marker->camera) { - expand_doit(fd, mainvar, marker->camera); + BLO_expand(expander, marker->camera); } } - expand_doit(fd, mainvar, sce->clip); + BLO_expand(expander, sce->clip); #ifdef USE_COLLECTION_COMPAT_28 if (sce->collection) { - expand_scene_collection(fd, mainvar, sce->collection); + expand_scene_collection(expander, sce->collection); } #endif if (sce->r.bake.cage_object) { - expand_doit(fd, mainvar, sce->r.bake.cage_object); + BLO_expand(expander, sce->r.bake.cage_object); } } -static void expand_camera(FileData *fd, Main *mainvar, Camera *ca) +static void expand_camera(BlendExpander *expander, Camera *ca) { - expand_doit(fd, mainvar, ca->ipo); // XXX deprecated - old animation system + BLO_expand(expander, ca->ipo); // XXX deprecated - old animation system LISTBASE_FOREACH (CameraBGImage *, bgpic, &ca->bg_images) { if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) { - expand_doit(fd, mainvar, bgpic->ima); + BLO_expand(expander, bgpic->ima); } else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) { - expand_doit(fd, mainvar, bgpic->ima); + BLO_expand(expander, bgpic->ima); } } } -static void expand_cachefile(FileData *UNUSED(fd), - Main *UNUSED(mainvar), - CacheFile *UNUSED(cache_file)) +static void expand_cachefile(BlendExpander *UNUSED(expander), CacheFile *UNUSED(cache_file)) { } -static void expand_speaker(FileData *fd, Main *mainvar, Speaker *spk) +static void expand_speaker(BlendExpander *expander, Speaker *spk) { - expand_doit(fd, mainvar, spk->sound); + BLO_expand(expander, spk->sound); } -static void expand_sound(FileData *fd, Main *mainvar, bSound *snd) +static void expand_sound(BlendExpander *expander, bSound *snd) { - expand_doit(fd, mainvar, snd->ipo); // XXX deprecated - old animation system + BLO_expand(expander, snd->ipo); // XXX deprecated - old animation system } -static void expand_lightprobe(FileData *UNUSED(fd), Main *UNUSED(mainvar), LightProbe *UNUSED(prb)) +static void expand_lightprobe(BlendExpander *UNUSED(expander), LightProbe *UNUSED(prb)) { } -static void expand_movieclip(FileData *UNUSED(fd), Main *UNUSED(mainvar), MovieClip *UNUSED(clip)) +static void expand_movieclip(BlendExpander *UNUSED(expander), MovieClip *UNUSED(clip)) { } -static void expand_mask_parent(FileData *fd, Main *mainvar, MaskParent *parent) +static void expand_mask_parent(BlendExpander *expander, MaskParent *parent) { if (parent->id) { - expand_doit(fd, mainvar, parent->id); + BLO_expand(expander, parent->id); } } -static void expand_mask(FileData *fd, Main *mainvar, Mask *mask) +static void expand_mask(BlendExpander *expander, Mask *mask) { MaskLayer *mask_layer; @@ -11479,98 +11261,98 @@ static void expand_mask(FileData *fd, Main *mainvar, Mask *mask) for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; - expand_mask_parent(fd, mainvar, &point->parent); + expand_mask_parent(expander, &point->parent); } - expand_mask_parent(fd, mainvar, &spline->parent); + expand_mask_parent(expander, &spline->parent); } } } -static void expand_linestyle(FileData *fd, Main *mainvar, FreestyleLineStyle *linestyle) +static void expand_linestyle(BlendExpander *expander, FreestyleLineStyle *linestyle) { int a; LineStyleModifier *m; for (a = 0; a < MAX_MTEX; a++) { if (linestyle->mtex[a]) { - expand_doit(fd, mainvar, linestyle->mtex[a]->tex); - expand_doit(fd, mainvar, linestyle->mtex[a]->object); + BLO_expand(expander, linestyle->mtex[a]->tex); + BLO_expand(expander, linestyle->mtex[a]->object); } } for (m = linestyle->color_modifiers.first; m; m = m->next) { if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - expand_doit(fd, mainvar, ((LineStyleColorModifier_DistanceFromObject *)m)->target); + BLO_expand(expander, ((LineStyleColorModifier_DistanceFromObject *)m)->target); } } for (m = linestyle->alpha_modifiers.first; m; m = m->next) { if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - expand_doit(fd, mainvar, ((LineStyleAlphaModifier_DistanceFromObject *)m)->target); + BLO_expand(expander, ((LineStyleAlphaModifier_DistanceFromObject *)m)->target); } } for (m = linestyle->thickness_modifiers.first; m; m = m->next) { if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - expand_doit(fd, mainvar, ((LineStyleThicknessModifier_DistanceFromObject *)m)->target); + BLO_expand(expander, ((LineStyleThicknessModifier_DistanceFromObject *)m)->target); } } } -static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd) +static void expand_gpencil(BlendExpander *expander, bGPdata *gpd) { LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { - expand_doit(fd, mainvar, gpl->parent); + BLO_expand(expander, gpl->parent); } for (int a = 0; a < gpd->totcol; a++) { - expand_doit(fd, mainvar, gpd->mat[a]); + BLO_expand(expander, gpd->mat[a]); } } -static void expand_workspace(FileData *fd, Main *mainvar, WorkSpace *workspace) +static void expand_workspace(BlendExpander *expander, WorkSpace *workspace) { LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { - expand_doit(fd, mainvar, BKE_workspace_layout_screen_get(layout)); + BLO_expand(expander, BKE_workspace_layout_screen_get(layout)); } } -static void expand_hair(FileData *fd, Main *mainvar, Hair *hair) +static void expand_hair(BlendExpander *expander, Hair *hair) { for (int a = 0; a < hair->totcol; a++) { - expand_doit(fd, mainvar, hair->mat[a]); + BLO_expand(expander, hair->mat[a]); } if (hair->adt) { - expand_animdata(fd, mainvar, hair->adt); + expand_animdata(expander, hair->adt); } } -static void expand_pointcloud(FileData *fd, Main *mainvar, PointCloud *pointcloud) +static void expand_pointcloud(BlendExpander *expander, PointCloud *pointcloud) { for (int a = 0; a < pointcloud->totcol; a++) { - expand_doit(fd, mainvar, pointcloud->mat[a]); + BLO_expand(expander, pointcloud->mat[a]); } if (pointcloud->adt) { - expand_animdata(fd, mainvar, pointcloud->adt); + expand_animdata(expander, pointcloud->adt); } } -static void expand_volume(FileData *fd, Main *mainvar, Volume *volume) +static void expand_volume(BlendExpander *expander, Volume *volume) { for (int a = 0; a < volume->totcol; a++) { - expand_doit(fd, mainvar, volume->mat[a]); + BLO_expand(expander, volume->mat[a]); } if (volume->adt) { - expand_animdata(fd, mainvar, volume->adt); + expand_animdata(expander, volume->adt); } } -static void expand_simulation(FileData *fd, Main *mainvar, Simulation *simulation) +static void expand_simulation(BlendExpander *expander, Simulation *simulation) { if (simulation->adt) { - expand_animdata(fd, mainvar, simulation->adt); + expand_animdata(expander, simulation->adt); } } @@ -11599,6 +11381,8 @@ void BLO_expand_main(void *fdhandle, Main *mainvar) int a; bool do_it = true; + BlendExpander expander = {fd, mainvar}; + while (do_it) { do_it = false; @@ -11607,104 +11391,104 @@ void BLO_expand_main(void *fdhandle, Main *mainvar) id = lbarray[a]->first; while (id) { if (id->tag & LIB_TAG_NEED_EXPAND) { - expand_id(fd, mainvar, id); + expand_id(&expander, id); switch (GS(id->name)) { case ID_OB: - expand_object(fd, mainvar, (Object *)id); + expand_object(&expander, (Object *)id); break; case ID_ME: - expand_mesh(fd, mainvar, (Mesh *)id); + expand_mesh(&expander, (Mesh *)id); break; case ID_CU: - expand_curve(fd, mainvar, (Curve *)id); + expand_curve(&expander, (Curve *)id); break; case ID_MB: - expand_mball(fd, mainvar, (MetaBall *)id); + expand_mball(&expander, (MetaBall *)id); break; case ID_SCE: - expand_scene(fd, mainvar, (Scene *)id); + expand_scene(&expander, (Scene *)id); break; case ID_MA: - expand_material(fd, mainvar, (Material *)id); + expand_material(&expander, (Material *)id); break; case ID_TE: - expand_texture(fd, mainvar, (Tex *)id); + expand_texture(&expander, (Tex *)id); break; case ID_WO: - expand_world(fd, mainvar, (World *)id); + expand_world(&expander, (World *)id); break; case ID_LT: - expand_lattice(fd, mainvar, (Lattice *)id); + expand_lattice(&expander, (Lattice *)id); break; case ID_LA: - expand_light(fd, mainvar, (Light *)id); + expand_light(&expander, (Light *)id); break; case ID_KE: - expand_key(fd, mainvar, (Key *)id); + expand_key(&expander, (Key *)id); break; case ID_CA: - expand_camera(fd, mainvar, (Camera *)id); + expand_camera(&expander, (Camera *)id); break; case ID_SPK: - expand_speaker(fd, mainvar, (Speaker *)id); + expand_speaker(&expander, (Speaker *)id); break; case ID_SO: - expand_sound(fd, mainvar, (bSound *)id); + expand_sound(&expander, (bSound *)id); break; case ID_LP: - expand_lightprobe(fd, mainvar, (LightProbe *)id); + expand_lightprobe(&expander, (LightProbe *)id); break; case ID_AR: - expand_armature(fd, mainvar, (bArmature *)id); + expand_armature(&expander, (bArmature *)id); break; case ID_AC: - expand_action(fd, mainvar, (bAction *)id); // XXX deprecated - old animation system + expand_action(&expander, (bAction *)id); // XXX deprecated - old animation system break; case ID_GR: - expand_collection(fd, mainvar, (Collection *)id); + expand_collection(&expander, (Collection *)id); break; case ID_NT: - expand_nodetree(fd, mainvar, (bNodeTree *)id); + expand_nodetree(&expander, (bNodeTree *)id); break; case ID_BR: - expand_brush(fd, mainvar, (Brush *)id); + expand_brush(&expander, (Brush *)id); break; case ID_IP: - expand_ipo(fd, mainvar, (Ipo *)id); // XXX deprecated - old animation system + expand_ipo(&expander, (Ipo *)id); // XXX deprecated - old animation system break; case ID_PA: - expand_particlesettings(fd, mainvar, (ParticleSettings *)id); + expand_particlesettings(&expander, (ParticleSettings *)id); break; case ID_MC: - expand_movieclip(fd, mainvar, (MovieClip *)id); + expand_movieclip(&expander, (MovieClip *)id); break; case ID_MSK: - expand_mask(fd, mainvar, (Mask *)id); + expand_mask(&expander, (Mask *)id); break; case ID_LS: - expand_linestyle(fd, mainvar, (FreestyleLineStyle *)id); + expand_linestyle(&expander, (FreestyleLineStyle *)id); break; case ID_GD: - expand_gpencil(fd, mainvar, (bGPdata *)id); + expand_gpencil(&expander, (bGPdata *)id); break; case ID_CF: - expand_cachefile(fd, mainvar, (CacheFile *)id); + expand_cachefile(&expander, (CacheFile *)id); break; case ID_WS: - expand_workspace(fd, mainvar, (WorkSpace *)id); + expand_workspace(&expander, (WorkSpace *)id); break; case ID_HA: - expand_hair(fd, mainvar, (Hair *)id); + expand_hair(&expander, (Hair *)id); break; case ID_PT: - expand_pointcloud(fd, mainvar, (PointCloud *)id); + expand_pointcloud(&expander, (PointCloud *)id); break; case ID_VO: - expand_volume(fd, mainvar, (Volume *)id); + expand_volume(&expander, (Volume *)id); break; case ID_SIM: - expand_simulation(fd, mainvar, (Simulation *)id); + expand_simulation(&expander, (Simulation *)id); break; default: break; @@ -12052,10 +11836,6 @@ ID *BLO_library_link_named_part(Main *mainl, * \param idcode: The kind of data-block to link. * \param name: The name of the data-block (without the 2 char ID prefix). * \param flag: Options for linking, used for instantiating. - * \param scene: The scene in which to instantiate objects/collections - * (if NULL, no instantiation is done). - * \param v3d: The active 3D viewport. - * (only to define active layers for instantiated objects & collections, can be NULL). * \return the linked ID when found. */ ID *BLO_library_link_named_part_ex( @@ -12094,13 +11874,13 @@ static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepa } /** - * Initialize the BlendHandle for linking library data. + * Initialize the #BlendHandle for linking library data. * * \param mainvar: The current main database, e.g. #G_MAIN or #CTX_data_main(C). * \param bh: A blender file handle as returned by * #BLO_blendhandle_from_file or #BLO_blendhandle_from_memory. - * \param filepath: Used for relative linking, copied to the \a lib->name. - * \return the library Main, to be passed to #BLO_library_append_named_part as \a mainl. + * \param filepath: Used for relative linking, copied to the `lib->filepath`. + * \return the library #Main, to be passed to #BLO_library_link_named_part_ex as \a mainl. */ Main *BLO_library_link_begin(Main *mainvar, BlendHandle **bh, const char *filepath) { @@ -12134,7 +11914,12 @@ static void split_main_newid(Main *mainptr, Main *main_newid) } } -/* scene and v3d may be NULL. */ +/** + * \param scene: The scene in which to instantiate objects/collections + * (if NULL, no instantiation is done). + * \param v3d: The active 3D viewport. + * (only to define active layers for instantiated objects & collections, can be NULL). + */ static void library_link_end(Main *mainl, FileData **fd, const short flag, @@ -12160,10 +11945,10 @@ static void library_link_end(Main *mainl, /* make the lib path relative if required */ if (flag & FILE_RELPATH) { /* use the full path, this could have been read by other library even */ - BLI_strncpy(curlib->name, curlib->filepath, sizeof(curlib->name)); + BLI_strncpy(curlib->filepath, curlib->filepath_abs, sizeof(curlib->filepath)); /* uses current .blend file as reference */ - BLI_path_rel(curlib->name, BKE_main_blendfile_path_from_global()); + BLI_path_rel(curlib->filepath, BKE_main_blendfile_path_from_global()); } blo_join_main((*fd)->mainlist); @@ -12215,7 +12000,7 @@ static void library_link_end(Main *mainl, /* Give a base to loose objects and collections. * Only directly linked objects & collections are instantiated by - * `BLO_library_link_named_part_ex()` & co, + * #BLO_library_link_named_part_ex & co, * here we handle indirect ones and other possible edge-cases. */ if (scene) { add_collections_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag); @@ -12310,7 +12095,7 @@ static void read_library_linked_id( "non-linkable data type"), BKE_idtype_idcode_to_name(GS(id->name)), id->name + 2, - mainvar->curlib->filepath, + mainvar->curlib->filepath_abs, library_parent_filepath(mainvar->curlib)); } @@ -12328,7 +12113,7 @@ static void read_library_linked_id( TIP_("LIB: %s: '%s' missing from '%s', parent '%s'"), BKE_idtype_idcode_to_name(GS(id->name)), id->name + 2, - mainvar->curlib->filepath, + mainvar->curlib->filepath_abs, library_parent_filepath(mainvar->curlib)); /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */ @@ -12448,22 +12233,22 @@ static FileData *read_library_file_data(FileData *basefd, blo_reportf_wrap(basefd->reports, RPT_INFO, TIP_("Read packed library: '%s', parent '%s'"), - mainptr->curlib->name, + mainptr->curlib->filepath, library_parent_filepath(mainptr->curlib)); fd = blo_filedata_from_memory(pf->data, pf->size, basefd->reports); /* Needed for library_append and read_libraries. */ - BLI_strncpy(fd->relabase, mainptr->curlib->filepath, sizeof(fd->relabase)); + BLI_strncpy(fd->relabase, mainptr->curlib->filepath_abs, sizeof(fd->relabase)); } else { /* Read file on disk. */ blo_reportf_wrap(basefd->reports, RPT_INFO, TIP_("Read library: '%s', '%s', parent '%s'"), + mainptr->curlib->filepath_abs, mainptr->curlib->filepath, - mainptr->curlib->name, library_parent_filepath(mainptr->curlib)); - fd = blo_filedata_from_file(mainptr->curlib->filepath, basefd->reports); + fd = blo_filedata_from_file(mainptr->curlib->filepath_abs, basefd->reports); } if (fd) { @@ -12500,7 +12285,7 @@ static FileData *read_library_file_data(FileData *basefd, if (fd == NULL) { blo_reportf_wrap( - basefd->reports, RPT_WARNING, TIP_("Cannot find lib '%s'"), mainptr->curlib->filepath); + basefd->reports, RPT_WARNING, TIP_("Cannot find lib '%s'"), mainptr->curlib->filepath_abs); } return fd; @@ -12532,7 +12317,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) #if 0 printf("Reading linked data-blocks from %s (%s)\n", mainptr->curlib->id.name, - mainptr->curlib->name); + mainptr->curlib->filepath); #endif /* Open file if it has not been done yet. */ @@ -12582,10 +12367,10 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) lib_link_all(mainptr->curlib->filedata, mainptr); } - /* Note: No need to call `do_versions_after_linking()` or `BKE_main_id_refcount_recompute()` + /* Note: No need to call #do_versions_after_linking() or #BKE_main_id_refcount_recompute() * here, as this function is only called for library 'subset' data handling, as part of either - * full blendfile reading (`blo_read_file_internal()`), or libdata linking - * (`library_link_end()`). */ + * full blendfile reading (#blo_read_file_internal()), or library-data linking + * (#library_link_end()). */ /* Free file data we no longer need. */ if (mainptr->curlib->filedata) { @@ -12726,7 +12511,7 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) int file_pointer_size = fd->filesdna->pointer_size; int current_pointer_size = fd->memsdna->pointer_size; - /* Overallocation is fine, but might be better to pass the length as parameter. */ + /* Over-allocation is fine, but might be better to pass the length as parameter. */ int array_size = MEM_allocN_len(orig_array) / file_pointer_size; void *final_array = NULL; diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index eaeef0d52c1..2c3b047af46 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -308,7 +308,7 @@ static void area_add_window_regions(ScrArea *area, SpaceLink *sl, ListBase *lb) region->v2d.tot.ymax = 0.0f; region->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); - region->v2d.scroll |= (V2D_SCROLL_RIGHT); + region->v2d.scroll |= V2D_SCROLL_RIGHT; region->v2d.align = V2D_ALIGN_NO_POS_Y; region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; break; @@ -334,7 +334,7 @@ static void area_add_window_regions(ScrArea *area, SpaceLink *sl, ListBase *lb) region->v2d.minzoom = 0.01f; region->v2d.maxzoom = 50; region->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); - region->v2d.scroll |= (V2D_SCROLL_RIGHT); + region->v2d.scroll |= V2D_SCROLL_RIGHT; region->v2d.keepzoom = V2D_LOCKZOOM_Y; region->v2d.align = V2D_ALIGN_NO_POS_Y; region->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 2a468026ac5..496c8353f85 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -981,7 +981,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) BLI_addtail(&ima->packedfiles, imapf); imapf->packedfile = ima->packedfile; - BLI_strncpy(imapf->filepath, ima->name, FILE_MAX); + BLI_strncpy(imapf->filepath, ima->filepath, FILE_MAX); ima->packedfile = NULL; } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 6211c58d7d4..111ac728cc3 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -1749,6 +1749,24 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports)) */ { /* Keep this block, even when empty. */ + /* Paint Brush. This ensure that the brush paints by default. Used during the development and + * patch review of the initial Sculpt Vertex Colors implementation (D5975) */ + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + if (brush->ob_mode & OB_MODE_SCULPT && brush->sculpt_tool == SCULPT_TOOL_PAINT) { + brush->tip_roundness = 1.0f; + brush->flow = 1.0f; + brush->density = 1.0f; + brush->tip_scale_x = 1.0f; + } + } + + /* Pose Brush with support for loose parts. */ + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + if (brush->sculpt_tool == SCULPT_TOOL_POSE && brush->disconnected_distance_max == 0.0f) { + brush->flag2 |= BRUSH_USE_CONNECTED_ONLY; + brush->disconnected_distance_max = 0.1f; + } + } } } @@ -3474,7 +3492,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) for (Mesh *me = bmain->meshes.first; me; me = me->id.next) { me->flag &= ~(ME_FLAG_UNUSED_0 | ME_FLAG_UNUSED_1 | ME_FLAG_UNUSED_3 | ME_FLAG_UNUSED_4 | - ME_FLAG_UNUSED_6 | ME_FLAG_UNUSED_7 | ME_FLAG_UNUSED_8); + ME_FLAG_UNUSED_6 | ME_FLAG_UNUSED_7 | ME_REMESH_REPROJECT_VERTEX_COLORS); } for (Material *mat = bmain->materials.first; mat; mat = mat->id.next) { @@ -5075,6 +5093,23 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) * \note Keep this message at the bottom of the function. */ { + /* Set the cloth wind factor to 1 for old forces. */ + if (!DNA_struct_elem_find(fd->filesdna, "PartDeflect", "float", "f_wind_factor")) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + if (ob->pd) { + ob->pd->f_wind_factor = 1.0f; + } + } + LISTBASE_FOREACH (ParticleSettings *, part, &bmain->particles) { + if (part->pd) { + part->pd->f_wind_factor = 1.0f; + } + if (part->pd2) { + part->pd2->f_wind_factor = 1.0f; + } + } + } + /* Keep this block, even when empty. */ } } diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index c5628b43960..2e93df09e1e 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -24,11 +24,13 @@ #include "BLI_utildefines.h" #include "DNA_brush_types.h" +#include "DNA_constraint_types.h" #include "DNA_genfile.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" +#include "DNA_shader_fx_types.h" #include "BKE_collection.h" #include "BKE_colortools.h" @@ -267,6 +269,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) { /* Keep this block, even when empty. */ + /* Transition to saving expansion for all of a modifier's sub-panels. */ if (!DNA_struct_elem_find(fd->filesdna, "ModifierData", "short", "ui_expand_flag")) { for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { @@ -279,5 +282,75 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* EEVEE Motion blur new parameters. */ + if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "motion_blur_depth_scale")) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + scene->eevee.motion_blur_depth_scale = 100.0f; + scene->eevee.motion_blur_max = 32; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "int", "motion_blur_steps")) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + scene->eevee.motion_blur_steps = 1; + } + } + + /* Transition to saving expansion for all of a constraint's sub-panels. */ + if (!DNA_struct_elem_find(fd->filesdna, "bConstraint", "short", "ui_expand_flag")) { + for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { + LISTBASE_FOREACH (bConstraint *, con, &object->constraints) { + if (con->flag & CONSTRAINT_EXPAND_DEPRECATED) { + con->ui_expand_flag = 1; + } + else { + con->ui_expand_flag = 0; + } + } + } + } + + /* Transition to saving expansion for all of grease pencil modifier's sub-panels. */ + if (!DNA_struct_elem_find(fd->filesdna, "GpencilModifierData", "short", "ui_expand_flag")) { + for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { + LISTBASE_FOREACH (GpencilModifierData *, md, &object->greasepencil_modifiers) { + if (md->mode & eGpencilModifierMode_Expanded_DEPRECATED) { + md->ui_expand_flag = 1; + } + else { + md->ui_expand_flag = 0; + } + } + } + } + + /* Transition to saving expansion for all of an effect's sub-panels. */ + if (!DNA_struct_elem_find(fd->filesdna, "ShaderFxData", "short", "ui_expand_flag")) { + for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { + LISTBASE_FOREACH (ShaderFxData *, fx, &object->shader_fx) { + if (fx->mode & eShaderFxMode_Expanded_DEPRECATED) { + fx->ui_expand_flag = 1; + } + else { + fx->ui_expand_flag = 0; + } + } + } + } + } + + /* Refactor bevel profile type to use an enum. */ + if (!DNA_struct_elem_find(fd->filesdna, "BevelModifierData", "short", "profile_type")) { + for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + if (md->type == eModifierType_Bevel) { + BevelModifierData *bmd = (BevelModifierData *)md; + bool use_custom_profile = bmd->flags & MOD_BEVEL_CUSTOM_PROFILE_DEPRECATED; + bmd->profile_type = use_custom_profile ? MOD_BEVEL_PROFILE_CUSTOM : + MOD_BEVEL_PROFILE_SUPERELLIPSE; + } + } + } } } diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c index ff3d4574561..46faddf6e5a 100644 --- a/source/blender/blenloader/intern/versioning_cycles.c +++ b/source/blender/blenloader/intern/versioning_cycles.c @@ -78,22 +78,45 @@ static IDProperty *cycles_properties_from_ID(ID *id) return (idprop) ? IDP_GetPropertyTypeFromGroup(idprop, "cycles", IDP_GROUP) : NULL; } +static IDProperty *cycles_properties_from_view_layer(ViewLayer *view_layer) +{ + IDProperty *idprop = view_layer->id_properties; + return (idprop) ? IDP_GetPropertyTypeFromGroup(idprop, "cycles", IDP_GROUP) : NULL; +} + static float cycles_property_float(IDProperty *idprop, const char *name, float default_value) { IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_FLOAT); return (prop) ? IDP_Float(prop) : default_value; } -static float cycles_property_int(IDProperty *idprop, const char *name, int default_value) +static int cycles_property_int(IDProperty *idprop, const char *name, int default_value) { IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_INT); return (prop) ? IDP_Int(prop) : default_value; } -static bool cycles_property_boolean(IDProperty *idprop, const char *name, bool default_value) +static void cycles_property_int_set(IDProperty *idprop, const char *name, int value) { IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_INT); - return (prop) ? IDP_Int(prop) : default_value; + if (prop) { + IDP_Int(prop) = value; + } + else { + IDPropertyTemplate val = {0}; + val.i = value; + IDP_AddToGroup(idprop, IDP_New(IDP_INT, &val, name)); + } +} + +static bool cycles_property_boolean(IDProperty *idprop, const char *name, bool default_value) +{ + return cycles_property_int(idprop, name, default_value); +} + +static void cycles_property_boolean_set(IDProperty *idprop, const char *name, bool value) +{ + cycles_property_int_set(idprop, name, value); } static void displacement_node_insert(bNodeTree *ntree) @@ -1524,4 +1547,53 @@ void do_versions_after_linking_cycles(Main *bmain) } FOREACH_NODETREE_END; } + + if (!MAIN_VERSION_ATLEAST(bmain, 290, 5)) { + /* New denoiser settings. */ + for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + IDProperty *cscene = cycles_properties_from_ID(&scene->id); + + /* Check if any view layers had (optix) denoising enabled. */ + bool use_optix = false; + bool use_denoising = false; + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; + view_layer = view_layer->next) { + IDProperty *cview_layer = cycles_properties_from_view_layer(view_layer); + if (cview_layer) { + use_denoising = use_denoising || + cycles_property_boolean(cview_layer, "use_denoising", false); + use_optix = use_optix || + cycles_property_boolean(cview_layer, "use_optix_denoising", false); + } + } + + if (cscene) { + const int DENOISER_AUTO = 0; + const int DENOISER_NLM = 1; + const int DENOISER_OPTIX = 2; + + /* Enable denoiser if it was enabled for one view layer before. */ + cycles_property_int_set(cscene, "denoiser", (use_optix) ? DENOISER_OPTIX : DENOISER_NLM); + cycles_property_boolean_set(cscene, "use_denoising", use_denoising); + + /* Migrate Optix denoiser to new settings. */ + if (cycles_property_int(cscene, "preview_denoising", 0)) { + cycles_property_boolean_set(cscene, "use_preview_denoising", true); + cycles_property_int_set(cscene, "preview_denoiser", DENOISER_AUTO); + } + } + + /* Enable denoising in all view layer if there was no denoising before, + * so that enabling the scene settings auto enables it for all view layers. */ + if (!use_denoising) { + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; + view_layer = view_layer->next) { + IDProperty *cview_layer = cycles_properties_from_view_layer(view_layer); + if (cview_layer) { + cycles_property_boolean_set(cview_layer, "use_denoising", true); + } + } + } + } + } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 91d89254c90..1217b69f1b5 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -682,6 +682,22 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) brush->sculpt_tool = SCULPT_TOOL_SLIDE_RELAX; } + brush_name = "Paint"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_PAINT; + } + + brush_name = "Smear"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_SMEAR; + } + brush_name = "Simplify"; brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); if (!brush) { diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 2cc811e213f..ce472a97337 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -856,8 +856,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) if (bmain->versionfile <= 223) { VFont *vf; for (vf = bmain->fonts.first; vf; vf = vf->id.next) { - if (STREQ(vf->name + strlen(vf->name) - 6, ".Bfont")) { - strcpy(vf->name, FO_BUILTIN_NAME); + if (STREQ(vf->filepath + strlen(vf->filepath) - 6, ".Bfont")) { + strcpy(vf->filepath, FO_BUILTIN_NAME); } } } @@ -1643,9 +1643,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) if (bmain->versionfile == 241) { Image *ima; for (ima = bmain->images.first; ima; ima = ima->id.next) { - if (STREQ(ima->name, "Compositor")) { + if (STREQ(ima->filepath, "Compositor")) { strcpy(ima->id.name + 2, "Viewer Node"); - strcpy(ima->name, "Viewer Node"); + strcpy(ima->filepath, "Viewer Node"); } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index e24ce5f3a77..d8576b4c6de 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -155,8 +155,10 @@ #include "BKE_blender_version.h" #include "BKE_bpath.h" #include "BKE_collection.h" +#include "BKE_colortools.h" #include "BKE_constraint.h" #include "BKE_curve.h" +#include "BKE_curveprofile.h" #include "BKE_fcurve.h" #include "BKE_fcurve_driver.h" #include "BKE_global.h" // for G @@ -970,26 +972,6 @@ static void write_animdata(BlendWriter *writer, AnimData *adt) write_nladata(writer, &adt->nla_tracks); } -static void write_curvemapping_curves(BlendWriter *writer, CurveMapping *cumap) -{ - for (int a = 0; a < CM_TOT; a++) { - BLO_write_struct_array(writer, CurveMapPoint, cumap->cm[a].totpoint, cumap->cm[a].curve); - } -} - -static void write_curvemapping(BlendWriter *writer, CurveMapping *cumap) -{ - BLO_write_struct(writer, CurveMapping, cumap); - - write_curvemapping_curves(writer, cumap); -} - -static void write_CurveProfile(BlendWriter *writer, CurveProfile *profile) -{ - BLO_write_struct(writer, CurveProfile, profile); - BLO_write_struct_array(writer, CurveProfilePoint, profile->path_len, profile->path); -} - static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *sock) { if (sock->default_value == NULL) { @@ -1090,7 +1072,7 @@ static void write_nodetree_nolib(BlendWriter *writer, bNodeTree *ntree) /* could be handlerized at some point, now only 1 exception still */ if ((ntree->type == NTREE_SHADER) && ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) { - write_curvemapping(writer, node->storage); + BKE_curvemapping_blend_write(writer, node->storage); } else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) { NodeShaderScript *nss = (NodeShaderScript *)node->storage; @@ -1104,11 +1086,11 @@ static void write_nodetree_nolib(BlendWriter *writer, bNodeTree *ntree) CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) { - write_curvemapping(writer, node->storage); + BKE_curvemapping_blend_write(writer, node->storage); } else if ((ntree->type == NTREE_TEXTURE) && (node->type == TEX_NODE_CURVE_RGB || node->type == TEX_NODE_CURVE_TIME)) { - write_curvemapping(writer, node->storage); + BKE_curvemapping_blend_write(writer, node->storage); } else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_MOVIEDISTORTION)) { /* pass */ @@ -1439,13 +1421,13 @@ static void write_particlesettings(BlendWriter *writer, BLO_write_struct(writer, EffectorWeights, part->effector_weights); if (part->clumpcurve) { - write_curvemapping(writer, part->clumpcurve); + BKE_curvemapping_blend_write(writer, part->clumpcurve); } if (part->roughcurve) { - write_curvemapping(writer, part->roughcurve); + BKE_curvemapping_blend_write(writer, part->roughcurve); } if (part->twistcurve) { - write_curvemapping(writer, part->twistcurve); + BKE_curvemapping_blend_write(writer, part->twistcurve); } LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) { @@ -1682,16 +1664,7 @@ static void write_modifiers(BlendWriter *writer, ListBase *modbase) BLO_write_struct_by_name(writer, mti->structName, md); - if (md->type == eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData *)md; - - if (hmd->curfalloff) { - write_curvemapping(writer, hmd->curfalloff); - } - - BLO_write_int32_array(writer, hmd->totindex, hmd->indexar); - } - else if (md->type == eModifierType_Cloth) { + if (md->type == eModifierType_Cloth) { ClothModifierData *clmd = (ClothModifierData *)md; BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms); @@ -1773,70 +1746,6 @@ static void write_modifiers(BlendWriter *writer, ListBase *modbase) writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces); #endif } - else if (md->type == eModifierType_MeshDeform) { - MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; - int size = mmd->dyngridsize; - - BLO_write_struct_array(writer, MDefInfluence, mmd->totinfluence, mmd->bindinfluences); - BLO_write_int32_array(writer, mmd->totvert + 1, mmd->bindoffsets); - BLO_write_float3_array(writer, mmd->totcagevert, mmd->bindcagecos); - BLO_write_struct_array(writer, MDefCell, size * size * size, mmd->dyngrid); - BLO_write_struct_array(writer, MDefInfluence, mmd->totinfluence, mmd->dyninfluences); - BLO_write_int32_array(writer, mmd->totvert, mmd->dynverts); - } - else if (md->type == eModifierType_Warp) { - WarpModifierData *tmd = (WarpModifierData *)md; - if (tmd->curfalloff) { - write_curvemapping(writer, tmd->curfalloff); - } - } - else if (md->type == eModifierType_WeightVGEdit) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; - - if (wmd->cmap_curve) { - write_curvemapping(writer, wmd->cmap_curve); - } - } - else if (md->type == eModifierType_CorrectiveSmooth) { - CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; - - if (csmd->bind_coords) { - BLO_write_float3_array(writer, csmd->bind_coords_num, (float *)csmd->bind_coords); - } - } - else if (md->type == eModifierType_SurfaceDeform) { - SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; - - BLO_write_struct_array(writer, SDefVert, smd->numverts, smd->verts); - - if (smd->verts) { - for (int i = 0; i < smd->numverts; i++) { - BLO_write_struct_array(writer, SDefBind, smd->verts[i].numbinds, smd->verts[i].binds); - - if (smd->verts[i].binds) { - for (int j = 0; j < smd->verts[i].numbinds; j++) { - BLO_write_uint32_array( - writer, smd->verts[i].binds[j].numverts, smd->verts[i].binds[j].vert_inds); - - if (smd->verts[i].binds[j].mode == MOD_SDEF_MODE_CENTROID || - smd->verts[i].binds[j].mode == MOD_SDEF_MODE_LOOPTRI) { - BLO_write_float3_array(writer, 1, smd->verts[i].binds[j].vert_weights); - } - else { - BLO_write_float_array( - writer, smd->verts[i].binds[j].numverts, smd->verts[i].binds[j].vert_weights); - } - } - } - } - } - } - else if (md->type == eModifierType_Bevel) { - BevelModifierData *bmd = (BevelModifierData *)md; - if (bmd->custom_profile) { - write_CurveProfile(writer, bmd->custom_profile); - } - } if (mti->blendWrite != NULL) { mti->blendWrite(writer, md); @@ -1864,21 +1773,21 @@ static void write_gpencil_modifiers(BlendWriter *writer, ListBase *modbase) ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; if (gpmd->curve_thickness) { - write_curvemapping(writer, gpmd->curve_thickness); + BKE_curvemapping_blend_write(writer, gpmd->curve_thickness); } } else if (md->type == eGpencilModifierType_Noise) { NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md; if (gpmd->curve_intensity) { - write_curvemapping(writer, gpmd->curve_intensity); + BKE_curvemapping_blend_write(writer, gpmd->curve_intensity); } } else if (md->type == eGpencilModifierType_Hook) { HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md; if (gpmd->curfalloff) { - write_curvemapping(writer, gpmd->curfalloff); + BKE_curvemapping_blend_write(writer, gpmd->curfalloff); } } else if (md->type == eGpencilModifierType_Tint) { @@ -1887,25 +1796,25 @@ static void write_gpencil_modifiers(BlendWriter *writer, ListBase *modbase) BLO_write_struct(writer, ColorBand, gpmd->colorband); } if (gpmd->curve_intensity) { - write_curvemapping(writer, gpmd->curve_intensity); + BKE_curvemapping_blend_write(writer, gpmd->curve_intensity); } } else if (md->type == eGpencilModifierType_Smooth) { SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md; if (gpmd->curve_intensity) { - write_curvemapping(writer, gpmd->curve_intensity); + BKE_curvemapping_blend_write(writer, gpmd->curve_intensity); } } else if (md->type == eGpencilModifierType_Color) { ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md; if (gpmd->curve_intensity) { - write_curvemapping(writer, gpmd->curve_intensity); + BKE_curvemapping_blend_write(writer, gpmd->curve_intensity); } } else if (md->type == eGpencilModifierType_Opacity) { OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; if (gpmd->curve_intensity) { - write_curvemapping(writer, gpmd->curve_intensity); + BKE_curvemapping_blend_write(writer, gpmd->curve_intensity); } } } @@ -2460,7 +2369,7 @@ static void write_light(BlendWriter *writer, Light *la, const void *id_address) } if (la->curfalloff) { - write_curvemapping(writer, la->curfalloff); + BKE_curvemapping_blend_write(writer, la->curfalloff); } /* Node-tree is integral part of lights, no libdata. */ @@ -2517,12 +2426,12 @@ static void write_sequence_modifiers(BlendWriter *writer, ListBase *modbase) if (smd->type == seqModifierType_Curves) { CurvesModifierData *cmd = (CurvesModifierData *)smd; - write_curvemapping(writer, &cmd->curve_mapping); + BKE_curvemapping_blend_write(writer, &cmd->curve_mapping); } else if (smd->type == seqModifierType_HueCorrect) { HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd; - write_curvemapping(writer, &hcmd->curve_mapping); + BKE_curvemapping_blend_write(writer, &hcmd->curve_mapping); } } else { @@ -2534,7 +2443,7 @@ static void write_sequence_modifiers(BlendWriter *writer, ListBase *modbase) static void write_view_settings(BlendWriter *writer, ColorManagedViewSettings *view_settings) { if (view_settings->curve_mapping) { - write_curvemapping(writer, view_settings->curve_mapping); + BKE_curvemapping_blend_write(writer, view_settings->curve_mapping); } } @@ -2548,7 +2457,7 @@ static void write_view3dshading(BlendWriter *writer, View3DShading *shading) static void write_paint(BlendWriter *writer, Paint *p) { if (p->cavity_curve) { - write_curvemapping(writer, p->cavity_curve); + BKE_curvemapping_blend_write(writer, p->cavity_curve); } BLO_write_struct_array(writer, PaintToolSlot, p->tool_slots_len, p->tool_slots); } @@ -2665,19 +2574,19 @@ static void write_scene(BlendWriter *writer, Scene *sce, const void *id_address) } /* write grease-pencil custom ipo curve to file */ if (tos->gp_interpolate.custom_ipo) { - write_curvemapping(writer, tos->gp_interpolate.custom_ipo); + BKE_curvemapping_blend_write(writer, tos->gp_interpolate.custom_ipo); } /* write grease-pencil multiframe falloff curve to file */ if (tos->gp_sculpt.cur_falloff) { - write_curvemapping(writer, tos->gp_sculpt.cur_falloff); + BKE_curvemapping_blend_write(writer, tos->gp_sculpt.cur_falloff); } /* write grease-pencil primitive curve to file */ if (tos->gp_sculpt.cur_primitive) { - write_curvemapping(writer, tos->gp_sculpt.cur_primitive); + BKE_curvemapping_blend_write(writer, tos->gp_sculpt.cur_primitive); } /* Write the curve profile to the file. */ if (tos->custom_bevel_profile_preset) { - write_CurveProfile(writer, tos->custom_bevel_profile_preset); + BKE_curveprofile_blend_write(writer, tos->custom_bevel_profile_preset); } write_paint(writer, &tos->imapaint.paint); @@ -2819,7 +2728,7 @@ static void write_scene(BlendWriter *writer, Scene *sce, const void *id_address) } write_previews(writer, sce->preview); - write_curvemapping_curves(writer, &sce->r.mblur_shutter_curve); + BKE_curvemapping_curves_blend_write(writer, &sce->r.mblur_shutter_curve); LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) { write_view_layer(writer, view_layer); @@ -3233,8 +3142,8 @@ static void write_text(BlendWriter *writer, Text *text, const void *id_address) BLO_write_id_struct(writer, Text, id_address, &text->id); write_iddata(writer, &text->id); - if (text->name) { - BLO_write_string(writer, text->name); + if (text->filepath) { + BLO_write_string(writer, text->filepath); } if (!(text->flags & TXT_ISEXT)) { @@ -3323,38 +3232,38 @@ static void write_brush(BlendWriter *writer, Brush *brush, const void *id_addres write_iddata(writer, &brush->id); if (brush->curve) { - write_curvemapping(writer, brush->curve); + BKE_curvemapping_blend_write(writer, brush->curve); } if (brush->gpencil_settings) { BLO_write_struct(writer, BrushGpencilSettings, brush->gpencil_settings); if (brush->gpencil_settings->curve_sensitivity) { - write_curvemapping(writer, brush->gpencil_settings->curve_sensitivity); + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_sensitivity); } if (brush->gpencil_settings->curve_strength) { - write_curvemapping(writer, brush->gpencil_settings->curve_strength); + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_strength); } if (brush->gpencil_settings->curve_jitter) { - write_curvemapping(writer, brush->gpencil_settings->curve_jitter); + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_jitter); } if (brush->gpencil_settings->curve_rand_pressure) { - write_curvemapping(writer, brush->gpencil_settings->curve_rand_pressure); + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_pressure); } if (brush->gpencil_settings->curve_rand_strength) { - write_curvemapping(writer, brush->gpencil_settings->curve_rand_strength); + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_strength); } if (brush->gpencil_settings->curve_rand_uv) { - write_curvemapping(writer, brush->gpencil_settings->curve_rand_uv); + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_uv); } if (brush->gpencil_settings->curve_rand_hue) { - write_curvemapping(writer, brush->gpencil_settings->curve_rand_hue); + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_hue); } if (brush->gpencil_settings->curve_rand_saturation) { - write_curvemapping(writer, brush->gpencil_settings->curve_rand_saturation); + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_saturation); } if (brush->gpencil_settings->curve_rand_value) { - write_curvemapping(writer, brush->gpencil_settings->curve_rand_value); + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_value); } } if (brush->gradient) { @@ -3615,28 +3524,30 @@ static void write_linestyle_alpha_modifiers(BlendWriter *writer, ListBase *modif for (m = modifiers->first; m; m = m->next) { switch (m->type) { case LS_MODIFIER_ALONG_STROKE: - write_curvemapping(writer, ((LineStyleAlphaModifier_AlongStroke *)m)->curve); + BKE_curvemapping_blend_write(writer, ((LineStyleAlphaModifier_AlongStroke *)m)->curve); break; case LS_MODIFIER_DISTANCE_FROM_CAMERA: - write_curvemapping(writer, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve); + BKE_curvemapping_blend_write(writer, + ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve); break; case LS_MODIFIER_DISTANCE_FROM_OBJECT: - write_curvemapping(writer, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve); + BKE_curvemapping_blend_write(writer, + ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve); break; case LS_MODIFIER_MATERIAL: - write_curvemapping(writer, ((LineStyleAlphaModifier_Material *)m)->curve); + BKE_curvemapping_blend_write(writer, ((LineStyleAlphaModifier_Material *)m)->curve); break; case LS_MODIFIER_TANGENT: - write_curvemapping(writer, ((LineStyleAlphaModifier_Tangent *)m)->curve); + BKE_curvemapping_blend_write(writer, ((LineStyleAlphaModifier_Tangent *)m)->curve); break; case LS_MODIFIER_NOISE: - write_curvemapping(writer, ((LineStyleAlphaModifier_Noise *)m)->curve); + BKE_curvemapping_blend_write(writer, ((LineStyleAlphaModifier_Noise *)m)->curve); break; case LS_MODIFIER_CREASE_ANGLE: - write_curvemapping(writer, ((LineStyleAlphaModifier_CreaseAngle *)m)->curve); + BKE_curvemapping_blend_write(writer, ((LineStyleAlphaModifier_CreaseAngle *)m)->curve); break; case LS_MODIFIER_CURVATURE_3D: - write_curvemapping(writer, ((LineStyleAlphaModifier_Curvature_3D *)m)->curve); + BKE_curvemapping_blend_write(writer, ((LineStyleAlphaModifier_Curvature_3D *)m)->curve); break; } } @@ -3684,25 +3595,28 @@ static void write_linestyle_thickness_modifiers(BlendWriter *writer, ListBase *m for (m = modifiers->first; m; m = m->next) { switch (m->type) { case LS_MODIFIER_ALONG_STROKE: - write_curvemapping(writer, ((LineStyleThicknessModifier_AlongStroke *)m)->curve); + BKE_curvemapping_blend_write(writer, ((LineStyleThicknessModifier_AlongStroke *)m)->curve); break; case LS_MODIFIER_DISTANCE_FROM_CAMERA: - write_curvemapping(writer, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve); + BKE_curvemapping_blend_write(writer, + ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve); break; case LS_MODIFIER_DISTANCE_FROM_OBJECT: - write_curvemapping(writer, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve); + BKE_curvemapping_blend_write(writer, + ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve); break; case LS_MODIFIER_MATERIAL: - write_curvemapping(writer, ((LineStyleThicknessModifier_Material *)m)->curve); + BKE_curvemapping_blend_write(writer, ((LineStyleThicknessModifier_Material *)m)->curve); break; case LS_MODIFIER_TANGENT: - write_curvemapping(writer, ((LineStyleThicknessModifier_Tangent *)m)->curve); + BKE_curvemapping_blend_write(writer, ((LineStyleThicknessModifier_Tangent *)m)->curve); break; case LS_MODIFIER_CREASE_ANGLE: - write_curvemapping(writer, ((LineStyleThicknessModifier_CreaseAngle *)m)->curve); + BKE_curvemapping_blend_write(writer, ((LineStyleThicknessModifier_CreaseAngle *)m)->curve); break; case LS_MODIFIER_CURVATURE_3D: - write_curvemapping(writer, ((LineStyleThicknessModifier_Curvature_3D *)m)->curve); + BKE_curvemapping_blend_write(writer, + ((LineStyleThicknessModifier_Curvature_3D *)m)->curve); break; } } @@ -3996,7 +3910,7 @@ static void write_libraries(WriteData *wd, Main *main) writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); if (wd->use_memfile == false) { - printf("write packed .blend: %s\n", main->curlib->name); + printf("write packed .blend: %s\n", main->curlib->filepath); } } @@ -4011,7 +3925,7 @@ static void write_libraries(WriteData *wd, Main *main) "ERROR: write file: data-block '%s' from lib '%s' is not linkable " "but is flagged as directly linked", id->name, - main->curlib->filepath); + main->curlib->filepath_abs); BLI_assert(0); } writestruct(wd, ID_LINK_PLACEHOLDER, ID, 1, id); @@ -4103,6 +4017,7 @@ static bool write_file_handle(Main *mainvar, MemFile *compare, MemFile *current, int write_flags, + bool use_userdef, const BlendThumbnail *thumb) { BHead bhead; @@ -4163,7 +4078,8 @@ static bool write_file_handle(Main *mainvar, BLI_assert( (id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0); - const bool do_override = !ELEM(override_storage, NULL, bmain) && id->override_library; + const bool do_override = !ELEM(override_storage, NULL, bmain) && + ID_IS_OVERRIDE_LIBRARY_REAL(id); if (do_override) { BKE_lib_override_library_operations_store_start(bmain, override_storage, id); @@ -4356,7 +4272,7 @@ static bool write_file_handle(Main *mainvar, /* So changes above don't cause a 'DNA1' to be detected as changed on undo. */ mywrite_flush(wd); - if (write_flags & G_FILE_USERPREFS) { + if (use_userdef) { write_userdef(&writer, &U); } @@ -4429,14 +4345,20 @@ static bool do_history(const char *name, ReportList *reports) */ bool BLO_write_file(Main *mainvar, const char *filepath, - int write_flags, - ReportList *reports, - const BlendThumbnail *thumb) + const int write_flags, + const struct BlendFileWriteParams *params, + ReportList *reports) { char tempname[FILE_MAX + 1]; eWriteWrapType ww_type; WriteWrap ww; + eBLO_WritePathRemap remap_mode = params->remap_mode; + const bool use_save_versions = params->use_save_versions; + const bool use_save_as_copy = params->use_save_as_copy; + const bool use_userdef = params->use_userdef; + const BlendThumbnail *thumb = params->thumb; + /* path backup/restore */ void *path_list_backup = NULL; const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE); @@ -4466,7 +4388,15 @@ bool BLO_write_file(Main *mainvar, } /* Remapping of relative paths to new file location. */ - if (write_flags & G_FILE_RELATIVE_REMAP) { + if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) { + + if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) { + /* Make all relative as none of the existing paths can be relative in an unsaved document. */ + if (G.relbase_valid == false) { + remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE_ALL; + } + } + char dir_src[FILE_MAX]; char dir_dst[FILE_MAX]; BLI_split_dir_part(mainvar->name, dir_src, sizeof(dir_src)); @@ -4476,29 +4406,49 @@ bool BLO_write_file(Main *mainvar, BLI_path_normalize(mainvar->name, dir_dst); BLI_path_normalize(mainvar->name, dir_src); - if (G.relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) { - /* Saved to same path. Nothing to do. */ - write_flags &= ~G_FILE_RELATIVE_REMAP; + /* Only for relative, not relative-all, as this means making existing paths relative. */ + if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) { + if (G.relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) { + /* Saved to same path. Nothing to do. */ + remap_mode = BLO_WRITE_PATH_REMAP_NONE; + } } - else { + else if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) { + if (G.relbase_valid == false) { + /* Unsaved, all paths are absolute.Even if the user manages to set a relative path, + * there is no base-path that can be used to make it absolute. */ + remap_mode = BLO_WRITE_PATH_REMAP_NONE; + } + } + + if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) { /* Check if we need to backup and restore paths. */ - if (UNLIKELY(G_FILE_SAVE_COPY & write_flags)) { + if (UNLIKELY(use_save_as_copy)) { path_list_backup = BKE_bpath_list_backup(mainvar, path_list_flag); } - if (G.relbase_valid) { - /* Saved, make relative paths relative to new location (if possible). */ - BKE_bpath_relative_rebase(mainvar, dir_src, dir_dst, NULL); - } - else { - /* Unsaved, make all relative. */ - BKE_bpath_relative_convert(mainvar, dir_dst, NULL); + switch (remap_mode) { + case BLO_WRITE_PATH_REMAP_RELATIVE: + /* Saved, make relative paths relative to new location (if possible). */ + BKE_bpath_relative_rebase(mainvar, dir_src, dir_dst, NULL); + break; + case BLO_WRITE_PATH_REMAP_RELATIVE_ALL: + /* Make all relative (when requested or unsaved). */ + BKE_bpath_relative_convert(mainvar, dir_dst, NULL); + break; + case BLO_WRITE_PATH_REMAP_ABSOLUTE: + /* Make all absolute (when requested or unsaved). */ + BKE_bpath_absolute_convert(mainvar, dir_src, NULL); + break; + case BLO_WRITE_PATH_REMAP_NONE: + BLI_assert(0); /* Unreachable. */ + break; } } } /* actual file writing */ - const bool err = write_file_handle(mainvar, &ww, NULL, NULL, write_flags, thumb); + const bool err = write_file_handle(mainvar, &ww, NULL, NULL, write_flags, use_userdef, thumb); ww.close(&ww); @@ -4516,7 +4466,7 @@ bool BLO_write_file(Main *mainvar, /* file save to temporary file was successful */ /* now do reverse file history (move .blend1 -> .blend2, .blend -> .blend1) */ - if (write_flags & G_FILE_HISTORY) { + if (use_save_versions) { const bool err_hist = do_history(filepath, reports); if (err_hist) { BKE_report(reports, RPT_ERROR, "Version backup failed (file saved with @)"); @@ -4542,9 +4492,10 @@ bool BLO_write_file(Main *mainvar, */ bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags) { - write_flags &= ~G_FILE_USERPREFS; + bool use_userdef = false; - const bool err = write_file_handle(mainvar, NULL, compare, current, write_flags, NULL); + const bool err = write_file_handle( + mainvar, NULL, compare, current, write_flags, use_userdef, NULL); return (err == 0); } diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 27c03f0a84f..82502227a9a 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -744,9 +744,21 @@ void BM_loop_interp_from_face( float co[2]; int i; - /* convert the 3d coords into 2d for projection */ - BLI_assert(BM_face_is_normal_valid(f_src)); - axis_dominant_v3_to_m3(axis_mat, f_src->no); + /* Convert the 3d coords into 2d for projection. */ + float axis_dominant[3]; + if (!is_zero_v3(f_src->no)) { + BLI_assert(BM_face_is_normal_valid(f_src)); + copy_v3_v3(axis_dominant, f_src->no); + } + else { + /* Rare case in which all the vertices of the face are aligned. + * Get a random axis that is orthogonal to the tangent. */ + float vec[3]; + BM_face_calc_tangent_auto(f_src, vec); + ortho_v3_v3(axis_dominant, vec); + normalize_v3(axis_dominant); + } + axis_dominant_v3_to_m3(axis_mat, axis_dominant); i = 0; l_iter = l_first = BM_FACE_FIRST_LOOP(f_src); diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c index b8508f7e12c..65bc4da49bc 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.c +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c @@ -925,7 +925,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh else if ((oldkey != NULL) && (cd_shape_keyindex_offset != -1) && ((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) && (keyi < currkey->totelem)) { - /* Old method of reconstructing keys via vertice's original key indices, + /* Old method of reconstructing keys via vertices original key indices, * currently used if the new method above fails * (which is theoretically possible in certain cases of undo). */ copy_v3_v3(fp, oldkey[keyi]); @@ -938,9 +938,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh /* Propagate edited basis offsets to other shapes. */ if (apply_offset) { add_v3_v3(fp, *ofs_pt++); - /* Apply back new coordinates of offsetted shape-keys into BMesh. - * Otherwise, in case we call again BM_mesh_bm_to_me on same BMesh, - * we'll apply diff from previous call to BM_mesh_bm_to_me, + /* Apply back new coordinates shape-keys that have offset into BMesh. + * Otherwise, in case we call again #BM_mesh_bm_to_me on same BMesh, + * we'll apply diff from previous call to #BM_mesh_bm_to_me, * to shape-key values from *original creation of the BMesh*. See T50524. */ copy_v3_v3(BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp); } @@ -976,7 +976,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh MEM_freeN(oldverts); } - /* Topology could be changed, ensure mdisps are ok. */ + /* Topology could be changed, ensure #CD_MDISPS are ok. */ multires_topology_changed(me); /* To be removed as soon as COW is enabled by default.. */ diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 04cdc0020d9..67c0fdba12b 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1724,6 +1724,13 @@ static BMO_FlagSet bmo_enum_bevel_offset_type[] = { {BEVEL_AMT_WIDTH, "WIDTH"}, {BEVEL_AMT_DEPTH, "DEPTH"}, {BEVEL_AMT_PERCENT, "PERCENT"}, + {BEVEL_AMT_ABSOLUTE, "ABSOLUTE"}, + {0, NULL}, +}; + +static BMO_FlagSet bmo_enum_bevel_profile_type[] = { + {BEVEL_PROFILE_SUPERELLIPSE, "SUPERELLIPSE"}, + {BEVEL_PROFILE_CUSTOM, "CUSTOM"}, {0, NULL}, }; @@ -1759,7 +1766,9 @@ static BMOpDefine bmo_bevel_def = { {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input edges and vertices */ {"offset", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */ {"offset_type", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, - bmo_enum_bevel_offset_type}, /* how to measure the offset */ + bmo_enum_bevel_offset_type}, /* how to measure the offset */ + {"profile_type", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, + bmo_enum_bevel_profile_type}, /* The profile type to use for bevel. */ {"segments", BMO_OP_SLOT_INT}, /* number of segments in bevel */ {"profile", BMO_OP_SLOT_FLT}, /* profile shape, 0->1 (.5=>round) */ {"vertex_only", BMO_OP_SLOT_BOOL}, /* only bevel vertices, not edges */ @@ -1777,9 +1786,7 @@ static BMOpDefine bmo_bevel_def = { bmo_enum_bevel_miter_type}, /* outer miter kind */ {"spread", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */ {"smoothresh", BMO_OP_SLOT_FLT}, /* for passing mesh's smoothresh, used in hardening */ - {"use_custom_profile", BMO_OP_SLOT_BOOL}, /* Whether to use custom profile feature */ - /* the ProfileWiget struct for the custom profile shape */ - {"custom_profile", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_STRUCT}}, + {"custom_profile", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_STRUCT}}, /* CurveProfile */ {"vmesh_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_bevel_vmesh_method}, {{'\0'}}, diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index 9f0107db693..29fcf7ca0ca 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -109,9 +109,16 @@ enum { BEVEL_AMT_WIDTH, BEVEL_AMT_DEPTH, BEVEL_AMT_PERCENT, + BEVEL_AMT_ABSOLUTE, }; -/* Bevel face_strength_mode values: should match face_str mode enum in DNA_modifer_types.h */ +/* Bevel profile type */ +enum { + BEVEL_PROFILE_SUPERELLIPSE, + BEVEL_PROFILE_CUSTOM, +}; + +/* Bevel face_strength_mode values: should match face_str mode enum in DNA_modifier_types.h */ enum { BEVEL_FACE_STRENGTH_NONE, BEVEL_FACE_STRENGTH_NEW, diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index 284f5265b90..a738b2139c4 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -1242,7 +1242,8 @@ bool BM_face_split_edgenet_connect_islands(BMesh *bm, uint *r_edge_net_new_len) { /* -------------------------------------------------------------------- */ - /* This function has 2 main parts. + /** + * This function has 2 main parts. * * - Check if there are any holes. * - Connect the holes with edges (if any are found). diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 18193beff58..67f875ac262 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -33,6 +33,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) { const float offset = BMO_slot_float_get(op->slots_in, "offset"); const int offset_type = BMO_slot_int_get(op->slots_in, "offset_type"); + const int profile_type = BMO_slot_int_get(op->slots_in, "profile_type"); const int seg = BMO_slot_int_get(op->slots_in, "segments"); const bool vonly = BMO_slot_bool_get(op->slots_in, "vertex_only"); const float profile = BMO_slot_float_get(op->slots_in, "profile"); @@ -47,7 +48,6 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) const int miter_inner = BMO_slot_int_get(op->slots_in, "miter_inner"); const float spread = BMO_slot_float_get(op->slots_in, "spread"); const float smoothresh = BMO_slot_float_get(op->slots_in, "smoothresh"); - const bool use_custom_profile = BMO_slot_bool_get(op->slots_in, "use_custom_profile"); const CurveProfile *custom_profile = BMO_slot_ptr_get(op->slots_in, "custom_profile"); const int vmesh_method = BMO_slot_int_get(op->slots_in, "vmesh_method"); @@ -76,6 +76,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) BM_mesh_bevel(bm, offset, offset_type, + profile_type, seg, profile, vonly, @@ -93,7 +94,6 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) miter_inner, spread, smoothresh, - use_custom_profile, custom_profile, vmesh_method); diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index 9969d31a4a5..b52c26a65f0 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -50,6 +50,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera BMLoop *l_tag_prev = NULL, *l_tag_first = NULL; BMLoop *l_iter, *l_first; uint i; + int result = 1; STACK_INIT(loops_split, pair_split_max); STACK_INIT(verts_pair, pair_split_max); @@ -109,30 +110,60 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera v_pair[1] = loops_split[i][1]->v; } + /* Clear and re-use to store duplicate faces, to remove after splitting is finished. */ + STACK_CLEAR(loops_split); + for (i = 0; i < STACK_SIZE(verts_pair); i++) { BMFace *f_new; BMLoop *l_new; - BMLoop *l_a, *l_b; - - if ((l_a = BM_face_vert_share_loop(f, verts_pair[i][0])) && - (l_b = BM_face_vert_share_loop(f, verts_pair[i][1]))) { - f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false); + BMLoop *l_pair[2]; + + /* Note that duplicate edges in this case is very unlikely but it can happen, see T70287. */ + bool edge_exists = (BM_edge_exists(verts_pair[i][0], verts_pair[i][1]) != NULL); + if ((l_pair[0] = BM_face_vert_share_loop(f, verts_pair[i][0])) && + (l_pair[1] = BM_face_vert_share_loop(f, verts_pair[i][1]))) { + f_new = BM_face_split(bm, f, l_pair[0], l_pair[1], &l_new, NULL, edge_exists); + + /* Check if duplicate faces have been created, store the loops for removal in this case. + * Note that this matches how triangulate works (newly created duplicates get removed). */ + if (UNLIKELY(edge_exists)) { + BMLoop **l_pair_deferred_remove = NULL; + for (int j = 0; j < 2; j++) { + if (BM_face_find_double(l_pair[j]->f)) { + if (l_pair_deferred_remove == NULL) { + l_pair_deferred_remove = STACK_PUSH_RET(loops_split); + l_pair_deferred_remove[0] = NULL; + l_pair_deferred_remove[1] = NULL; + } + l_pair_deferred_remove[j] = l_pair[j]; + } + } + } } else { f_new = NULL; l_new = NULL; } - f = f_new; - if (!l_new || !f_new) { - return -1; + result = -1; + break; } + + f = f_new; // BMO_face_flag_enable(bm, f_new, FACE_NEW); BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT); } - return 1; + for (i = 0; i < STACK_SIZE(loops_split); i++) { + for (int j = 0; j < 2; j++) { + if (loops_split[i][j] != NULL) { + BM_face_kill(bm, loops_split[i][j]->f); + } + } + } + + return result; } void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 00b647555cf..f4c08f3153b 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -22,6 +22,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_curveprofile_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_scene_types.h" @@ -32,15 +33,13 @@ #include "BLI_memarena.h" #include "BLI_utildefines.h" +#include "BKE_curveprofile.h" #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_mesh.h" #include "eigen_capi.h" -#include "BKE_curveprofile.h" -#include "DNA_curveprofile_types.h" - #include "bmesh.h" #include "bmesh_bevel.h" /* own include */ @@ -176,6 +175,26 @@ typedef struct ProfileSpacing { } ProfileSpacing; /** + * If the mesh has custom data Loop layers that 'have math' we use this + * data to help decide which face to use as representative when there + * is an ambiguous choice as to which face to use, which happens + * when there is an odd number of segments. + * + * The face_compent field of the following will only be set if there are an odd + * number of segments. The it uses BMFace indices to index into it, so will + * only be valid as long BMFaces are not added or deleted in the BMesh. + * "Connected Component" here means connected in UV space: + * i.e., one face is directly connected to another if they share an edge and + * all of Loop UV custom layers are contiguous across that edge. + */ +typedef struct MathLayerInfo { + /** A connected-component id for each BMFace in the mesh. */ + int *face_component; + /** Does the mesh have any custom loop uv layers? */ + bool has_math_layers; +} MathLayerInfo; + +/** * An element in a cyclic boundary of a Vertex Mesh (VMesh), placed on each side of beveled edges * where each profile starts, or on each side of a miter. */ @@ -298,10 +317,14 @@ typedef struct BevelParams { ProfileSpacing pro_spacing; /** Parameter values for evenly spaced profile points for the miter profiles. */ ProfileSpacing pro_spacing_miter; + /** Information about 'math' loop layers, like UV layers. */ + MathLayerInfo math_layer_info; /** Blender units to offset each side of a beveled edge. */ float offset; /** How offset is measured; enum defined in bmesh_operators.h. */ int offset_type; + /** Profile type: radius, superellipse, or custom */ + int profile_type; /** Number of segments in beveled edge profile. */ int seg; /** User profile setting. */ @@ -324,9 +347,7 @@ typedef struct BevelParams { bool mark_sharp; /** Should we harden normals? */ bool harden_normals; - /** Should we use the custom profiles feature? */ - bool use_custom_profile; - char _pad[3]; + char _pad[1]; /** The struct used to store the custom profile input. */ const struct CurveProfile *custom_profile; /** Vertex group array, maybe set if vertex_only. */ @@ -734,12 +755,13 @@ static BMFace *bev_create_quad_ex(BMesh *bm, BMEdge *e2, BMEdge *e3, BMEdge *e4, + BMFace *frep, int mat_nr) { BMVert *varr[4] = {v1, v2, v3, v4}; BMFace *farr[4] = {f1, f2, f3, f4}; BMEdge *earr[4] = {e1, e2, e3, e4}; - return bev_create_ngon(bm, varr, 4, farr, f1, earr, mat_nr, true); + return bev_create_ngon(bm, varr, 4, farr, frep, earr, mat_nr, true); } /* Is Loop layer layer_index contiguous across shared vertex of l1 and l2? */ @@ -753,7 +775,8 @@ static bool contig_ldata_across_loops(BMesh *bm, BMLoop *l1, BMLoop *l2, int lay } /* Are all loop layers with have math (e.g., UVs) - * contiguous from face f1 to face f2 across edge e? */ + * contiguous from face f1 to face f2 across edge e? + */ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f2) { BMLoop *lef1, *lef2; @@ -765,41 +788,202 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f return true; } - v1 = e->v1; - v2 = e->v2; if (!BM_edge_loop_pair(e, &lef1, &lef2)) { return false; } + /* If faces are oriented consistently around e, + * should now have lef1 and lef2 being f1 and f2 in either order. + */ if (lef1->f == f2) { SWAP(BMLoop *, lef1, lef2); } - - if (lef1->v == v1) { - lv1f1 = lef1; - lv2f1 = BM_face_other_edge_loop(f1, e, v2); + if (lef1->f != f1 || lef2->f != f2) { + return false; } - else { - lv2f1 = lef1; - lv1f1 = BM_face_other_edge_loop(f1, e, v1); + v1 = lef1->v; + v2 = lef2->v; + BLI_assert((v1 == e->v1 && v2 == e->v2) || (v1 == e->v2 && v2 == e->v1)); + lv1f1 = lef1; + lv2f1 = lef1->next; + lv1f2 = lef2->next; + lv2f2 = lef2; + BLI_assert(lv1f1->v == v1 && lv1f1->f == f1 && lv2f1->v == v2 && lv2f1->f == f1 && + lv1f2->v == v1 && lv1f2->f == f2 && lv2f2->v == v2 && lv2f2->f == f2); + for (i = 0; i < bm->ldata.totlayer; i++) { + if (CustomData_layer_has_math(&bm->ldata, i)) { + if (!contig_ldata_across_loops(bm, lv1f1, lv1f2, i) || + !contig_ldata_across_loops(bm, lv2f1, lv2f2, i)) { + return false; + } + } } + return true; +} + +/* + * Set up the fields of bp->math_layer_info. + * We always set has_math_layers to the correct value. + * Only if there are UV layers and the number of segments is odd, + * we need to calculate connected face components in UV space. + */ +static void math_layer_info_init(BevelParams *bp, BMesh *bm) +{ + int i, f, stack_top, totface, current_component; + int bmf_index, bmf_other_index; + int *face_component; + BMFace *bmf, *bmf_other; + BMEdge *bme; + BMFace **stack; + BMIter eiter, fiter; - if (lef2->v == v1) { - lv1f2 = lef2; - lv2f2 = BM_face_other_edge_loop(f2, e, v2); + bp->math_layer_info.has_math_layers = false; + bp->math_layer_info.face_component = NULL; + for (i = 0; i < bm->ldata.totlayer; i++) { + if (CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) { + bp->math_layer_info.has_math_layers = true; + break; + } } - else { - lv2f2 = lef2; - lv1f2 = BM_face_other_edge_loop(f2, e, v1); + if (!bp->math_layer_info.has_math_layers || (bp->seg % 2) == 0) { + return; } - for (i = 0; i < bm->ldata.totlayer; i++) { - if (CustomData_layer_has_math(&bm->ldata, i) && - (!contig_ldata_across_loops(bm, lv1f1, lv1f2, i) || - !contig_ldata_across_loops(bm, lv2f1, lv2f2, i))) { - return false; + BM_mesh_elem_index_ensure(bm, BM_FACE); + BM_mesh_elem_table_ensure(bm, BM_FACE); + totface = bm->totface; + face_component = BLI_memarena_alloc(bp->mem_arena, totface * sizeof(int)); + bp->math_layer_info.face_component = face_component; + + /* Set all component ids by DFS from faces with unassigned components. */ + for (f = 0; f < totface; f++) { + face_component[f] = -1; + } + current_component = -1; + + /* Use an array as a stack. Stack size can't exceed double total faces. */ + stack = MEM_malloc_arrayN(2 * totface, sizeof(BMFace *), __func__); + for (f = 0; f < totface; f++) { + if (face_component[f] == -1) { + stack_top = 0; + current_component++; + BLI_assert(stack_top < 2 * totface); + stack[stack_top] = BM_face_at_index(bm, f); + while (stack_top >= 0) { + bmf = stack[stack_top]; + stack_top--; + bmf_index = BM_elem_index_get(bmf); + if (face_component[bmf_index] != -1) { + continue; + } + face_component[bmf_index] = current_component; + /* Neighbors are faces that share an edge with bmf and + * are where contig_ldata_across_edge(...) is true for the + * shared edge and two faces. + */ + BM_ITER_ELEM (bme, &eiter, bmf, BM_EDGES_OF_FACE) { + BM_ITER_ELEM (bmf_other, &fiter, bme, BM_FACES_OF_EDGE) { + if (bmf_other != bmf) { + bmf_other_index = BM_elem_index_get(bmf_other); + if (face_component[bmf_other_index] != -1) { + continue; + } + if (contig_ldata_across_edge(bm, bme, bmf, bmf_other)) { + stack_top++; + BLI_assert(stack_top < 2 * totface); + stack[stack_top] = bmf_other; + } + } + } + } + } } } - return true; + MEM_freeN(stack); +} + +/* Use a tie-breaking rule to choose a representative face when + * there are number of choices, face[0], face[1], ..., face[nfaces]. + * This is needed when there are an odd number of segments, and the center + * segmment (and its continuation into vmesh) can usually arbitrarily be + * the previous face or the next face. + * Or, for the center polygon of a corner, all of the faces around + * the vertex are possible choices. + * If we just choose randomly, the resulting UV maps or material + * assignment can look ugly/inconsistent. + * Allow for the case when args are null. + */ +static BMFace *choose_rep_face(BevelParams *bp, BMFace **face, int nfaces) +{ + int bmf_index, value_index, best_f, i; + BMFace *bmf; + float cent[3]; +#define VEC_VALUE_LEN 6 + float(*value_vecs)[VEC_VALUE_LEN] = NULL; + bool *still_viable = NULL; + int num_viable = 0; + + value_vecs = BLI_array_alloca(value_vecs, nfaces); + still_viable = BLI_array_alloca(still_viable, nfaces); + for (int f = 0; f < nfaces; f++) { + bmf = face[f]; + if (bmf == NULL) { + still_viable[f] = false; + continue; + } + still_viable[f] = true; + num_viable++; + bmf_index = BM_elem_index_get(bmf); + value_index = 0; + /* First tie-breaker: lower math-layer connected component id. */ + value_vecs[f][value_index++] = bp->math_layer_info.face_component ? + (float)bp->math_layer_info.face_component[bmf_index] : + 0.0f; + /* Next tie-breaker: selected face beats unselected one. */ + value_vecs[f][value_index++] = BM_elem_flag_test(bmf, BM_ELEM_SELECT) ? 0.0f : 1.0f; + /* Next tie-breaker: lower material index. */ + value_vecs[f][value_index++] = bmf->mat_nr >= 0 ? (float)bmf->mat_nr : 0.0f; + /* Next three tie-breakers: z, x, y components of face center. */ + BM_face_calc_center_bounds(bmf, cent); + value_vecs[f][value_index++] = cent[2]; + value_vecs[f][value_index++] = cent[0]; + value_vecs[f][value_index++] = cent[1]; + BLI_assert(value_index == VEC_VALUE_LEN); + } + + /* Look for a face that has a unique minimum value for in a value_index, + * trying each value_index in turn until find a unique minimum. + */ + best_f = -1; + for (value_index = 0; num_viable > 1 && value_index < VEC_VALUE_LEN; value_index++) { + for (int f = 0; f < nfaces; f++) { + if (!still_viable[f] || f == best_f) { + continue; + } + if (best_f == -1) { + best_f = f; + continue; + } + if (value_vecs[f][value_index] < value_vecs[best_f][value_index]) { + best_f = f; + /* Previous f's are now not viable any more. */ + for (i = f - 1; i >= 0; i--) { + if (still_viable[i]) { + still_viable[i] = false; + num_viable--; + } + } + } + else if (value_vecs[f][value_index] > value_vecs[best_f][value_index]) { + still_viable[f] = false; + num_viable--; + } + } + } + if (best_f == -1) { + best_f = 0; + } + return face[best_f]; +#undef VEC_VALUE_LEN } /* Merge (using average) all the UV values for loops of v's faces. @@ -1737,7 +1921,7 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv, bool reversed, b } } r = pro->super_r; - if (!bp->use_custom_profile && r == PRO_LINE_R) { + if (bp->profile_type == BEVEL_PROFILE_SUPERELLIPSE && r == PRO_LINE_R) { map_ok = false; } else { @@ -1746,8 +1930,7 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv, bool reversed, b if (bp->vmesh_method == BEVEL_VMESH_CUTOFF && map_ok) { /* Calculate the "height" of the profile by putting the (0,0) and (1,1) corners of the - * un-transformed profile throughout the 2D->3D map and calculating the distance between them. - */ + * un-transformed profile through the 2D->3D map and calculating the distance between them. */ zero_v3(p); mul_v3_m4v3(bottom_corner, map, p); p[0] = 1.0f; @@ -1784,14 +1967,8 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv, bool reversed, b } else { if (map_ok) { - if (reversed) { - p[0] = (float)yvals[ns - k]; - p[1] = (float)xvals[ns - k]; - } - else { - p[0] = (float)xvals[k]; - p[1] = (float)yvals[k]; - } + p[0] = reversed ? (float)yvals[ns - k] : (float)xvals[k]; + p[1] = reversed ? (float)xvals[ns - k] : (float)yvals[k]; p[2] = 0.0f; /* Do the 2D->3D transformation of the profile coordinates. */ mul_v3_m4v3(co, map, p); @@ -2334,7 +2511,7 @@ static void calculate_vm_profiles(BevelParams *bp, BevVert *bv, VMesh *vm) } bool miter_profile = false; bool reverse_profile = false; - if (bp->use_custom_profile) { + if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { /* Use the miter profile spacing struct if the default is filled with the custom profile. */ miter_profile = (bndv->is_arc_start || bndv->is_patch_start); /* Don't bother reversing the profile if it's a miter profile */ @@ -2464,7 +2641,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, } /* For the edges not adjacent to the beveled edge, slide the bevel amount along. */ d = efirst->offset_l_spec; - if (bp->use_custom_profile || bp->profile < 0.25f) { + if (bp->profile_type == BEVEL_PROFILE_CUSTOM || bp->profile < 0.25f) { d *= sqrtf(2.0f); /* Need to go further along the edge to make room for full profile area. */ } for (e = e->next; e->next != efirst; e = e->next) { @@ -2496,7 +2673,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, } else if (vm->count == 3) { use_tri_fan = true; - if (bp->use_custom_profile) { + if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { /* Prevent overhanging edges: use M_POLY if the extra point is planar with the profile. */ bndv = efirst->leftv; float profile_plane[4]; @@ -3831,7 +4008,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) copy_v3_v3(co, mesh_vert(vm_in, i, 0, k)->co); /* Smooth boundary rule. Custom profiles shouldn't be smoothed. */ - if (!bp->use_custom_profile) { + if (bp->profile_type != BEVEL_PROFILE_CUSTOM) { copy_v3_v3(co1, mesh_vert(vm_in, i, 0, k - 1)->co); copy_v3_v3(co2, mesh_vert(vm_in, i, 0, k + 1)->co); @@ -3850,7 +4027,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) get_profile_point(bp, &bndv->profile, k, ns_out, co); /* Smooth if using a non-custom profile. */ - if (!bp->use_custom_profile) { + if (bp->profile_type != BEVEL_PROFILE_CUSTOM) { copy_v3_v3(co1, mesh_vert_canon(vm_out, i, 0, k - 1)->co); copy_v3_v3(co2, mesh_vert_canon(vm_out, i, 0, k + 1)->co); @@ -4078,7 +4255,7 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) int i, j, k, ns2; float co[3], coc[3]; - if (!bp->use_custom_profile) { + if (bp->profile_type != BEVEL_PROFILE_CUSTOM) { if (r == PRO_SQUARE_R) { return make_cube_corner_square(mem_arena, nseg); } @@ -4162,7 +4339,7 @@ static int tri_corner_test(BevelParams *bp, BevVert *bv) int in_plane_e = 0; /* The superellipse snapping of this case isn't helpful with custom profiles enabled. */ - if (bp->vertex_only || bp->use_custom_profile) { + if (bp->vertex_only || bp->profile_type == BEVEL_PROFILE_CUSTOM) { return -1; } if (bv->vmesh->count != 3) { @@ -4281,7 +4458,7 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv) fullness = bp->pro_spacing.fullness; sub_v3_v3v3(center_direction, original_vertex, boundverts_center); if (len_squared_v3(center_direction) > BEVEL_EPSILON_SQ) { - if (bp->use_custom_profile) { + if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { fullness *= 2.0f; madd_v3_v3v3fl(mesh_vert(vm0, 0, 1, 1)->co, negative_fullest, center_direction, fullness); } @@ -4359,7 +4536,7 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) bool even, midline; float *profile_point_pipe1, *profile_point_pipe2, f; - /* Some unecessary overhead running this subdivision with custom profile snapping later on. */ + /* Some unnecessary overhead running this subdivision with custom profile snapping later on. */ vm = adj_vmesh(bp, bv); /* Now snap all interior coordinates to be on the epipe profile. */ @@ -4377,7 +4554,7 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) continue; } /* With a custom profile just copy the shape of the profile at each ring. */ - if (bp->use_custom_profile) { + if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { /* Find both profile vertices that correspond to this point. */ if (i == ipipe1 || i == ipipe2) { if (n_bndv == 3 && i == ipipe1) { @@ -4480,6 +4657,105 @@ static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, flo return beste_d2; } +/* What would be the area of the polygon around bv if interpolated in face frep? + */ +static float interp_poly_area(BevVert *bv, BMFace *frep) +{ + BoundVert *v; + VMesh *vm = bv->vmesh; + BMEdge *snape; + int n; + float(*uv_co)[3] = NULL; + float area; + + BLI_assert(vm != NULL); + uv_co = BLI_array_alloca(uv_co, vm->count); + v = vm->boundstart; + n = 0; + do { + BLI_assert(n < vm->count); + snap_face_dist_squared(v->nv.v->co, frep, &snape, uv_co[n]); + n++; + } while ((v = v->next) != vm->boundstart); + area = fabsf(area_poly_v3(uv_co, n)); + return area; +} + +/** + * If we make a poly out of verts around bv, snapping to rep frep, will uv poly have zero area? + * The uv poly is made by snapping all outside-of-frep vertices to the closest edge in frep. + * Sometimes this results in a zero or very small area polygon, which translates to a zero + * or very small area polygong in UV space -- not good for interpolating textures. + */ +static bool is_bad_uv_poly(BevVert *bv, BMFace *frep) +{ + float area = interp_poly_area(bv, frep); + return area < BEVEL_EPSILON_BIG; +} + +/* + * Pick a good face from all the faces around bv to use for + * a representative face, using choose_rep_face. + * We want to choose from among the faces that would be + * chosen for a single-segment edge polygon between two successive + * Boundverts. + * But the single beveled edge is a special case, + * where we also want to consider the third face (else can get + * zero-area UV interpolated face). + * + * If there are math-having custom loop layers, like UV, then + * don't include faces that would result in zero-area UV polygons + * if chosen as the rep. + */ +static BMFace *frep_for_center_poly(BevelParams *bp, BevVert *bv) +{ + int i, j, fcount; + BMFace **fchoices, *bmf, *bmf1, *bmf2, *any_bmf; + BMFace *ftwo[2]; + bool already_there; + bool consider_all_faces; + + fcount = 0; + any_bmf = NULL; + consider_all_faces = bv->selcount == 1; + /* Make an array that can hold maximum possible number of choices. */ + fchoices = BLI_array_alloca(fchoices, bv->edgecount); + for (i = 0; i < bv->edgecount; i++) { + if (!bv->edges[i].is_bev && !consider_all_faces) { + continue; + } + bmf1 = bv->edges[i].fprev; + bmf2 = bv->edges[i].fnext; + ftwo[0] = bmf1; + ftwo[1] = bmf2; + bmf = choose_rep_face(bp, ftwo, 2); + if (bmf != NULL) { + if (any_bmf == NULL) { + any_bmf = bmf; + } + already_there = false; + for (j = fcount - 1; j >= 0; j--) { + if (fchoices[j] == bmf) { + already_there = true; + break; + } + } + if (!already_there) { + if (bp->math_layer_info.has_math_layers) { + if (is_bad_uv_poly(bv, bmf)) { + continue; + } + } + fchoices[fcount++] = bmf; + } + } + } + if (fcount == 0) { + return any_bmf; + } + return choose_rep_face(bp, fchoices, fcount); +} + static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_nr) { VMesh *vm = bv->vmesh; @@ -4496,7 +4772,7 @@ static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_n ns2 = vm->seg / 2; if (bv->any_seam) { - frep = boundvert_rep_face(vm->boundstart, NULL); + frep = frep_for_center_poly(bp, bv); get_incident_edges(frep, bv->v, &frep_e1, &frep_e2); } else { @@ -4821,7 +5097,8 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert VMesh *vm1, *vm; BoundVert *bndv; BMVert *bmv1, *bmv2, *bmv3, *bmv4; - BMFace *f, *f2, *r_f; + BMFace *f, *f2, *r_f, *fc; + BMFace *fchoices[2]; BMEdge *bme, *bme1, *bme2, *bme3; EdgeHalf *e; int mat_nr = bp->mat_nr; @@ -4832,7 +5109,8 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert odd = ns % 2; BLI_assert(n_bndv >= 3 && ns > 1); - if (bp->pro_super_r == PRO_SQUARE_R && bv->selcount >= 3 && !odd && !bp->use_custom_profile) { + if (bp->pro_super_r == PRO_SQUARE_R && bv->selcount >= 3 && !odd && + bp->profile_type != BEVEL_PROFILE_CUSTOM) { vm1 = square_out_adj_vmesh(bp, bv); } else if (vpipe) { @@ -4842,7 +5120,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert vm1 = tri_corner_adj_vmesh(bp, bv); /* The PRO_SQUARE_IN_R profile has boundary edges that merge * and no internal ring polys except possibly center ngon. */ - if (bp->pro_super_r == PRO_SQUARE_IN_R && !bp->use_custom_profile) { + if (bp->pro_super_r == PRO_SQUARE_IN_R && bp->profile_type != BEVEL_PROFILE_CUSTOM) { build_square_in_vmesh(bp, bm, bv, vm1); return; } @@ -4874,6 +5152,14 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert i = bndv->index; f = boundvert_rep_face(bndv, NULL); f2 = boundvert_rep_face(bndv->next, NULL); + fchoices[0] = f; + fchoices[1] = f2; + if (odd) { + fc = choose_rep_face(bp, fchoices, 2); + } + else { + fc = NULL; + } if (bp->vertex_only) { e = bndv->efirst; } @@ -4884,7 +5170,10 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert /* For odd ns, make polys with lower left corner at (i,j,k) for * j in [0, ns2-1], k in [0, ns2]. And then the center ngon. * For even ns, - * j in [0, ns2-1], k in [0, ns2-1]. */ + * j in [0, ns2-1], k in [0, ns2-1]. + * + * Recall: j is ring index, k is segment index. + */ for (j = 0; j < ns2; j++) { for (k = 0; k < ns2 + odd; k++) { bmv1 = mesh_vert(vm, i, j, k)->v; @@ -4908,6 +5197,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert NULL, bndv->next->efirst->e, bme, + f2, mat_nr); } else { @@ -4921,11 +5211,11 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert /* Only one edge attached to v, since vertex_only. */ if (e->is_seam) { r_f = bev_create_quad_ex( - bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, bme, NULL, bme, NULL, mat_nr); + bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, bme, NULL, bme, NULL, f2, mat_nr); } else { r_f = bev_create_quad_ex( - bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f, bme, NULL, bme, NULL, mat_nr); + bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f, bme, NULL, bme, NULL, f2, mat_nr); } } } @@ -4934,10 +5224,11 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert if (k == ns2) { if (e && e->is_seam) { r_f = bev_create_quad_ex( - bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, NULL, bme, bme, NULL, mat_nr); + bm, bmv1, bmv2, bmv3, bmv4, fc, fc, fc, fc, NULL, bme, bme, NULL, fc, mat_nr); } else { - r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, mat_nr); + r_f = bev_create_quad_ex( + bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, NULL, bme, bme, NULL, fc, mat_nr); } } else { @@ -4952,7 +5243,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert } bme2 = bme1 != NULL ? bme1 : bme3; r_f = bev_create_quad_ex( - bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, NULL, bme1, bme2, bme3, mat_nr); + bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, NULL, bme1, bme2, bme3, f, mat_nr); } } record_face_kind(bp, r_f, F_VERT); @@ -5150,43 +5441,9 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) } } -/** - * If we make a poly out of verts around bv, snapping to rep frep, will uv poly have zero area? - * The uv poly is made by snapping all outside-of-frep vertices to the closest edge in frep. - * Assume that this function is called when the only inside-of-frep vertex is vm->boundstart. - * The poly will have zero area if the distance of that first vertex to some edge e is zero, - * and all the other vertices snap to e or snap to an edge - * at a point that is essentially on e too. - */ -static bool is_bad_uv_poly(BevVert *bv, BMFace *frep) -{ - BoundVert *v; - BMEdge *snape, *firste; - float co[3]; - VMesh *vm = bv->vmesh; - float d2; - - v = vm->boundstart; - d2 = snap_face_dist_squared(v->nv.v->co, frep, &firste, co); - if (d2 > BEVEL_EPSILON_BIG_SQ || firste == NULL) { - return false; - } - - for (v = v->next; v != vm->boundstart; v = v->next) { - snap_face_dist_squared(v->nv.v->co, frep, &snape, co); - if (snape != firste) { - d2 = dist_to_line_v3(co, firste->v1->co, firste->v2->co); - if (d2 > BEVEL_EPSILON_BIG_SQ) { - return false; - } - } - } - return true; -} - static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv) { - BMFace *f, *repface, *frep2; + BMFace *f, *repface; int n, k; VMesh *vm = bv->vmesh; BoundVert *bndv; @@ -5199,10 +5456,7 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv) BLI_array_staticdeclare(bmfaces, BM_DEFAULT_NGON_STACK_SIZE); if (bv->any_seam) { - repface = boundvert_rep_face(vm->boundstart, &frep2); - if (frep2 && repface && is_bad_uv_poly(bv, repface)) { - repface = frep2; - } + repface = frep_for_center_poly(bp, bv); get_incident_edges(repface, bv->v, &repface_e1, &repface_e2); } else { @@ -5446,7 +5700,7 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) for (k = 1; k < ns; k++) { v_weld1 = mesh_vert(bv->vmesh, weld1->index, 0, k)->co; v_weld2 = mesh_vert(bv->vmesh, weld2->index, 0, ns - k)->co; - if (bp->use_custom_profile) { + if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { /* Don't bother with special case profile check from below. */ mid_v3_v3v3(co, v_weld1, v_weld2); } @@ -5771,9 +6025,8 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) float vert_axis[3] = {0, 0, 0}; int i, ccw_test_sum; int nsel = 0; - int ntot = 0; - int nwire = 0; - int fcnt; + int tot_edges = 0; + int tot_wire = 0; /* Gather input selected edges. * Only bevel selected edges that have exactly two incident faces. @@ -5785,24 +6038,24 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) first_bme = NULL; BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) { - fcnt = BM_edge_face_count(bme); + int face_count = BM_edge_face_count(bme); BM_BEVEL_EDGE_TAG_DISABLE(bme); if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) { - BLI_assert(fcnt == 2); + BLI_assert(face_count == 2); nsel++; if (!first_bme) { first_bme = bme; } } - if (fcnt == 1) { + if (face_count == 1) { /* Good to start face chain from this edge. */ first_bme = bme; } - if (fcnt > 0 || bp->vertex_only) { - ntot++; + if (face_count > 0 || bp->vertex_only) { + tot_edges++; } if (BM_edge_is_wire(bme)) { - nwire++; + tot_wire++; /* If edge beveling, exclude wire edges from edges array. * Mark this edge as "chosen" so loop below won't choose it. */ if (!bp->vertex_only) { @@ -5814,7 +6067,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) first_bme = v->e; } - if ((nsel == 0 && !bp->vertex_only) || (ntot < 2 && bp->vertex_only)) { + if ((nsel == 0 && !bp->vertex_only) || (tot_edges < 2 && bp->vertex_only)) { /* Signal this vert isn't being beveled. */ BM_elem_flag_disable(v, BM_ELEM_TAG); return NULL; @@ -5822,13 +6075,13 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) bv = (BevVert *)BLI_memarena_alloc(bp->mem_arena, (sizeof(BevVert))); bv->v = v; - bv->edgecount = ntot; + bv->edgecount = tot_edges; bv->selcount = nsel; - bv->wirecount = nwire; + bv->wirecount = tot_wire; bv->offset = bp->offset; - bv->edges = (EdgeHalf *)BLI_memarena_alloc(bp->mem_arena, ntot * sizeof(EdgeHalf)); - if (nwire) { - bv->wire_edges = (BMEdge **)BLI_memarena_alloc(bp->mem_arena, nwire * sizeof(BMEdge *)); + bv->edges = (EdgeHalf *)BLI_memarena_alloc(bp->mem_arena, tot_edges * sizeof(EdgeHalf)); + if (tot_wire) { + bv->wire_edges = (BMEdge **)BLI_memarena_alloc(bp->mem_arena, tot_wire * sizeof(BMEdge *)); } else { bv->wire_edges = NULL; @@ -5841,7 +6094,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) find_bevel_edge_order(bm, bv, first_bme); /* Fill in other attributes of EdgeHalfs. */ - for (i = 0; i < ntot; i++) { + for (i = 0; i < tot_edges; i++) { e = &bv->edges[i]; bme = e->e; if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) { @@ -5864,27 +6117,27 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) /* If edge array doesn't go CCW around vertex from average normal side, * reverse the array, being careful to reverse face pointers too. */ - if (ntot > 1) { + if (tot_edges > 1) { ccw_test_sum = 0; - for (i = 0; i < ntot; i++) { + for (i = 0; i < tot_edges; i++) { ccw_test_sum += bev_ccw_test( - bv->edges[i].e, bv->edges[(i + 1) % ntot].e, bv->edges[i].fnext); + bv->edges[i].e, bv->edges[(i + 1) % tot_edges].e, bv->edges[i].fnext); } if (ccw_test_sum < 0) { - for (i = 0; i <= (ntot / 2) - 1; i++) { - SWAP(EdgeHalf, bv->edges[i], bv->edges[ntot - i - 1]); + for (i = 0; i <= (tot_edges / 2) - 1; i++) { + SWAP(EdgeHalf, bv->edges[i], bv->edges[tot_edges - i - 1]); SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext); - SWAP(BMFace *, bv->edges[ntot - i - 1].fprev, bv->edges[ntot - i - 1].fnext); + SWAP(BMFace *, bv->edges[tot_edges - i - 1].fprev, bv->edges[tot_edges - i - 1].fnext); } - if (ntot % 2 == 1) { - i = ntot / 2; + if (tot_edges % 2 == 1) { + i = tot_edges / 2; SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext); } } } if (bp->vertex_only) { - /* If weighted, modify offset by weight. */ + /* Modify the offset by the vertex group or bevel weight if they are specified. */ if (bp->dvert != NULL && bp->vertex_group != -1) { weight = BKE_defvert_find_weight(bp->dvert + BM_elem_index_get(v), bp->vertex_group); bv->offset *= weight; @@ -5896,7 +6149,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) /* Find center axis. Note: Don't use vert normal, can give unwanted results. */ if (ELEM(bp->offset_type, BEVEL_AMT_WIDTH, BEVEL_AMT_DEPTH)) { float edge_dir[3]; - for (i = 0, e = bv->edges; i < ntot; i++, e++) { + for (i = 0, e = bv->edges; i < tot_edges; i++, e++) { v2 = BM_edge_other_vert(e->e, bv->v); sub_v3_v3v3(edge_dir, bv->v->co, v2->co); normalize_v3(edge_dir); @@ -5905,14 +6158,14 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) } } - for (i = 0, e = bv->edges; i < ntot; i++, e++) { - e->next = &bv->edges[(i + 1) % ntot]; - e->prev = &bv->edges[(i + ntot - 1) % ntot]; + /* Set offsets for each beveled edge. */ + for (i = 0, e = bv->edges; i < tot_edges; i++, e++) { + e->next = &bv->edges[(i + 1) % tot_edges]; + e->prev = &bv->edges[(i + tot_edges - 1) % tot_edges]; - /* Set offsets. */ if (e->is_bev) { /* Convert distance as specified by user into offsets along - * faces on left side and right side of this edgehalf. + * faces on the left side and right sides of this edgehalf. * Except for percent method, offset will be same on each side. */ switch (bp->offset_type) { @@ -5938,8 +6191,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) } break; case BEVEL_AMT_PERCENT: - /* Offset needs to be such that it meets adjacent edges at percentage of their lengths. - */ + /* Offset needs to meet adjacent edges at percentage of their lengths. */ v1 = BM_edge_other_vert(e->prev->e, v); v2 = BM_edge_other_vert(e->e, v); z = sinf(angle_v3v3v3(v1->co, v->co, v2->co)); @@ -5949,12 +6201,23 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) z = sinf(angle_v3v3v3(v1->co, v->co, v2->co)); e->offset_r_spec = BM_edge_calc_length(e->next->e) * bp->offset * z / 100.0f; break; + case BEVEL_AMT_ABSOLUTE: + /* Like Percent, but the amount gives the absolute distance along adjacent edges. */ + v1 = BM_edge_other_vert(e->prev->e, v); + v2 = BM_edge_other_vert(e->e, v); + z = sinf(angle_v3v3v3(v1->co, v->co, v2->co)); + e->offset_l_spec = bp->offset * z; + v1 = BM_edge_other_vert(e->e, v); + v2 = BM_edge_other_vert(e->next->e, v); + z = sinf(angle_v3v3v3(v1->co, v->co, v2->co)); + e->offset_r_spec = bp->offset * z; + break; default: BLI_assert(!"bad bevel offset kind"); e->offset_l_spec = bp->offset; break; } - if (bp->offset_type != BEVEL_AMT_PERCENT) { + if (bp->offset_type != BEVEL_AMT_PERCENT && bp->offset_type != BEVEL_AMT_ABSOLUTE) { e->offset_r_spec = e->offset_l_spec; } if (bp->use_weights) { @@ -6000,6 +6263,10 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) e->offset_l_spec = BM_edge_calc_length(e->e) * bv->offset / 100.0f; break; } + case BEVEL_AMT_ABSOLUTE: { + e->offset_l_spec = bv->offset; + break; + } } e->offset_r_spec = e->offset_l_spec; } @@ -6017,7 +6284,8 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) } } - if (nwire) { + /* Collect wire edges if we found any earlier. */ + if (tot_wire) { i = 0; BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) { if (BM_edge_is_wire(bme)) { @@ -6406,7 +6674,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) VMesh *vm1, *vm2; EdgeHalf *e1, *e2; BMEdge *bme1, *bme2, *center_bme; - BMFace *f1, *f2, *f, *r_f; + BMFace *f1, *f2, *f, *r_f, *f_choice; BMVert *verts[4]; BMFace *faces[4]; BMEdge *edges[4]; @@ -6467,15 +6735,17 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) verts[3] = mesh_vert(vm1, i1, 0, k)->v; verts[2] = mesh_vert(vm2, i2, 0, nseg - k)->v; if (odd && k == mid + 1) { + BMFace *fchoices[2] = {f1, f2}; + edges[0] = edges[1] = NULL; + edges[2] = edges[3] = bme; + f_choice = choose_rep_face(bp, fchoices, 2); if (e1->is_seam) { - /* Straddles a seam: choose to interpolate in f1 and snap right edge to bme. */ - edges[0] = edges[1] = NULL; - edges[2] = edges[3] = bme; - r_f = bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true); + /* Straddles a seam: choose to interpolate in f_choice and snap right edge to bme. */ + r_f = bev_create_ngon(bm, verts, 4, NULL, f_choice, edges, mat_nr, true); } else { /* Straddles but not a seam: interpolate left half in f1, right half in f2. */ - r_f = bev_create_ngon(bm, verts, 4, faces, NULL, NULL, mat_nr, true); + r_f = bev_create_ngon(bm, verts, 4, faces, f_choice, NULL, mat_nr, true); } } else if (!odd && k == mid) { @@ -6820,7 +7090,7 @@ static float find_profile_fullness(BevelParams *bp) 0.647f, /* 11 */ }; - if (bp->use_custom_profile) { + if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { /* Set fullness to the average "height" of the profile's sampled points. */ fullness = 0.0f; for (int i = 0; i < nseg; i++) { /* Don't use the end points. */ @@ -7156,6 +7426,7 @@ static void bevel_limit_offset(BevelParams *bp, BMesh *bm) void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, + const int profile_type, const int segments, const float profile, const bool vertex_only, @@ -7173,7 +7444,6 @@ void BM_mesh_bevel(BMesh *bm, const int miter_inner, const float spread, const float smoothresh, - const bool use_custom_profile, const struct CurveProfile *custom_profile, const int vmesh_method) { @@ -7194,7 +7464,7 @@ void BM_mesh_bevel(BMesh *bm, bp.use_weights = use_weights; bp.loop_slide = loop_slide; bp.limit_offset = limit_offset; - bp.offset_adjust = true; + bp.offset_adjust = !vertex_only && !ELEM(offset_type, BEVEL_AMT_PERCENT, BEVEL_AMT_ABSOLUTE); bp.dvert = dvert; bp.vertex_group = vertex_group; bp.mat_nr = mat; @@ -7207,12 +7477,11 @@ void BM_mesh_bevel(BMesh *bm, bp.spread = spread; bp.smoothresh = smoothresh; bp.face_hash = NULL; - bp.use_custom_profile = use_custom_profile; + bp.profile_type = profile_type; bp.custom_profile = custom_profile; bp.vmesh_method = vmesh_method; - /* Disable the miters with the cutoff vertex mesh method, this combination isn't useful anyway. - */ + /* Disable the miters with the cutoff vertex mesh method, the combination isn't useful anyway. */ if (bp.vmesh_method == BEVEL_VMESH_CUTOFF) { bp.miter_outer = BEVEL_MITER_SHARP; bp.miter_inner = BEVEL_MITER_SHARP; @@ -7242,13 +7511,15 @@ void BM_mesh_bevel(BMesh *bm, BLI_memarena_use_calloc(bp.mem_arena); /* Get the 2D profile point locations from either the superellipse or the custom profile. */ - set_profile_spacing(&bp, &bp.pro_spacing, bp.use_custom_profile); + set_profile_spacing(&bp, &bp.pro_spacing, bp.profile_type == BEVEL_PROFILE_CUSTOM); + + /* Get the 'fullness' of the profile for the ADJ vertex mesh method. */ if (bp.seg > 1) { bp.pro_spacing.fullness = find_profile_fullness(&bp); } - /* Get separate non-custom profile samples for the miter profiles if they are needed. */ - if (bp.use_custom_profile && + /* Get separate non-custom profile samples for the miter profiles if they are needed */ + if (bp.profile_type == BEVEL_PROFILE_CUSTOM && (bp.miter_inner != BEVEL_MITER_SHARP || bp.miter_outer != BEVEL_MITER_SHARP)) { set_profile_spacing(&bp, &bp.pro_spacing_miter, false); } @@ -7256,6 +7527,8 @@ void BM_mesh_bevel(BMesh *bm, bp.face_hash = BLI_ghash_ptr_new(__func__); BLI_ghash_flag_set(bp.face_hash, GHASH_FLAG_ALLOW_DUPES); + math_layer_info_init(&bp, bm); + /* Analyze input vertices, sorting edges and assigning initial new vertex positions. */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { @@ -7282,12 +7555,12 @@ void BM_mesh_bevel(BMesh *bm, } /* Perhaps do a pass to try to even out widths. */ - if (!bp.vertex_only && bp.offset_adjust && bp.offset_type != BEVEL_AMT_PERCENT) { + if (bp.offset_adjust) { adjust_offsets(&bp, bm); } /* Maintain consistent orientations for the asymmetrical custom profiles. */ - if (bp.use_custom_profile) { + if (bp.profile_type == BEVEL_PROFILE_CUSTOM) { BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e, BM_ELEM_TAG)) { regularize_profile_orientation(&bp, e); diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h index 8562e584ec9..667482960d3 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.h +++ b/source/blender/bmesh/tools/bmesh_bevel.h @@ -27,6 +27,7 @@ struct MDeformVert; void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, + const int profile_type, const int segments, const float profile, const bool vertex_only, @@ -44,7 +45,6 @@ void BM_mesh_bevel(BMesh *bm, const int miter_inner, const float spread, const float smoothresh, - const bool use_custom_profile, const struct CurveProfile *custom_profile, const int vmesh_method); diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index 07f482f9e5f..d2c896a2e56 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -167,7 +167,7 @@ class NodeOperation : public SocketReader { * the ExecutionSystem. * * \see ExecutionSystem - * \group check + * \ingroup check * \param rendering: [true false] * true: rendering * false: editing diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp index 5ce6ca34b34..53a6d115e97 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp @@ -98,10 +98,10 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system) add_operation_input_constants(); - add_datatype_conversions(); - resolve_proxies(); + add_datatype_conversions(); + determineResolutions(); /* surround complex ops with read/write buffer */ diff --git a/source/blender/compositor/nodes/COM_FlipNode.cpp b/source/blender/compositor/nodes/COM_FlipNode.cpp index 47148ceb1a9..d89e6b7b844 100644 --- a/source/blender/compositor/nodes/COM_FlipNode.cpp +++ b/source/blender/compositor/nodes/COM_FlipNode.cpp @@ -33,8 +33,8 @@ void FlipNode::convertToOperations(NodeConverter &converter, NodeOutput *outputSocket = this->getOutputSocket(0); FlipOperation *operation = new FlipOperation(); switch (this->getbNode()->custom1) { - case 0: /// \TODO: I didn't find any constants in the old implementation, should I introduce - /// them. + case 0: /* TODO: I didn't find any constants in the old implementation, + * should I introduce them. */ operation->setFlipX(true); operation->setFlipY(false); break; diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 82f3ea7d182..39de6054615 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -50,7 +50,8 @@ #include "DEG_depsgraph.h" -namespace DEG { +namespace blender { +namespace deg { bool deg_check_id_in_depsgraph(const Depsgraph *graph, ID *id_orig) { @@ -240,4 +241,5 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph) } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h index 2db861b6fca..36b6b1bf17d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.h +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -29,7 +29,8 @@ struct Main; struct Object; struct bPoseChannel; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; class DepsgraphBuilderCache; @@ -58,4 +59,5 @@ bool deg_check_id_in_depsgraph(const Depsgraph *graph, ID *id_orig); bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base); void deg_graph_build_finalize(Main *bmain, Depsgraph *graph); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc index 104676f7ab6..2faedc4fcd6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc @@ -31,7 +31,8 @@ #include "BKE_animsys.h" -namespace DEG { +namespace blender { +namespace deg { /* Animated property storage. */ @@ -155,21 +156,16 @@ DepsgraphBuilderCache::DepsgraphBuilderCache() DepsgraphBuilderCache::~DepsgraphBuilderCache() { - for (AnimatedPropertyStorageMap::value_type &iter : animated_property_storage_map_) { - AnimatedPropertyStorage *animated_property_storage = iter.second; + for (AnimatedPropertyStorage *animated_property_storage : + animated_property_storage_map_.values()) { OBJECT_GUARDED_DELETE(animated_property_storage, AnimatedPropertyStorage); } } AnimatedPropertyStorage *DepsgraphBuilderCache::ensureAnimatedPropertyStorage(ID *id) { - AnimatedPropertyStorageMap::iterator it = animated_property_storage_map_.find(id); - if (it != animated_property_storage_map_.end()) { - return it->second; - } - AnimatedPropertyStorage *animated_property_storage = OBJECT_GUARDED_NEW(AnimatedPropertyStorage); - animated_property_storage_map_.insert(make_pair(id, animated_property_storage)); - return animated_property_storage; + return animated_property_storage_map_.lookup_or_add_cb( + id, []() { return OBJECT_GUARDED_NEW(AnimatedPropertyStorage); }); } AnimatedPropertyStorage *DepsgraphBuilderCache::ensureInitializedAnimatedPropertyStorage(ID *id) @@ -182,4 +178,5 @@ AnimatedPropertyStorage *DepsgraphBuilderCache::ensureInitializedAnimatedPropert return animated_property_storage; } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.h b/source/blender/depsgraph/intern/builder/deg_builder_cache.h index bb4e1f5c96a..6e159f55c94 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cache.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.h @@ -31,7 +31,8 @@ struct ID; struct PointerRNA; struct PropertyRNA; -namespace DEG { +namespace blender { +namespace deg { class DepsgraphBuilderCache; @@ -45,8 +46,6 @@ class AnimatedPropertyID { AnimatedPropertyID(ID *id, StructRNA *type, void *data, const char *property_name); uint32_t hash() const; - - bool operator<(const AnimatedPropertyID &other) const; friend bool operator==(const AnimatedPropertyID &a, const AnimatedPropertyID &b); /* Corresponds to PointerRNA.data. */ @@ -73,8 +72,6 @@ class AnimatedPropertyStorage { Set<AnimatedPropertyID> animated_properties_set; }; -typedef map<ID *, AnimatedPropertyStorage *> AnimatedPropertyStorageMap; - /* Cached data which can be re-used by multiple builders. */ class DepsgraphBuilderCache { public: @@ -100,7 +97,8 @@ class DepsgraphBuilderCache { return animated_property_storage->isPropertyAnimated(args...); } - AnimatedPropertyStorageMap animated_property_storage_map_; + Map<ID *, AnimatedPropertyStorage *> animated_property_storage_map_; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index 6deecfde9e1..f8c7737c843 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -37,7 +37,8 @@ #include "intern/depsgraph.h" #include "intern/depsgraph_relation.h" -namespace DEG { +namespace blender { +namespace deg { namespace { @@ -234,4 +235,5 @@ void deg_graph_detect_cycles(Depsgraph *graph) } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.h b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h index aafdcdbea04..f9674e0e60d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h @@ -23,11 +23,13 @@ #pragma once -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; /* Detect and solve dependency cycles. */ void deg_graph_detect_cycles(Depsgraph *graph); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_map.cc b/source/blender/depsgraph/intern/builder/deg_builder_map.cc index 4bca4f037b0..e605e83a862 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_map.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_map.cc @@ -25,7 +25,8 @@ #include "DNA_ID.h" -namespace DEG { +namespace blender { +namespace deg { BuilderMap::BuilderMap() { @@ -42,33 +43,21 @@ bool BuilderMap::checkIsBuilt(ID *id, int tag) const void BuilderMap::tagBuild(ID *id, int tag) { - IDTagMap::iterator it = id_tags_.find(id); - if (it == id_tags_.end()) { - id_tags_.insert(make_pair(id, tag)); - return; - } - it->second |= tag; + id_tags_.lookup_or_add(id, 0) |= tag; } bool BuilderMap::checkIsBuiltAndTag(ID *id, int tag) { - IDTagMap::iterator it = id_tags_.find(id); - if (it == id_tags_.end()) { - id_tags_.insert(make_pair(id, tag)); - return false; - } - const bool result = (it->second & tag) == tag; - it->second |= tag; + int &id_tag = id_tags_.lookup_or_add(id, 0); + const bool result = (id_tag & tag) == tag; + id_tag |= tag; return result; } int BuilderMap::getIDTag(ID *id) const { - IDTagMap::const_iterator it = id_tags_.find(id); - if (it == id_tags_.end()) { - return 0; - } - return it->second; + return id_tags_.lookup_default(id, 0); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_map.h b/source/blender/depsgraph/intern/builder/deg_builder_map.h index 65b493e2467..5dfc3297b3e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_map.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_map.h @@ -27,7 +27,8 @@ struct ID; -namespace DEG { +namespace blender { +namespace deg { class BuilderMap { public: @@ -75,8 +76,8 @@ class BuilderMap { protected: int getIDTag(ID *id) const; - typedef map<ID *, int> IDTagMap; - IDTagMap id_tags_; + Map<ID *, int> id_tags_; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 513472f6ec9..f5cc5963253 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -119,7 +119,8 @@ #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" -namespace DEG { +namespace blender { +namespace deg { /* ************ */ /* Node Builder */ @@ -594,7 +595,7 @@ void DepsgraphNodeBuilder::build_object(int base_index, } id_node->has_base |= (base_index != -1); /* Various flags, flushing from bases/collections. */ - build_object_flags(base_index, object, linked_state); + build_object_from_layer(base_index, object, linked_state); /* Transform. */ build_object_transform(object); /* Parent. */ @@ -662,6 +663,21 @@ void DepsgraphNodeBuilder::build_object(int base_index, function_bind(BKE_object_sync_to_original, _1, object_cow)); } +void DepsgraphNodeBuilder::build_object_from_layer(int base_index, + Object *object, + eDepsNode_LinkedState_Type linked_state) +{ + + OperationNode *entry_node = add_operation_node( + &object->id, NodeType::OBJECT_FROM_LAYER, OperationCode::OBJECT_FROM_LAYER_ENTRY); + entry_node->set_as_entry(); + OperationNode *exit_node = add_operation_node( + &object->id, NodeType::OBJECT_FROM_LAYER, OperationCode::OBJECT_FROM_LAYER_EXIT); + exit_node->set_as_exit(); + + build_object_flags(base_index, object, linked_state); +} + void DepsgraphNodeBuilder::build_object_flags(int base_index, Object *object, eDepsNode_LinkedState_Type linked_state) @@ -733,7 +749,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visi break; case OB_ARMATURE: if (ID_IS_LINKED(object) && object->proxy_from != nullptr) { - build_proxy_rig(object); + build_proxy_rig(object, is_object_visible); } else { build_rig(object, is_object_visible); @@ -1884,4 +1900,5 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/, } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 8c0e486ec04..256fa3450a6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -64,7 +64,8 @@ struct bNodeTree; struct bPoseChannel; struct bSound; -namespace DEG { +namespace blender { +namespace deg { struct ComponentNode; struct Depsgraph; @@ -168,6 +169,9 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { virtual void build_object_proxy_from(Object *object, bool is_object_visible); virtual void build_object_proxy_group(Object *object, bool is_object_visible); virtual void build_object_instance_collection(Object *object, bool is_object_visible); + virtual void build_object_from_layer(int base_index, + Object *object, + eDepsNode_LinkedState_Type linked_state); virtual void build_object_flags(int base_index, Object *object, eDepsNode_LinkedState_Type linked_state); @@ -200,7 +204,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); virtual void build_rig(Object *object, bool is_object_visible); - virtual void build_proxy_rig(Object *object); + virtual void build_proxy_rig(Object *object, bool is_object_visible); virtual void build_armature(bArmature *armature); virtual void build_armature_bones(ListBase *bones); virtual void build_shapekeys(Key *key); @@ -287,4 +291,5 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { BuilderMap built_map_; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index ab0a5c13321..62282ac4d37 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -54,7 +54,8 @@ #include "intern/node/deg_node_component.h" #include "intern/node/deg_node_operation.h" -namespace DEG { +namespace blender { +namespace deg { void DepsgraphNodeBuilder::build_pose_constraints(Object *object, bPoseChannel *pchan, @@ -283,7 +284,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) } } -void DepsgraphNodeBuilder::build_proxy_rig(Object *object) +void DepsgraphNodeBuilder::build_proxy_rig(Object *object, bool is_object_visible) { bArmature *armature = (bArmature *)object->data; OperationNode *op_node; @@ -326,6 +327,11 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name); } + /* Custom shape. */ + if (pchan->custom != nullptr) { + build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + pchan_index++; } op_node = add_operation_node(&object->id, @@ -339,4 +345,5 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) op_node->set_as_exit(); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc index 60e843f9124..ee40fa3f5c8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc @@ -25,7 +25,8 @@ #include "DNA_scene_types.h" -namespace DEG { +namespace blender { +namespace deg { void DepsgraphNodeBuilder::build_scene_render(Scene *scene, ViewLayer *view_layer) { @@ -83,4 +84,5 @@ void DepsgraphNodeBuilder::build_scene_compositor(Scene *scene) build_nodetree(scene->nodetree); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index 58cfb36b4ab..1d6712d16ef 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -55,7 +55,8 @@ #include "intern/node/deg_node_component.h" #include "intern/node/deg_node_operation.h" -namespace DEG { +namespace blender { +namespace deg { void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb) { @@ -174,4 +175,5 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene, } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index a0179181866..924088cbc13 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -28,7 +28,8 @@ #include "BLI_utildefines.h" -namespace DEG { +namespace blender { +namespace deg { RootPChanMap::RootPChanMap() { @@ -77,4 +78,5 @@ bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) const return Set<StringRefNull>::Intersects(*bone1_roots, *bone2_roots); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h index df8b295f5bb..7a6ea38a0f0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h @@ -25,7 +25,8 @@ #include "intern/depsgraph_type.h" -namespace DEG { +namespace blender { +namespace deg { struct RootPChanMap { /* Constructor and destructor - Create and free the internal map respectively. */ @@ -49,4 +50,5 @@ struct RootPChanMap { Map<StringRefNull, Set<StringRefNull>> map_; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 92dff751b8a..50c52a519b4 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -118,7 +118,8 @@ #include "intern/depsgraph_relation.h" #include "intern/depsgraph_type.h" -namespace DEG { +namespace blender { +namespace deg { /* ***************** */ /* Relations Builder */ @@ -321,7 +322,7 @@ void DepsgraphRelationBuilder::add_customdata_mask(Object *object, { if (customdata_masks != DEGCustomDataMeshMasks() && object != nullptr && object->type == OB_MESH) { - DEG::IDNode *id_node = graph_->find_id_node(&object->id); + IDNode *id_node = graph_->find_id_node(&object->id); if (id_node == nullptr) { BLI_assert(!"ID should always be valid"); @@ -334,7 +335,7 @@ void DepsgraphRelationBuilder::add_customdata_mask(Object *object, void DepsgraphRelationBuilder::add_special_eval_flag(ID *id, uint32_t flag) { - DEG::IDNode *id_node = graph_->find_id_node(id); + IDNode *id_node = graph_->find_id_node(id); if (id_node == nullptr) { BLI_assert(!"ID should always be valid"); } @@ -496,7 +497,7 @@ void DepsgraphRelationBuilder::build_id(ID *id) build_collection(nullptr, nullptr, (Collection *)id); break; case ID_OB: - build_object(nullptr, (Object *)id); + build_object((Object *)id); break; case ID_KE: build_shapekeys((Key *)id); @@ -598,7 +599,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll ComponentKey duplicator_key(object != nullptr ? &object->id : nullptr, NodeType::DUPLI); if (!group_done) { LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - build_object(nullptr, cob->ob); + build_object(cob->ob); } LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { build_collection(nullptr, nullptr, child->collection); @@ -621,12 +622,9 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll } } -void DepsgraphRelationBuilder::build_object(Base *base, Object *object) +void DepsgraphRelationBuilder::build_object(Object *object) { if (built_map_.checkIsBuiltAndTag(object)) { - if (base != nullptr) { - build_object_flags(base, object); - } return; } /* Object Transforms */ @@ -644,11 +642,11 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) OperationKey ob_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); add_relation(init_transform_key, local_transform_key, "Transform Init"); /* Various flags, flushing from bases/collections. */ - build_object_flags(base, object); + build_object_from_layer_relations(object); /* Parenting. */ if (object->parent != nullptr) { /* Make sure parent object's relations are built. */ - build_object(nullptr, object->parent); + build_object(object->parent); /* Parent relationship. */ build_object_parent(object); /* Local -> parent. */ @@ -736,7 +734,7 @@ void DepsgraphRelationBuilder::build_object_proxy_from(Object *object) return; } /* Object is linked here (comes from the library). */ - build_object(nullptr, object->proxy_from); + build_object(object->proxy_from); ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM); ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM); add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform"); @@ -748,27 +746,40 @@ void DepsgraphRelationBuilder::build_object_proxy_group(Object *object) return; } /* Object is local here (local in .blend file, users interacts with it). */ - build_object(nullptr, object->proxy_group); + build_object(object->proxy_group); OperationKey proxy_group_eval_key( &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); OperationKey transform_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform"); } -void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object) +void DepsgraphRelationBuilder::build_object_from_layer_relations(Object *object) { - if (base == nullptr) { - return; - } - OperationKey view_layer_done_key( - &scene_->id, NodeType::LAYER_COLLECTIONS, OperationCode::VIEW_LAYER_EVAL); + OperationKey object_from_layer_entry_key( + &object->id, NodeType::OBJECT_FROM_LAYER, OperationCode::OBJECT_FROM_LAYER_ENTRY); + OperationKey object_from_layer_exit_key( + &object->id, NodeType::OBJECT_FROM_LAYER, OperationCode::OBJECT_FROM_LAYER_EXIT); OperationKey object_flags_key( &object->id, NodeType::OBJECT_FROM_LAYER, OperationCode::OBJECT_BASE_FLAGS); - add_relation(view_layer_done_key, object_flags_key, "Base flags flush"); + + if (!has_node(object_flags_key)) { + /* Just connect Entry -> Exit if there is no OBJECT_BASE_FLAGS node. */ + add_relation(object_from_layer_entry_key, object_from_layer_exit_key, "Object from Layer"); + return; + } + + /* Entry -> OBJECT_BASE_FLAGS -> Exit */ + add_relation(object_from_layer_entry_key, object_flags_key, "Base flags flush Entry"); + add_relation(object_flags_key, object_from_layer_exit_key, "Base flags flush Exit"); + /* Synchronization back to original object. */ OperationKey synchronize_key( &object->id, NodeType::SYNCHRONIZATION, OperationCode::SYNCHRONIZE_TO_ORIGINAL); - add_relation(object_flags_key, synchronize_key, "Synchronize to Original"); + add_relation(object_from_layer_exit_key, synchronize_key, "Synchronize to Original"); + + OperationKey view_layer_done_key( + &scene_->id, NodeType::LAYER_COLLECTIONS, OperationCode::VIEW_LAYER_EVAL); + add_relation(view_layer_done_key, object_from_layer_entry_key, "View Layer flags to Object"); } void DepsgraphRelationBuilder::build_object_data(Object *object) @@ -1729,9 +1740,9 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) continue; } /* Make sure indirectly linked objects are fully built. */ - build_object(nullptr, object); - build_object(nullptr, rbc->ob1); - build_object(nullptr, rbc->ob2); + build_object(object); + build_object(rbc->ob1); + build_object(rbc->ob2); /* final result of the constraint object's transform controls how * the constraint affects the physics sim for these objects. */ ComponentKey trans_key(&object->id, NodeType::TRANSFORM); @@ -1820,7 +1831,7 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object) continue; } /* Make sure target object is pulled into the graph. */ - build_object(nullptr, particle_target->ob); + build_object(particle_target->ob); /* Use geometry component, since that's where particles are * actually evaluated. */ ComponentKey target_key(&particle_target->ob->id, NodeType::GEOMETRY); @@ -1832,7 +1843,7 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object) case PART_DRAW_OB: if (part->instance_object != nullptr) { /* Make sure object's relations are all built. */ - build_object(nullptr, part->instance_object); + build_object(part->instance_object); /* Build relation for the particle visualization. */ build_particle_system_visualization_object(object, psys, part->instance_object); } @@ -2123,19 +2134,19 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) add_relation(bevob_geom_key, obdata_geom_eval_key, "Curve Bevel Geometry"); ComponentKey bevob_key(&cu->bevobj->id, NodeType::TRANSFORM); add_relation(bevob_key, obdata_geom_eval_key, "Curve Bevel Transform"); - build_object(nullptr, cu->bevobj); + build_object(cu->bevobj); } if (cu->taperobj != nullptr) { ComponentKey taperob_key(&cu->taperobj->id, NodeType::GEOMETRY); add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper"); - build_object(nullptr, cu->taperobj); + build_object(cu->taperobj); } if (cu->textoncurve != nullptr) { ComponentKey textoncurve_geom_key(&cu->textoncurve->id, NodeType::GEOMETRY); add_relation(textoncurve_geom_key, obdata_geom_eval_key, "Text on Curve Geometry"); ComponentKey textoncurve_key(&cu->textoncurve->id, NodeType::TRANSFORM); add_relation(textoncurve_key, obdata_geom_eval_key, "Text on Curve Transform"); - build_object(nullptr, cu->textoncurve); + build_object(cu->textoncurve); } break; } @@ -2232,7 +2243,7 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera) build_animdata(&camera->id); build_parameters(&camera->id); if (camera->dof.focus_object != nullptr) { - build_object(nullptr, camera->dof.focus_object); + build_object(camera->dof.focus_object); ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); ComponentKey dof_ob_key(&camera->dof.focus_object->id, NodeType::TRANSFORM); add_relation(dof_ob_key, camera_parameters_key, "Camera DOF"); @@ -2307,7 +2318,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) add_relation(image_key, shading_key, "Image -> Node"); } else if (id_type == ID_OB) { - build_object(nullptr, (Object *)id); + build_object((Object *)id); ComponentKey object_transform_key(id, NodeType::TRANSFORM); add_relation(object_transform_key, shading_key, "Object Transform -> Node"); if (object_have_geometry_component(reinterpret_cast<Object *>(id))) { @@ -2323,7 +2334,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) * On the one hand it's annoying to always pull it in, but on another hand it's also annoying * to have hardcoded node-type exception here. */ if (node_scene->camera != nullptr) { - build_object(nullptr, node_scene->camera); + build_object(node_scene->camera); } } else if (id_type == ID_TXT) { @@ -2661,7 +2672,7 @@ void DepsgraphRelationBuilder::build_scene_speakers(Scene * /*scene*/, ViewLayer if (object->type != OB_SPEAKER || !need_pull_base_into_graph(base)) { continue; } - build_object(nullptr, base->object); + build_object(base->object); } } @@ -2887,9 +2898,7 @@ void DepsgraphRelationBuilder::build_driver_relations(IDNode *id_node) } // Mapping from RNA prefix -> set of driver evaluation nodes: - typedef Vector<Node *> DriverGroup; - typedef map<string, DriverGroup> DriverGroupMap; - DriverGroupMap driver_groups; + Map<string, Vector<Node *>> driver_groups; LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { if (fcu->rna_path == nullptr) { @@ -2897,33 +2906,33 @@ void DepsgraphRelationBuilder::build_driver_relations(IDNode *id_node) } // Get the RNA path except the part after the last dot. char *last_dot = strrchr(fcu->rna_path, '.'); - string rna_prefix; + StringRef rna_prefix; if (last_dot != nullptr) { - rna_prefix = string(fcu->rna_path, last_dot); + rna_prefix = StringRef(fcu->rna_path, last_dot); } // Insert this driver node into the group belonging to the RNA prefix. OperationKey driver_key( id_orig, NodeType::PARAMETERS, OperationCode::DRIVER, fcu->rna_path, fcu->array_index); Node *node_driver = get_node(driver_key); - driver_groups[rna_prefix].append(node_driver); + driver_groups.lookup_or_add_default_as(rna_prefix).append(node_driver); } - for (pair<string, DriverGroup> prefix_group : driver_groups) { + for (Span<Node *> prefix_group : driver_groups.values()) { // For each node in the driver group, try to connect it to another node // in the same group without creating any cycles. - int num_drivers = prefix_group.second.size(); + int num_drivers = prefix_group.size(); if (num_drivers < 2) { // A relation requires two drivers. continue; } for (int from_index = 0; from_index < num_drivers; ++from_index) { - Node *op_from = prefix_group.second[from_index]; + Node *op_from = prefix_group[from_index]; // Start by trying the next node in the group. for (int to_offset = 1; to_offset < num_drivers; ++to_offset) { int to_index = (from_index + to_offset) % num_drivers; - Node *op_to = prefix_group.second[to_index]; + Node *op_to = prefix_group[to_index]; // Investigate whether this relation would create a dependency cycle. // Example graph: @@ -2975,4 +2984,5 @@ void DepsgraphRelationBuilder::constraint_walk(bConstraint * /*con*/, data->builder->build_id(id); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index aa6d8ababd3..b4b0dc71f85 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -84,7 +84,8 @@ struct bSound; struct PropertyRNA; -namespace DEG { +namespace blender { +namespace deg { struct ComponentNode; struct DepsNodeHandle; @@ -210,10 +211,10 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { virtual void build_collection(LayerCollection *from_layer_collection, Object *object, Collection *collection); - virtual void build_object(Base *base, Object *object); + virtual void build_object(Object *object); virtual void build_object_proxy_from(Object *object); virtual void build_object_proxy_group(Object *object); - virtual void build_object_flags(Base *base, Object *object); + virtual void build_object_from_layer_relations(Object *object); virtual void build_object_data(Object *object); virtual void build_object_data_camera(Object *object); virtual void build_object_data_geometry(Object *object); @@ -385,6 +386,7 @@ struct DepsNodeHandle { const char *default_name; }; -} // namespace DEG +} // namespace deg +} // namespace blender #include "intern/builder/deg_builder_relations_impl.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h index 5983627fafc..d4c28060878 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h @@ -28,7 +28,8 @@ #include "DNA_ID.h" #include "DNA_object_types.h" -namespace DEG { +namespace blender { +namespace deg { template<typename KeyType> OperationNode *DepsgraphRelationBuilder::find_operation_node(const KeyType &key) @@ -215,4 +216,5 @@ bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency(const KeyFrom &k return true; } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc index 6c449900f03..2220ba6ee13 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc @@ -25,7 +25,8 @@ #include "intern/builder/deg_builder_relations.h" -namespace DEG { +namespace blender { +namespace deg { //////////////////////////////////////////////////////////////////////////////// // Time source. @@ -192,4 +193,5 @@ string RNAPathKey::identifier() const return string("RnaPathKey(") + "id: " + id_name + ", prop: '" + prop_name + "')"; } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index fe9adecbf0a..b695c43402f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -58,7 +58,8 @@ #include "intern/depsgraph_relation.h" #include "intern/depsgraph_type.h" -namespace DEG { +namespace blender { +namespace deg { /* IK Solver Eval Steps */ void DepsgraphRelationBuilder::build_ik_pose(Object *object, @@ -449,7 +450,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object) } /* Custom shape. */ if (pchan->custom != nullptr) { - build_object(nullptr, pchan->custom); + build_object(pchan->custom); } } } @@ -509,4 +510,5 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object) } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc index 410df839875..6ebf5210b63 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc @@ -25,7 +25,8 @@ #include "DNA_scene_types.h" -namespace DEG { +namespace blender { +namespace deg { void DepsgraphRelationBuilder::build_scene_render(Scene *scene, ViewLayer *view_layer) { @@ -43,7 +44,7 @@ void DepsgraphRelationBuilder::build_scene_render(Scene *scene, ViewLayer *view_ build_scene_speakers(scene, view_layer); } if (scene->camera != nullptr) { - build_object(nullptr, scene->camera); + build_object(scene->camera); } } @@ -71,4 +72,5 @@ void DepsgraphRelationBuilder::build_scene_compositor(Scene *scene) build_nodetree(scene->nodetree); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index e132ba30e67..6e64eba60dc 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -56,7 +56,8 @@ #include "intern/depsgraph_type.h" -namespace DEG { +namespace blender { +namespace deg { void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb) { @@ -96,14 +97,14 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, * do nullptr-pointer check of the base, so it's fine to pass original one. */ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { if (need_pull_base_into_graph(base)) { - build_object(base, base->object); + build_object(base->object); } } build_layer_collections(&view_layer->layer_collections); if (scene->camera != nullptr) { - build_object(nullptr, scene->camera); + build_object(scene->camera); } /* Rigidbody. */ if (scene->rigidbody_world != nullptr) { @@ -153,4 +154,5 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc index c6545362bb1..a9b405cfb27 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc @@ -33,7 +33,8 @@ #include "intern/depsgraph_relation.h" #include "intern/depsgraph_type.h" -namespace DEG { +namespace blender { +namespace deg { static inline bool is_unused_noop(OperationNode *op_node) { @@ -84,4 +85,5 @@ void deg_graph_remove_unused_noops(Depsgraph *graph) (::Depsgraph *)graph, BUILD, "Removed %d relations to no-op nodes\n", num_removed_relations); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.h b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.h index e7a2e90cf7c..e30e90af9c0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.h @@ -23,11 +23,13 @@ #pragma once -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; /* Remove all no-op nodes that have zero outgoing relations. */ void deg_graph_remove_unused_noops(Depsgraph *graph); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index fbd53bf46f8..98ae653d294 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -48,7 +48,8 @@ #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" -namespace DEG { +namespace blender { +namespace deg { /* ********************************* ID Data ******************************** */ @@ -365,8 +366,9 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, RNANodeQueryIDData *RNANodeQuery::ensure_id_data(const ID *id) { unique_ptr<RNANodeQueryIDData> &id_data = id_data_map_.lookup_or_add_cb( - id, [&]() { return blender::make_unique<RNANodeQueryIDData>(id); }); + id, [&]() { return std::make_unique<RNANodeQueryIDData>(id); }); return id_data.get(); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h index bd806ce058a..52d0e5f6b12 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h @@ -30,7 +30,8 @@ struct ID; struct PointerRNA; struct PropertyRNA; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; struct Node; @@ -94,4 +95,5 @@ class RNANodeQuery { RNANodeQueryIDData *ensure_id_data(const ID *id); }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index 22ceac899b8..8ffb20a9999 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -33,7 +33,8 @@ #include "intern/depsgraph.h" #include "intern/depsgraph_relation.h" -namespace DEG { +namespace blender { +namespace deg { /* -------------------------------------------------- */ @@ -109,4 +110,5 @@ void deg_graph_transitive_reduction(Depsgraph *graph) DEG_DEBUG_PRINTF((::Depsgraph *)graph, BUILD, "Removed %d relations\n", num_removed_relations); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.h b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h index 43068886809..3f083381f83 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h @@ -23,11 +23,13 @@ #pragma once -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; /* Performs a transitive reduction to remove redundant relations. */ void deg_graph_transitive_reduction(Depsgraph *graph); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/debug/deg_debug.cc b/source/blender/depsgraph/intern/debug/deg_debug.cc index ca27cef2c56..ab6adea6416 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug.cc @@ -32,7 +32,8 @@ #include "BKE_global.h" -namespace DEG { +namespace blender { +namespace deg { DepsgraphDebug::DepsgraphDebug() : flags(G.debug), is_ever_evaluated(false), graph_evaluation_start_time_(0) @@ -97,4 +98,5 @@ string color_end(void) return string(TRUECOLOR_ANSI_COLOR_FINISH); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/debug/deg_debug.h b/source/blender/depsgraph/intern/debug/deg_debug.h index f5e2f2c4b51..043cdc85333 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug.h +++ b/source/blender/depsgraph/intern/debug/deg_debug.h @@ -30,7 +30,8 @@ #include "DEG_depsgraph_debug.h" -namespace DEG { +namespace blender { +namespace deg { class DepsgraphDebug { public: @@ -89,4 +90,5 @@ bool terminal_do_color(void); string color_for_pointer(const void *pointer); string color_end(void); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index 1f33bdefb79..458baf4fb1e 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -40,10 +40,13 @@ #include "intern/node/deg_node_operation.h" #include "intern/node/deg_node_time.h" +namespace deg = blender::deg; + /* ****************** */ /* Graphviz Debugging */ -namespace DEG { +namespace blender { +namespace deg { #define NL "\r\n" @@ -578,7 +581,8 @@ static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, const De } } -} // namespace DEG +} // namespace deg +} // namespace blender void DEG_debug_relations_graphviz(const Depsgraph *graph, FILE *f, const char *label) { @@ -586,29 +590,29 @@ void DEG_debug_relations_graphviz(const Depsgraph *graph, FILE *f, const char *l return; } - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); - DEG::DebugContext ctx; + deg::DebugContext ctx; ctx.file = f; - DEG::deg_debug_fprintf(ctx, "digraph depgraph {" NL); - DEG::deg_debug_fprintf(ctx, "rankdir=LR;" NL); - DEG::deg_debug_fprintf(ctx, "graph ["); - DEG::deg_debug_fprintf(ctx, "compound=true"); - DEG::deg_debug_fprintf(ctx, ",labelloc=\"t\""); - DEG::deg_debug_fprintf(ctx, ",fontsize=%f", DEG::deg_debug_graphviz_graph_label_size); - DEG::deg_debug_fprintf(ctx, ",fontname=\"%s\"", DEG::deg_debug_graphviz_fontname); - DEG::deg_debug_fprintf(ctx, ",label=\"%s\"", label); - DEG::deg_debug_fprintf(ctx, ",splines=ortho"); - DEG::deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato - DEG::deg_debug_fprintf(ctx, "];" NL); + deg::deg_debug_fprintf(ctx, "digraph depgraph {" NL); + deg::deg_debug_fprintf(ctx, "rankdir=LR;" NL); + deg::deg_debug_fprintf(ctx, "graph ["); + deg::deg_debug_fprintf(ctx, "compound=true"); + deg::deg_debug_fprintf(ctx, ",labelloc=\"t\""); + deg::deg_debug_fprintf(ctx, ",fontsize=%f", deg::deg_debug_graphviz_graph_label_size); + deg::deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg::deg_debug_graphviz_fontname); + deg::deg_debug_fprintf(ctx, ",label=\"%s\"", label); + deg::deg_debug_fprintf(ctx, ",splines=ortho"); + deg::deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato + deg::deg_debug_fprintf(ctx, "];" NL); - DEG::deg_debug_graphviz_graph_nodes(ctx, deg_graph); - DEG::deg_debug_graphviz_graph_relations(ctx, deg_graph); + deg::deg_debug_graphviz_graph_nodes(ctx, deg_graph); + deg::deg_debug_graphviz_graph_relations(ctx, deg_graph); - DEG::deg_debug_graphviz_legend(ctx); + deg::deg_debug_graphviz_legend(ctx); - DEG::deg_debug_fprintf(ctx, "}" NL); + deg::deg_debug_fprintf(ctx, "}" NL); } #undef NL diff --git a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc index 9e751093ae2..78525ba6b69 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc @@ -36,7 +36,10 @@ #define NL "\r\n" -namespace DEG { +namespace deg = blender::deg; + +namespace blender { +namespace deg { namespace { struct DebugContext { @@ -147,7 +150,8 @@ void deg_debug_stats_gnuplot(const DebugContext &ctx) } } // namespace -} // namespace DEG +} // namespace deg +} // namespace blender void DEG_debug_stats_gnuplot(const Depsgraph *depsgraph, FILE *f, @@ -157,10 +161,10 @@ void DEG_debug_stats_gnuplot(const Depsgraph *depsgraph, if (depsgraph == nullptr) { return; } - DEG::DebugContext ctx; + deg::DebugContext ctx; ctx.file = f; - ctx.graph = (DEG::Depsgraph *)depsgraph; + ctx.graph = (deg::Depsgraph *)depsgraph; ctx.label = label; ctx.output_filename = output_filename; - DEG::deg_debug_stats_gnuplot(ctx); + deg::deg_debug_stats_gnuplot(ctx); } diff --git a/source/blender/depsgraph/intern/debug/deg_time_average.h b/source/blender/depsgraph/intern/debug/deg_time_average.h index 9794e9a88c3..838ceff8d96 100644 --- a/source/blender/depsgraph/intern/debug/deg_time_average.h +++ b/source/blender/depsgraph/intern/debug/deg_time_average.h @@ -23,7 +23,8 @@ #pragma once -namespace DEG { +namespace blender { +namespace deg { // Utility class which takes care of calculating average of time series, such as // FPS counters. @@ -68,4 +69,5 @@ template<int MaxSamples> class AveragedTimeSampler { int next_sample_index_; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 51ae56ac613..ce2c7110aee 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -55,7 +55,10 @@ #include "intern/node/deg_node_operation.h" #include "intern/node/deg_node_time.h" -namespace DEG { +namespace deg = blender::deg; + +namespace blender { +namespace deg { Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode) : time_source(nullptr), @@ -258,7 +261,8 @@ ID *Depsgraph::get_cow_id(const ID *id_orig) const return id_node->id_cow; } -} // namespace DEG +} // namespace deg +} // namespace blender /* **************** */ /* Public Graph API */ @@ -266,9 +270,9 @@ ID *Depsgraph::get_cow_id(const ID *id_orig) const /* Initialize a new Depsgraph */ Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode) { - DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW( - DEG::Depsgraph, bmain, scene, view_layer, mode); - DEG::register_graph(deg_depsgraph); + deg::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW( + deg::Depsgraph, bmain, scene, view_layer, mode); + deg::register_graph(deg_depsgraph); return reinterpret_cast<Depsgraph *>(deg_depsgraph); } @@ -279,11 +283,11 @@ void DEG_graph_replace_owners(struct Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); const bool do_update_register = deg_graph->bmain != bmain; if (do_update_register && deg_graph->bmain != NULL) { - DEG::unregister_graph(deg_graph); + deg::unregister_graph(deg_graph); } deg_graph->bmain = bmain; @@ -291,7 +295,7 @@ void DEG_graph_replace_owners(struct Depsgraph *depsgraph, deg_graph->view_layer = view_layer; if (do_update_register) { - DEG::register_graph(deg_graph); + deg::register_graph(deg_graph); } } @@ -301,15 +305,15 @@ void DEG_graph_free(Depsgraph *graph) if (graph == nullptr) { return; } - using DEG::Depsgraph; - DEG::Depsgraph *deg_depsgraph = reinterpret_cast<DEG::Depsgraph *>(graph); - DEG::unregister_graph(deg_depsgraph); + using deg::Depsgraph; + deg::Depsgraph *deg_depsgraph = reinterpret_cast<deg::Depsgraph *>(graph); + deg::unregister_graph(deg_depsgraph); OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph); } bool DEG_is_evaluating(const struct Depsgraph *depsgraph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph); return deg_graph->is_evaluating; } @@ -322,19 +326,19 @@ bool DEG_is_active(const struct Depsgraph *depsgraph) * cases. */ return false; } - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph); return deg_graph->is_active; } void DEG_make_active(struct Depsgraph *depsgraph) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); deg_graph->is_active = true; /* TODO(sergey): Copy data from evaluated state to original. */ } void DEG_make_inactive(struct Depsgraph *depsgraph) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); deg_graph->is_active = false; } diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index e0686bd04aa..9dea518b89c 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -47,7 +47,8 @@ struct ID; struct Scene; struct ViewLayer; -namespace DEG { +namespace blender { +namespace deg { struct IDNode; struct Node; @@ -169,4 +170,5 @@ struct Depsgraph { Map<const ID *, ListBase *> *physics_relations[DEG_PHYSICS_RELATIONS_NUM]; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index cdaf68cb826..c11d051e663 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -64,22 +64,24 @@ /* ****************** */ /* External Build API */ -static DEG::NodeType deg_build_scene_component_type(eDepsSceneComponentType component) +namespace deg = blender::deg; + +static deg::NodeType deg_build_scene_component_type(eDepsSceneComponentType component) { switch (component) { case DEG_SCENE_COMP_PARAMETERS: - return DEG::NodeType::PARAMETERS; + return deg::NodeType::PARAMETERS; case DEG_SCENE_COMP_ANIMATION: - return DEG::NodeType::ANIMATION; + return deg::NodeType::ANIMATION; case DEG_SCENE_COMP_SEQUENCER: - return DEG::NodeType::SEQUENCER; + return deg::NodeType::SEQUENCER; } - return DEG::NodeType::UNDEFINED; + return deg::NodeType::UNDEFINED; } -static DEG::DepsNodeHandle *get_node_handle(DepsNodeHandle *node_handle) +static deg::DepsNodeHandle *get_node_handle(DepsNodeHandle *node_handle) { - return reinterpret_cast<DEG::DepsNodeHandle *>(node_handle); + return reinterpret_cast<deg::DepsNodeHandle *>(node_handle); } void DEG_add_scene_relation(DepsNodeHandle *node_handle, @@ -87,9 +89,9 @@ void DEG_add_scene_relation(DepsNodeHandle *node_handle, eDepsSceneComponentType component, const char *description) { - DEG::NodeType type = deg_build_scene_component_type(component); - DEG::ComponentKey comp_key(&scene->id, type); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg::NodeType type = deg_build_scene_component_type(component); + deg::ComponentKey comp_key(&scene->id, type); + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); } @@ -98,9 +100,9 @@ void DEG_add_object_relation(DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = DEG::nodeTypeFromObjectComponent(component); - DEG::ComponentKey comp_key(&object->id, type); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg::NodeType type = deg::nodeTypeFromObjectComponent(component); + deg::ComponentKey comp_key(&object->id, type); + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); } @@ -108,9 +110,9 @@ void DEG_add_simulation_relation(DepsNodeHandle *node_handle, Simulation *simulation, const char *description) { - DEG::OperationKey operation_key( - &simulation->id, DEG::NodeType::SIMULATION, DEG::OperationCode::SIMULATION_EVAL); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg::OperationKey operation_key( + &simulation->id, deg::NodeType::SIMULATION, deg::OperationCode::SIMULATION_EVAL); + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description); } @@ -119,9 +121,9 @@ void DEG_add_object_cache_relation(DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = DEG::nodeTypeFromObjectComponent(component); - DEG::ComponentKey comp_key(&cache_file->id, type); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg::NodeType type = deg::nodeTypeFromObjectComponent(component); + deg::ComponentKey comp_key(&cache_file->id, type); + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); } @@ -131,9 +133,9 @@ void DEG_add_bone_relation(DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = DEG::nodeTypeFromObjectComponent(component); - DEG::ComponentKey comp_key(&object->id, type, bone_name); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg::NodeType type = deg::nodeTypeFromObjectComponent(component); + deg::ComponentKey comp_key(&object->id, type, bone_name); + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); } @@ -142,18 +144,18 @@ void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = DEG::nodeTypeFromObjectComponent(component); - DEG::ComponentKey comp_key(&object->id, type); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - DEG::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder; + deg::NodeType type = deg::nodeTypeFromObjectComponent(component); + deg::ComponentKey comp_key(&object->id, type); + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder; /* Add relation from source to the node handle. */ relation_builder->add_node_handle_relation(comp_key, deg_node_handle, description); /* Node deduct point cache component and connect source to it. */ ID *id = DEG_get_id_from_handle(node_handle); - DEG::ComponentKey point_cache_key(id, DEG::NodeType::POINT_CACHE); - DEG::Relation *rel = relation_builder->add_relation(comp_key, point_cache_key, "Point Cache"); + deg::ComponentKey point_cache_key(id, deg::NodeType::POINT_CACHE); + deg::Relation *rel = relation_builder->add_relation(comp_key, point_cache_key, "Point Cache"); if (rel != nullptr) { - rel->flag |= DEG::RELATION_FLAG_FLUSH_USER_EDIT_ONLY; + rel->flag |= deg::RELATION_FLAG_FLUSH_USER_EDIT_ONLY; } else { fprintf(stderr, "Error in point cache relation from %s to ^%s.\n", object->id.name, id->name); @@ -164,22 +166,22 @@ void DEG_add_generic_id_relation(struct DepsNodeHandle *node_handle, struct ID *id, const char *description) { - DEG::OperationKey operation_key( - id, DEG::NodeType::GENERIC_DATABLOCK, DEG::OperationCode::GENERIC_DATABLOCK_UPDATE); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg::OperationKey operation_key( + id, deg::NodeType::GENERIC_DATABLOCK, deg::OperationCode::GENERIC_DATABLOCK_UPDATE); + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description); } void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle, const char *description) { - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_modifier_to_transform_relation(deg_node_handle, description); } void DEG_add_special_eval_flag(struct DepsNodeHandle *node_handle, ID *id, uint32_t flag) { - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_special_eval_flag(id, flag); } @@ -187,41 +189,41 @@ void DEG_add_customdata_mask(struct DepsNodeHandle *node_handle, struct Object *object, const CustomData_MeshMasks *masks) { - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_customdata_mask(object, DEG::DEGCustomDataMeshMasks(masks)); + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg_node_handle->builder->add_customdata_mask(object, deg::DEGCustomDataMeshMasks(masks)); } struct ID *DEG_get_id_from_handle(struct DepsNodeHandle *node_handle) { - DEG::DepsNodeHandle *deg_handle = get_node_handle(node_handle); + deg::DepsNodeHandle *deg_handle = get_node_handle(node_handle); return deg_handle->node->owner->owner->id_orig; } struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *node_handle) { - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - DEG::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder; + deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder; return reinterpret_cast<Depsgraph *>(relation_builder->getGraph()); } /* ******************** */ /* Graph Building API's */ -static void graph_build_finalize_common(DEG::Depsgraph *deg_graph, Main *bmain) +static void graph_build_finalize_common(deg::Depsgraph *deg_graph, Main *bmain) { /* Detect and solve cycles. */ - DEG::deg_graph_detect_cycles(deg_graph); + deg::deg_graph_detect_cycles(deg_graph); /* Simplify the graph by removing redundant relations (to optimize * traversal later). */ /* TODO: it would be useful to have an option to disable this in cases where * it is causing trouble. */ if (G.debug_value == 799) { - DEG::deg_graph_transitive_reduction(deg_graph); + deg::deg_graph_transitive_reduction(deg_graph); } /* Store pointers to commonly used valuated datablocks. */ deg_graph->scene_cow = (Scene *)deg_graph->get_cow_id(°_graph->scene->id); /* Flush visibility layer and re-schedule nodes for update. */ - DEG::deg_graph_build_finalize(bmain, deg_graph); + deg::deg_graph_build_finalize(bmain, deg_graph); DEG_graph_on_visible_update(bmain, reinterpret_cast<::Depsgraph *>(deg_graph), false); #if 0 if (!DEG_debug_consistency_check(deg_graph)) { @@ -243,21 +245,21 @@ void DEG_graph_build_from_view_layer(Depsgraph *graph, if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) { start_time = PIL_check_seconds_timer(); } - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); /* Perform sanity checks. */ BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1); BLI_assert(deg_graph->scene == scene); BLI_assert(deg_graph->view_layer == view_layer); - DEG::DepsgraphBuilderCache builder_cache; + deg::DepsgraphBuilderCache builder_cache; /* Generate all the nodes in the graph first */ - DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph, &builder_cache); + deg::DepsgraphNodeBuilder node_builder(bmain, deg_graph, &builder_cache); node_builder.begin_build(); - node_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY); + node_builder.build_view_layer(scene, view_layer, deg::DEG_ID_LINKED_DIRECTLY); node_builder.end_build(); /* Hook up relationships between operations - to determine evaluation order. */ - DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph, &builder_cache); + deg::DepsgraphRelationBuilder relation_builder(bmain, deg_graph, &builder_cache); relation_builder.begin_build(); - relation_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY); + relation_builder.build_view_layer(scene, view_layer, deg::DEG_ID_LINKED_DIRECTLY); relation_builder.build_copy_on_write_relations(); relation_builder.build_driver_relations(); /* Finalize building. */ @@ -277,19 +279,19 @@ void DEG_graph_build_for_render_pipeline(Depsgraph *graph, if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) { start_time = PIL_check_seconds_timer(); } - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); /* Perform sanity checks. */ BLI_assert(deg_graph->scene == scene); deg_graph->is_render_pipeline_depsgraph = true; - DEG::DepsgraphBuilderCache builder_cache; + deg::DepsgraphBuilderCache builder_cache; /* Generate all the nodes in the graph first */ - DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph, &builder_cache); + deg::DepsgraphNodeBuilder node_builder(bmain, deg_graph, &builder_cache); node_builder.begin_build(); node_builder.build_scene_render(scene, view_layer); node_builder.end_build(); /* Hook up relationships between operations - to determine evaluation * order. */ - DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph, &builder_cache); + deg::DepsgraphRelationBuilder relation_builder(bmain, deg_graph, &builder_cache); relation_builder.begin_build(); relation_builder.build_scene_render(scene, view_layer); relation_builder.build_copy_on_write_relations(); @@ -309,20 +311,20 @@ void DEG_graph_build_for_compositor_preview( if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) { start_time = PIL_check_seconds_timer(); } - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); /* Perform sanity checks. */ BLI_assert(deg_graph->scene == scene); deg_graph->is_render_pipeline_depsgraph = true; - DEG::DepsgraphBuilderCache builder_cache; + deg::DepsgraphBuilderCache builder_cache; /* Generate all the nodes in the graph first */ - DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph, &builder_cache); + deg::DepsgraphNodeBuilder node_builder(bmain, deg_graph, &builder_cache); node_builder.begin_build(); node_builder.build_scene_render(scene, view_layer); node_builder.build_nodetree(nodetree); node_builder.end_build(); /* Hook up relationships between operations - to determine evaluation * order. */ - DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph, &builder_cache); + deg::DepsgraphRelationBuilder relation_builder(bmain, deg_graph, &builder_cache); relation_builder.begin_build(); relation_builder.build_scene_render(scene, view_layer); relation_builder.build_nodetree(nodetree); @@ -349,7 +351,8 @@ void DEG_graph_build_for_compositor_preview( * This way we avoid high-poly character body pulled into the dependency graph when it's coming * from a library into an animation file and the dependency graph constructed for a proxy rig. */ -namespace DEG { +namespace blender { +namespace deg { namespace { class DepsgraphFromIDsFilter { @@ -433,7 +436,8 @@ class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder { }; } // namespace -} // namespace DEG +} // namespace deg +} // namespace blender void DEG_graph_build_from_ids(Depsgraph *graph, Main *bmain, @@ -446,25 +450,25 @@ void DEG_graph_build_from_ids(Depsgraph *graph, if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) { start_time = PIL_check_seconds_timer(); } - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); /* Perform sanity checks. */ BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1); BLI_assert(deg_graph->scene == scene); BLI_assert(deg_graph->view_layer == view_layer); - DEG::DepsgraphBuilderCache builder_cache; + deg::DepsgraphBuilderCache builder_cache; /* Generate all the nodes in the graph first */ - DEG::DepsgraphFromIDsNodeBuilder node_builder(bmain, deg_graph, &builder_cache, ids, num_ids); + deg::DepsgraphFromIDsNodeBuilder node_builder(bmain, deg_graph, &builder_cache, ids, num_ids); node_builder.begin_build(); - node_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY); + node_builder.build_view_layer(scene, view_layer, deg::DEG_ID_LINKED_DIRECTLY); for (int i = 0; i < num_ids; ++i) { node_builder.build_id(ids[i]); } node_builder.end_build(); /* Hook up relationships between operations - to determine evaluation order. */ - DEG::DepsgraphFromIDsRelationBuilder relation_builder( + deg::DepsgraphFromIDsRelationBuilder relation_builder( bmain, deg_graph, &builder_cache, ids, num_ids); relation_builder.begin_build(); - relation_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY); + relation_builder.build_view_layer(scene, view_layer, deg::DEG_ID_LINKED_DIRECTLY); for (int i = 0; i < num_ids; ++i) { relation_builder.build_id(ids[i]); } @@ -482,7 +486,7 @@ void DEG_graph_build_from_ids(Depsgraph *graph, void DEG_graph_tag_relations_update(Depsgraph *graph) { DEG_DEBUG_PRINTF(graph, TAG, "%s: Tagging relations for update.\n", __func__); - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); deg_graph->need_update = true; /* NOTE: When relations are updated, it's quite possible that * we've got new bases in the scene. This means, we need to @@ -490,16 +494,16 @@ void DEG_graph_tag_relations_update(Depsgraph *graph) * * TODO(sergey): Try to make it so we don't flush updates * to the whole depsgraph. */ - DEG::IDNode *id_node = deg_graph->find_id_node(°_graph->scene->id); + deg::IDNode *id_node = deg_graph->find_id_node(°_graph->scene->id); if (id_node != nullptr) { - id_node->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_RELATIONS); + id_node->tag_update(deg_graph, deg::DEG_UPDATE_SOURCE_RELATIONS); } } /* Create or update relations in the specified graph. */ void DEG_graph_relations_update(Depsgraph *graph, Main *bmain, Scene *scene, ViewLayer *view_layer) { - DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)graph; + deg::Depsgraph *deg_graph = (deg::Depsgraph *)graph; if (!deg_graph->need_update) { /* Graph is up to date, nothing to do. */ return; @@ -511,7 +515,7 @@ void DEG_graph_relations_update(Depsgraph *graph, Main *bmain, Scene *scene, Vie void DEG_relations_tag_update(Main *bmain) { DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__); - for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) { + for (deg::Depsgraph *depsgraph : deg::get_all_registered_graphs(bmain)) { DEG_graph_tag_relations_update(reinterpret_cast<Depsgraph *>(depsgraph)); } } diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index 8f5117ec0f6..0763738ff59 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -42,27 +42,29 @@ #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_time.h" +namespace deg = blender::deg; + void DEG_debug_flags_set(Depsgraph *depsgraph, int flags) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); deg_graph->debug.flags = flags; } int DEG_debug_flags_get(const Depsgraph *depsgraph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph); return deg_graph->debug.flags; } void DEG_debug_name_set(struct Depsgraph *depsgraph, const char *name) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); deg_graph->debug.name = name; } const char *DEG_debug_name_get(struct Depsgraph *depsgraph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph); return deg_graph->debug.name.c_str(); } @@ -70,8 +72,8 @@ bool DEG_debug_compare(const struct Depsgraph *graph1, const struct Depsgraph *g { BLI_assert(graph1 != nullptr); BLI_assert(graph2 != nullptr); - const DEG::Depsgraph *deg_graph1 = reinterpret_cast<const DEG::Depsgraph *>(graph1); - const DEG::Depsgraph *deg_graph2 = reinterpret_cast<const DEG::Depsgraph *>(graph2); + const deg::Depsgraph *deg_graph1 = reinterpret_cast<const deg::Depsgraph *>(graph1); + const deg::Depsgraph *deg_graph2 = reinterpret_cast<const deg::Depsgraph *>(graph2); if (deg_graph1->operations.size() != deg_graph2->operations.size()) { return false; } @@ -103,18 +105,18 @@ bool DEG_debug_graph_relations_validate(Depsgraph *graph, bool DEG_debug_consistency_check(Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); /* Validate links exists in both directions. */ - for (DEG::OperationNode *node : deg_graph->operations) { - for (DEG::Relation *rel : node->outlinks) { + for (deg::OperationNode *node : deg_graph->operations) { + for (deg::Relation *rel : node->outlinks) { int counter1 = 0; - for (DEG::Relation *tmp_rel : node->outlinks) { + for (deg::Relation *tmp_rel : node->outlinks) { if (tmp_rel == rel) { counter1++; } } int counter2 = 0; - for (DEG::Relation *tmp_rel : rel->to->inlinks) { + for (deg::Relation *tmp_rel : rel->to->inlinks) { if (tmp_rel == rel) { counter2++; } @@ -130,16 +132,16 @@ bool DEG_debug_consistency_check(Depsgraph *graph) } } - for (DEG::OperationNode *node : deg_graph->operations) { - for (DEG::Relation *rel : node->inlinks) { + for (deg::OperationNode *node : deg_graph->operations) { + for (deg::Relation *rel : node->inlinks) { int counter1 = 0; - for (DEG::Relation *tmp_rel : node->inlinks) { + for (deg::Relation *tmp_rel : node->inlinks) { if (tmp_rel == rel) { counter1++; } } int counter2 = 0; - for (DEG::Relation *tmp_rel : rel->from->outlinks) { + for (deg::Relation *tmp_rel : rel->from->outlinks) { if (tmp_rel == rel) { counter2++; } @@ -153,19 +155,19 @@ bool DEG_debug_consistency_check(Depsgraph *graph) } /* Validate node valency calculated in both directions. */ - for (DEG::OperationNode *node : deg_graph->operations) { + for (deg::OperationNode *node : deg_graph->operations) { node->num_links_pending = 0; node->custom_flags = 0; } - for (DEG::OperationNode *node : deg_graph->operations) { + for (deg::OperationNode *node : deg_graph->operations) { if (node->custom_flags) { printf("Node %s is twice in the operations!\n", node->identifier().c_str()); return false; } - for (DEG::Relation *rel : node->outlinks) { - if (rel->to->type == DEG::NodeType::OPERATION) { - DEG::OperationNode *to = (DEG::OperationNode *)rel->to; + for (deg::Relation *rel : node->outlinks) { + if (rel->to->type == deg::NodeType::OPERATION) { + deg::OperationNode *to = (deg::OperationNode *)rel->to; BLI_assert(to->num_links_pending < to->inlinks.size()); ++to->num_links_pending; } @@ -173,10 +175,10 @@ bool DEG_debug_consistency_check(Depsgraph *graph) node->custom_flags = 1; } - for (DEG::OperationNode *node : deg_graph->operations) { + for (deg::OperationNode *node : deg_graph->operations) { int num_links_pending = 0; - for (DEG::Relation *rel : node->inlinks) { - if (rel->from->type == DEG::NodeType::OPERATION) { + for (deg::Relation *rel : node->inlinks) { + if (rel->from->type == deg::NodeType::OPERATION) { num_links_pending++; } } @@ -205,7 +207,7 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_operations, size_t *r_relations) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); /* number of operations */ if (r_operations) { @@ -219,17 +221,17 @@ void DEG_stats_simple(const Depsgraph *graph, size_t tot_outer = 0; size_t tot_rels = 0; - for (DEG::IDNode *id_node : deg_graph->id_nodes) { + for (deg::IDNode *id_node : deg_graph->id_nodes) { tot_outer++; - for (DEG::ComponentNode *comp_node : id_node->components.values()) { + for (deg::ComponentNode *comp_node : id_node->components.values()) { tot_outer++; - for (DEG::OperationNode *op_node : comp_node->operations) { + for (deg::OperationNode *op_node : comp_node->operations) { tot_rels += op_node->inlinks.size(); } } } - DEG::TimeSourceNode *time_source = deg_graph->find_time_source(); + deg::TimeSourceNode *time_source = deg_graph->find_time_source(); if (time_source != nullptr) { tot_rels += time_source->inlinks.size(); } @@ -243,13 +245,13 @@ void DEG_stats_simple(const Depsgraph *graph, } } -static DEG::string depsgraph_name_for_logging(struct Depsgraph *depsgraph) +static deg::string depsgraph_name_for_logging(struct Depsgraph *depsgraph) { const char *name = DEG_debug_name_get(depsgraph); if (name[0] == '\0') { return ""; } - return "[" + DEG::string(name) + "]: "; + return "[" + deg::string(name) + "]: "; } void DEG_debug_print_begin(struct Depsgraph *depsgraph) @@ -270,9 +272,9 @@ void DEG_debug_print_eval(struct Depsgraph *depsgraph, depsgraph_name_for_logging(depsgraph).c_str(), function_name, object_name, - DEG::color_for_pointer(object_address).c_str(), + deg::color_for_pointer(object_address).c_str(), object_address, - DEG::color_end().c_str()); + deg::color_end().c_str()); fflush(stdout); } @@ -292,14 +294,14 @@ void DEG_debug_print_eval_subdata(struct Depsgraph *depsgraph, depsgraph_name_for_logging(depsgraph).c_str(), function_name, object_name, - DEG::color_for_pointer(object_address).c_str(), + deg::color_for_pointer(object_address).c_str(), object_address, - DEG::color_end().c_str(), + deg::color_end().c_str(), subdata_comment, subdata_name, - DEG::color_for_pointer(subdata_address).c_str(), + deg::color_for_pointer(subdata_address).c_str(), subdata_address, - DEG::color_end().c_str()); + deg::color_end().c_str()); fflush(stdout); } @@ -320,15 +322,15 @@ void DEG_debug_print_eval_subdata_index(struct Depsgraph *depsgraph, depsgraph_name_for_logging(depsgraph).c_str(), function_name, object_name, - DEG::color_for_pointer(object_address).c_str(), + deg::color_for_pointer(object_address).c_str(), object_address, - DEG::color_end().c_str(), + deg::color_end().c_str(), subdata_comment, subdata_name, subdata_index, - DEG::color_for_pointer(subdata_address).c_str(), + deg::color_for_pointer(subdata_address).c_str(), subdata_address, - DEG::color_end().c_str()); + deg::color_end().c_str()); fflush(stdout); } @@ -348,14 +350,14 @@ void DEG_debug_print_eval_parent_typed(struct Depsgraph *depsgraph, depsgraph_name_for_logging(depsgraph).c_str(), function_name, object_name, - DEG::color_for_pointer(object_address).c_str(), + deg::color_for_pointer(object_address).c_str(), object_address, - DEG::color_end().c_str(), + deg::color_end().c_str(), parent_comment, parent_name, - DEG::color_for_pointer(parent_address).c_str(), + deg::color_for_pointer(parent_address).c_str(), parent_address, - DEG::color_end().c_str()); + deg::color_end().c_str()); fflush(stdout); } @@ -373,9 +375,9 @@ void DEG_debug_print_eval_time(struct Depsgraph *depsgraph, depsgraph_name_for_logging(depsgraph).c_str(), function_name, object_name, - DEG::color_for_pointer(object_address).c_str(), + deg::color_for_pointer(object_address).c_str(), object_address, - DEG::color_end().c_str(), + deg::color_end().c_str(), time); fflush(stdout); } diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index b6c6129e9ba..8a641f23a42 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -45,44 +45,46 @@ #include "intern/depsgraph.h" +namespace deg = blender::deg; + /* Evaluate all nodes tagged for updating. */ void DEG_evaluate_on_refresh(Main *bmain, Depsgraph *graph) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); deg_graph->ctime = BKE_scene_frame_get(deg_graph->scene); /* Update time on primary timesource. */ - DEG::TimeSourceNode *tsrc = deg_graph->find_time_source(); + deg::TimeSourceNode *tsrc = deg_graph->find_time_source(); tsrc->cfra = deg_graph->ctime; /* Update time in scene. */ if (deg_graph->scene_cow) { BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime); } - DEG::deg_graph_flush_updates(bmain, deg_graph); - DEG::deg_evaluate_on_refresh(deg_graph); + deg::deg_graph_flush_updates(bmain, deg_graph); + deg::deg_evaluate_on_refresh(deg_graph); deg_graph->need_update_time = false; } /* Frame-change happened for root scene that graph belongs to. */ void DEG_evaluate_on_framechange(Main *bmain, Depsgraph *graph, float ctime) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); deg_graph->ctime = ctime; /* Update time on primary timesource. */ - DEG::TimeSourceNode *tsrc = deg_graph->find_time_source(); + deg::TimeSourceNode *tsrc = deg_graph->find_time_source(); tsrc->cfra = ctime; deg_graph->need_update_time = true; - DEG::deg_graph_flush_updates(bmain, deg_graph); + deg::deg_graph_flush_updates(bmain, deg_graph); /* Update time in scene. */ if (deg_graph->scene_cow) { BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime); } /* Perform recalculation updates. */ - DEG::deg_evaluate_on_refresh(deg_graph); + deg::deg_evaluate_on_refresh(deg_graph); deg_graph->need_update_time = false; } bool DEG_needs_eval(Depsgraph *graph) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); return !deg_graph->entry_tags.is_empty() || deg_graph->need_update_time; } diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc index ad67117fda3..76f3a2e8ff4 100644 --- a/source/blender/depsgraph/intern/depsgraph_physics.cc +++ b/source/blender/depsgraph/intern/depsgraph_physics.cc @@ -44,6 +44,8 @@ #include "depsgraph.h" +namespace deg = blender::deg; + /*************************** Evaluation Query API *****************************/ static ePhysicsRelationType modifier_to_relation_type(unsigned int modifier_type) @@ -63,7 +65,7 @@ static ePhysicsRelationType modifier_to_relation_type(unsigned int modifier_type ListBase *DEG_get_effector_relations(const Depsgraph *graph, Collection *collection) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); if (deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR] == nullptr) { return nullptr; } @@ -77,7 +79,7 @@ ListBase *DEG_get_collision_relations(const Depsgraph *graph, Collection *collection, unsigned int modifier_type) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); const ePhysicsRelationType type = modifier_to_relation_type(modifier_type); if (deg_graph->physics_relations[type] == nullptr) { return nullptr; @@ -96,7 +98,7 @@ void DEG_add_collision_relations(DepsNodeHandle *handle, const char *name) { Depsgraph *depsgraph = DEG_get_graph_from_handle(handle); - DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph; + deg::Depsgraph *deg_graph = (deg::Depsgraph *)depsgraph; ListBase *relations = build_collision_relations(deg_graph, collection, modifier_type); LISTBASE_FOREACH (CollisionRelation *, relation, relations) { Object *ob1 = relation->ob; @@ -119,7 +121,7 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle, const char *name) { Depsgraph *depsgraph = DEG_get_graph_from_handle(handle); - DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph; + deg::Depsgraph *deg_graph = (deg::Depsgraph *)depsgraph; ListBase *relations = build_effector_relations(deg_graph, effector_weights->group); LISTBASE_FOREACH (EffectorRelation *, relation, relations) { if (relation->ob == object) { @@ -158,7 +160,8 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle, /******************************** Internal API ********************************/ -namespace DEG { +namespace blender { +namespace deg { ListBase *build_effector_relations(Depsgraph *graph, Collection *collection) { @@ -218,4 +221,5 @@ void clear_physics_relations(Depsgraph *graph) } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph_physics.h b/source/blender/depsgraph/intern/depsgraph_physics.h index f5d7b9817b5..dbcb577b0b2 100644 --- a/source/blender/depsgraph/intern/depsgraph_physics.h +++ b/source/blender/depsgraph/intern/depsgraph_physics.h @@ -26,7 +26,8 @@ struct Collection; struct ListBase; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -36,4 +37,5 @@ ListBase *build_collision_relations(Depsgraph *graph, unsigned int modifier_type); void clear_physics_relations(Depsgraph *graph); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 3c760e71197..0b6014c18f1 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -47,39 +47,41 @@ #include "intern/eval/deg_eval_copy_on_write.h" #include "intern/node/deg_node_id.h" +namespace deg = blender::deg; + struct Scene *DEG_get_input_scene(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); return deg_graph->scene; } struct ViewLayer *DEG_get_input_view_layer(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); return deg_graph->view_layer; } eEvaluationMode DEG_get_mode(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); return deg_graph->mode; } float DEG_get_ctime(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); return deg_graph->ctime; } bool DEG_id_type_updated(const Depsgraph *graph, short id_type) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); return deg_graph->id_type_updated[BKE_idtype_idcode_to_index(id_type)] != 0; } bool DEG_id_type_any_updated(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); /* Loop over all ID types. */ for (int id_type_index = 0; id_type_index < MAX_LIBARRAY; id_type_index++) { @@ -93,7 +95,7 @@ bool DEG_id_type_any_updated(const Depsgraph *graph) bool DEG_id_type_any_exists(const Depsgraph *depsgraph, short id_type) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph); return deg_graph->id_type_exist[BKE_idtype_idcode_to_index(id_type)] != 0; } @@ -108,8 +110,8 @@ uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id) return 0; } - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); - const DEG::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(id)); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); + const deg::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(id)); if (id_node == nullptr) { /* TODO(sergey): Does it mean we need to check set scene? */ return 0; @@ -131,8 +133,8 @@ void DEG_get_customdata_mask_for_object(const Depsgraph *graph, return; } - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); - const DEG::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(&ob->id)); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); + const deg::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(&ob->id)); if (id_node == nullptr) { /* TODO(sergey): Does it mean we need to check set scene? */ return; @@ -147,17 +149,17 @@ void DEG_get_customdata_mask_for_object(const Depsgraph *graph, Scene *DEG_get_evaluated_scene(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); Scene *scene_cow = deg_graph->scene_cow; /* TODO(sergey): Shall we expand data-block here? Or is it OK to assume * that caller is OK with just a pointer in case scene is not updated yet? */ - BLI_assert(scene_cow != nullptr && DEG::deg_copy_on_write_is_expanded(&scene_cow->id)); + BLI_assert(scene_cow != nullptr && deg::deg_copy_on_write_is_expanded(&scene_cow->id)); return scene_cow; } ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph); Scene *scene_cow = DEG_get_evaluated_scene(graph); if (scene_cow == nullptr) { return nullptr; /* Happens with new, not-yet-built/evaluated graphes. */ @@ -184,8 +186,8 @@ ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id) /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(), * but here we never do assert, since we don't know nature of the * incoming ID data-block. */ - const DEG::Depsgraph *deg_graph = (const DEG::Depsgraph *)depsgraph; - const DEG::IDNode *id_node = deg_graph->find_id_node(id); + const deg::Depsgraph *deg_graph = (const deg::Depsgraph *)depsgraph; + const deg::IDNode *id_node = deg_graph->find_id_node(id); if (id_node == nullptr) { return id; } @@ -309,7 +311,7 @@ bool DEG_is_evaluated_object(const Object *object) bool DEG_is_fully_evaluated(const struct Depsgraph *depsgraph) { - const DEG::Depsgraph *deg_graph = (const DEG::Depsgraph *)depsgraph; + const deg::Depsgraph *deg_graph = (const deg::Depsgraph *)depsgraph; /* Check whether relations are up to date. */ if (deg_graph->need_update) { return false; diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index b68c4b91fcc..ebdd08ce519 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -40,9 +40,12 @@ #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" +namespace deg = blender::deg; + /* ************************ DEG TRAVERSAL ********************* */ -namespace DEG { +namespace blender { +namespace deg { namespace { typedef deque<OperationNode *> TraversalQueue; @@ -262,14 +265,15 @@ void deg_foreach_id(const Depsgraph *depsgraph, DEGForeachIDCallback callback, v } } // namespace -} // namespace DEG +} // namespace deg +} // namespace blender void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, const ID *id, DEGForeachIDCallback callback, void *user_data) { - DEG::deg_foreach_dependent_ID((const DEG::Depsgraph *)depsgraph, id, callback, user_data); + deg::deg_foreach_dependent_ID((const deg::Depsgraph *)depsgraph, id, callback, user_data); } void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph, @@ -279,8 +283,8 @@ void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph, DEGForeachIDComponentCallback callback, void *user_data) { - DEG::deg_foreach_dependent_ID_component( - (const DEG::Depsgraph *)depsgraph, id, source_component_type, flags, callback, user_data); + deg::deg_foreach_dependent_ID_component( + (const deg::Depsgraph *)depsgraph, id, source_component_type, flags, callback, user_data); } void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph, @@ -288,10 +292,10 @@ void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data) { - DEG::deg_foreach_ancestor_ID((const DEG::Depsgraph *)depsgraph, id, callback, user_data); + deg::deg_foreach_ancestor_ID((const deg::Depsgraph *)depsgraph, id, callback, user_data); } void DEG_foreach_ID(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data) { - DEG::deg_foreach_id((const DEG::Depsgraph *)depsgraph, callback, user_data); + deg::deg_foreach_id((const deg::Depsgraph *)depsgraph, callback, user_data); } diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 1eb07206465..c27a7cc3b93 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -59,6 +59,8 @@ # define INVALIDATE_WORK_DATA #endif +namespace deg = blender::deg; + /* ************************ DEG ITERATORS ********************* */ namespace { @@ -169,14 +171,14 @@ bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); invert_m4_m4(data->temp_dupli_object.imat, data->temp_dupli_object.obmat); iter->current = &data->temp_dupli_object; - BLI_assert(DEG::deg_validate_copy_on_write_datablock(&data->temp_dupli_object.id)); + BLI_assert(deg::deg_validate_copy_on_write_datablock(&data->temp_dupli_object.id)); return true; } return false; } -void deg_iterator_objects_step(BLI_Iterator *iter, DEG::IDNode *id_node) +void deg_iterator_objects_step(BLI_Iterator *iter, deg::IDNode *id_node) { /* Set it early in case we need to exit and we are running from within a loop. */ iter->skip = true; @@ -193,17 +195,17 @@ void deg_iterator_objects_step(BLI_Iterator *iter, DEG::IDNode *id_node) } switch (id_node->linked_state) { - case DEG::DEG_ID_LINKED_DIRECTLY: + case deg::DEG_ID_LINKED_DIRECTLY: if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY) == 0) { return; } break; - case DEG::DEG_ID_LINKED_VIA_SET: + case deg::DEG_ID_LINKED_VIA_SET: if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) == 0) { return; } break; - case DEG::DEG_ID_LINKED_INDIRECTLY: + case deg::DEG_ID_LINKED_INDIRECTLY: if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY) == 0) { return; } @@ -211,7 +213,7 @@ void deg_iterator_objects_step(BLI_Iterator *iter, DEG::IDNode *id_node) } Object *object = (Object *)id_node->id_cow; - BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id)); + BLI_assert(deg::deg_validate_copy_on_write_datablock(&object->id)); int ob_visibility = OB_VISIBLE_ALL; if (data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) { @@ -241,7 +243,7 @@ void deg_iterator_objects_step(BLI_Iterator *iter, DEG::IDNode *id_node) void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) { Depsgraph *depsgraph = data->graph; - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); const size_t num_id_nodes = deg_graph->id_nodes.size(); iter->data = data; @@ -261,7 +263,7 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) data->eval_mode = DEG_get_mode(depsgraph); deg_invalidate_iterator_work_data(data); - DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; + deg::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; deg_iterator_objects_step(iter, id_node); if (iter->skip) { @@ -273,7 +275,7 @@ void DEG_iterator_objects_next(BLI_Iterator *iter) { DEGObjectIterData *data = (DEGObjectIterData *)iter->data; Depsgraph *depsgraph = data->graph; - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); do { iter->skip = false; if (data->dupli_list) { @@ -297,7 +299,7 @@ void DEG_iterator_objects_next(BLI_Iterator *iter) return; } - DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; + deg::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; deg_iterator_objects_step(iter, id_node); } while (iter->skip); } @@ -314,7 +316,7 @@ void DEG_iterator_objects_end(BLI_Iterator *iter) /* ************************ DEG ID ITERATOR ********************* */ -static void DEG_iterator_ids_step(BLI_Iterator *iter, DEG::IDNode *id_node, bool only_updated) +static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool only_updated) { ID *id_cow = id_node->id_cow; @@ -339,7 +341,7 @@ static void DEG_iterator_ids_step(BLI_Iterator *iter, DEG::IDNode *id_node, bool void DEG_iterator_ids_begin(BLI_Iterator *iter, DEGIDIterData *data) { Depsgraph *depsgraph = data->graph; - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); const size_t num_id_nodes = deg_graph->id_nodes.size(); iter->data = data; @@ -352,7 +354,7 @@ void DEG_iterator_ids_begin(BLI_Iterator *iter, DEGIDIterData *data) data->id_node_index = 0; data->num_id_nodes = num_id_nodes; - DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; + deg::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; DEG_iterator_ids_step(iter, id_node, data->only_updated); if (iter->skip) { @@ -364,7 +366,7 @@ void DEG_iterator_ids_next(BLI_Iterator *iter) { DEGIDIterData *data = (DEGIDIterData *)iter->data; Depsgraph *depsgraph = data->graph; - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); do { iter->skip = false; @@ -375,7 +377,7 @@ void DEG_iterator_ids_next(BLI_Iterator *iter) return; } - DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; + deg::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; DEG_iterator_ids_step(iter, id_node, data->only_updated); } while (iter->skip); } diff --git a/source/blender/depsgraph/intern/depsgraph_registry.cc b/source/blender/depsgraph/intern/depsgraph_registry.cc index 7eac7b45069..6bfd2e881cc 100644 --- a/source/blender/depsgraph/intern/depsgraph_registry.cc +++ b/source/blender/depsgraph/intern/depsgraph_registry.cc @@ -27,7 +27,8 @@ #include "intern/depsgraph.h" -namespace DEG { +namespace blender { +namespace deg { static Map<Main *, VectorSet<Depsgraph *>> g_graph_registry; @@ -58,4 +59,5 @@ Span<Depsgraph *> get_all_registered_graphs(Main *bmain) return {}; } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph_registry.h b/source/blender/depsgraph/intern/depsgraph_registry.h index 967791d2fbf..dc29f9d8edf 100644 --- a/source/blender/depsgraph/intern/depsgraph_registry.h +++ b/source/blender/depsgraph/intern/depsgraph_registry.h @@ -27,7 +27,8 @@ struct Main; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -35,4 +36,5 @@ void register_graph(Depsgraph *depsgraph); void unregister_graph(Depsgraph *depsgraph); Span<Depsgraph *> get_all_registered_graphs(Main *bmain); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph_relation.cc b/source/blender/depsgraph/intern/depsgraph_relation.cc index a4ec48658f5..d09247b03d9 100644 --- a/source/blender/depsgraph/intern/depsgraph_relation.cc +++ b/source/blender/depsgraph/intern/depsgraph_relation.cc @@ -28,7 +28,8 @@ #include "intern/depsgraph_type.h" #include "intern/node/deg_node.h" -namespace DEG { +namespace blender { +namespace deg { Relation::Relation(Node *from, Node *to, const char *description) : from(from), to(to), name(description), flag(0) @@ -64,4 +65,5 @@ void Relation::unlink() to->inlinks.remove_first_occurrence_and_reorder(this); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph_relation.h b/source/blender/depsgraph/intern/depsgraph_relation.h index 2f9f0249b1f..a5d69c08d1f 100644 --- a/source/blender/depsgraph/intern/depsgraph_relation.h +++ b/source/blender/depsgraph/intern/depsgraph_relation.h @@ -23,7 +23,8 @@ #pragma once -namespace DEG { +namespace blender { +namespace deg { struct Node; @@ -60,4 +61,5 @@ struct Relation { int flag; /* Bitmask of RelationFlag) */ }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index b757a4fc477..f13153545fd 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -70,10 +70,13 @@ #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" +namespace deg = blender::deg; + /* *********************** */ /* Update Tagging/Flushing */ -namespace DEG { +namespace blender { +namespace deg { namespace { @@ -109,7 +112,7 @@ void depsgraph_select_tag_to_component_opcode(const ID *id, } else if (id_type == ID_OB) { *component_type = NodeType::OBJECT_FROM_LAYER; - *operation_code = OperationCode::OBJECT_BASE_FLAGS; + *operation_code = OperationCode::OBJECT_FROM_LAYER_ENTRY; } else if (id_type == ID_MC) { *component_type = NodeType::BATCH_CACHE; @@ -510,7 +513,7 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti /* NOTE: It is possible to have this function called with `do_time=false` first and later (prior * to evaluation though) with `do_time=true`. This means early output checks should be aware of * this. */ - for (DEG::IDNode *id_node : graph->id_nodes) { + for (deg::IDNode *id_node : graph->id_nodes) { const ID_Type id_type = GS(id_node->id_orig->name); if (id_type == ID_OB) { Object *object_orig = reinterpret_cast<Object *>(id_node->id_orig); @@ -525,7 +528,7 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti continue; } int flag = 0; - if (!DEG::deg_copy_on_write_is_expanded(id_node->id_cow)) { + if (!deg::deg_copy_on_write_is_expanded(id_node->id_cow)) { flag |= ID_RECALC_COPY_ON_WRITE; if (do_time) { if (BKE_animdata_from_id(id_node->id_orig) != nullptr) { @@ -619,7 +622,7 @@ NodeType geometry_tag_to_component(const ID *id) void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source) { graph_id_tag_update(bmain, nullptr, id, flag, update_source); - for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) { + for (deg::Depsgraph *depsgraph : deg::get_all_registered_graphs(bmain)) { graph_id_tag_update(bmain, depsgraph, id, flag, update_source); } @@ -684,7 +687,8 @@ void graph_id_tag_update( } } -} // namespace DEG +} // namespace deg +} // namespace blender const char *DEG_update_tag_as_string(IDRecalcFlag flag) { @@ -759,7 +763,7 @@ void DEG_id_tag_update_ex(Main *bmain, ID *id, int flag) /* Ideally should not happen, but old depsgraph allowed this. */ return; } - DEG::id_tag_update(bmain, id, flag, DEG::DEG_UPDATE_SOURCE_USER_EDIT); + deg::id_tag_update(bmain, id, flag, deg::DEG_UPDATE_SOURCE_USER_EDIT); } void DEG_graph_id_tag_update(struct Main *bmain, @@ -767,8 +771,8 @@ void DEG_graph_id_tag_update(struct Main *bmain, struct ID *id, int flag) { - DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph; - DEG::graph_id_tag_update(bmain, graph, id, flag, DEG::DEG_UPDATE_SOURCE_USER_EDIT); + deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph; + deg::graph_id_tag_update(bmain, graph, id, flag, deg::DEG_UPDATE_SOURCE_USER_EDIT); } /* Mark a particular datablock type as having changing. */ @@ -784,13 +788,13 @@ void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type) DEG_graph_id_type_tag(depsgraph, ID_SCE); } const int id_type_index = BKE_idtype_idcode_to_index(id_type); - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); deg_graph->id_type_updated[id_type_index] = 1; } void DEG_id_type_tag(Main *bmain, short id_type) { - for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) { + for (deg::Depsgraph *depsgraph : deg::get_all_registered_graphs(bmain)) { DEG_graph_id_type_tag(reinterpret_cast<::Depsgraph *>(depsgraph), id_type); } } @@ -798,13 +802,13 @@ void DEG_id_type_tag(Main *bmain, short id_type) /* Update dependency graph when visible scenes/layers changes. */ void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph, const bool do_time) { - DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph; - DEG::deg_graph_on_visible_update(bmain, graph, do_time); + deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph; + deg::deg_graph_on_visible_update(bmain, graph, do_time); } void DEG_on_visible_update(Main *bmain, const bool do_time) { - for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) { + for (deg::Depsgraph *depsgraph : deg::get_all_registered_graphs(bmain)) { DEG_graph_on_visible_update(bmain, reinterpret_cast<::Depsgraph *>(depsgraph), do_time); } } @@ -821,7 +825,7 @@ void DEG_ids_check_recalc( update_ctx.depsgraph = depsgraph; update_ctx.scene = scene; update_ctx.view_layer = view_layer; - DEG::deg_editors_scene_update(&update_ctx, updated); + deg::deg_editors_scene_update(&update_ctx, updated); } static void deg_graph_clear_id_recalc_flags(ID *id) @@ -837,14 +841,14 @@ static void deg_graph_clear_id_recalc_flags(ID *id) void DEG_ids_clear_recalc(Main *UNUSED(bmain), Depsgraph *depsgraph) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); /* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags * and id_tags storage from the new dependency graph. */ if (!DEG_id_type_any_updated(depsgraph)) { return; } /* Go over all ID nodes nodes, clearing tags. */ - for (DEG::IDNode *id_node : deg_graph->id_nodes) { + for (deg::IDNode *id_node : deg_graph->id_nodes) { /* TODO: we clear original ID recalc flags here, but this may not work * correctly when there are multiple depsgraph with others still using * the recalc flag. */ diff --git a/source/blender/depsgraph/intern/depsgraph_tag.h b/source/blender/depsgraph/intern/depsgraph_tag.h index e79372f2459..68b6a164be4 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.h +++ b/source/blender/depsgraph/intern/depsgraph_tag.h @@ -26,7 +26,8 @@ struct ID; struct Main; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -40,4 +41,5 @@ void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source); void graph_id_tag_update( Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph_type.cc b/source/blender/depsgraph/intern/depsgraph_type.cc index 92d775b0ae4..25e9a4643b3 100644 --- a/source/blender/depsgraph/intern/depsgraph_type.cc +++ b/source/blender/depsgraph/intern/depsgraph_type.cc @@ -37,13 +37,15 @@ #include "intern/node/deg_node_factory.h" #include "intern/node/deg_node_operation.h" +namespace deg = blender::deg; + /* Register all node types */ void DEG_register_node_types(void) { /* register node types */ - DEG::deg_register_base_depsnodes(); - DEG::deg_register_component_depsnodes(); - DEG::deg_register_operation_depsnodes(); + deg::deg_register_base_depsnodes(); + deg::deg_register_component_depsnodes(); + deg::deg_register_operation_depsnodes(); } /* Free registry on exit */ @@ -51,7 +53,7 @@ void DEG_free_node_types(void) { } -DEG::DEGCustomDataMeshMasks::DEGCustomDataMeshMasks(const CustomData_MeshMasks *other) +deg::DEGCustomDataMeshMasks::DEGCustomDataMeshMasks(const CustomData_MeshMasks *other) : vert_mask(other->vmask), edge_mask(other->emask), face_mask(other->fmask), diff --git a/source/blender/depsgraph/intern/depsgraph_type.h b/source/blender/depsgraph/intern/depsgraph_type.h index 3d386695e6c..50f697323c4 100644 --- a/source/blender/depsgraph/intern/depsgraph_type.h +++ b/source/blender/depsgraph/intern/depsgraph_type.h @@ -50,20 +50,13 @@ struct Depsgraph; struct CustomData_MeshMasks; -namespace DEG { +namespace blender { +namespace deg { /* Commonly used types. */ -using blender::Map; -using blender::Set; -using blender::Span; -using blender::StringRef; -using blender::StringRefNull; -using blender::Vector; -using blender::VectorSet; using std::deque; -using std::map; +using std::optional; using std::pair; -using std::set; using std::string; using std::unique_ptr; @@ -176,4 +169,5 @@ struct DEGCustomDataMeshMasks { } }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph_update.cc b/source/blender/depsgraph/intern/depsgraph_update.cc index d10bfaaace8..98ff136f7bc 100644 --- a/source/blender/depsgraph/intern/depsgraph_update.cc +++ b/source/blender/depsgraph/intern/depsgraph_update.cc @@ -27,7 +27,10 @@ #include "intern/depsgraph_type.h" -namespace DEG { +namespace deg = blender::deg; + +namespace blender { +namespace deg { static DEG_EditorUpdateIDCb deg_editor_update_id_cb = nullptr; static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = nullptr; @@ -46,11 +49,12 @@ void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool upd } } -} // namespace DEG +} // namespace deg +} // namespace blender /* Set callbacks which are being called when depsgraph changes. */ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func) { - DEG::deg_editor_update_id_cb = id_func; - DEG::deg_editor_update_scene_cb = scene_func; + deg::deg_editor_update_id_cb = id_func; + deg::deg_editor_update_scene_cb = scene_func; } diff --git a/source/blender/depsgraph/intern/depsgraph_update.h b/source/blender/depsgraph/intern/depsgraph_update.h index 1723658ced3..6f40a4366a5 100644 --- a/source/blender/depsgraph/intern/depsgraph_update.h +++ b/source/blender/depsgraph/intern/depsgraph_update.h @@ -26,10 +26,12 @@ struct DEGEditorUpdateContext; struct ID; -namespace DEG { +namespace blender { +namespace deg { void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, struct ID *id); void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool updated); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 189beb506b3..6ca30a67f1f 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -54,7 +54,8 @@ #include "intern/node/deg_node_operation.h" #include "intern/node/deg_node_time.h" -namespace DEG { +namespace blender { +namespace deg { namespace { @@ -416,4 +417,5 @@ void deg_evaluate_on_refresh(Depsgraph *graph) graph->debug.end_graph_evaluation(); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h index 5baf13653ca..49690f15412 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.h +++ b/source/blender/depsgraph/intern/eval/deg_eval.h @@ -25,7 +25,8 @@ #pragma once -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -38,4 +39,5 @@ struct Depsgraph; */ void deg_evaluate_on_refresh(Depsgraph *graph); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 70a6875f1c0..2290c37fc2a 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -100,7 +100,8 @@ #include "intern/node/deg_node.h" #include "intern/node/deg_node_id.h" -namespace DEG { +namespace blender { +namespace deg { #define DEBUG_PRINT \ if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) \ @@ -945,7 +946,7 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, DepsgraphNodeBuilder *node_builder, bool create_placeholders) { - DEG::IDNode *id_node = depsgraph->find_id_node(id_orig); + IDNode *id_node = depsgraph->find_id_node(id_orig); BLI_assert(id_node != nullptr); return deg_expand_copy_on_write_datablock(depsgraph, id_node, node_builder, create_placeholders); } @@ -969,7 +970,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode /* NOTE: Depsgraph is supposed to have ID node already. */ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, ID *id_orig) { - DEG::IDNode *id_node = depsgraph->find_id_node(id_orig); + IDNode *id_node = depsgraph->find_id_node(id_orig); BLI_assert(id_node != nullptr); return deg_update_copy_on_write_datablock(depsgraph, id_node); } @@ -1089,7 +1090,7 @@ void deg_free_copy_on_write_datablock(ID *id_cow) void deg_evaluate_copy_on_write(struct ::Depsgraph *graph, const IDNode *id_node) { - const DEG::Depsgraph *depsgraph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const Depsgraph *depsgraph = reinterpret_cast<const Depsgraph *>(graph); DEG_debug_print_eval(graph, __func__, id_node->id_orig->name, id_node->id_cow); if (id_node->id_orig == &depsgraph->scene->id) { /* NOTE: This is handled by eval_ctx setup routines, which @@ -1137,4 +1138,5 @@ bool deg_copy_on_write_is_needed(const ID_Type id_type) return ID_TYPE_IS_COW(id_type); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h index 05464d11f13..255ea840088 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h @@ -43,7 +43,8 @@ struct ID; struct Depsgraph; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; class DepsgraphNodeBuilder; @@ -98,4 +99,5 @@ bool deg_copy_on_write_is_expanded(const struct ID *id_cow); bool deg_copy_on_write_is_needed(const ID *id_orig); bool deg_copy_on_write_is_needed(const ID_Type id_type); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index df6c139e916..a0a9ff7eca3 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -32,9 +32,11 @@ #include "BLI_task.h" #include "BLI_utildefines.h" +#include "BKE_key.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "DNA_key_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -67,7 +69,8 @@ // catch usage of invalid state. #undef INVALIDATE_ON_FLUSH -namespace DEG { +namespace blender { +namespace deg { enum { ID_STATE_NONE = 0, @@ -227,7 +230,7 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd ID *id_orig = id_node->id_orig; ID *id_cow = id_node->id_cow; /* Gather recalc flags from all changed components. */ - for (DEG::ComponentNode *comp_node : id_node->components.values()) { + for (ComponentNode *comp_node : id_node->components.values()) { if (comp_node->custom_flags != COMPONENT_STATE_DONE) { continue; } @@ -250,9 +253,30 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd if (deg_copy_on_write_is_expanded(id_cow)) { if (graph->is_active && id_node->is_user_modified) { deg_editors_id_update(update_ctx, id_orig); - } - if (ID_IS_OVERRIDE_LIBRARY(id_orig)) { - id_orig->tag |= LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH; + + /* We only want to tag an ID for lib-override auto-refresh if it was actually tagged as + * changed. CoW IDs indirectly modified because of changes in other IDs should never + * require a lib-override diffing. */ + if (ID_IS_OVERRIDE_LIBRARY_REAL(id_orig)) { + id_orig->tag |= LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH; + } + else if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id_orig)) { + switch (GS(id_orig->name)) { + case ID_KE: + ((Key *)id_orig)->from->tag |= LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH; + break; + case ID_GR: + BLI_assert(id_orig->flag & LIB_EMBEDDED_DATA); + /* TODO. */ + break; + case ID_NT: + BLI_assert(id_orig->flag & LIB_EMBEDDED_DATA); + /* TODO. */ + break; + default: + BLI_assert(0); + } + } } /* Inform draw engines that something was changed. */ flush_engine_data_update(id_cow); @@ -336,9 +360,9 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) if (graph->need_update_time) { const Scene *scene_orig = graph->scene; const float ctime = BKE_scene_frame_get(scene_orig); - DEG::TimeSourceNode *time_source = graph->find_time_source(); + TimeSourceNode *time_source = graph->find_time_source(); graph->ctime = ctime; - time_source->tag_update(graph, DEG::DEG_UPDATE_SOURCE_TIME); + time_source->tag_update(graph, DEG_UPDATE_SOURCE_TIME); } if (graph->entry_tags.is_empty()) { return; @@ -389,4 +413,5 @@ void deg_graph_clear_tags(Depsgraph *graph) graph->entry_tags.clear(); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h index a4550dd4851..c76dc9fe01d 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h @@ -27,7 +27,8 @@ struct Main; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -39,4 +40,5 @@ void deg_graph_flush_updates(struct Main *bmain, struct Depsgraph *graph); /* Clear tags from all operation nodes. */ void deg_graph_clear_tags(struct Depsgraph *graph); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc index c3733cb235c..f3d9422a88b 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc @@ -29,7 +29,8 @@ #include "DRW_engine.h" -namespace DEG { +namespace blender { +namespace deg { RuntimeBackup::RuntimeBackup(const Depsgraph *depsgraph) : have_backup(false), @@ -116,4 +117,5 @@ void RuntimeBackup::restore_to_id(ID *id) } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h index dde7d0b2782..c6249c83daa 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h @@ -32,7 +32,8 @@ #include "intern/eval/deg_eval_runtime_backup_sound.h" #include "intern/eval/deg_eval_runtime_backup_volume.h" -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -67,4 +68,5 @@ class RuntimeBackup { VolumeBackup volume_backup; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc index 29f70e8548e..6c4eb8a91ee 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc @@ -32,7 +32,8 @@ #include "intern/depsgraph.h" -namespace DEG { +namespace blender { +namespace deg { namespace { @@ -141,4 +142,5 @@ void AnimationBackup::restore_to_id(ID *id) } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h index d021354e6f2..6b5d5eab75f 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h @@ -27,7 +27,8 @@ #include "intern/depsgraph_type.h" -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -62,4 +63,5 @@ class AnimationBackup { Vector<AnimationValueBackup> values_backup; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc index 3361c26a077..f2d9a87ca9d 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc @@ -23,7 +23,8 @@ #include "intern/eval/deg_eval_runtime_backup_modifier.h" -namespace DEG { +namespace blender { +namespace deg { ModifierDataBackupID::ModifierDataBackupID(const Depsgraph * /*depsgraph*/) : ModifierDataBackupID(nullptr, eModifierType_None) @@ -35,15 +36,16 @@ ModifierDataBackupID::ModifierDataBackupID(ModifierData *modifier_data, Modifier { } -bool ModifierDataBackupID::operator<(const ModifierDataBackupID &other) const +bool operator==(const ModifierDataBackupID &a, const ModifierDataBackupID &b) { - if (modifier_data < other.modifier_data) { - return true; - } - if (modifier_data == other.modifier_data) { - return static_cast<int>(type) < static_cast<int>(other.type); - } - return false; + return a.modifier_data == b.modifier_data && a.type == b.type; } -} // namespace DEG +uint32_t ModifierDataBackupID::hash() const +{ + uintptr_t ptr = (uintptr_t)modifier_data; + return (ptr >> 4) ^ (uintptr_t)type; +} + +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h index 4b3d46126f3..dc16bdcc1b8 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h @@ -29,7 +29,8 @@ struct ModifierData; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -46,13 +47,16 @@ class ModifierDataBackupID { ModifierDataBackupID(const Depsgraph *depsgraph); ModifierDataBackupID(ModifierData *modifier_data, ModifierType type); - bool operator<(const ModifierDataBackupID &other) const; + friend bool operator==(const ModifierDataBackupID &a, const ModifierDataBackupID &b); + + uint32_t hash() const; ModifierData *modifier_data; ModifierType type; }; /* Storage for backed up runtime modifier data. */ -typedef map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup; +typedef Map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc index d552c8da99a..9d3740258cc 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc @@ -27,7 +27,8 @@ #include "BLI_utildefines.h" -namespace DEG { +namespace blender { +namespace deg { MovieClipBackup::MovieClipBackup(const Depsgraph * /*depsgraph*/) { @@ -58,4 +59,5 @@ void MovieClipBackup::restore_to_movieclip(MovieClip *movieclip) reset(); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h index 427e9c7b483..0b1de633696 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h @@ -27,7 +27,8 @@ struct MovieClip; struct MovieClipCache; struct anim; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -45,4 +46,5 @@ class MovieClipBackup { struct MovieClipCache *cache; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc index 2b172f824b6..e0957a10cb1 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc @@ -32,7 +32,8 @@ #include "BKE_action.h" #include "BKE_object.h" -namespace DEG { +namespace blender { +namespace deg { ObjectRuntimeBackup::ObjectRuntimeBackup(const Depsgraph * /*depsgraph*/) : base_flag(0), base_local_view_bits(0) @@ -75,7 +76,7 @@ void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object) } BLI_assert(modifier_data->orig_modifier_data != nullptr); ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data); - modifier_runtime_data.insert(make_pair(modifier_data_id, modifier_data->runtime)); + modifier_runtime_data.add(modifier_data_id, modifier_data->runtime); modifier_data->runtime = nullptr; } } @@ -86,7 +87,7 @@ void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object) LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { /* This is nullptr in Edit mode. */ if (pchan->orig_pchan != nullptr) { - pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime; + pose_channel_runtime_data.add(pchan->orig_pchan, pchan->runtime); BKE_pose_channel_runtime_reset(&pchan->runtime); } } @@ -153,22 +154,16 @@ void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object) LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) { BLI_assert(modifier_data->orig_modifier_data != nullptr); ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data); - ModifierRuntimeDataBackup::iterator runtime_data_iterator = modifier_runtime_data.find( - modifier_data_id); - if (runtime_data_iterator != modifier_runtime_data.end()) { - modifier_data->runtime = runtime_data_iterator->second; - runtime_data_iterator->second = nullptr; + void *runtime = modifier_runtime_data.pop_default(modifier_data_id, nullptr); + if (runtime != nullptr) { + modifier_data->runtime = runtime; } } - for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) { - const ModifierDataBackupID modifier_data_id = value.first; - void *runtime = value.second; - if (value.second == nullptr) { - continue; - } - const ModifierTypeInfo *modifier_type_info = BKE_modifier_get_info(modifier_data_id.type); + + for (ModifierRuntimeDataBackup::Item item : modifier_runtime_data.items()) { + const ModifierTypeInfo *modifier_type_info = BKE_modifier_get_info(item.key.type); BLI_assert(modifier_type_info != nullptr); - modifier_type_info->freeRuntimeData(runtime); + modifier_type_info->freeRuntimeData(item.value); } } @@ -178,18 +173,18 @@ void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object) LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { /* This is nullptr in Edit mode. */ if (pchan->orig_pchan != nullptr) { - PoseChannelRuntimeDataBackup::iterator runtime_data_iterator = - pose_channel_runtime_data.find(pchan->orig_pchan); - if (runtime_data_iterator != pose_channel_runtime_data.end()) { - pchan->runtime = runtime_data_iterator->second; - pose_channel_runtime_data.erase(runtime_data_iterator); + optional<bPoseChannel_Runtime> runtime = pose_channel_runtime_data.pop_try( + pchan->orig_pchan); + if (runtime.has_value()) { + pchan->runtime = *runtime; } } } } - for (PoseChannelRuntimeDataBackup::value_type &value : pose_channel_runtime_data) { - BKE_pose_channel_runtime_free(&value.second); + for (bPoseChannel_Runtime &runtime : pose_channel_runtime_data.values()) { + BKE_pose_channel_runtime_free(&runtime); } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h index e5c3d6a967a..04d7fb1bc22 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h @@ -30,7 +30,8 @@ struct Object; -namespace DEG { +namespace blender { +namespace deg { class ObjectRuntimeBackup { public: @@ -53,7 +54,8 @@ class ObjectRuntimeBackup { short base_flag; unsigned short base_local_view_bits; ModifierRuntimeDataBackup modifier_runtime_data; - PoseChannelRuntimeDataBackup pose_channel_runtime_data; + Map<bPoseChannel *, bPoseChannel_Runtime> pose_channel_runtime_data; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc index 821cc21f359..45663378f67 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc @@ -23,6 +23,8 @@ #include "intern/eval/deg_eval_runtime_backup_pose.h" -namespace DEG { +namespace blender { +namespace deg { -} // namespace DEG +} +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h index 53a2c4c0784..a6ce97529b7 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h @@ -27,11 +27,8 @@ #include "DNA_action_types.h" -struct bPoseChannel; +namespace blender { +namespace deg { -namespace DEG { - -/* Storage for backed up pose channel runtime data. */ -typedef map<bPoseChannel *, bPoseChannel_Runtime> PoseChannelRuntimeDataBackup; - -} // namespace DEG +} +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc index 32b2d0b93c1..f000c8b5d4d 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc @@ -28,7 +28,8 @@ #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" -namespace DEG { +namespace blender { +namespace deg { SceneBackup::SceneBackup(const Depsgraph *depsgraph) : sequencer_backup(depsgraph) { @@ -85,4 +86,5 @@ void SceneBackup::restore_to_scene(Scene *scene) reset(); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h index 751bc4208d2..007236e7890 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h @@ -27,7 +27,8 @@ struct Scene; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -55,4 +56,5 @@ class SceneBackup { SequencerBackup sequencer_backup; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc index f26d78d3138..3866a89cc17 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc @@ -25,7 +25,8 @@ #include "DNA_sequence_types.h" -namespace DEG { +namespace blender { +namespace deg { SequenceBackup::SequenceBackup(const Depsgraph * /*depsgraph*/) { @@ -55,4 +56,5 @@ bool SequenceBackup::isEmpty() const return (scene_sound == nullptr); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h index 8a762a2785e..eb38dc3dc5b 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h @@ -25,7 +25,8 @@ struct Sequence; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -44,4 +45,5 @@ class SequenceBackup { void *scene_sound; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc index adc7fd570e8..2780938fe05 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc @@ -29,7 +29,8 @@ #include "BKE_sequencer.h" #include "BKE_sound.h" -namespace DEG { +namespace blender { +namespace deg { SequencerBackup::SequencerBackup(const Depsgraph *depsgraph) : depsgraph(depsgraph) { @@ -42,7 +43,7 @@ void SequencerBackup::init_from_scene(Scene *scene) SequenceBackup sequence_backup(depsgraph); sequence_backup.init_from_sequence(sequence); if (!sequence_backup.isEmpty()) { - sequences_backup.insert(make_pair(sequence->orig_sequence, sequence_backup)); + sequences_backup.add(sequence->orig_sequence, sequence_backup); } } SEQ_END; @@ -52,21 +53,19 @@ void SequencerBackup::restore_to_scene(Scene *scene) { Sequence *sequence; SEQ_BEGIN (scene->ed, sequence) { - SequencesBackupMap::iterator it = sequences_backup.find(sequence->orig_sequence); - if (it == sequences_backup.end()) { - continue; + SequenceBackup *sequence_backup = sequences_backup.lookup_ptr(sequence->orig_sequence); + if (sequence_backup != nullptr) { + sequence_backup->restore_to_sequence(sequence); } - SequenceBackup &sequence_backup = it->second; - sequence_backup.restore_to_sequence(sequence); } SEQ_END; /* Cleanup audio while the scene is still known. */ - for (SequencesBackupMap::value_type &it : sequences_backup) { - SequenceBackup &sequence_backup = it.second; + for (SequenceBackup &sequence_backup : sequences_backup.values()) { if (sequence_backup.scene_sound != nullptr) { BKE_sound_remove_scene_sound(scene, sequence_backup.scene_sound); } } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h index 05f37b45dc4..9fe38ec270c 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h @@ -28,7 +28,8 @@ struct Scene; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -42,8 +43,8 @@ class SequencerBackup { const Depsgraph *depsgraph; - typedef map<Sequence *, SequenceBackup> SequencesBackupMap; - SequencesBackupMap sequences_backup; + Map<Sequence *, SequenceBackup> sequences_backup; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc index f427d57a8ef..4b63ada8bde 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc @@ -27,7 +27,8 @@ #include "DNA_sound_types.h" -namespace DEG { +namespace blender { +namespace deg { SoundBackup::SoundBackup(const Depsgraph * /*depsgraph*/) { @@ -61,4 +62,5 @@ void SoundBackup::restore_to_sound(bSound *sound) reset(); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h index 87783146701..754deb57556 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h @@ -25,7 +25,8 @@ struct bSound; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -44,4 +45,5 @@ class SoundBackup { void *playback_handle; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.cc index 09e13ec131d..8808673ce6a 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.cc @@ -33,7 +33,8 @@ #include <stdio.h> -namespace DEG { +namespace blender { +namespace deg { VolumeBackup::VolumeBackup(const Depsgraph * /*depsgraph*/) : grids(nullptr) { @@ -57,4 +58,5 @@ void VolumeBackup::restore_to_volume(Volume *volume) } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h index cf57c702c8f..c0ef5204653 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h @@ -26,7 +26,8 @@ struct Volume; struct VolumeGridVector; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; @@ -42,4 +43,5 @@ class VolumeBackup { char filepath[1024]; /* FILE_MAX */ }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc index 9d3b1356570..3c84c781cbb 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc @@ -32,7 +32,8 @@ #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" -namespace DEG { +namespace blender { +namespace deg { void deg_eval_stats_aggregate(Depsgraph *graph) { @@ -54,4 +55,5 @@ void deg_eval_stats_aggregate(Depsgraph *graph) } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.h b/source/blender/depsgraph/intern/eval/deg_eval_stats.h index 988b42e15ae..8f0d3b1b938 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_stats.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.h @@ -23,11 +23,13 @@ #pragma once -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; /* Aggregate operation timings to overall component and ID nodes timing. */ void deg_eval_stats_aggregate(Depsgraph *graph); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc index 10760d3170b..54a22a07ee4 100644 --- a/source/blender/depsgraph/intern/node/deg_node.cc +++ b/source/blender/depsgraph/intern/node/deg_node.cc @@ -36,7 +36,8 @@ #include "intern/node/deg_node_operation.h" #include "intern/node/deg_node_time.h" -namespace DEG { +namespace blender { +namespace deg { const char *nodeClassAsString(NodeClass node_class) { @@ -340,4 +341,5 @@ void deg_register_base_depsnodes() register_node_typeinfo(&DNTI_ID_REF); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h index f0ce38ddeae..94953c4ec5d 100644 --- a/source/blender/depsgraph/intern/node/deg_node.h +++ b/source/blender/depsgraph/intern/node/deg_node.h @@ -32,7 +32,8 @@ struct ID; struct Scene; -namespace DEG { +namespace blender { +namespace deg { struct Depsgraph; struct OperationNode; @@ -212,4 +213,5 @@ struct Node { void deg_register_base_depsnodes(); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index 87d704bb0a0..c99b3aba312 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -38,7 +38,8 @@ #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" -namespace DEG { +namespace blender { +namespace deg { /* *********** */ /* Outer Nodes */ @@ -377,4 +378,5 @@ void deg_register_component_depsnodes() register_node_typeinfo(&DNTI_SIMULATION); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h index 036baa9d46c..3757a1dea5b 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.h +++ b/source/blender/depsgraph/intern/node/deg_node_component.h @@ -32,7 +32,8 @@ struct ID; struct bPoseChannel; -namespace DEG { +namespace blender { +namespace deg { struct BoneComponentNode; struct Depsgraph; @@ -83,12 +84,9 @@ struct ComponentNode : public Node { * when node may have been partially created earlier (e.g. parent ref before * parent item is added) * - * \param type: Operation node type (corresponding to context/component that - * it operates in) - * \param optype: Role that operation plays within component - * (i.e. where in eval process) - * \param op: The operation to perform - * \param name: Identifier for operation - used to find/locate it again */ + * \param opcode: The operation to perform. + * \param name: Identifier for operation - used to find/locate it again. + */ OperationNode *add_operation(const DepsEvalOperationCb &op, OperationCode opcode, const char *name, @@ -203,4 +201,5 @@ struct BoneComponentNode : public ComponentNode { void deg_register_component_depsnodes(); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node_factory.cc b/source/blender/depsgraph/intern/node/deg_node_factory.cc index 9dfd018b4fd..9bb093139a1 100644 --- a/source/blender/depsgraph/intern/node/deg_node_factory.cc +++ b/source/blender/depsgraph/intern/node/deg_node_factory.cc @@ -23,7 +23,8 @@ #include "intern/node/deg_node_factory.h" -namespace DEG { +namespace blender { +namespace deg { /* Global type registry */ static DepsNodeFactory *node_typeinfo_registry[static_cast<int>(NodeType::NUM_TYPES)] = {nullptr}; @@ -42,4 +43,5 @@ DepsNodeFactory *type_get_factory(const NodeType type) return node_typeinfo_registry[type_as_int]; } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node_factory.h b/source/blender/depsgraph/intern/node/deg_node_factory.h index db2c3bb2f44..125f340a0fa 100644 --- a/source/blender/depsgraph/intern/node/deg_node_factory.h +++ b/source/blender/depsgraph/intern/node/deg_node_factory.h @@ -30,7 +30,8 @@ struct ID; -namespace DEG { +namespace blender { +namespace deg { struct DepsNodeFactory { virtual NodeType type() const = 0; @@ -56,6 +57,7 @@ void register_node_typeinfo(DepsNodeFactory *factory); /* Get typeinfo for specified type */ DepsNodeFactory *type_get_factory(const NodeType type); -} // namespace DEG +} // namespace deg +} // namespace blender #include "intern/node/deg_node_factory_impl.h" diff --git a/source/blender/depsgraph/intern/node/deg_node_factory_impl.h b/source/blender/depsgraph/intern/node/deg_node_factory_impl.h index ad25ffdf26c..f5dd7122fca 100644 --- a/source/blender/depsgraph/intern/node/deg_node_factory_impl.h +++ b/source/blender/depsgraph/intern/node/deg_node_factory_impl.h @@ -27,7 +27,8 @@ struct ID; -namespace DEG { +namespace blender { +namespace deg { template<class ModeObjectType> NodeType DepsNodeFactoryImpl<ModeObjectType>::type() const { @@ -63,4 +64,5 @@ Node *DepsNodeFactoryImpl<ModeObjectType>::create_node(const ID *id, return node; } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index 984873fbcac..843f59b446a 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -41,7 +41,8 @@ #include "intern/node/deg_node_factory.h" #include "intern/node/deg_node_time.h" -namespace DEG { +namespace blender { +namespace deg { const char *linkedStateAsString(eDepsNode_LinkedState_Type linked_state) { @@ -212,4 +213,5 @@ IDComponentsMask IDNode::get_visible_components_mask() const return result; } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h index 1e315195c1a..9bd6130bbdc 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.h +++ b/source/blender/depsgraph/intern/node/deg_node_id.h @@ -28,7 +28,8 @@ #include "DNA_ID.h" #include "intern/node/deg_node.h" -namespace DEG { +namespace blender { +namespace deg { struct ComponentNode; @@ -115,4 +116,5 @@ struct IDNode : public Node { DEG_DEPSNODE_DECLARE; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index 91bd0117f6c..680e7757ebb 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -32,7 +32,8 @@ #include "intern/node/deg_node_factory.h" #include "intern/node/deg_node_id.h" -namespace DEG { +namespace blender { +namespace deg { const char *operationCodeAsString(OperationCode opcode) { @@ -63,8 +64,12 @@ const char *operationCodeAsString(OperationCode opcode) case OperationCode::AUDIO_VOLUME: return "AUDIO_VOLUME"; /* Object related. */ + case OperationCode::OBJECT_FROM_LAYER_ENTRY: + return "OBJECT_FROM_LAYER_ENTRY"; case OperationCode::OBJECT_BASE_FLAGS: return "OBJECT_BASE_FLAGS"; + case OperationCode::OBJECT_FROM_LAYER_EXIT: + return "OBJECT_FROM_LAYER_EXIT"; case OperationCode::DIMENSIONS: return "DIMENSIONS"; /* Transform. */ @@ -266,4 +271,5 @@ void deg_register_operation_depsnodes() register_node_typeinfo(&DNTI_OPERATION); } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h index 6b14e6af02f..87168fc3659 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.h +++ b/source/blender/depsgraph/intern/node/deg_node_operation.h @@ -29,7 +29,8 @@ struct Depsgraph; -namespace DEG { +namespace blender { +namespace deg { struct ComponentNode; @@ -63,7 +64,9 @@ enum class OperationCode { AUDIO_VOLUME, /* Object related. ------------------------------------------------------ */ + OBJECT_FROM_LAYER_ENTRY, OBJECT_BASE_FLAGS, + OBJECT_FROM_LAYER_EXIT, DIMENSIONS, /* Transform. ----------------------------------------------------------- */ @@ -274,4 +277,5 @@ struct OperationNode : public Node { void deg_register_operation_depsnodes(); -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node_time.cc b/source/blender/depsgraph/intern/node/deg_node_time.cc index ff3e950bb44..af931fbae34 100644 --- a/source/blender/depsgraph/intern/node/deg_node_time.cc +++ b/source/blender/depsgraph/intern/node/deg_node_time.cc @@ -28,7 +28,8 @@ #include "intern/depsgraph.h" #include "intern/depsgraph_relation.h" -namespace DEG { +namespace blender { +namespace deg { void TimeSourceNode::tag_update(Depsgraph *graph, eUpdateSource /*source*/) { @@ -38,4 +39,5 @@ void TimeSourceNode::tag_update(Depsgraph *graph, eUpdateSource /*source*/) } } -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/node/deg_node_time.h b/source/blender/depsgraph/intern/node/deg_node_time.h index 684414f7780..364c214b014 100644 --- a/source/blender/depsgraph/intern/node/deg_node_time.h +++ b/source/blender/depsgraph/intern/node/deg_node_time.h @@ -25,7 +25,8 @@ #include "intern/node/deg_node.h" -namespace DEG { +namespace blender { +namespace deg { /* Time Source Node. */ struct TimeSourceNode : public Node { @@ -42,4 +43,5 @@ struct TimeSourceNode : public Node { DEG_DEPSNODE_DECLARE; }; -} // namespace DEG +} // namespace deg +} // namespace blender diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index a26c150cb51..1ddae11999b 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -214,6 +214,7 @@ data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_downsample_cube_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_gtao_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_velocity_resolve_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/effect_velocity_tile_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_mist_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC) @@ -224,6 +225,8 @@ data_to_c_simple(engines/eevee/shaders/effect_temporal_aa.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl SRC) +data_to_c_simple(engines/eevee/shaders/object_motion_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/object_motion_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/shadow_accum_frag.glsl SRC) @@ -310,6 +313,7 @@ data_to_c_simple(engines/basic/shaders/depth_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/antialiasing_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/antialiasing_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/armature_dof_vert.glsl SRC) +data_to_c_simple(engines/overlay/shaders/armature_dof_solid_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/armature_envelope_outline_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_vert.glsl SRC) diff --git a/source/blender/draw/DRW_select_buffer.h b/source/blender/draw/DRW_select_buffer.h index 6ebc30d0382..66dee3a9aa9 100644 --- a/source/blender/draw/DRW_select_buffer.h +++ b/source/blender/draw/DRW_select_buffer.h @@ -56,16 +56,16 @@ struct ObjectOffsets { uint vert; }; -struct SELECTID_Context { +typedef struct SELECTID_Context { /* All context objects */ struct Object **objects; - uint objects_len; /* Array with only drawn objects. When a new object is found within the rect, * it is added to the end of the list. * The list is reset to any viewport or context update. */ - struct ObjectOffsets *index_offsets; struct Object **objects_drawn; + struct ObjectOffsets *index_offsets; + uint objects_len; uint objects_drawn_len; /** Total number of element indices `index_offsets[object_drawn_len - 1].vert`. */ @@ -73,13 +73,13 @@ struct SELECTID_Context { short select_mode; + /* rect is used to check which objects whose indexes need to be drawn. */ + rcti last_rect; + /* To check for updates. */ float persmat[4][4]; bool is_dirty; - - /* rect is used to check which objects whose indexes need to be drawn. */ - rcti last_rect; -}; +} SELECTID_Context; /* draw_select_buffer.c */ bool DRW_select_buffer_elem_get(const uint sel_id, diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index bbc3c407f14..0dd3cc14234 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -131,7 +131,7 @@ static void basic_cache_init(void *vedata) stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); } - /* Twice for normal and infront objects. */ + /* Twice for normal and in front objects. */ for (int i = 0; i < 2; i++) { DRWState clip_state = (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? DRW_STATE_CLIP_PLANES : 0; DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0; diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index a19af77124f..a4aa0e10198 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -24,11 +24,153 @@ #include "DRW_render.h" +#include "BLI_ghash.h" #include "BLI_memblock.h" +#include "BKE_duplilist.h" + +#include "DEG_depsgraph_query.h" + +#include "GPU_vertex_buffer.h" + #include "eevee_lightcache.h" #include "eevee_private.h" +/* Motion Blur data. */ + +static void eevee_motion_blur_mesh_data_free(void *val) +{ + EEVEE_GeometryMotionData *geom_mb = (EEVEE_GeometryMotionData *)val; + switch (geom_mb->type) { + case EEVEE_HAIR_GEOM_MOTION_DATA: + for (int i = 0; i < ARRAY_SIZE(geom_mb->vbo); i++) { + GPU_VERTBUF_DISCARD_SAFE(geom_mb->hair_pos[i]); + DRW_TEXTURE_FREE_SAFE(geom_mb->hair_pos_tx[i]); + } + break; + + case EEVEE_MESH_GEOM_MOTION_DATA: + for (int i = 0; i < ARRAY_SIZE(geom_mb->vbo); i++) { + GPU_VERTBUF_DISCARD_SAFE(geom_mb->vbo[i]); + } + break; + } + MEM_freeN(val); +} + +static uint eevee_object_key_hash(const void *key) +{ + EEVEE_ObjectKey *ob_key = (EEVEE_ObjectKey *)key; + uint hash = BLI_ghashutil_ptrhash(ob_key->ob); + hash = BLI_ghashutil_combine_hash(hash, BLI_ghashutil_ptrhash(ob_key->parent)); + for (int i = 0; i < 16; i++) { + if (ob_key->id[i] != 0) { + hash = BLI_ghashutil_combine_hash(hash, BLI_ghashutil_inthash(ob_key->id[i])); + } + else { + break; + } + } + return hash; +} + +/* Return false if equal. */ +static bool eevee_object_key_cmp(const void *a, const void *b) +{ + EEVEE_ObjectKey *key_a = (EEVEE_ObjectKey *)a; + EEVEE_ObjectKey *key_b = (EEVEE_ObjectKey *)b; + + if (key_a->ob != key_b->ob) { + return true; + } + if (key_a->parent != key_b->parent) { + return true; + } + if (memcmp(key_a->id, key_b->id, sizeof(key_a->id)) != 0) { + return true; + } + return false; +} + +void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb) +{ + if (mb->object == NULL) { + mb->object = BLI_ghash_new(eevee_object_key_hash, eevee_object_key_cmp, "EEVEE Object Motion"); + } + if (mb->geom == NULL) { + mb->geom = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EEVEE Mesh Motion"); + } +} + +void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb) +{ + if (mb->object) { + BLI_ghash_free(mb->object, MEM_freeN, MEM_freeN); + mb->object = NULL; + } + if (mb->geom) { + BLI_ghash_free(mb->geom, NULL, eevee_motion_blur_mesh_data_free); + mb->geom = NULL; + } +} + +EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair) +{ + if (mb->object == NULL) { + return NULL; + } + + EEVEE_ObjectKey key, *key_p; + /* Small hack to avoid another comparisson. */ + key.ob = (Object *)((char *)ob + hair); + DupliObject *dup = DRW_object_get_dupli(ob); + if (dup) { + key.parent = DRW_object_get_dupli_parent(ob); + memcpy(key.id, dup->persistent_id, sizeof(key.id)); + } + else { + key.parent = key.ob; + memset(key.id, 0, sizeof(key.id)); + } + + EEVEE_ObjectMotionData *ob_step = BLI_ghash_lookup(mb->object, &key); + if (ob_step == NULL) { + key_p = MEM_mallocN(sizeof(*key_p), __func__); + memcpy(key_p, &key, sizeof(*key_p)); + + ob_step = MEM_callocN(sizeof(EEVEE_ObjectMotionData), __func__); + + BLI_ghash_insert(mb->object, key_p, ob_step); + } + return ob_step; +} + +EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair) +{ + if (mb->geom == NULL) { + return NULL; + } + + /* Use original data as key to ensure matching accross update. */ + Object *ob_orig = DEG_get_original_object(ob); + + void *key = (char *)ob_orig->data + hair; + EEVEE_GeometryMotionData *geom_step = BLI_ghash_lookup(mb->geom, key); + if (geom_step == NULL) { + geom_step = MEM_callocN(sizeof(EEVEE_GeometryMotionData), __func__); + geom_step->type = (hair) ? EEVEE_HAIR_GEOM_MOTION_DATA : EEVEE_MESH_GEOM_MOTION_DATA; + BLI_ghash_insert(mb->geom, key, geom_step); + } + + return geom_step; +} + +/* View Layer data. */ + void EEVEE_view_layer_data_free(void *storage) { EEVEE_ViewLayerData *sldata = (EEVEE_ViewLayerData *)storage; @@ -105,6 +247,8 @@ static void eevee_object_data_init(DrawData *dd) { EEVEE_ObjectEngineData *eevee_data = (EEVEE_ObjectEngineData *)dd; eevee_data->shadow_caster_id = -1; + eevee_data->need_update = false; + eevee_data->geom_update = false; } EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index ab846fe0f11..8c48ae65d9b 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -153,7 +153,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, effects->enabled_effects = 0; effects->enabled_effects |= (G.debug_value == 9) ? EFFECT_VELOCITY_BUFFER : 0; - effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata, camera); + effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata); effects->enabled_effects |= EEVEE_bloom_init(sldata, vedata); effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata, camera); effects->enabled_effects |= EEVEE_temporal_sampling_init(sldata, vedata); @@ -225,10 +225,13 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, */ if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { effects->velocity_tx = DRW_texture_pool_query_2d( - size_fs[0], size_fs[1], GPU_RG16, &draw_engine_eevee_type); + size_fs[0], size_fs[1], GPU_RGBA16, &draw_engine_eevee_type); - /* TODO output objects velocity during the mainpass. */ - // GPU_framebuffer_texture_attach(fbl->main_fb, effects->velocity_tx, 1, 0); + GPU_framebuffer_ensure_config(&fbl->velocity_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(effects->velocity_tx), + }); GPU_framebuffer_ensure_config( &fbl->velocity_resolve_fb, @@ -328,14 +331,18 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { + EEVEE_MotionBlurData *mb_data = &effects->motion_blur; + /* This pass compute camera motions to the non moving objects. */ DRW_PASS_CREATE(psl->velocity_resolve, DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(EEVEE_shaders_velocity_resolve_sh_get(), psl->velocity_resolve); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); - DRW_shgroup_uniform_mat4(grp, "currPersinv", effects->velocity_curr_persinv); - DRW_shgroup_uniform_mat4(grp, "pastPersmat", effects->velocity_past_persmat); + + DRW_shgroup_uniform_mat4(grp, "prevViewProjMatrix", mb_data->camera[MB_PREV].persmat); + DRW_shgroup_uniform_mat4(grp, "currViewProjMatrixInv", mb_data->camera[MB_CURR].persinv); + DRW_shgroup_uniform_mat4(grp, "nextViewProjMatrix", mb_data->camera[MB_NEXT].persmat); DRW_shgroup_call(grp, quad, NULL); } } @@ -501,17 +508,19 @@ static void EEVEE_velocity_resolve(EEVEE_Data *vedata) EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - struct DRWView *view = effects->taa_view; if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); e_data.depth_src = dtxl->depth; - DRW_view_persmat_get(view, effects->velocity_curr_persinv, true); GPU_framebuffer_bind(fbl->velocity_resolve_fb); DRW_draw_pass(psl->velocity_resolve); + + if (psl->velocity_object) { + GPU_framebuffer_bind(fbl->velocity_fb); + DRW_draw_pass(psl->velocity_object); + } } - DRW_view_persmat_get(view, effects->velocity_past_persmat, false); } void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) @@ -529,6 +538,7 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) effects->target_buffer = fbl->effect_color_fb; /* next target to render to */ /* Post process stack (order matters) */ + EEVEE_velocity_resolve(vedata); EEVEE_motion_blur_draw(vedata); EEVEE_depth_of_field_draw(vedata); @@ -537,7 +547,6 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) * Velocity resolve use a hack to exclude lookdev * spheres from creating shimmering re-projection vectors. */ EEVEE_lookdev_draw(vedata); - EEVEE_velocity_resolve(vedata); EEVEE_temporal_sampling_draw(vedata); EEVEE_bloom_draw(vedata); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index b698574f9d7..bac96ab1079 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -166,7 +166,9 @@ static void eevee_cache_finish(void *vedata) EEVEE_materials_cache_finish(sldata, vedata); EEVEE_lights_cache_finish(sldata, vedata); EEVEE_lightprobes_cache_finish(sldata, vedata); + EEVEE_renderpasses_cache_finish(sldata, vedata); + EEVEE_subsurface_draw_init(sldata, vedata); EEVEE_effects_draw_init(sldata, vedata); EEVEE_volumes_draw_init(sldata, vedata); @@ -213,6 +215,10 @@ static void eevee_draw_scene(void *vedata) loop_len = MAX2(1, scene->eevee.taa_samples); } + if (stl->effects->bypass_drawing) { + loop_len = 0; + } + while (loop_len--) { float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float clear_depth = 1.0f; @@ -351,11 +357,18 @@ static void eevee_draw_scene(void *vedata) EEVEE_renderpasses_draw(sldata, vedata); } + if (stl->effects->bypass_drawing) { + /* Restore the depth from sample 1. */ + GPU_framebuffer_blit(fbl->double_buffer_depth_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT); + } + EEVEE_renderpasses_draw_debug(vedata); EEVEE_volumes_free_smoke_textures(); stl->g_data->view_updated = false; + + DRW_view_set_active(NULL); } static void eevee_view_update(void *vedata) @@ -370,7 +383,7 @@ static void eevee_id_object_update(void *UNUSED(vedata), Object *object) { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object); if (ped != NULL && ped->dd.recalc != 0) { - ped->need_update = (ped->dd.recalc & (ID_RECALC_TRANSFORM)) != 0; + ped->need_update = (ped->dd.recalc & ID_RECALC_TRANSFORM) != 0; ped->dd.recalc = 0; } EEVEE_LightEngineData *led = EEVEE_light_data_get(object); @@ -381,6 +394,7 @@ static void eevee_id_object_update(void *UNUSED(vedata), Object *object) EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object); if (oedata != NULL && oedata->dd.recalc != 0) { oedata->need_update = true; + oedata->geom_update = (oedata->dd.recalc & (ID_RECALC_GEOMETRY)) != 0; oedata->dd.recalc = 0; } } @@ -390,6 +404,11 @@ static void eevee_id_world_update(void *vedata, World *wo) EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; LightCache *lcache = stl->g_data->light_cache; + if (lcache == NULL || lcache == stl->lookdev_lightcache) { + /* Avoid Lookdev viewport clearing the update flag (see T67741). */ + return; + } + EEVEE_WorldEngineData *wedata = EEVEE_world_data_ensure(wo); if (wedata != NULL && wedata->dd.recalc != 0) { @@ -400,7 +419,7 @@ static void eevee_id_world_update(void *vedata, World *wo) } } -static void eevee_id_update(void *vedata, ID *id) +void eevee_id_update(void *vedata, ID *id) { /* Handle updates based on ID type. */ switch (GS(id->name)) { @@ -416,23 +435,129 @@ static void eevee_id_update(void *vedata, ID *id) } } +static void eevee_render_reset_passes(EEVEE_Data *vedata) +{ + /* Reset passlist. This is safe as they are stored into managed memory chunks. */ + memset(vedata->psl, 0, sizeof(*vedata->psl)); +} + static void eevee_render_to_image(void *vedata, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect) { + EEVEE_Data *ved = (EEVEE_Data *)vedata; const DRWContextState *draw_ctx = DRW_context_state_get(); + Depsgraph *depsgraph = draw_ctx->depsgraph; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + const bool do_motion_blur = (scene->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) != 0; + const bool do_motion_blur_fx = do_motion_blur && (scene->eevee.motion_blur_max > 0); - if (!EEVEE_render_init(vedata, engine, draw_ctx->depsgraph)) { + if (!EEVEE_render_init(vedata, engine, depsgraph)) { return; } + EEVEE_PrivateData *g_data = ved->stl->g_data; + + int steps = max_ii(1, scene->eevee.motion_blur_steps); + int time_steps_tot = (do_motion_blur) ? steps : 1; + g_data->render_tot_samples = divide_ceil_u(scene->eevee.taa_render_samples, time_steps_tot); + /* Centered on frame for now. */ + float time = CFRA - scene->eevee.motion_blur_shutter / 2.0f; + float time_step = scene->eevee.motion_blur_shutter / time_steps_tot; + for (int i = 0; i < time_steps_tot && !RE_engine_test_break(engine); i++) { + float time_prev = time; + float time_curr = time + time_step * 0.5f; + float time_next = time + time_step; + time += time_step; + + /* Previous motion step. */ + if (do_motion_blur_fx) { + if (i > 0) { + /* The previous step of this iteration N is exactly the next step of iteration N - 1. + * So we just swap the resources to avoid too much re-evaluation. */ + EEVEE_motion_blur_swap_data(vedata); + } + else { + EEVEE_motion_blur_step_set(ved, MB_PREV); + RE_engine_frame_set(engine, floorf(time_prev), fractf(time_prev)); + + EEVEE_render_view_sync(vedata, engine, depsgraph); + EEVEE_render_cache_init(sldata, vedata); + + DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache); + + EEVEE_motion_blur_cache_finish(vedata); + EEVEE_materials_cache_finish(sldata, vedata); + eevee_render_reset_passes(vedata); + } + } + + /* Next motion step. */ + if (do_motion_blur_fx) { + EEVEE_motion_blur_step_set(ved, MB_NEXT); + RE_engine_frame_set(engine, floorf(time_next), fractf(time_next)); - DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, EEVEE_render_cache); + EEVEE_render_view_sync(vedata, engine, depsgraph); + EEVEE_render_cache_init(sldata, vedata); - /* Actually do the rendering. */ - EEVEE_render_draw(vedata, engine, render_layer, rect); + DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache); + + EEVEE_motion_blur_cache_finish(vedata); + EEVEE_materials_cache_finish(sldata, vedata); + eevee_render_reset_passes(vedata); + } + + /* Current motion step. */ + { + if (do_motion_blur) { + EEVEE_motion_blur_step_set(ved, MB_CURR); + RE_engine_frame_set(engine, floorf(time_curr), fractf(time_curr)); + } + + EEVEE_render_view_sync(vedata, engine, depsgraph); + EEVEE_render_cache_init(sldata, vedata); + + DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache); + + EEVEE_motion_blur_cache_finish(vedata); + EEVEE_volumes_cache_finish(sldata, vedata); + EEVEE_materials_cache_finish(sldata, vedata); + EEVEE_lights_cache_finish(sldata, vedata); + EEVEE_lightprobes_cache_finish(sldata, vedata); + EEVEE_renderpasses_cache_finish(sldata, vedata); + + EEVEE_subsurface_draw_init(sldata, vedata); + EEVEE_effects_draw_init(sldata, vedata); + EEVEE_volumes_draw_init(sldata, vedata); + } + + /* Actual drawing. */ + { + EEVEE_renderpasses_output_init(sldata, vedata, g_data->render_tot_samples * time_steps_tot); + + EEVEE_temporal_sampling_create_view(vedata); + EEVEE_render_draw(vedata, engine, render_layer, rect); + + if (i < time_steps_tot - 1) { + /* Don't reset after the last loop. Since EEVEE_render_read_result + * might need some DRWPasses. */ + DRW_cache_restart(); + } + } + } EEVEE_volumes_free_smoke_textures(); + EEVEE_motion_blur_data_free(&ved->stl->effects->motion_blur); + + if (RE_engine_test_break(engine)) { + return; + } + + EEVEE_render_read_result(vedata, engine, render_layer, rect); + + /* Restore original viewport size. */ + DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]}); } static void eevee_engine_free(void) diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 4cdd166f09c..78d50a02fc7 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -849,6 +849,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb /* Disable volumetrics when baking. */ stl->effects->enabled_effects &= ~EFFECT_VOLUMETRIC; + EEVEE_subsurface_draw_init(sldata, vedata); EEVEE_effects_draw_init(sldata, vedata); EEVEE_volumes_draw_init(sldata, vedata); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 83b2a9bb6d4..71c8294d123 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -957,8 +957,8 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us /* Slight modification: we handle refraction as normal * shading and don't do SSRefraction. */ - DRW_draw_pass(psl->depth_ps); - DRW_draw_pass(psl->depth_refract_ps); + DRW_draw_pass(psl->depth_clip_ps); + DRW_draw_pass(psl->depth_refract_clip_ps); DRW_draw_pass(psl->probe_background); EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index cfc70baaf01..8537ad0e532 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -801,6 +801,8 @@ static void eevee_hair_cache_populate(EEVEE_Data *vedata, *matcache.shadow_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shadow_grp); *cast_shadow = true; } + + EEVEE_motion_blur_hair_cache_populate(sldata, vedata, ob, psys, md); } #define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ @@ -851,8 +853,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, */ bool use_volume_material = (matcache[0].shading_gpumat && GPU_material_has_volume_output(matcache[0].shading_gpumat)); - - if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) { + if ((ob->dt >= OB_SOLID) || DRW_state_is_scene_render()) { if (use_sculpt_pbvh) { struct DRWShadingGroup **shgrps_array = BLI_array_alloca(shgrps_array, materials_len); @@ -901,6 +902,9 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, } } } + + /* Motion Blur Vectors. */ + EEVEE_motion_blur_cache_populate(sldata, vedata, ob); } /* Volumetrics */ @@ -946,17 +950,15 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata, eevee_hair_cache_populate(vedata, sldata, ob, NULL, NULL, HAIR_MATERIAL_NR, cast_shadow); } -void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_PrivateData *pd = vedata->stl->g_data; EEVEE_EffectsInfo *effects = vedata->stl->effects; BLI_ghash_free(pd->material_hash, NULL, NULL); + pd->material_hash = NULL; SET_FLAG_FROM_TEST(effects->enabled_effects, effects->sss_surface_count > 0, EFFECT_SSS); - - /* TODO(fclem) this is not really clean. Init should not be done in cache finish. */ - EEVEE_subsurface_draw_init(sldata, vedata); } void EEVEE_materials_free(void) @@ -1015,7 +1017,7 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, /* Should be enough precision for many samples. */ const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F; - const bool do_clear = DRW_state_is_image_render() || (effects->taa_current_sample == 1); + const bool do_clear = (effects->taa_current_sample == 1); /* Create FrameBuffer. */ GPU_framebuffer_ensure_config(&fbl->material_accum_fb, {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c index 7b942784ee9..1cedd334d67 100644 --- a/source/blender/draw/engines/eevee/eevee_mist.c +++ b/source/blender/draw/engines/eevee/eevee_mist.c @@ -75,7 +75,7 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->mist_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->mist_accum_fb); GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index a6e6b30a6b1..586ee780f1d 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -24,12 +24,19 @@ #include "DRW_render.h" +#include "BLI_rand.h" +#include "BLI_string_utils.h" + #include "BKE_animsys.h" #include "BKE_camera.h" #include "BKE_object.h" +#include "BKE_screen.h" #include "DNA_anim_types.h" #include "DNA_camera_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_particle_types.h" #include "DNA_screen_types.h" #include "ED_screen.h" @@ -37,172 +44,517 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "GPU_batch.h" #include "GPU_texture.h" #include "eevee_private.h" static struct { /* Motion Blur */ struct GPUShader *motion_blur_sh; + struct GPUShader *motion_blur_object_sh; + struct GPUShader *motion_blur_hair_sh; + struct GPUShader *velocity_tiles_sh; + struct GPUShader *velocity_tiles_expand_sh; } e_data = {NULL}; /* Engine data */ +extern char datatoc_effect_velocity_tile_frag_glsl[]; extern char datatoc_effect_motion_blur_frag_glsl[]; +extern char datatoc_object_motion_frag_glsl[]; +extern char datatoc_object_motion_vert_glsl[]; +extern char datatoc_common_hair_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; -static void eevee_motion_blur_camera_get_matrix_at_time(Scene *scene, - ARegion *region, - RegionView3D *rv3d, - View3D *v3d, - Object *camera, - float time, - float r_mat[4][4]) -{ - float obmat[4][4]; +#define EEVEE_VELOCITY_TILE_SIZE 32 - /* HACK */ - Object cam_cpy = *camera; - Camera camdata_cpy = *(Camera *)(camera->data); - cam_cpy.data = &camdata_cpy; +static void eevee_create_shader_motion_blur(void) +{ + e_data.motion_blur_sh = DRW_shader_create_fullscreen( + datatoc_effect_motion_blur_frag_glsl, + "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"); + e_data.motion_blur_object_sh = DRW_shader_create_with_lib(datatoc_object_motion_vert_glsl, + NULL, + datatoc_object_motion_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); + e_data.velocity_tiles_sh = DRW_shader_create_fullscreen( + datatoc_effect_velocity_tile_frag_glsl, + "#define TILE_GATHER\n" + "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"); + e_data.velocity_tiles_expand_sh = DRW_shader_create_fullscreen( + datatoc_effect_velocity_tile_frag_glsl, + "#define TILE_EXPANSION\n" + "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"); + + char *vert = BLI_string_joinN(datatoc_common_hair_lib_glsl, datatoc_object_motion_vert_glsl); + e_data.motion_blur_hair_sh = DRW_shader_create_with_lib( + vert, NULL, datatoc_object_motion_frag_glsl, datatoc_common_view_lib_glsl, "#define HAIR\n"); + MEM_freeN(vert); +} - /* Reset original pointers, so direct evaluation does not attempt to flush - * animation back to the original object: otherwise viewport with motion - * blur enabled will always loose non-keyed changes. */ - cam_cpy.id.orig_id = NULL; - camdata_cpy.id.orig_id = NULL; +int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_EffectsInfo *effects = stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; - /* Past matrix */ - /* FIXME : This is a temporal solution that does not take care of parent animations */ - /* Recalc Anim manually */ - BKE_animsys_evaluate_animdata(&camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL, false); - BKE_object_where_is_calc_time(draw_ctx->depsgraph, scene, &cam_cpy, time); + /* Viewport not supported for now. */ + if (!DRW_state_is_scene_render()) { + return 0; + } + + effects->motion_blur_max = max_ii(0, scene->eevee.motion_blur_max); + + if ((effects->motion_blur_max > 0) && (scene->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED)) { + if (!e_data.motion_blur_sh) { + eevee_create_shader_motion_blur(); + } - /* Compute winmat */ - CameraParams params; - BKE_camera_params_init(¶ms); + if (DRW_state_is_scene_render()) { + int mb_step = effects->motion_blur_step; + DRW_view_viewmat_get(NULL, effects->motion_blur.camera[mb_step].viewmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persinv, true); + } - if (v3d != NULL) { - BKE_camera_params_from_view3d(¶ms, draw_ctx->depsgraph, v3d, rv3d); - BKE_camera_params_compute_viewplane(¶ms, region->winx, region->winy, 1.0f, 1.0f); + const float *fs_size = DRW_viewport_size_get(); + int tx_size[2] = {1 + ((int)fs_size[0] / EEVEE_VELOCITY_TILE_SIZE), + 1 + ((int)fs_size[1] / EEVEE_VELOCITY_TILE_SIZE)}; + + effects->velocity_tiles_x_tx = DRW_texture_pool_query_2d( + tx_size[0], fs_size[1], GPU_RGBA16, &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->velocity_tiles_fb[0], + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->velocity_tiles_x_tx), + }); + + effects->velocity_tiles_tx = DRW_texture_pool_query_2d( + tx_size[0], tx_size[1], GPU_RGBA16, &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->velocity_tiles_fb[1], + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->velocity_tiles_tx), + }); + + return EFFECT_MOTION_BLUR | EFFECT_POST_BUFFER | EFFECT_VELOCITY_BUFFER; } - else { - BKE_camera_params_from_object(¶ms, &cam_cpy); - BKE_camera_params_compute_viewplane( - ¶ms, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp); + return 0; +} + +void EEVEE_motion_blur_step_set(EEVEE_Data *vedata, int step) +{ + BLI_assert(step < 3); + vedata->stl->effects->motion_blur_step = step; +} + +static void eevee_motion_blur_sync_camera(EEVEE_Data *vedata) +{ + EEVEE_EffectsInfo *effects = vedata->stl->effects; + if (DRW_state_is_scene_render()) { + int mb_step = effects->motion_blur_step; + DRW_view_viewmat_get(NULL, effects->motion_blur.camera[mb_step].viewmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persinv, true); } - BKE_camera_params_compute_matrix(¶ms); + effects->motion_blur_near_far[0] = fabsf(DRW_view_near_distance_get(NULL)); + effects->motion_blur_near_far[1] = fabsf(DRW_view_far_distance_get(NULL)); +} + +void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_MotionBlurData *mb_data = &effects->motion_blur; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { + const float *fs_size = DRW_viewport_size_get(); + int tx_size[2] = {GPU_texture_width(effects->velocity_tiles_tx), + GPU_texture_height(effects->velocity_tiles_tx)}; + + eevee_motion_blur_sync_camera(vedata); + + DRWShadingGroup *grp; + { + DRW_PASS_CREATE(psl->velocity_tiles_x, DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->velocity_tiles, DRW_STATE_WRITE_COLOR); + + /* Create max velocity tiles in 2 passes. One for X and one for Y */ + GPUShader *sh = e_data.velocity_tiles_sh; + grp = DRW_shgroup_create(sh, psl->velocity_tiles_x); + DRW_shgroup_uniform_texture(grp, "velocityBuffer", effects->velocity_tx); + DRW_shgroup_uniform_ivec2_copy(grp, "velocityBufferSize", (int[2]){fs_size[0], fs_size[1]}); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(grp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_uniform_ivec2_copy(grp, "gatherStep", (int[2]){1, 0}); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + grp = DRW_shgroup_create(sh, psl->velocity_tiles); + DRW_shgroup_uniform_texture(grp, "velocityBuffer", effects->velocity_tiles_x_tx); + DRW_shgroup_uniform_ivec2_copy(grp, "velocityBufferSize", (int[2]){tx_size[0], fs_size[1]}); + DRW_shgroup_uniform_ivec2_copy(grp, "gatherStep", (int[2]){0, 1}); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + /* Expand max tiles by keeping the max tile in each tile neighborhood. */ + DRW_PASS_CREATE(psl->velocity_tiles_expand[0], DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->velocity_tiles_expand[1], DRW_STATE_WRITE_COLOR); + for (int i = 0; i < 2; i++) { + GPUTexture *tile_tx = (i == 0) ? effects->velocity_tiles_tx : effects->velocity_tiles_x_tx; + GPUShader *sh_expand = e_data.velocity_tiles_expand_sh; + grp = DRW_shgroup_create(sh_expand, psl->velocity_tiles_expand[i]); + DRW_shgroup_uniform_ivec2_copy(grp, "velocityBufferSize", tx_size); + DRW_shgroup_uniform_texture(grp, "velocityBuffer", tile_tx); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(grp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + } + { + DRW_PASS_CREATE(psl->motion_blur, DRW_STATE_WRITE_COLOR); + eGPUSamplerState state = 0; + int expand_steps = 1 + (max_ii(0, effects->motion_blur_max - 1) / EEVEE_VELOCITY_TILE_SIZE); + GPUTexture *tile_tx = (expand_steps & 1) ? effects->velocity_tiles_x_tx : + effects->velocity_tiles_tx; + + grp = DRW_shgroup_create(e_data.motion_blur_sh, psl->motion_blur); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture_ref_ex(grp, "colorBuffer", &effects->source_buffer, state); + DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &dtxl->depth, state); + DRW_shgroup_uniform_texture_ref_ex(grp, "velocityBuffer", &effects->velocity_tx, state); + DRW_shgroup_uniform_texture(grp, "tileMaxBuffer", tile_tx); + DRW_shgroup_uniform_float_copy(grp, "depthScale", scene->eevee.motion_blur_depth_scale); + DRW_shgroup_uniform_vec2(grp, "nearFar", effects->motion_blur_near_far, 1); + DRW_shgroup_uniform_bool_copy(grp, "isPerspective", DRW_view_is_persp_get(NULL)); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(grp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_uniform_ivec2_copy(grp, "tileBufferSize", tx_size); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + { + DRW_PASS_CREATE(psl->velocity_object, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + + grp = DRW_shgroup_create(e_data.motion_blur_object_sh, psl->velocity_object); + DRW_shgroup_uniform_mat4(grp, "prevViewProjMatrix", mb_data->camera[MB_PREV].persmat); + DRW_shgroup_uniform_mat4(grp, "currViewProjMatrix", mb_data->camera[MB_CURR].persmat); + DRW_shgroup_uniform_mat4(grp, "nextViewProjMatrix", mb_data->camera[MB_NEXT].persmat); + + DRW_PASS_CREATE(psl->velocity_hair, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + + mb_data->hair_grp = grp = DRW_shgroup_create(e_data.motion_blur_hair_sh, psl->velocity_hair); + DRW_shgroup_uniform_mat4(grp, "prevViewProjMatrix", mb_data->camera[MB_PREV].persmat); + DRW_shgroup_uniform_mat4(grp, "currViewProjMatrix", mb_data->camera[MB_CURR].persmat); + DRW_shgroup_uniform_mat4(grp, "nextViewProjMatrix", mb_data->camera[MB_NEXT].persmat); + + DRW_pass_link(psl->velocity_object, psl->velocity_hair); + } - /* FIXME Should be done per view (MULTIVIEW) */ - normalize_m4_m4(obmat, cam_cpy.obmat); - invert_m4(obmat); - mul_m4_m4m4(r_mat, params.winmat, obmat); + EEVEE_motion_blur_data_init(mb_data); + } + else { + psl->motion_blur = NULL; + psl->velocity_object = NULL; + psl->velocity_hair = NULL; + } } -static void eevee_create_shader_motion_blur(void) +void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + Object *ob, + ParticleSystem *psys, + ModifierData *md) { - e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL); + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + DRWShadingGroup *grp = NULL; + + if (!DRW_state_is_scene_render() || psl->velocity_hair == NULL) { + return; + } + + /* For now we assume hair objects are always moving. */ + EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get( + &effects->motion_blur, ob, true); + + if (mb_data) { + int mb_step = effects->motion_blur_step; + /* Store transform */ + DRW_hair_duplimat_get(ob, psys, md, mb_data->obmat[mb_step]); + + EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_geometry_data_get( + &effects->motion_blur, ob, true); + + if (mb_step == MB_CURR) { + /* Fill missing matrices if the object was hidden in previous or next frame. */ + if (is_zero_m4(mb_data->obmat[MB_PREV])) { + copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_CURR]); + } + if (is_zero_m4(mb_data->obmat[MB_NEXT])) { + copy_m4_m4(mb_data->obmat[MB_NEXT], mb_data->obmat[MB_CURR]); + } + + grp = DRW_shgroup_hair_create_sub(ob, psys, md, effects->motion_blur.hair_grp); + DRW_shgroup_uniform_mat4(grp, "prevModelMatrix", mb_data->obmat[MB_PREV]); + DRW_shgroup_uniform_mat4(grp, "currModelMatrix", mb_data->obmat[MB_CURR]); + DRW_shgroup_uniform_mat4(grp, "nextModelMatrix", mb_data->obmat[MB_NEXT]); + DRW_shgroup_uniform_texture(grp, "prvBuffer", mb_geom->hair_pos_tx[MB_PREV]); + DRW_shgroup_uniform_texture(grp, "nxtBuffer", mb_geom->hair_pos_tx[MB_NEXT]); + DRW_shgroup_uniform_bool(grp, "useDeform", &mb_geom->use_deform, 1); + } + else { + /* Store vertex position buffer. */ + mb_geom->hair_pos[mb_step] = DRW_hair_pos_buffer_get(ob, psys, md); + mb_geom->use_deform = true; + } + } } -int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera) +void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + Object *ob) { + EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; + DRWShadingGroup *grp = NULL; - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - Scene *scene = draw_ctx->scene; + if (!DRW_state_is_scene_render() || psl->velocity_object == NULL) { + return; + } - View3D *v3d = draw_ctx->v3d; - RegionView3D *rv3d = draw_ctx->rv3d; - ARegion *region = draw_ctx->region; + const bool is_dupli = (ob->base_flag & BASE_FROM_DUPLI) != 0; + /* For now we assume dupli objects are moving. */ + const bool object_moves = is_dupli || BKE_object_moves_in_time(ob, true); + const bool is_deform = BKE_object_is_deform_modified(DRW_context_state_get()->scene, ob); - if (scene_eval->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) { - /* Update Motion Blur Matrices */ - if (camera && (camera->type == OB_CAMERA) && (camera->data != NULL)) { - float persmat[4][4]; - float ctime = DEG_get_ctime(draw_ctx->depsgraph); - float delta = scene_eval->eevee.motion_blur_shutter; - Object *ob_camera_eval = DEG_get_evaluated_object(draw_ctx->depsgraph, camera); + if (!(object_moves || is_deform)) { + return; + } - /* Viewport Matrix */ - /* Note: This does not have TAA jitter applied. */ - DRW_view_persmat_get(NULL, persmat, false); + EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get( + &effects->motion_blur, ob, false); - bool view_is_valid = (stl->g_data->view_updated == false); + if (mb_data) { + int mb_step = effects->motion_blur_step; + /* Store transform */ + copy_m4_m4(mb_data->obmat[mb_step], ob->obmat); + + EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_geometry_data_get( + &effects->motion_blur, ob, false); + + if (mb_step == MB_CURR) { + GPUBatch *batch = DRW_cache_object_surface_get(ob); + if (batch == NULL) { + return; + } - if (draw_ctx->evil_C != NULL) { - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - view_is_valid = view_is_valid && (ED_screen_animation_no_scrub(wm) == NULL); + /* Fill missing matrices if the object was hidden in previous or next frame. */ + if (is_zero_m4(mb_data->obmat[MB_PREV])) { + copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_CURR]); + } + if (is_zero_m4(mb_data->obmat[MB_NEXT])) { + copy_m4_m4(mb_data->obmat[MB_NEXT], mb_data->obmat[MB_CURR]); } - /* The view is jittered by the oglrenderer. So avoid testing in this case. */ - if (!DRW_state_is_image_render()) { - view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); - /* WATCH: assume TAA init code runs last. */ - if (scene_eval->eevee.taa_samples == 1) { - /* Only if TAA is disabled. If not, TAA will update prev_drw_persmat itself. */ - copy_m4_m4(effects->prev_drw_persmat, persmat); + grp = DRW_shgroup_create(e_data.motion_blur_object_sh, psl->velocity_object); + DRW_shgroup_uniform_mat4(grp, "prevModelMatrix", mb_data->obmat[MB_PREV]); + DRW_shgroup_uniform_mat4(grp, "currModelMatrix", mb_data->obmat[MB_CURR]); + DRW_shgroup_uniform_mat4(grp, "nextModelMatrix", mb_data->obmat[MB_NEXT]); + DRW_shgroup_uniform_bool(grp, "useDeform", &mb_geom->use_deform, 1); + + DRW_shgroup_call(grp, batch, ob); + + if (mb_geom->use_deform) { + EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); + if (!oedata->geom_update) { + /* FIXME(fclem) There can be false positive where the actual mesh is not updated. + * This avoids a crash but removes the motion blur from some object. + * Maybe an issue with depsgraph tagging. */ + mb_geom->use_deform = false; + oedata->geom_update = false; + + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_NEXT]); } + /* Keep to modify later (after init). */ + mb_geom->batch = batch; } + } + else if (is_deform) { + /* Store vertex position buffer. */ + mb_geom->vbo[mb_step] = DRW_cache_object_pos_vertbuf_get(ob); + mb_geom->use_deform = (mb_geom->vbo[mb_step] != NULL); + } + else { + mb_geom->vbo[mb_step] = NULL; + mb_geom->use_deform = false; + } + } +} + +void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + GHashIterator ghi; - effects->motion_blur_mat_cached = view_is_valid && !DRW_state_is_image_render(); + if ((effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) { + return; + } - /* Current matrix */ - if (effects->motion_blur_mat_cached == false) { - eevee_motion_blur_camera_get_matrix_at_time( - scene, region, rv3d, v3d, ob_camera_eval, ctime, effects->current_world_to_ndc); - } + int mb_step = effects->motion_blur_step; + + if (mb_step != MB_CURR) { + /* Push instances attributes to the GPU. */ + DRW_render_instance_buffer_finish(); + + /* Need to be called after DRW_render_instance_buffer_finish() */ + /* Also we weed to have a correct fbo bound for DRW_hair_update */ + GPU_framebuffer_bind(vedata->fbl->main_fb); + DRW_hair_update(); - /* Only continue if camera is not being keyed */ - if (DRW_state_is_image_render() || - compare_m4m4(persmat, effects->current_world_to_ndc, 0.0001f)) { - /* Past matrix */ - if (effects->motion_blur_mat_cached == false) { - eevee_motion_blur_camera_get_matrix_at_time( - scene, region, rv3d, v3d, ob_camera_eval, ctime - delta, effects->past_world_to_ndc); - -#if 0 /* for future high quality blur */ - /* Future matrix */ - eevee_motion_blur_camera_get_matrix_at_time( - scene, region, rv3d, v3d, ob_camera_eval, ctime + delta, effects->future_world_to_ndc); -#endif - invert_m4_m4(effects->current_ndc_to_world, effects->current_world_to_ndc); + DRW_cache_restart(); + } + + for (BLI_ghashIterator_init(&ghi, effects->motion_blur.geom); + BLI_ghashIterator_done(&ghi) == false; + BLI_ghashIterator_step(&ghi)) { + EEVEE_GeometryMotionData *mb_geom = BLI_ghashIterator_getValue(&ghi); + + if (!mb_geom->use_deform) { + continue; + } + + switch (mb_geom->type) { + case EEVEE_HAIR_GEOM_MOTION_DATA: + if (mb_step == MB_CURR) { + /* TODO(fclem) Check if vertex count mismatch. */ + mb_geom->use_deform = true; } + else { + mb_geom->hair_pos[mb_step] = GPU_vertbuf_duplicate(mb_geom->hair_pos[mb_step]); - effects->motion_blur_mat_cached = true; - effects->motion_blur_samples = scene_eval->eevee.motion_blur_samples; + /* Create vbo immediately to bind to texture buffer. */ + GPU_vertbuf_use(mb_geom->hair_pos[mb_step]); - if (!e_data.motion_blur_sh) { - eevee_create_shader_motion_blur(); + mb_geom->hair_pos_tx[mb_step] = GPU_texture_create_from_vertbuf( + mb_geom->hair_pos[mb_step]); + } + break; + + case EEVEE_MESH_GEOM_MOTION_DATA: + if (mb_step == MB_CURR) { + /* Modify batch to have data from adjacent frames. */ + GPUBatch *batch = mb_geom->batch; + for (int i = 0; i < MB_CURR; i++) { + GPUVertBuf *vbo = mb_geom->vbo[i]; + if (vbo && batch) { + if (vbo->vertex_len != batch->verts[0]->vertex_len) { + /* Vertex count mismatch, disable deform motion blur. */ + mb_geom->use_deform = false; + } + + if (mb_geom->use_deform == false) { + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_NEXT]); + break; + } + else { + /* Modify the batch to include the previous & next position. */ + if (i == MB_PREV) { + GPU_batch_vertbuf_add_ex(batch, vbo, true); + mb_geom->vbo[i] = NULL; + } + else { + /* This VBO can be reuse by next time step. Don't pass ownership. */ + GPU_batch_vertbuf_add_ex(batch, vbo, false); + } + } + } + } + } + else { + GPUVertBuf *vbo = mb_geom->vbo[mb_step]; + /* If this assert fails, it means that different EEVEE_GeometryMotionDatas + * has been used for each motion blur step. */ + BLI_assert(vbo); + if (vbo) { + /* Use the vbo to perform the copy on the GPU. */ + GPU_vertbuf_use(vbo); + /* Perform a copy to avoid loosing it after RE_engine_frame_set(). */ + mb_geom->vbo[mb_step] = vbo = GPU_vertbuf_duplicate(vbo); + /* Find and replace "pos" attrib name. */ + int attrib_id = GPU_vertformat_attr_id_get(&vbo->format, "pos"); + GPU_vertformat_attr_rename( + &vbo->format, attrib_id, (mb_step == MB_PREV) ? "prv" : "nxt"); + } } + break; - return EFFECT_MOTION_BLUR | EFFECT_POST_BUFFER; - } + default: + BLI_assert(0); + break; } } - - return 0; } -void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_motion_blur_swap_data(EEVEE_Data *vedata) { - EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); + GHashIterator ghi; - if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { - DRW_PASS_CREATE(psl->motion_blur, DRW_STATE_WRITE_COLOR); + BLI_assert((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.motion_blur_sh, psl->motion_blur); - DRW_shgroup_uniform_int(grp, "samples", &effects->motion_blur_samples, 1); - DRW_shgroup_uniform_mat4(grp, "currInvViewProjMatrix", effects->current_ndc_to_world); - DRW_shgroup_uniform_mat4(grp, "pastViewProjMatrix", effects->past_world_to_ndc); - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_call(grp, quad, NULL); + /* Camera Data. */ + effects->motion_blur.camera[MB_PREV] = effects->motion_blur.camera[MB_CURR]; + + /* Object Data. */ + for (BLI_ghashIterator_init(&ghi, effects->motion_blur.object); + BLI_ghashIterator_done(&ghi) == false; + BLI_ghashIterator_step(&ghi)) { + EEVEE_ObjectMotionData *mb_data = BLI_ghashIterator_getValue(&ghi); + + copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_NEXT]); + } + + /* Deformation Data. */ + for (BLI_ghashIterator_init(&ghi, effects->motion_blur.geom); + BLI_ghashIterator_done(&ghi) == false; + BLI_ghashIterator_step(&ghi)) { + EEVEE_GeometryMotionData *mb_geom = BLI_ghashIterator_getValue(&ghi); + + switch (mb_geom->type) { + case EEVEE_HAIR_GEOM_MOTION_DATA: + GPU_VERTBUF_DISCARD_SAFE(mb_geom->hair_pos[MB_PREV]); + DRW_TEXTURE_FREE_SAFE(mb_geom->hair_pos_tx[MB_PREV]); + mb_geom->hair_pos[MB_PREV] = mb_geom->hair_pos[MB_NEXT]; + mb_geom->hair_pos_tx[MB_PREV] = mb_geom->hair_pos_tx[MB_NEXT]; + break; + + case EEVEE_MESH_GEOM_MOTION_DATA: + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); + mb_geom->vbo[MB_PREV] = mb_geom->vbo[MB_NEXT]; + + if (mb_geom->vbo[MB_NEXT]) { + GPUVertBuf *vbo = mb_geom->vbo[MB_NEXT]; + int attrib_id = GPU_vertformat_attr_id_get(&vbo->format, "nxt"); + GPU_vertformat_attr_rename(&vbo->format, attrib_id, "prv"); + } + break; + + default: + BLI_assert(0); + break; + } } } @@ -216,6 +568,30 @@ void EEVEE_motion_blur_draw(EEVEE_Data *vedata) /* Motion Blur */ if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { + /* Create velocity max tiles in 2 passes. One for each dimension. */ + GPU_framebuffer_bind(fbl->velocity_tiles_fb[0]); + DRW_draw_pass(psl->velocity_tiles_x); + + GPU_framebuffer_bind(fbl->velocity_tiles_fb[1]); + DRW_draw_pass(psl->velocity_tiles); + + /* Expand the tiles by reading the neighborhood. Do as many passes as required. */ + int buf = 0; + for (int i = effects->motion_blur_max; i > 0; i -= EEVEE_VELOCITY_TILE_SIZE) { + GPU_framebuffer_bind(fbl->velocity_tiles_fb[buf]); + + /* Change viewport to avoid invoking more pixel shaders than necessary since in one of the + * buffer the texture is way bigger in height. This avoid creating another texture and + * reduce VRAM usage. */ + int w = GPU_texture_width(effects->velocity_tiles_tx); + int h = GPU_texture_height(effects->velocity_tiles_tx); + GPU_framebuffer_viewport_set(fbl->velocity_tiles_fb[buf], 0, 0, w, h); + + DRW_draw_pass(psl->velocity_tiles_expand[buf]); + + buf = buf ? 0 : 1; + } + GPU_framebuffer_bind(effects->target_buffer); DRW_draw_pass(psl->motion_blur); SWAP_BUFFERS(); @@ -225,4 +601,8 @@ void EEVEE_motion_blur_draw(EEVEE_Data *vedata) void EEVEE_motion_blur_free(void) { DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh); + DRW_SHADER_FREE_SAFE(e_data.motion_blur_object_sh); + DRW_SHADER_FREE_SAFE(e_data.motion_blur_hair_sh); + DRW_SHADER_FREE_SAFE(e_data.velocity_tiles_sh); + DRW_SHADER_FREE_SAFE(e_data.velocity_tiles_expand_sh); } diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index f5ebbe08dd1..a075210967c 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -155,7 +155,7 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ao_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->ao_accum_fb); GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 40008c5c364..5005c5a8ba9 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -29,6 +29,8 @@ #include "DNA_lightprobe_types.h" +#include "BKE_camera.h" + struct EEVEE_ShadowCasterBuffer; struct GPUFrameBuffer; struct Object; @@ -256,7 +258,12 @@ typedef struct EEVEE_PassList { struct DRWPass *sss_translucency_ps; struct DRWPass *color_downsample_ps; struct DRWPass *color_downsample_cube_ps; + struct DRWPass *velocity_object; + struct DRWPass *velocity_hair; struct DRWPass *velocity_resolve; + struct DRWPass *velocity_tiles_x; + struct DRWPass *velocity_tiles; + struct DRWPass *velocity_tiles_expand[2]; struct DRWPass *taa_resolve; struct DRWPass *alpha_checker; @@ -327,6 +334,8 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *renderpass_fb; struct GPUFrameBuffer *ao_accum_fb; struct GPUFrameBuffer *velocity_resolve_fb; + struct GPUFrameBuffer *velocity_fb; + struct GPUFrameBuffer *velocity_tiles_fb[2]; struct GPUFrameBuffer *update_noise_fb; @@ -556,6 +565,58 @@ enum { PROBE_UPDATE_ALL = 0xFFFFFF, }; +/* ************** MOTION BLUR ************ */ + +#define MB_PREV 0 +#define MB_NEXT 1 +#define MB_CURR 2 + +typedef struct EEVEE_MotionBlurData { + struct GHash *object; + struct GHash *geom; + struct { + float viewmat[4][4]; + float persmat[4][4]; + float persinv[4][4]; + } camera[3]; + DRWShadingGroup *hair_grp; +} EEVEE_MotionBlurData; + +typedef struct EEVEE_ObjectKey { + /** Object or source object for duplis */ + struct Object *ob; + /** Parent object for duplis */ + struct Object *parent; + /** Dupli objects recursive unique identifier */ + int id[16]; /* 2*MAX_DUPLI_RECUR */ +} EEVEE_ObjectKey; + +typedef struct EEVEE_ObjectMotionData { + float obmat[3][4][4]; +} EEVEE_ObjectMotionData; + +typedef enum eEEVEEMotionData { + EEVEE_MESH_GEOM_MOTION_DATA = 0, + EEVEE_HAIR_GEOM_MOTION_DATA, +} eEEVEEMotionData; + +typedef struct EEVEE_GeometryMotionData { + eEEVEEMotionData type; + int use_deform; /* To disable deform mb if vertcount mismatch. */ + union { + struct { + /* Mesh */ + struct GPUBatch *batch; /* Batch for time = t. */ + struct GPUVertBuf *vbo[2]; /* Vbo for time = t +/- step. */ + }; + struct { + /* Hair */ + struct GPUVertBuf *hair_pos[2]; /* Position buffer for time = t +/- step. */ + struct GPUTexture *hair_pos_tx[2]; /* Buffer Texture of the corresponding VBO. */ + }; + }; +} EEVEE_GeometryMotionData; + /* ************ EFFECTS DATA ************* */ typedef enum EEVEE_EffectsFlag { @@ -607,9 +668,10 @@ typedef struct EEVEE_EffectsInfo { int taa_render_sample; int taa_total_sample; float taa_alpha; + bool bypass_drawing; bool prev_drw_support; bool prev_is_navigating; - float prev_drw_persmat[4][4]; + float prev_drw_persmat[4][4]; /* Used for checking view validity and reprojection. */ struct DRWView *taa_view; /* Ambient Occlusion */ int ao_depth_layer; @@ -617,15 +679,24 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *gtao_horizons; /* Textures from pool */ struct GPUTexture *gtao_horizons_debug; /* Motion Blur */ - float current_world_to_ndc[4][4]; float current_ndc_to_world[4][4]; + float current_world_to_ndc[4][4]; + float current_world_to_view[4][4]; float past_world_to_ndc[4][4]; - int motion_blur_samples; - bool motion_blur_mat_cached; + float past_world_to_view[4][4]; + CameraParams past_cam_params; + CameraParams current_cam_params; + char motion_blur_step; /* Which step we are evaluating. */ + int motion_blur_max; /* Maximum distance in pixels a motion blured pixel can cover. */ + float motion_blur_near_far[2]; /* Camera near/far clip distances (positive). */ + bool cam_params_init; + /* TODO(fclem) Only used in render mode for now. + * This is because we are missing a per scene persistent place to hold this. */ + struct EEVEE_MotionBlurData motion_blur; /* Velocity Pass */ - float velocity_curr_persinv[4][4]; - float velocity_past_persmat[4][4]; struct GPUTexture *velocity_tx; /* Texture from pool */ + struct GPUTexture *velocity_tiles_x_tx; + struct GPUTexture *velocity_tiles_tx; /* Depth Of Field */ float dof_near_far[2]; float dof_params[2]; @@ -805,6 +876,7 @@ typedef struct EEVEE_ObjectEngineData { bool ob_vis, ob_vis_dirty; bool need_update; + bool geom_update; uint shadow_caster_id; } EEVEE_ObjectEngineData; @@ -880,15 +952,25 @@ typedef struct EEVEE_PrivateData { struct DRWView *world_views[6]; /** For rendering planar reflections. */ struct DRWView *planar_views[MAX_PLANAR]; + + int render_tot_samples; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ +void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb); +void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb); void EEVEE_view_layer_data_free(void *sldata); EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void); EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_layer); EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void); EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob); EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob); +EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair); +EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair); EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob); EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob); EEVEE_LightEngineData *EEVEE_light_data_get(Object *ob); @@ -896,6 +978,8 @@ EEVEE_LightEngineData *EEVEE_light_data_ensure(Object *ob); EEVEE_WorldEngineData *EEVEE_world_data_get(World *wo); EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo); +void eevee_id_update(void *vedata, ID *id); + /* eevee_materials.c */ struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, @@ -1112,8 +1196,17 @@ void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data void EEVEE_subsurface_free(void); /* eevee_motion_blur.c */ -int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera); +int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_motion_blur_step_set(EEVEE_Data *vedata, int step); void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *ob); +void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + Object *ob, + struct ParticleSystem *psys, + struct ModifierData *md); +void EEVEE_motion_blur_swap_data(EEVEE_Data *vedata); +void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata); void EEVEE_motion_blur_draw(EEVEE_Data *vedata); void EEVEE_motion_blur_free(void); @@ -1127,6 +1220,7 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata); void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); +void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, bool post_effect); @@ -1140,6 +1234,7 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata); /* eevee_temporal_sampling.c */ void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata); +void EEVEE_temporal_sampling_create_view(EEVEE_Data *vedata); int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_temporal_sampling_offset_calc(const double ht_point[2], const float filter_size, @@ -1183,6 +1278,10 @@ void EEVEE_effects_free(void); bool EEVEE_render_init(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph); +void EEVEE_render_view_sync(EEVEE_Data *vedata, + struct RenderEngine *engine, + struct Depsgraph *depsgraph); +void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_render_cache(void *vedata, struct Object *ob, struct RenderEngine *engine, @@ -1191,6 +1290,10 @@ void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const struct rcti *rect); +void EEVEE_render_read_result(EEVEE_Data *vedata, + struct RenderEngine *engine, + struct RenderLayer *rl, + const rcti *rect); void EEVEE_render_update_passes(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 89a5ad2198a..f903fa905e8 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -131,6 +131,29 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * &sldata->common_data); } + EEVEE_render_view_sync(vedata, engine, depsgraph); + + /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ + struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); + + DRWView *view = (DRWView *)DRW_view_default_get(); + DRW_view_camtexco_set(view, camtexcofac); + + /* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`. + * `EEVEE_effects_init` needs to go second for TAA. */ + EEVEE_renderpasses_init(vedata); + EEVEE_effects_init(sldata, vedata, ob_camera_eval, false); + EEVEE_materials_init(sldata, vedata, stl, fbl); + EEVEE_shadows_init(sldata); + EEVEE_lightprobes_init(sldata, vedata); + + return true; +} + +void EEVEE_render_view_sync(EEVEE_Data *vedata, RenderEngine *engine, struct Depsgraph *depsgraph) +{ + EEVEE_PrivateData *g_data = vedata->stl->g_data; + /* Set the pers & view matrix. */ float winmat[4][4], viewmat[4][4], viewinv[4][4]; /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ @@ -143,19 +166,13 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * invert_m4_m4(viewmat, viewinv); DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); - DRW_view_camtexco_set(view, camtexcofac); + DRW_view_reset(); DRW_view_default_set(view); DRW_view_set_active(view); +} - /* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`. - * `EEVEE_effects_init` needs to go second for TAA. */ - EEVEE_renderpasses_init(vedata); - EEVEE_effects_init(sldata, vedata, ob_camera_eval, false); - EEVEE_materials_init(sldata, vedata, stl, fbl); - EEVEE_shadows_init(sldata); - EEVEE_lightprobes_init(sldata, vedata); - - /* INIT CACHE */ +void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ EEVEE_bloom_cache_init(sldata, vedata); EEVEE_depth_of_field_cache_init(sldata, vedata); EEVEE_effects_cache_init(sldata, vedata); @@ -168,8 +185,6 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * EEVEE_subsurface_cache_init(sldata, vedata); EEVEE_temporal_sampling_cache_init(sldata, vedata); EEVEE_volumes_cache_init(sldata, vedata); - - return true; } /* Used by light cache. in this case engine is NULL. */ @@ -182,6 +197,8 @@ void EEVEE_render_cache(void *vedata, EEVEE_LightProbesInfo *pinfo = sldata->probes; bool cast_shadow = false; + eevee_id_update(vedata, &ob->id); + if (pinfo->vis_data.collection) { /* Used for rendering probe with visibility groups. */ bool ob_vis = BKE_collection_has_object_recursive(pinfo->vis_data.collection, ob); @@ -478,27 +495,12 @@ static void eevee_render_draw_background(EEVEE_Data *vedata) void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl, const rcti *rect) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); const char *viewname = RE_GetActiveRenderView(engine->re); EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); - EEVEE_PrivateData *g_data = stl->g_data; - - /* FINISH CACHE */ - EEVEE_volumes_cache_finish(sldata, vedata); - EEVEE_materials_cache_finish(sldata, vedata); - EEVEE_lights_cache_finish(sldata, vedata); - EEVEE_lightprobes_cache_finish(sldata, vedata); - - EEVEE_effects_draw_init(sldata, vedata); - EEVEE_volumes_draw_init(sldata, vedata); - - /* Sort transparents before the loop. */ - DRW_pass_sort_shgroup_z(psl->transparent_pass); /* Push instances attributes to the GPU. */ DRW_render_instance_buffer_finish(); @@ -508,20 +510,17 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl GPU_framebuffer_bind(fbl->main_fb); DRW_hair_update(); - uint tot_sample = scene_eval->eevee.taa_render_samples; + /* Sort transparents before the loop. */ + DRW_pass_sort_shgroup_z(psl->transparent_pass); + + uint tot_sample = stl->g_data->render_tot_samples; uint render_samples = 0; /* SSR needs one iteration to start properly. */ - if (stl->effects->enabled_effects & EFFECT_SSR) { + if ((stl->effects->enabled_effects & EFFECT_SSR) && !stl->effects->ssr_was_valid_double_buffer) { tot_sample += 1; } - EEVEE_renderpasses_output_init(sldata, vedata, tot_sample); - - if (RE_engine_test_break(engine)) { - return; - } - while (render_samples < tot_sample && !RE_engine_test_break(engine)) { float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float clear_depth = 1.0f; @@ -617,6 +616,15 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl RE_engine_update_progress(engine, (float)(render_samples++) / (float)tot_sample); } +} + +void EEVEE_render_read_result(EEVEE_Data *vedata, + RenderEngine *engine, + RenderLayer *rl, + const rcti *rect) +{ + const char *viewname = RE_GetActiveRenderView(engine->re); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); eevee_render_result_combined(rl, viewname, rect, vedata, sldata); eevee_render_result_mist(rl, viewname, rect, vedata, sldata); @@ -631,9 +639,6 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl eevee_render_result_bloom(rl, viewname, rect, vedata, sldata); eevee_render_result_volume_scatter(rl, viewname, rect, vedata, sldata); eevee_render_result_volume_transmittance(rl, viewname, rect, vedata, sldata); - - /* Restore original viewport size. */ - DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]}); } void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 9a47ca19e7b..be771d7cf42 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -136,24 +136,13 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; - EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; EEVEE_PrivateData *g_data = stl->g_data; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); const bool needs_post_processing = (g_data->render_passes & EEVEE_RENDERPASSES_WITH_POST_PROCESSING) > 0; if (needs_post_processing) { - if (e_data.postprocess_sh == NULL) { - char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_common_uniforms_lib_glsl, - datatoc_bsdf_common_lib_glsl, - datatoc_renderpass_postprocess_frag_glsl); - e_data.postprocess_sh = DRW_shader_create_fullscreen(frag_str, NULL); - MEM_freeN(frag_str); - } - /* Create FrameBuffer. */ /* Should be enough to store the data needs for a single pass. @@ -188,29 +177,51 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, EEVEE_volumes_output_init(sldata, vedata, tot_samples); } - /* Create Pass. */ - DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.postprocess_sh, psl->renderpass_pass); /* We set a default texture as not all post processes uses the inputBuffer. */ g_data->renderpass_input = txl->color; g_data->renderpass_col_input = txl->color; g_data->renderpass_light_input = txl->color; + } + else { + /* Free unneeded memory */ + DRW_TEXTURE_FREE_SAFE(txl->renderpass); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb); + } +} + +void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_PrivateData *g_data = vedata->stl->g_data; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + const bool needs_post_processing = (g_data->render_passes & + EEVEE_RENDERPASSES_WITH_POST_PROCESSING) > 0; + if (needs_post_processing) { + if (e_data.postprocess_sh == NULL) { + char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_renderpass_postprocess_frag_glsl); + e_data.postprocess_sh = DRW_shader_create_fullscreen(frag_str, NULL); + MEM_freeN(frag_str); + } + + DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.postprocess_sh, psl->renderpass_pass); DRW_shgroup_uniform_texture_ref(grp, "inputBuffer", &g_data->renderpass_input); DRW_shgroup_uniform_texture_ref(grp, "inputColorBuffer", &g_data->renderpass_col_input); DRW_shgroup_uniform_texture_ref( grp, "inputSecondLightBuffer", &g_data->renderpass_light_input); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_uniform_block_ref(grp, "common_block", &sldata->common_ubo); + DRW_shgroup_uniform_block_ref(grp, "renderpass_block", &sldata->renderpass_ubo.combined); DRW_shgroup_uniform_int(grp, "currentSample", &g_data->renderpass_current_sample, 1); DRW_shgroup_uniform_int(grp, "renderpassType", &g_data->renderpass_type, 1); DRW_shgroup_uniform_int(grp, "postProcessType", &g_data->renderpass_postprocess, 1); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } else { - /* Free unneeded memory */ - DRW_TEXTURE_FREE_SAFE(txl->renderpass); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb); psl->renderpass_pass = NULL; } } diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index cece67334c5..32d758dba4b 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -358,7 +358,7 @@ void EEVEE_reflection_output_init(EEVEE_ViewLayerData *UNUSED(sldata), {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ssr_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->ssr_accum_fb); GPU_framebuffer_clear_color(fbl->ssr_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index 84c50a22ae6..d0e430e115f 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -412,7 +412,7 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->shadow_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->shadow_accum_fb); GPU_framebuffer_clear_color(fbl->shadow_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 7674148f76a..ef4588f4aca 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -75,18 +75,8 @@ static void eevee_create_shader_subsurface(void) MEM_freeN(frag_str); } -void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *UNUSED(vedata)) { - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - - effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; - effects->sss_surface_count = 0; - common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; } void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) @@ -197,22 +187,31 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), * already higher than one. This is noticeable when loading a file that has the diffuse light * pass in look dev mode active. `texture_created` will make sure that newly created textures * are cleared. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1 || texture_created) { + if (effects->taa_current_sample == 1 || texture_created) { float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; GPU_framebuffer_bind(fbl->sss_accum_fb); GPU_framebuffer_clear_color(fbl->sss_accum_fb, clear); } } -void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + EEVEE_EffectsInfo *effects = vedata->stl->effects; EEVEE_PassList *psl = vedata->psl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); + /* Shaders */ if (!e_data.sss_sh[0]) { eevee_create_shader_subsurface(); } + effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; + effects->sss_surface_count = 0; + common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; + /** Screen Space SubSurface Scattering overview * TODO */ diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index d57048f2c4e..714481c39f1 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -186,6 +186,18 @@ void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata) vedata->stl->effects->taa_current_sample = 1; } +void EEVEE_temporal_sampling_create_view(EEVEE_Data *vedata) +{ + EEVEE_EffectsInfo *effects = vedata->stl->effects; + /* Create a sub view to disable clipping planes (if any). */ + const DRWView *default_view = DRW_view_default_get(); + float viewmat[4][4], winmat[4][4]; + DRW_view_viewmat_get(default_view, viewmat, false); + DRW_view_winmat_get(default_view, winmat, false); + effects->taa_view = DRW_view_create_sub(default_view, viewmat, winmat); + DRW_view_clip_planes_set(effects->taa_view, NULL, 0); +} + int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; @@ -201,15 +213,9 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * we accumulate the redraw inside the drawing loop in eevee_draw_scene(). **/ effects->taa_render_sample = 1; - effects->taa_view = NULL; + effects->bypass_drawing = false; - /* Create a sub view to disable clipping planes (if any). */ - const DRWView *default_view = DRW_view_default_get(); - float viewmat[4][4], winmat[4][4]; - DRW_view_viewmat_get(default_view, viewmat, false); - DRW_view_winmat_get(default_view, winmat, false); - effects->taa_view = DRW_view_create_sub(default_view, viewmat, winmat); - DRW_view_clip_planes_set(effects->taa_view, NULL, 0); + EEVEE_temporal_sampling_create_view(vedata); const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); @@ -241,7 +247,6 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data DRW_view_persmat_get(NULL, persmat, false); view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); - copy_m4_m4(effects->prev_drw_persmat, persmat); /* Prevent ghosting from probe data. */ view_is_valid = view_is_valid && (effects->prev_drw_support == DRW_state_draw_support()) && @@ -251,7 +256,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data if (((effects->taa_total_sample == 0) || (effects->taa_current_sample < effects->taa_total_sample)) || - DRW_state_is_image_render()) { + (!view_is_valid) || DRW_state_is_image_render()) { if (view_is_valid) { /* Viewport rendering updates the matrices in `eevee_draw_scene` */ if (!DRW_state_is_image_render()) { @@ -264,7 +269,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data } } else { - effects->taa_current_sample = 1; + effects->bypass_drawing = true; } return repro_flag | EFFECT_TAA | EFFECT_DOUBLE_BUFFER | EFFECT_DEPTH_DOUBLE_BUFFER | @@ -283,7 +288,7 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; - if ((effects->enabled_effects & (EFFECT_TAA | EFFECT_TAA_REPROJECT)) != 0) { + if (effects->enabled_effects & EFFECT_TAA) { struct GPUShader *sh = EEVEE_shaders_taa_resolve_sh_get(effects->enabled_effects); DRW_PASS_CREATE(psl->taa_resolve, DRW_STATE_WRITE_COLOR); @@ -295,8 +300,9 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); if (effects->enabled_effects & EFFECT_TAA_REPROJECT) { - // DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - DRW_shgroup_uniform_texture_ref(grp, "velocityBuffer", &effects->velocity_tx); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_mat4(grp, "prevViewProjectionMatrix", effects->prev_drw_persmat); } else { DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1); @@ -359,10 +365,13 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) effects->taa_current_sample += 1; } else { - if ((effects->taa_total_sample == 0) || - (effects->taa_current_sample < effects->taa_total_sample)) { + if (!DRW_state_is_playback() && + ((effects->taa_total_sample == 0) || + (effects->taa_current_sample < effects->taa_total_sample))) { DRW_viewport_request_redraw(); } } + + DRW_view_persmat_get(NULL, effects->prev_drw_persmat, false); } } diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 90860e94270..17f53113939 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -894,7 +894,7 @@ void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->volumetric_accum_fb); GPU_framebuffer_clear_color(fbl->volumetric_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 402d306df45..393ecaf1fc5 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -877,6 +877,14 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac) { Closure cl; cl.holdout = mix(cl1.holdout, cl2.holdout, fac); + + if (FLAG_TEST(cl1.flag, CLOSURE_HOLDOUT_FLAG)) { + fac = 1.0; + } + else if (FLAG_TEST(cl2.flag, CLOSURE_HOLDOUT_FLAG)) { + fac = 0.0; + } + cl.transmittance = mix(cl1.transmittance, cl2.transmittance, fac); cl.radiance = mix(cl1.radiance, cl2.radiance, fac); cl.flag = cl1.flag | cl2.flag; @@ -958,7 +966,7 @@ void main() { Closure cl = nodetree_exec(); - float holdout = 1.0 - saturate(cl.holdout); + float holdout = saturate(1.0 - cl.holdout); float transmit = saturate(avg(cl.transmittance)); float alpha = 1.0 - transmit; @@ -972,8 +980,9 @@ void main() * Since we do that using the blending pipeline we need to account for material transmittance. */ vol_scatter -= vol_scatter * cl.transmittance; - outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, alpha * holdout); - outTransmittance = vec4(cl.transmittance, transmit * holdout); + cl.radiance = cl.radiance * holdout * vol_transmit + vol_scatter; + outRadiance = vec4(cl.radiance, alpha * holdout); + outTransmittance = vec4(cl.transmittance, transmit) * holdout; # else outRadiance = vec4(cl.radiance, holdout); ssrNormals = cl.ssr_normal; diff --git a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl index b7935235d06..fbf507a2e40 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl @@ -1,64 +1,235 @@ +/* + * Based on: + * A Fast and Stable Feature-Aware Motion Blur Filter + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + * + * With modification from the presentation: + * Next Generation Post Processing in Call of Duty Advanced Warfare + * by Jorge Jimenez + */ uniform sampler2D colorBuffer; uniform sampler2D depthBuffer; +uniform sampler2D velocityBuffer; +uniform sampler2D tileMaxBuffer; -/* current frame */ -uniform mat4 currInvViewProjMatrix; +#define KERNEL 8 -/* past frame frame */ -uniform mat4 pastViewProjMatrix; +/* TODO(fclem) deduplicate this code. */ +uniform sampler2DArray utilTex; +#define LUT_SIZE 64 +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) + +uniform float depthScale; +uniform ivec2 tileBufferSize; +uniform vec2 viewportSize; +uniform vec2 viewportSizeInv; +uniform bool isPerspective; +uniform vec2 nearFar; /* Near & far view depths values */ + +#define linear_depth(z) \ + ((isPerspective) ? (nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) : \ + z * (nearFar.y - nearFar.x) + nearFar.x) /* Only true for camera view! */ in vec4 uvcoordsvar; -out vec4 FragColor; +out vec4 fragColor; -#define MAX_SAMPLE 64 +#define saturate(a) clamp(a, 0.0, 1.0) -uniform int samples; +vec2 spread_compare(float center_motion_length, float sample_motion_length, float offset_length) +{ + return saturate(vec2(center_motion_length, sample_motion_length) - offset_length + 1.0); +} -float wang_hash_noise(uint s) +vec2 depth_compare(float center_depth, float sample_depth) { - uint seed = (uint(gl_FragCoord.x) * 1664525u + uint(gl_FragCoord.y)) + s; + return saturate(0.5 + vec2(depthScale, -depthScale) * (sample_depth - center_depth)); +} - seed = (seed ^ 61u) ^ (seed >> 16u); - seed *= 9u; - seed = seed ^ (seed >> 4u); - seed *= 0x27d4eb2du; - seed = seed ^ (seed >> 15u); +/* Kill contribution if not going the same direction. */ +float dir_compare(vec2 offset, vec2 sample_motion, float sample_motion_length) +{ + if (sample_motion_length < 0.5) { + return 1.0; + } + return (dot(offset, sample_motion) > 0.0) ? 1.0 : 0.0; +} - float value = float(seed); - value *= 1.0 / 4294967296.0; - return fract(value); +/* Return background (x) and foreground (y) weights. */ +vec2 sample_weights(float center_depth, + float sample_depth, + float center_motion_length, + float sample_motion_length, + float offset_length) +{ + /* Clasify foreground/background. */ + vec2 depth_weight = depth_compare(center_depth, sample_depth); + /* Weight if sample is overlapping or under the center pixel. */ + vec2 spread_weight = spread_compare(center_motion_length, sample_motion_length, offset_length); + return depth_weight * spread_weight; } -void main() +vec4 decode_velocity(vec4 velocity) { - vec3 ndc_pos; - ndc_pos.xy = uvcoordsvar.xy; - ndc_pos.z = texture(depthBuffer, uvcoordsvar.xy).x; + velocity = velocity * 2.0 - 1.0; + /* Needed to match cycles. Can't find why... (fclem) */ + velocity *= 0.5; + /* Transpose to pixelspace. */ + velocity *= viewportSize.xyxy; + return velocity; +} - float inv_samples = 1.0 / float(samples); - float noise = 2.0 * wang_hash_noise(0u) * inv_samples; +vec4 sample_velocity(vec2 uv) +{ + vec4 data = texture(velocityBuffer, uv); + return decode_velocity(data); +} - /* Normalize Device Coordinates are [-1, +1]. */ - ndc_pos = ndc_pos * 2.0 - 1.0; +vec2 sample_velocity(vec2 uv, const bool next) +{ + vec4 data = sample_velocity(uv); + data.xy = (next ? data.zw : data.xy); + return data.xy; +} - vec4 p = currInvViewProjMatrix * vec4(ndc_pos, 1.0); - vec3 world_pos = p.xyz / p.w; /* Perspective divide */ +void gather_sample(vec2 screen_uv, + float center_depth, + float center_motion_len, + vec2 offset, + float offset_len, + const bool next, + inout vec4 accum, + inout vec4 accum_bg, + inout vec3 w_accum) +{ + vec2 sample_uv = screen_uv - offset * viewportSizeInv; + vec2 sample_motion = sample_velocity(sample_uv, next); + float sample_motion_len = length(sample_motion); + float sample_depth = linear_depth(texture(depthBuffer, sample_uv).r); + vec4 col = textureLod(colorBuffer, sample_uv, 0.0); + + vec3 weights; + weights.xy = sample_weights( + center_depth, sample_depth, center_motion_len, sample_motion_len, offset_len); + weights.z = dir_compare(offset, sample_motion, sample_motion_len); + weights.xy *= weights.z; + + accum += col * weights.y; + accum_bg += col * weights.x; + w_accum += weights; +} - /* Now find where was this pixel position - * inside the past camera viewport */ - vec4 old_ndc = pastViewProjMatrix * vec4(world_pos, 1.0); - old_ndc.xyz /= old_ndc.w; /* Perspective divide */ +void gather_blur(vec2 screen_uv, + vec2 center_motion, + float center_depth, + vec2 max_motion, + float ofs, + const bool next, + inout vec4 accum, + inout vec4 accum_bg, + inout vec3 w_accum) +{ + float center_motion_len = length(center_motion); + float max_motion_len = length(max_motion); + + /* Tile boundaries randomization can fetch a tile where there is less motion than this pixel. + * Fix this by overriding the max_motion. */ + if (max_motion_len < center_motion_len) { + max_motion_len = center_motion_len; + max_motion = center_motion; + } - vec2 motion = (ndc_pos.xy - old_ndc.xy) * 0.25; /* 0.25 fit cycles ref */ + if (max_motion_len < 0.5) { + return; + } - float inc = 2.0 * inv_samples; - float i = -1.0 + noise; + int i; + float t, inc = 1.0 / float(KERNEL); + for (i = 0, t = ofs * inc; i < KERNEL; i++, t += inc) { + gather_sample(screen_uv, + center_depth, + center_motion_len, + max_motion * t, + max_motion_len * t, + next, + accum, + accum_bg, + w_accum); + } - FragColor = vec4(0.0); - for (int j = 0; j < samples && j < MAX_SAMPLE; j++) { - FragColor += textureLod(colorBuffer, uvcoordsvar.xy + motion * i, 0.0) * inv_samples; - i += inc; + if (center_motion_len < 0.5) { + return; } + + for (i = 0, t = ofs * inc; i < KERNEL; i++, t += inc) { + /* Also sample in center motion direction. + * Allow to recover motion where there is conflicting + * motion between foreground and background. */ + gather_sample(screen_uv, + center_depth, + center_motion_len, + center_motion * t, + center_motion_len * t, + next, + accum, + accum_bg, + w_accum); + } +} + +void main() +{ + vec2 uv = uvcoordsvar.xy; + + /* Data of the center pixel of the gather (target). */ + float center_depth = linear_depth(texture(depthBuffer, uv).r); + vec4 center_motion = sample_velocity(uv); + vec4 center_color = textureLod(colorBuffer, uv, 0.0); + + vec2 rand = texelfetch_noise_tex(gl_FragCoord.xy).xy; + + /* Randomize tile boundary to avoid ugly discontinuities. Randomize 1/4th of the tile. + * Note this randomize only in one direction but in practice it's enough. */ + rand.x = rand.x * 2.0 - 1.0; + ivec2 tile = ivec2(gl_FragCoord.xy + rand.x * float(EEVEE_VELOCITY_TILE_SIZE) * 0.25) / + EEVEE_VELOCITY_TILE_SIZE; + tile = clamp(tile, ivec2(0), tileBufferSize - 1); + vec4 max_motion = decode_velocity(texelFetch(tileMaxBuffer, tile, 0)); + + /* First (center) sample: time = T */ + /* x: Background, y: Foreground, z: dir. */ + vec3 w_accum = vec3(0.0, 0.0, 1.0); + vec4 accum_bg = vec4(0.0); + vec4 accum = vec4(0.0); + /* First linear gather. time = [T - delta, T] */ + gather_blur( + uv, center_motion.xy, center_depth, max_motion.xy, rand.y, false, accum, accum_bg, w_accum); + /* Second linear gather. time = [T, T + delta] */ + gather_blur( + uv, center_motion.zw, center_depth, max_motion.zw, rand.y, true, accum, accum_bg, w_accum); + +#if 1 + /* Avoid division by 0.0. */ + float w = 1.0 / (50.0 * float(KERNEL) * 4.0); + accum_bg += center_color * w; + w_accum.x += w; + /* Note: In Jimenez's presentation, they used center sample. + * We use background color as it contains more informations for foreground + * elements that have not enough weights. + * Yield beter blur in complex motion. */ + center_color = accum_bg / w_accum.x; +#endif + /* Merge background. */ + accum += accum_bg; + w_accum.y += w_accum.x; + /* Balance accumulation for failled samples. + * We replace the missing foreground by the background. */ + float blend_fac = saturate(1.0 - w_accum.y / w_accum.z); + fragColor = (accum / w_accum.z) + center_color * blend_fac; + +#if 0 /* For debugging. */ + fragColor.rgb = fragColor.ggg; + fragColor.rg += max_motion.xy; +#endif } diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl index 428318e3c68..b44645174bd 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl @@ -1,6 +1,6 @@ uniform sampler2D colorHistoryBuffer; -uniform sampler2D velocityBuffer; +uniform mat4 prevViewProjectionMatrix; out vec4 FragColor; @@ -38,16 +38,19 @@ vec3 clip_to_aabb(vec3 color, vec3 minimum, vec3 maximum, vec3 average) */ void main() { + vec2 screen_res = vec2(textureSize(colorBuffer, 0).xy); + vec2 uv = gl_FragCoord.xy / screen_res; ivec2 texel = ivec2(gl_FragCoord.xy); - vec2 motion = texelFetch(velocityBuffer, texel, 0).rg; - - /* Decode from unsigned normalized 16bit texture. */ - motion = motion * 2.0 - 1.0; /* Compute pixel position in previous frame. */ - vec2 screen_res = vec2(textureSize(colorBuffer, 0).xy); - vec2 uv = gl_FragCoord.xy / screen_res; - vec2 uv_history = uv - motion; + float depth = textureLod(depthBuffer, uv, 0.0).r; + vec3 pos = get_world_space_from_depth(uv, depth); + vec2 uv_history = project_point(prevViewProjectionMatrix, pos).xy * 0.5 + 0.5; + + /* HACK: Reject lookdev spheres from TAA reprojection. */ + if (depth == 0.0) { + uv_history = uv; + } ivec2 texel_history = ivec2(uv_history * screen_res); vec4 color_history = textureLod(colorHistoryBuffer, uv_history, 0.0); diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl index 7d701bce5cb..d927fd78d30 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl @@ -1,8 +1,9 @@ -uniform mat4 currPersinv; -uniform mat4 pastPersmat; +uniform mat4 prevViewProjMatrix; +uniform mat4 currViewProjMatrixInv; +uniform mat4 nextViewProjMatrix; -out vec2 outData; +out vec4 outData; void main() { @@ -12,13 +13,12 @@ void main() float depth = texelFetch(depthBuffer, texel, 0).r; - vec3 world_position = project_point(currPersinv, vec3(uv, depth) * 2.0 - 1.0); - vec2 uv_history = project_point(pastPersmat, world_position).xy * 0.5 + 0.5; + vec3 world_position = project_point(currViewProjMatrixInv, vec3(uv, depth) * 2.0 - 1.0); + vec2 uv_prev = project_point(prevViewProjMatrix, world_position).xy * 0.5 + 0.5; + vec2 uv_next = project_point(nextViewProjMatrix, world_position).xy * 0.5 + 0.5; - outData = uv - uv_history; - - /* HACK: Reject lookdev spheres from TAA reprojection. */ - outData = (depth > 0.0) ? outData : vec2(0.0); + outData.xy = uv_prev - uv; + outData.zw = uv_next - uv; /* Encode to unsigned normalized 16bit texture. */ outData = outData * 0.5 + 0.5; diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl new file mode 100644 index 00000000000..0eb598521af --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl @@ -0,0 +1,151 @@ +/** + * Shaders that down-sample velocity buffer, + * + * Based on: + * A Fast and Stable Feature-Aware Motion Blur Filter + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + * + * Adapted from G3D Innovation Engine implementation. + */ + +uniform sampler2D velocityBuffer; +uniform vec2 viewportSize; +uniform vec2 viewportSizeInv; +uniform ivec2 velocityBufferSize; + +out vec4 tileMaxVelocity; + +vec4 sample_velocity(ivec2 texel) +{ + texel = clamp(texel, ivec2(0), velocityBufferSize - 1); + vec4 data = texelFetch(velocityBuffer, texel, 0); + /* Decode data. */ + return (data * 2.0 - 1.0) * viewportSize.xyxy; +} + +vec4 encode_velocity(vec4 velocity) +{ + return velocity * viewportSizeInv.xyxy * 0.5 + 0.5; +} + +#ifdef TILE_GATHER + +uniform ivec2 gatherStep; + +void main() +{ + vec4 max_motion = vec4(0.0); + float max_motion_len_sqr_prev = 0.0; + float max_motion_len_sqr_next = 0.0; + ivec2 texel = ivec2(gl_FragCoord.xy); + texel = texel * gatherStep.yx + texel * EEVEE_VELOCITY_TILE_SIZE * gatherStep; + + for (int i = 0; i < EEVEE_VELOCITY_TILE_SIZE; ++i) { + vec4 motion = sample_velocity(texel + i * gatherStep); + float motion_len_sqr_prev = dot(motion.xy, motion.xy); + float motion_len_sqr_next = dot(motion.zw, motion.zw); + + if (motion_len_sqr_prev > max_motion_len_sqr_prev) { + max_motion_len_sqr_prev = motion_len_sqr_prev; + max_motion.xy = motion.xy; + } + if (motion_len_sqr_next > max_motion_len_sqr_next) { + max_motion_len_sqr_next = motion_len_sqr_next; + max_motion.zw = motion.zw; + } + } + + tileMaxVelocity = encode_velocity(max_motion); +} + +#else /* TILE_EXPANSION */ + +bool neighbor_affect_this_tile(ivec2 offset, vec2 velocity) +{ + /* Manhattan distance to the tiles, which is used for + * differentiating corners versus middle blocks */ + float displacement = float(abs(offset.x) + abs(offset.y)); + /** + * Relative sign on each axis of the offset compared + * to the velocity for that tile. In order for a tile + * to affect the center tile, it must have a + * neighborhood velocity in which x and y both have + * identical or both have opposite signs relative to + * offset. If the offset coordinate is zero then + * velocity is irrelevant. + **/ + vec2 point = sign(offset * velocity); + + float dist = (point.x + point.y); + /** + * Here's an example of the logic for this code. + * In this diagram, the upper-left tile has offset = (-1, -1). + * V1 is velocity = (1, -2). point in this case = (-1, 1), and therefore dist = 0, + * so the upper-left tile does not affect the center. + * + * Now, look at another case. V2 = (-1, -2). point = (1, 1), so dist = 2 and the tile + * does affect the center. + * + * V2(-1,-2) V1(1, -2) + * \ / + * \ / + * \/___ ____ ____ + * (-1, -1)| | | | + * |____|____|____| + * | | | | + * |____|____|____| + * | | | | + * |____|____|____| + **/ + return (abs(dist) == displacement); +} + +/** + * Only gather neighborhood velocity into tiles that could be affected by it. + * In the general case, only six of the eight neighbors contribute: + * + * This tile can't possibly be affected by the center one + * | + * v + * ____ ____ ____ + * | | ///|/// | + * |____|////|//__| + * | |////|/ | + * |___/|////|____| + * | //|////| | <--- This tile can't possibly be affected by the center one + * |_///|///_|____| + **/ +void main() +{ + vec4 max_motion = vec4(0.0); + float max_motion_len_sqr_prev = -1.0; + float max_motion_len_sqr_next = -1.0; + + ivec2 tile = ivec2(gl_FragCoord.xy); + ivec2 offset = ivec2(0); + for (offset.y = -1; offset.y <= 1; ++offset.y) { + for (offset.x = -1; offset.x <= 1; ++offset.x) { + vec4 motion = sample_velocity(tile + offset); + float motion_len_sqr_prev = dot(motion.xy, motion.xy); + float motion_len_sqr_next = dot(motion.zw, motion.zw); + + if (motion_len_sqr_prev > max_motion_len_sqr_prev) { + if (neighbor_affect_this_tile(offset, motion.xy)) { + max_motion_len_sqr_prev = motion_len_sqr_prev; + max_motion.xy = motion.xy; + } + } + + if (motion_len_sqr_next > max_motion_len_sqr_next) { + if (neighbor_affect_this_tile(offset, motion.zw)) { + max_motion_len_sqr_next = motion_len_sqr_next; + max_motion.zw = motion.zw; + } + } + } + } + + tileMaxVelocity = encode_velocity(max_motion); +} + +#endif
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/object_motion_frag.glsl b/source/blender/draw/engines/eevee/shaders/object_motion_frag.glsl new file mode 100644 index 00000000000..66b098ef6c5 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/object_motion_frag.glsl @@ -0,0 +1,27 @@ + +uniform mat4 prevViewProjMatrix; +uniform mat4 currViewProjMatrix; +uniform mat4 nextViewProjMatrix; + +in vec3 prevWorldPos; +in vec3 currWorldPos; +in vec3 nextWorldPos; + +out vec4 outData; + +void main() +{ + vec4 prev_wpos = prevViewProjMatrix * vec4(prevWorldPos, 1.0); + vec4 curr_wpos = currViewProjMatrix * vec4(currWorldPos, 1.0); + vec4 next_wpos = nextViewProjMatrix * vec4(nextWorldPos, 1.0); + + vec2 prev_uv = (prev_wpos.xy / prev_wpos.w); + vec2 curr_uv = (curr_wpos.xy / curr_wpos.w); + vec2 next_uv = (next_wpos.xy / next_wpos.w); + + outData.xy = prev_uv - curr_uv; + outData.zw = next_uv - curr_uv; + + /* Encode to unsigned normalized 16bit texture. */ + outData = outData * 0.5 + 0.5; +} diff --git a/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl b/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl new file mode 100644 index 00000000000..95cd69ba310 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl @@ -0,0 +1,54 @@ + +uniform mat4 currModelMatrix; +uniform mat4 prevModelMatrix; +uniform mat4 nextModelMatrix; +uniform bool useDeform; + +#ifdef HAIR +uniform samplerBuffer prvBuffer; /* RGBA32F */ +uniform samplerBuffer nxtBuffer; /* RGBA32F */ +#else +in vec3 pos; +in vec3 prv; /* Previous frame position. */ +in vec3 nxt; /* Next frame position. */ +#endif + +out vec3 currWorldPos; +out vec3 prevWorldPos; +out vec3 nextWorldPos; + +void main() +{ +#ifdef HAIR + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + float time, thick_time, thickness; + vec3 tan, binor; + vec3 wpos; + + hair_get_pos_tan_binor_time(is_persp, + ModelMatrixInverse, + ViewMatrixInverse[3].xyz, + ViewMatrixInverse[2].xyz, + wpos, + tan, + binor, + time, + thickness, + thick_time); + + int id = hair_get_base_id(); + vec3 pos = texelFetch(hairPointBuffer, id).point_position; + vec3 prv = texelFetch(prvBuffer, id).point_position; + vec3 nxt = texelFetch(nxtBuffer, id).point_position; +#endif + prevWorldPos = (prevModelMatrix * vec4(useDeform ? prv : pos, 1.0)).xyz; + currWorldPos = (currModelMatrix * vec4(pos, 1.0)).xyz; + nextWorldPos = (nextModelMatrix * vec4(useDeform ? nxt : pos, 1.0)).xyz; + /* Use jittered projmatrix to be able to match exact sample depth (depth equal test). + * Note that currModelMatrix needs to also be equal to ModelMatrix for the samples to match. */ +#ifndef HAIR + gl_Position = ViewProjectionMatrix * vec4(currWorldPos, 1.0); +#else + gl_Position = ViewProjectionMatrix * vec4(wpos, 1.0); +#endif +} diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index 2f448b784ed..3ef20dbe9ec 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -97,8 +97,6 @@ typedef struct EXTERNAL_PrivateData { /* Do we need to update the depth or can we reuse the last calculated texture. */ bool need_depth; bool update_depth; - - float last_persmat[4][4]; } EXTERNAL_PrivateData; /* Transient data */ /* Functions */ diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 2b811f1d52e..d97bf9255d2 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -159,7 +159,7 @@ void gpencil_object_cache_sort(GPENCIL_PrivateData *pd) } } - /* Join both lists, adding infront. */ + /* Join both lists, adding in front. */ if (pd->tobjects_infront.first != NULL) { if (pd->tobjects.last != NULL) { pd->tobjects.last->next = pd->tobjects_infront.first; @@ -265,8 +265,10 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, GPENCIL_VERTEX_MODE(gpd) || pd->is_render; bool is_masked = (gpl->flag & GP_LAYER_USE_MASK) && !BLI_listbase_is_empty(&gpl->mask_layers); - float vert_col_opacity = (overide_vertcol) ? (is_vert_col_mode ? 1.0f : 0.0f) : - gpl->vertex_paint_opacity; + float vert_col_opacity = (overide_vertcol) ? + (is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) : + pd->is_render ? gpl->vertex_paint_opacity : + pd->vertex_paint_opacity; /* Negate thickness sign to tag that strokes are in screen space. * Convert to world units (by default, 1 meter = 2000 px). */ float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / GPENCIL_PIXEL_FACTOR); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 495de7ef10b..dded83bacf1 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -224,6 +224,7 @@ void GPENCIL_cache_init(void *ved) const bool is_fade_layer = ((!hide_overlay) && (!pd->is_render) && (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS)); pd->fade_layer_opacity = (is_fade_layer) ? draw_ctx->v3d->overlay.gpencil_fade_layer : -1.0f; + pd->vertex_paint_opacity = draw_ctx->v3d->overlay.gpencil_vertex_paint_opacity; /* Fade GPencil Objects. */ const bool is_fade_object = ((!hide_overlay) && (!pd->is_render) && (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS) && @@ -383,7 +384,7 @@ static void gpencil_drawcall_flush(gpIterPopulateData *iter) } /* Group drawcalls that are consecutive and with the same type. Reduces GPU driver overhead. */ -static void gp_drawcall_add( +static void gpencil_drawcall_add( gpIterPopulateData *iter, struct GPUBatch *geom, bool instancing, int v_first, int v_count) { #if DISABLE_BATCHING @@ -413,7 +414,7 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, bGPDstroke *gps, void *thunk); -static void gp_sbuffer_cache_populate(gpIterPopulateData *iter) +static void gpencil_sbuffer_cache_populate(gpIterPopulateData *iter) { iter->do_sbuffer_call = DRAW_NOW; /* In order to draw the sbuffer stroke correctly mixed with other strokes, @@ -450,7 +451,7 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl, gpencil_drawcall_flush(iter); if (iter->do_sbuffer_call) { - gp_sbuffer_cache_populate(iter); + gpencil_sbuffer_cache_populate(iter); } else { iter->do_sbuffer_call = !pd->do_fast_drawing && (gpd == pd->sbuffer_gpd) && @@ -492,8 +493,10 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, (!iter->pd->simplify_fill) && ((gps->flag & GP_STROKE_NOFILL) == 0); bool only_lines = gpl && gpf && gpl->actframe != gpf && iter->pd->use_multiedit_lines_only; + bool hide_onion = gpl && gpf && gpf->runtime.onion_id != 0 && + ((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0); - if (hide_material || (!show_stroke && !show_fill) || only_lines) { + if (hide_material || (!show_stroke && !show_fill) || only_lines || hide_onion) { return; } @@ -537,7 +540,7 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, DRW_cache_gpencil_fills_get(iter->ob, iter->pd->cfra); int vfirst = gps->runtime.fill_start * 3; int vcount = gps->tot_triangles * 3; - gp_drawcall_add(iter, geom, false, vfirst, vcount); + gpencil_drawcall_add(iter, geom, false, vfirst, vcount); } if (show_stroke) { @@ -547,13 +550,13 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, int vfirst = gps->runtime.stroke_start - 1; /* Include "potential" cyclic vertex and start adj vertex (see shader). */ int vcount = gps->totpoints + 1 + 1; - gp_drawcall_add(iter, geom, true, vfirst, vcount); + gpencil_drawcall_add(iter, geom, true, vfirst, vcount); } iter->stroke_index_last = gps->runtime.stroke_start + gps->totpoints + 1; } -static void gp_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopulateData *iter) +static void gpencil_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopulateData *iter) { bGPdata *gpd = (bGPdata *)iter->ob->data; if (gpd != iter->pd->sbuffer_gpd) { @@ -630,13 +633,13 @@ void GPENCIL_cache_populate(void *ved, Object *ob) gpencil_drawcall_flush(&iter); if (iter.do_sbuffer_call) { - gp_sbuffer_cache_populate(&iter); + gpencil_sbuffer_cache_populate(&iter); } gpencil_vfx_cache_populate(vedata, ob, iter.tgp_ob); if (pd->do_fast_drawing) { - gp_sbuffer_cache_populate_fast(vedata, &iter); + gpencil_sbuffer_cache_populate_fast(vedata, &iter); } } diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index cedd75af813..7baca28dca3 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -363,6 +363,8 @@ typedef struct GPENCIL_PrivateData { float xray_alpha; /* Mask invert uniform. */ int mask_invert; + /* Vertex Paint opacity. */ + float vertex_paint_opacity; } GPENCIL_PrivateData; /* geometry batch cache functions */ diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index 7ce7a726bb7..cf6e78f4702 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -262,6 +262,8 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat mul_v3_m4v3(ob_center, persmat, ob->obmat[3]); mul_v3_fl(ob_center, 1.0f / w); + const bool use_antialiasing = ((fx->flag & FX_PIXEL_FILTER_NEAREST) == 0); + /* Convert to uvs. */ mul_v2_fl(ob_center, 0.5f); add_v2_fl(ob_center, 0.5f); @@ -285,7 +287,8 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat DRW_shgroup_uniform_vec2_copy(grp, "targetPixelSize", pixsize_uniform); DRW_shgroup_uniform_vec2_copy(grp, "targetPixelOffset", ob_center); DRW_shgroup_uniform_vec2_copy(grp, "accumOffset", (float[2]){pixel_size[0], 0.0f}); - DRW_shgroup_uniform_int_copy(grp, "sampCount", (pixel_size[0] / vp_size_inv[0] > 3.0) ? 2 : 1); + int samp_count = (pixel_size[0] / vp_size_inv[0] > 3.0) ? 2 : 1; + DRW_shgroup_uniform_int_copy(grp, "sampCount", use_antialiasing ? samp_count : 0); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } @@ -294,7 +297,8 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat grp = gpencil_vfx_pass_create("Fx Pixelize Y", state, iter, sh); DRW_shgroup_uniform_vec2_copy(grp, "targetPixelSize", pixsize_uniform); DRW_shgroup_uniform_vec2_copy(grp, "accumOffset", (float[2]){0.0f, pixel_size[1]}); - DRW_shgroup_uniform_int_copy(grp, "sampCount", (pixel_size[1] / vp_size_inv[1] > 3.0) ? 2 : 1); + int samp_count = (pixel_size[1] / vp_size_inv[1] > 3.0) ? 2 : 1; + DRW_shgroup_uniform_int_copy(grp, "sampCount", use_antialiasing ? samp_count : 0); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } } diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index 481dec340ba..7ccb5d5a753 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -228,11 +228,12 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) { format = formats->instance_extra; - sh = OVERLAY_shader_armature_degrees_of_freedom(); + sh = OVERLAY_shader_armature_degrees_of_freedom_wire(); grp = DRW_shgroup_create(sh, armature_ps); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get()); + sh = OVERLAY_shader_armature_degrees_of_freedom_solid(); grp = DRW_shgroup_create(sh, armature_transp_ps); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get()); @@ -2167,7 +2168,8 @@ static void armature_context_setup(ArmatureDrawContext *ctx, ctx->do_relations = !DRW_state_is_select() && pd->armature.show_relations && (is_edit_mode | is_pose_mode); ctx->const_color = DRW_state_is_select() ? select_const_color : const_color; - ctx->const_wire = (((ob->base_flag & BASE_SELECTED) || (arm->drawtype == ARM_WIRE)) ? + ctx->const_wire = ((((ob->base_flag & BASE_SELECTED) && (pd->v3d_flag & V3D_SELECT_OUTLINE)) || + (arm->drawtype == ARM_WIRE)) ? 1.5f : ((!is_filled || is_transparent) ? 1.0f : 0.0f)); } diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.c b/source/blender/draw/engines/overlay/overlay_edit_text.c index c4d020adc11..4ee936f5ce6 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_text.c +++ b/source/blender/draw/engines/overlay/overlay_edit_text.c @@ -53,13 +53,22 @@ void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_vec4_copy(grp, "color", G_draw.block.colorWire); } { - state = DRW_STATE_WRITE_COLOR | DRW_STATE_LOGIC_INVERT; + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; DRW_PASS_CREATE(psl->edit_text_overlay_ps, state | pd->clipping_state); sh = OVERLAY_shader_uniform_color(); pd->edit_text_overlay_grp = grp = DRW_shgroup_create(sh, psl->edit_text_overlay_ps); - DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); + DRW_shgroup_uniform_vec4(grp, "color", pd->edit_text.overlay_color, 1); + + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL | DRW_STATE_DEPTH_GREATER_EQUAL | + pd->clipping_state; + DRW_PASS_INSTANCE_CREATE(psl->edit_text_darken_ps, psl->edit_text_overlay_ps, state); + } + { + /* Create view which will render everything (hopefully) behind the text geometry. */ + DRWView *default_view = (DRWView *)DRW_view_default_get(); + pd->view_edit_text = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, -5.0f); } } @@ -193,16 +202,24 @@ void OVERLAY_edit_text_cache_populate(OVERLAY_Data *vedata, Object *ob) void OVERLAY_edit_text_draw(OVERLAY_Data *vedata) { + OVERLAY_PrivateData *pd = vedata->stl->pd; OVERLAY_PassList *psl = vedata->psl; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + OVERLAY_FramebufferList *fbl = vedata->fbl; if (DRW_state_is_fbo()) { - /* Text overlay need final color for color inversion. */ - GPU_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_bind(fbl->overlay_default_fb); } DRW_draw_pass(psl->edit_text_wire_ps[0]); DRW_draw_pass(psl->edit_text_wire_ps[1]); + DRW_view_set_active(pd->view_edit_text); + + /* Alpha blended. */ + copy_v4_fl4(pd->edit_text.overlay_color, 0.8f, 0.8f, 0.8f, 0.5f); DRW_draw_pass(psl->edit_text_overlay_ps); + + /* Multiply previous result where depth test fail. */ + copy_v4_fl4(pd->edit_text.overlay_color, 0.0f, 0.0f, 0.0f, 1.0f); + DRW_draw_pass(psl->edit_text_darken_ps); } diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index 61337ac8d1d..e76b3c82c1d 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -423,7 +423,7 @@ static void OVERLAY_cache_finish(void *vedata) { /* TODO(fclem) Only do this when really needed. */ { - /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */ + /* HACK we allocate the in front depth here to avoid the overhead when if is not needed. */ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index 15bf26a5fa8..e591f54c750 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -1318,7 +1318,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, else { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); - if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) { + if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag && (1 << 0))) { ListBase targets = {NULL, NULL}; bConstraintTarget *ct; diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c index 5ed32de6d93..e3079870d8f 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.c +++ b/source/blender/draw/engines/overlay/overlay_grid.c @@ -41,6 +41,7 @@ enum { CLIP_ZPOS = (1 << 7), CLIP_ZNEG = (1 << 8), GRID_BACK = (1 << 9), + GRID_CAMERA = (1 << 10), }; void OVERLAY_grid_init(OVERLAY_Data *vedata) @@ -145,6 +146,9 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata) if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) { Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera); dist = ((Camera *)(camera_object->data))->clip_end; + shd->grid_flag |= GRID_CAMERA; + shd->zneg_flag |= GRID_CAMERA; + shd->zpos_flag |= GRID_CAMERA; } else { dist = v3d->clip_end; diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index ed0a9cf6981..59fa58c0c03 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -71,6 +71,7 @@ typedef struct OVERLAY_PassList { DRWPass *edit_mesh_normals_ps; DRWPass *edit_particle_ps; DRWPass *edit_text_overlay_ps; + DRWPass *edit_text_darken_ps; DRWPass *edit_text_wire_ps[2]; DRWPass *extra_ps[2]; DRWPass *extra_blend_ps; @@ -264,6 +265,7 @@ typedef struct OVERLAY_PrivateData { DRWView *view_edit_faces_cage; DRWView *view_edit_edges; DRWView *view_edit_verts; + DRWView *view_edit_text; DRWView *view_reference_images; /** TODO get rid of this. */ @@ -300,6 +302,9 @@ typedef struct OVERLAY_PrivateData { int handle_display; } edit_curve; struct { + float overlay_color[4]; + } edit_text; + struct { int ghost_ob; int edit_ob; bool do_zbufclip; @@ -563,7 +568,8 @@ void OVERLAY_wireframe_draw(OVERLAY_Data *vedata); void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *vedata); GPUShader *OVERLAY_shader_antialiasing(void); -GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void); +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_wire(void); +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_solid(void); GPUShader *OVERLAY_shader_armature_envelope(bool use_outline); GPUShader *OVERLAY_shader_armature_shape(bool use_outline); GPUShader *OVERLAY_shader_armature_shape_wire(void); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index 0610b8397a1..edf91c99531 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -31,6 +31,7 @@ extern char datatoc_antialiasing_frag_glsl[]; extern char datatoc_antialiasing_vert_glsl[]; extern char datatoc_armature_dof_vert_glsl[]; +extern char datatoc_armature_dof_solid_frag_glsl[]; extern char datatoc_armature_envelope_distance_frag_glsl[]; extern char datatoc_armature_envelope_outline_vert_glsl[]; extern char datatoc_armature_envelope_solid_frag_glsl[]; @@ -130,7 +131,8 @@ extern char datatoc_common_view_lib_glsl[]; typedef struct OVERLAY_Shaders { GPUShader *antialiasing; - GPUShader *armature_dof; + GPUShader *armature_dof_wire; + GPUShader *armature_dof_solid; GPUShader *armature_envelope_outline; GPUShader *armature_envelope_solid; GPUShader *armature_shape_outline; @@ -473,13 +475,13 @@ GPUShader *OVERLAY_shader_armature_stick(void) return sh_data->armature_stick; } -GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void) +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_wire(void) { const DRWContextState *draw_ctx = DRW_context_state_get(); const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->armature_dof) { - sh_data->armature_dof = GPU_shader_create_from_arrays({ + if (!sh_data->armature_dof_wire) { + sh_data->armature_dof_wire = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg->lib, datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl, @@ -487,10 +489,31 @@ GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void) NULL}, .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, "#define EDGE\n", NULL}, + }); + } + return sh_data->armature_dof_wire; +} + +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_solid(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->armature_dof_solid) { + sh_data->armature_dof_solid = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_armature_dof_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_armature_dof_solid_frag_glsl, + NULL}, .defs = (const char *[]){sh_cfg->def, NULL}, }); } - return sh_data->armature_dof; + return sh_data->armature_dof_solid; } GPUShader *OVERLAY_shader_armature_wire(void) diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index eebfc88fdce..ea45ad5190c 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -76,7 +76,8 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; DRWPass *pass; - GPUTexture **depth_tx = ((pd->xray_enabled || pd->xray_opacity > 0.0f) && DRW_state_is_fbo()) ? + GPUTexture **depth_tx = ((!pd->xray_enabled || pd->xray_opacity > 0.0f) && + DRW_state_is_fbo()) ? &txl->temp_depth_tx : &txl->dummy_depth_tx; diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl new file mode 100644 index 00000000000..e511aab69c1 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl @@ -0,0 +1,11 @@ + +flat in vec4 finalColor; + +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 lineOutput; + +void main() +{ + fragColor = finalColor; + lineOutput = vec4(0.0); +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl index b15554bbb6a..18a80fc1fb4 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl @@ -8,8 +8,10 @@ in vec4 color; in mat4 inst_obmat; flat out vec4 finalColor; +#ifdef EDGE flat out vec2 edgeStart; noperspective out vec2 edgePos; +#endif vec3 sphere_project(float ax, float az) { @@ -35,7 +37,9 @@ void main() gl_Position = point_world_to_ndc(world_pos); finalColor = color; +#ifdef EDGE edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; +#endif #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl index 203f6cb1901..2cefab56722 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl @@ -83,7 +83,7 @@ void main() finalColor = EDIT_MESH_facedot_color(norAndFlag.w); /* Bias Facedot Z position in clipspace. */ - gl_Position.z -= 0.00035; + gl_Position.z -= (ProjectionMatrix[3][3] == 0.0) ? 0.00035 : 1e-6; gl_PointSize = sizeFaceDot; bool occluded = test_occlusion(); diff --git a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl index 9743f918ce3..317e9fe0447 100644 --- a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl @@ -28,7 +28,8 @@ uniform float gridSteps[STEPS_LEN] = float[](0.001, 0.01, 0.1, 1.0, 10.0, 100.0, #define PLANE_XY (1 << 4) #define PLANE_XZ (1 << 5) #define PLANE_YZ (1 << 6) -#define GRID_BACK (1 << 9) /* grid is behind objects */ +#define GRID_BACK (1 << 9) /* grid is behind objects */ +#define GRID_CAMERA (1 << 10) /* In camera view */ #define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */ @@ -104,7 +105,9 @@ void main() fade *= 1.0 - smoothstep(0.0, gridDistance, dist - gridDistance); } else { - dist = abs(gl_FragCoord.z * 2.0 - 1.0); + dist = gl_FragCoord.z * 2.0 - 1.0; + /* Avoid fading in +Z direction in camera view (see T70193). */ + dist = ((gridFlag & GRID_CAMERA) != 0) ? clamp(dist, 0.0, 1.0) : abs(dist); fade = 1.0 - smoothstep(0.0, 0.5, dist - 0.5); dist = 1.0; /* avoid branch after */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl index 87d04144cde..d8cb4f86f7b 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl @@ -23,7 +23,7 @@ void cavity_compute(vec2 screenco, float depth = texture(depthBuffer, screenco).x; - /* Early out if background and infront. */ + /* Early out if background and in front. */ if (depth == 1.0 || depth == 0.0) { return; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index 0c2b7850f94..2920a504062 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -107,7 +107,6 @@ void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction) #ifdef USE_COBA float val = sample_volume_texture(densityTexture, co).r; vec4 tval = texture(transferTexture, val) * densityScale; - tval.rgb = pow(tval.rgb, vec3(2.2)); scattering = tval.rgb * 1500.0; extinction = max(1e-4, tval.a * 50.0); #else @@ -127,7 +126,7 @@ void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction) # ifdef VOLUME_SMOKE /* 800 is arbitrary and here to mimic old viewport. TODO make it a parameter */ - scattering += pow(emission.rgb, vec3(2.2)) * emission.a * 800.0; + scattering += emission.rgb * emission.a * 800.0; # endif #endif } diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 828a9127fb1..c8dde4d513b 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -174,8 +174,19 @@ static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd, color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR); if (use_single_drawcall) { - struct GPUBatch *geom = (use_vcol) ? DRW_cache_mesh_surface_vertpaint_get(ob) : - DRW_cache_object_surface_get(ob); + struct GPUBatch *geom; + if (use_vcol) { + if (ob->mode & OB_MODE_VERTEX_PAINT) { + geom = DRW_cache_mesh_surface_vertpaint_get(ob); + } + else { + geom = DRW_cache_mesh_surface_sculptcolors_get(ob); + } + } + else { + geom = DRW_cache_object_surface_get(ob); + } + if (geom) { DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, r_transp); DRW_shgroup_call(grp, geom, ob); @@ -240,15 +251,19 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, const bool is_texpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_TEXTURE); const bool is_vertpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_VERTEX); - if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (ob->dt < OB_TEXTURE)) { - color_type = V3D_SHADING_MATERIAL_COLOR; - } - /* Disable color mode if data layer is unavailable. */ - if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (me == NULL || me->mloopuv == NULL)) { - color_type = V3D_SHADING_MATERIAL_COLOR; + if (color_type == V3D_SHADING_TEXTURE_COLOR) { + if (ob->dt < OB_TEXTURE) { + color_type = V3D_SHADING_MATERIAL_COLOR; + } + else if ((me == NULL) || (me->mloopuv == NULL)) { + /* Disable color mode if data layer is unavailable. */ + color_type = V3D_SHADING_MATERIAL_COLOR; + } } - if ((color_type == V3D_SHADING_VERTEX_COLOR) && (me == NULL || me->mloopcol == NULL)) { - color_type = V3D_SHADING_OBJECT_COLOR; + else if (color_type == V3D_SHADING_VERTEX_COLOR) { + if ((me == NULL) || !CustomData_has_layer(&me->vdata, CD_PROP_COLOR)) { + color_type = V3D_SHADING_OBJECT_COLOR; + } } if (r_sculpt_pbvh) { @@ -379,7 +394,7 @@ void workbench_cache_finish(void *ved) /* TODO(fclem) Only do this when really needed. */ { - /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */ + /* HACK we allocate the in front depth here to avoid the overhead when if is not needed. */ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 0b2d508fee5..d6d3ff8610b 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -57,7 +57,7 @@ void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd, case V3D_SHADING_RANDOM_COLOR: { uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); if (ob->id.lib) { - hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name); + hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->filepath); } float hue = BLI_hash_int_01(hash); float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE}; diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 20b6d368ac0..ee9960ea0ef 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -293,7 +293,7 @@ typedef struct WORKBENCH_PrivateData { /** Object IDs buffer for curvature & outline. */ struct GPUTexture *object_id_tx; - /** Prepass infos for each draw types [transparent][infront][hair]. */ + /** Pre-pass information for each draw types [transparent][infront][hair]. */ WORKBENCH_Prepass prepass[2][2][2]; /* Materials */ diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c index 5fd8229304a..1c40a350300 100644 --- a/source/blender/draw/engines/workbench/workbench_transparent.c +++ b/source/blender/draw/engines/workbench/workbench_transparent.c @@ -157,7 +157,7 @@ void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data) WORKBENCH_FramebufferList *fbl = data->fbl; WORKBENCH_PassList *psl = data->psl; - const bool do_xray_depth_pass = XRAY_ALPHA(wpd) > 0.0f; + const bool do_xray_depth_pass = !XRAY_FLAG_ENABLED(wpd) || XRAY_ALPHA(wpd) > 0.0f; const bool do_transparent_depth_pass = psl->outline_ps || wpd->dof_enabled || do_xray_depth_pass; if (do_transparent_depth_pass) { @@ -165,14 +165,14 @@ void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data) if (!DRW_pass_is_empty(psl->transp_accum_ps)) { GPU_framebuffer_bind(fbl->opaque_fb); - /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */ + /* TODO(fclem) Disable writing to first two buffers. Unnecessary waste of bandwidth. */ DRW_pass_state_set(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state); DRW_draw_pass(psl->transp_accum_ps); } if (!DRW_pass_is_empty(psl->transp_accum_infront_ps)) { GPU_framebuffer_bind(fbl->opaque_infront_fb); - /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */ + /* TODO(fclem) Disable writing to first two buffers. Unnecessary waste of bandwidth. */ DRW_pass_state_set(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state); DRW_draw_pass(psl->transp_accum_infront_ps); } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 89dd6fa210c..555043ab408 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -462,6 +462,10 @@ void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex, eGPUSamplerState sampler_state); +void DRW_shgroup_uniform_texture_ref_ex(DRWShadingGroup *shgroup, + const char *name, + GPUTexture **tex, + eGPUSamplerState sampler_state); void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); @@ -569,7 +573,7 @@ void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float w const DRWView *DRW_view_default_get(void); void DRW_view_default_set(DRWView *view); - +void DRW_view_reset(void); void DRW_view_set_active(DRWView *view); void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len); @@ -626,6 +630,8 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, void (*callback)(void *vedata, void *user_data), void *user_data); +void DRW_cache_restart(void); + /* ViewLayers */ void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type); void **DRW_view_layer_engine_data_ensure_ex(struct ViewLayer *view_layer, diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index af5b9cd05dd..9f30cd85957 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -888,6 +888,32 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob) } } +/* Returns the vertbuf used by shaded surface batch. */ +GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob) +{ + Mesh *me = BKE_object_get_evaluated_mesh(ob); + short type = (me != NULL) ? OB_MESH : ob->type; + + switch (type) { + case OB_MESH: + return DRW_mesh_batch_cache_pos_vertbuf_get((me != NULL) ? me : ob->data); + case OB_CURVE: + case OB_SURF: + case OB_FONT: + return DRW_curve_batch_cache_pos_vertbuf_get(ob->data); + case OB_MBALL: + return DRW_mball_batch_cache_pos_vertbuf_get(ob); + case OB_HAIR: + return NULL; + case OB_POINTCLOUD: + return NULL; + case OB_VOLUME: + return NULL; + default: + return NULL; + } +} + int DRW_cache_object_material_count_get(struct Object *ob) { Mesh *me = BKE_object_get_evaluated_mesh(ob); @@ -2844,6 +2870,12 @@ GPUBatch *DRW_cache_mesh_surface_vertpaint_get(Object *ob) return DRW_mesh_batch_cache_get_surface_vertpaint(ob->data); } +GPUBatch *DRW_cache_mesh_surface_sculptcolors_get(Object *ob) +{ + BLI_assert(ob->type == OB_MESH); + return DRW_mesh_batch_cache_get_surface_sculpt(ob->data); +} + GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob) { BLI_assert(ob->type == OB_MESH); diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 221fb89612f..2f289bf4110 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -63,6 +63,8 @@ struct GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, struct GPUBatch *DRW_cache_object_face_wireframe_get(struct Object *ob); int DRW_cache_object_material_count_get(struct Object *ob); +struct GPUVertBuf *DRW_cache_object_pos_vertbuf_get(struct Object *ob); + /* Empties */ struct GPUBatch *DRW_cache_plain_axes_get(void); struct GPUBatch *DRW_cache_single_arrow_get(void); @@ -134,6 +136,7 @@ struct GPUBatch **DRW_cache_mesh_surface_shaded_get(struct Object *ob, struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_vertpaint_get(struct Object *ob); +struct GPUBatch *DRW_cache_mesh_surface_sculptcolors_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_face_wireframe_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index f203c2ff1ea..302f9a0d3a8 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -53,6 +53,7 @@ typedef struct DRW_MeshCDMask { uint32_t uv : 8; uint32_t tan : 8; uint32_t vcol : 8; + uint32_t sculpt_vcol : 8; uint32_t orco : 1; uint32_t tan_orco : 1; /** Edit uv layer is from the base edit mesh as @@ -62,7 +63,7 @@ typedef struct DRW_MeshCDMask { typedef enum eMRIterType { MR_ITER_LOOPTRI = 1 << 0, - MR_ITER_LOOP = 1 << 1, + MR_ITER_POLY = 1 << 1, MR_ITER_LEDGE = 1 << 2, MR_ITER_LVERT = 1 << 3, } eMRIterType; diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index f3dc8f0fd2a..c92722fad7e 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -128,7 +128,7 @@ typedef struct MeshRenderData { BMEdge *eed_act; BMFace *efa_act; BMFace *efa_act_uv; - /* Data created on-demand (usually not for bmesh-based data). */ + /* Data created on-demand (usually not for #BMesh based data). */ MLoopTri *mlooptri; float (*loop_normals)[3]; float (*poly_normals)[3]; @@ -145,17 +145,17 @@ static void mesh_render_data_update_loose_geom(MeshRenderData *mr, mr->vert_loose_len = 0; mr->edge_loose_len = 0; - BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, "lvert map"); + BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__); mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__); - const MEdge *medge = mr->medge; - for (int e = 0; e < mr->edge_len; e++, medge++) { - if (medge->flag & ME_LOOSEEDGE) { - mr->ledges[mr->edge_loose_len++] = e; + const MEdge *med = mr->medge; + for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) { + if (med->flag & ME_LOOSEEDGE) { + mr->ledges[mr->edge_loose_len++] = med_index; } /* Tag verts as not loose. */ - BLI_BITMAP_ENABLE(lvert_map, medge->v1); - BLI_BITMAP_ENABLE(lvert_map, medge->v2); + BLI_BITMAP_ENABLE(lvert_map, med->v1); + BLI_BITMAP_ENABLE(lvert_map, med->v2); } if (mr->edge_loose_len < mr->edge_len) { mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges)); @@ -173,11 +173,11 @@ static void mesh_render_data_update_loose_geom(MeshRenderData *mr, MEM_freeN(lvert_map); - mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2; + mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2); } } else { - /* BMesh */ + /* #BMesh */ BMesh *bm = mr->bm; if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) { int elem_id; @@ -212,7 +212,9 @@ static void mesh_render_data_update_loose_geom(MeshRenderData *mr, } } -/* Part of the creation of the MeshRenderData that happens in a thread. */ +/** + * Part of the creation of the #MeshRenderData that happens in a thread. + */ static void mesh_render_data_update_looptris(MeshRenderData *mr, const eMRIterType iter_type, const eMRDataType data_flag) @@ -227,7 +229,7 @@ static void mesh_render_data_update_looptris(MeshRenderData *mr, } } else { - /* BMesh */ + /* #BMesh */ if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { /* Edit mode ensures this is valid, no need to calculate. */ BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL)); @@ -278,9 +280,9 @@ static void mesh_render_data_update_normals(MeshRenderData *mr, } } else { - /* BMesh */ + /* #BMesh */ if (data_flag & MR_DATA_POLY_NOR) { - /* Use bmface->no instead. */ + /* Use #BMFace.no instead. */ } if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { @@ -295,7 +297,7 @@ static void mesh_render_data_update_normals(MeshRenderData *mr, } mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); - int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); + const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); BM_loops_calc_normal_vcos(mr->bm, vert_coords, vert_normals, @@ -419,7 +421,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); } else { - /* BMesh */ + /* #BMesh */ BMesh *bm = mr->bm; mr->vert_len = bm->totvert; @@ -486,7 +488,7 @@ BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *e } else { UNUSED_VARS(mr); - return eve->co; + return eve->no; } } @@ -505,48 +507,283 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Mesh Elements Extract Iter +/** \name Mesh Elements Extract: Loop Triangles + * \{ */ + +typedef struct ExtractTriBMesh_Params { + BMLoop *(*looptris)[3]; + int tri_range[2]; +} ExtractTriBMesh_Params; +typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, + const ExtractTriBMesh_Params *params, + void *data); + +#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \ + CHECK_TYPE(params, const ExtractTriBMesh_Params *); \ + { \ + const int _tri_index_end = (params)->tri_range[1]; \ + BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \ + for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \ + index_tri += 1, elem_tri += 3) +#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END } + +typedef struct ExtractTriMesh_Params { + const MLoopTri *mlooptri; + int tri_range[2]; +} ExtractTriMesh_Params; +typedef void(ExtractTriMeshFn)(const MeshRenderData *mr, + const ExtractTriMesh_Params *params, + void *data); + +#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \ + CHECK_TYPE(params, const ExtractTriMesh_Params *); \ + { \ + const int _tri_index_end = (params)->tri_range[1]; \ + const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \ + for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \ + index_tri += 1, elem_tri += 1) +#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract: Polygons, Loops + * \{ */ + +typedef struct ExtractPolyBMesh_Params { + BMLoop *(*looptris)[3]; + int poly_range[2]; +} ExtractPolyBMesh_Params; +typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data); + +#define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \ + CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ + BMFace **_ftable = mr->bm->ftable; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + BMFace *elem_poly = _ftable[index_poly]; \ + (void)elem_poly; + +#define EXTRACT_POLY_FOREACH_BM_END \ + } \ + } + +/* Iterate over polygon and loop. */ +#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \ + CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ + BMFace **_ftable = mr->bm->ftable; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + BMFace *elem_face = _ftable[index_poly]; \ + BMLoop *elem_loop, *l_first; \ + elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \ + do { \ + const int index_loop = BM_elem_index_get(elem_loop); \ + (void)index_loop; /* Quiet warning when unused. */ + +#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \ + } \ + while ((elem_loop = elem_loop->next) != l_first) \ + ; \ + } \ + } + +typedef struct ExtractPolyMesh_Params { + int poly_range[2]; +} ExtractPolyMesh_Params; +typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data); + +#define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \ + CHECK_TYPE(params, const ExtractPolyMesh_Params *); \ + { \ + const MPoly *_mpoly = mr->mpoly; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + const MPoly *elem_poly = &_mpoly[index_poly]; \ + (void)elem_poly; + +#define EXTRACT_POLY_FOREACH_MESH_END \ + } \ + } + +/* Iterate over polygon and loop. */ +#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \ + elem_poly, index_poly, elem_loop, index_loop, params, mr) \ + CHECK_TYPE(params, const ExtractPolyMesh_Params *); \ + { \ + const MPoly *_mpoly = mr->mpoly; \ + const MLoop *_mloop = mr->mloop; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + const MPoly *elem_poly = &_mpoly[index_poly]; \ + const int _index_end = elem_poly->loopstart + elem_poly->totloop; \ + for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \ + const MLoop *elem_loop = &_mloop[index_loop]; \ + (void)elem_loop; + +#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \ + } \ + } \ + } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract: Loose Edges + * \{ */ + +typedef struct ExtractLEdgeBMesh_Params { + const int *ledge; + int ledge_range[2]; +} ExtractLEdgeBMesh_Params; +typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *data); + +#define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \ + CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \ + BMEdge **_etable = mr->bm->etable; \ + const int *_ledge = (params)->ledge; \ + const int _ledge_index_end = (params)->ledge_range[1]; \ + for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \ + index_ledge += 1) { \ + BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \ + (void)elem_edge; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LEDGE_FOREACH_BM_END \ + } \ + } \ + } + +typedef struct ExtractLEdgeMesh_Params { + const int *ledge; + int ledge_range[2]; +} ExtractLEdgeMesh_Params; +typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *data); + +#define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \ + CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \ + { \ + const MEdge *_medge = mr->medge; \ + const int *_ledge = (params)->ledge; \ + const int _ledge_index_end = (params)->ledge_range[1]; \ + for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \ + index_ledge += 1) { \ + const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \ + (void)elem_edge; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LEDGE_FOREACH_MESH_END \ + } \ + } \ + } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract: Loose Vertices + * \{ */ + +typedef struct ExtractLVertBMesh_Params { + const int *lvert; + int lvert_range[2]; +} ExtractLVertBMesh_Params; +typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *data); + +#define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \ + CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ + BMVert **vtable = mr->bm->vtable; \ + const int *lverts = (params)->lvert; \ + const int _lvert_index_end = (params)->lvert_range[1]; \ + for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \ + index_lvert += 1) { \ + BMVert *elem_vert = vtable[lverts[index_lvert]]; \ + (void)elem_vert; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LVERT_FOREACH_BM_END \ + } \ + } \ + } + +typedef struct ExtractLVertMesh_Params { + const int *lvert; + int lvert_range[2]; +} ExtractLVertMesh_Params; +typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *data); + +#define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \ + CHECK_TYPE(params, const ExtractLVertMesh_Params *); \ + { \ + const MVert *mvert = mr->mvert; \ + const int *lverts = (params)->lvert; \ + const int _lvert_index_end = (params)->lvert_range[1]; \ + for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \ + index_lvert += 1) { \ + const MVert *elem = &mvert[lverts[index_lvert]]; \ + (void)elem; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LVERT_FOREACH_MESH_END \ + } \ + } \ + } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract Struct * \{ */ typedef void *(ExtractInitFn)(const MeshRenderData *mr, void *buffer); -typedef void(ExtractEditTriFn)(const MeshRenderData *mr, int t, BMLoop **e, void *data); -typedef void(ExtractEditLoopFn)(const MeshRenderData *mr, int l, BMLoop *el, void *data); -typedef void(ExtractEditLedgeFn)(const MeshRenderData *mr, int e, BMEdge *ed, void *data); -typedef void(ExtractEditLvertFn)(const MeshRenderData *mr, int v, BMVert *ev, void *data); -typedef void(ExtractTriFn)(const MeshRenderData *mr, int t, const MLoopTri *mlt, void *data); -typedef void(ExtractLoopFn)( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data); -typedef void(ExtractLedgeFn)(const MeshRenderData *mr, int e, const MEdge *medge, void *data); -typedef void(ExtractLvertFn)(const MeshRenderData *mr, int v, const MVert *mvert, void *data); typedef void(ExtractFinishFn)(const MeshRenderData *mr, void *buffer, void *data); typedef struct MeshExtract { - /** Executed on main thread and return user data for iter functions. */ + /** Executed on main thread and return user data for iteration functions. */ ExtractInitFn *init; /** Executed on one (or more if use_threading) worker thread(s). */ - ExtractEditTriFn *iter_looptri_bm; - ExtractTriFn *iter_looptri; - ExtractEditLoopFn *iter_loop_bm; - ExtractLoopFn *iter_loop; - ExtractEditLedgeFn *iter_ledge_bm; - ExtractLedgeFn *iter_ledge; - ExtractEditLvertFn *iter_lvert_bm; - ExtractLvertFn *iter_lvert; + ExtractTriBMeshFn *iter_looptri_bm; + ExtractTriMeshFn *iter_looptri_mesh; + ExtractPolyBMeshFn *iter_poly_bm; + ExtractPolyMeshFn *iter_poly_mesh; + ExtractLEdgeBMeshFn *iter_ledge_bm; + ExtractLEdgeMeshFn *iter_ledge_mesh; + ExtractLVertBMeshFn *iter_lvert_bm; + ExtractLVertMeshFn *iter_lvert_mesh; /** Executed on one worker thread after all elements iterations. */ ExtractFinishFn *finish; /** Used to request common data. */ const eMRDataType data_flag; - /** Used to know if the element callbacks are threadsafe and can be parallelized. */ + /** Used to know if the element callbacks are thread-safe and can be parallelized. */ const bool use_threading; } MeshExtract; BLI_INLINE eMRIterType mesh_extract_iter_type(const MeshExtract *ext) { eMRIterType type = 0; - SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri), MR_ITER_LOOPTRI); - SET_FLAG_FROM_TEST(type, (ext->iter_loop_bm || ext->iter_loop), MR_ITER_LOOP); - SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge), MR_ITER_LEDGE); - SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert), MR_ITER_LVERT); + SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI); + SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY); + SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE); + SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT); return type; } @@ -583,15 +820,15 @@ static void *extract_tris_init(const MeshRenderData *mr, void *UNUSED(ibo)) } } else { - const MPoly *mpoly = mr->mpoly; - for (int p = 0; p < mr->poly_len; p++, mpoly++) { - if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) { - int mat = min_ii(mpoly->mat_nr, mr->mat_len - 1); - mat_tri_len[mat] += mpoly->totloop - 2; + const MPoly *mp = mr->mpoly; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + int mat = min_ii(mp->mat_nr, mr->mat_len - 1); + mat_tri_len[mat] += mp->totloop - 2; } } } - /* Accumulate tri len per mat to have correct offsets. */ + /* Accumulate triangle lengths per material to have correct offsets. */ int ofs = mat_tri_len[0]; mat_tri_len[0] = 0; for (int i = 1; i < mr->mat_len; i++) { @@ -608,51 +845,59 @@ static void *extract_tris_init(const MeshRenderData *mr, void *UNUSED(ibo)) return data; } -static void extract_tris_looptri_bmesh(const MeshRenderData *mr, - int UNUSED(t), - BMLoop **elt, - void *_data) +static void extract_tris_iter_looptri_bm(const MeshRenderData *mr, + const struct ExtractTriBMesh_Params *params, + void *_data) { - if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { - MeshExtract_Tri_Data *data = _data; - int *mat_tri_ofs = data->tri_mat_end; - int mat = min_ii(elt[0]->f->mat_nr, mr->mat_len - 1); - GPU_indexbuf_set_tri_verts(&data->elb, - mat_tri_ofs[mat]++, - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2])); + MeshExtract_Tri_Data *data = _data; + const int mat_last = mr->mat_len - 1; + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) + { + if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { + int *mat_tri_ofs = data->tri_mat_end; + const int mat = min_ii(elt[0]->f->mat_nr, mat_last); + GPU_indexbuf_set_tri_verts(&data->elb, + mat_tri_ofs[mat]++, + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2])); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } -static void extract_tris_looptri_mesh(const MeshRenderData *mr, - int UNUSED(t), - const MLoopTri *mlt, - void *_data) +static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr, + const struct ExtractTriMesh_Params *params, + void *_data) { - const MPoly *mpoly = &mr->mpoly[mlt->poly]; - if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) { - MeshExtract_Tri_Data *data = _data; - int *mat_tri_ofs = data->tri_mat_end; - int mat = min_ii(mpoly->mat_nr, mr->mat_len - 1); - GPU_indexbuf_set_tri_verts( - &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]); + MeshExtract_Tri_Data *data = _data; + const int mat_last = mr->mat_len - 1; + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) + { + const MPoly *mp = &mr->mpoly[mlt->poly]; + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + int *mat_tri_ofs = data->tri_mat_end; + const int mat = min_ii(mp->mat_nr, mat_last); + GPU_indexbuf_set_tri_verts( + &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data) { MeshExtract_Tri_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); - /* HACK Create ibo subranges and assign them to each GPUBatch. */ + /* HACK: Create ibo sub-ranges and assign them to each #GPUBatch. */ if (mr->use_final_mesh && mr->cache->surface_per_mat && mr->cache->surface_per_mat[0]) { BLI_assert(mr->cache->surface_per_mat[0]->elem == ibo); for (int i = 0; i < mr->mat_len; i++) { /* Multiply by 3 because these are triangle indices. */ - int start = data->tri_mat_start[i] * 3; - int len = data->tri_mat_end[i] * 3 - data->tri_mat_start[i] * 3; + const int start = data->tri_mat_start[i] * 3; + const int len = data->tri_mat_end[i] * 3 - data->tri_mat_start[i] * 3; GPUIndexBuf *sub_ibo = GPU_indexbuf_create_subrange(ibo, start, len); - /* WARNING: We modify the GPUBatch here! */ + /* WARNING: We modify the #GPUBatch here! */ GPU_batch_elembuf_set(mr->cache->surface_per_mat[i], sub_ibo, true); } } @@ -662,18 +907,12 @@ static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data } static const MeshExtract extract_tris = { - extract_tris_init, - extract_tris_looptri_bmesh, - extract_tris_looptri_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_tris_finish, - 0, - false, + .init = extract_tris_init, + .iter_looptri_bm = extract_tris_iter_looptri_bm, + .iter_looptri_mesh = extract_tris_iter_looptri_mesh, + .finish = extract_tris_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -691,71 +930,113 @@ static void *extract_lines_init(const MeshRenderData *mr, void *UNUSED(buf)) return elb; } -static void extract_lines_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *elb) -{ - if (!BM_elem_flag_test(loop->e, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_line_verts(elb, BM_elem_index_get(loop->e), l, BM_elem_index_get(loop->next)); - } - else { - GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(loop->e)); - } -} - -static void extract_lines_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *elb) -{ - const MEdge *medge = &mr->medge[mloop->e]; - if (!((mr->use_hide && (medge->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[mloop->e] == ORIGINDEX_NONE)))) { - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1); - GPU_indexbuf_set_line_verts(elb, mloop->e, l, other_loop); +static void extract_lines_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *elb) +{ + /* Using poly & loop iterator would complicate accessing the adjacent loop. */ + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + BMLoop *l_iter, *l_first; + /* Use #BMLoop.prev to match mesh order (to avoid minor differences in data extraction). */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f)->prev; + do { + if (!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) { + GPU_indexbuf_set_line_verts(elb, + BM_elem_index_get(l_iter->e), + BM_elem_index_get(l_iter), + BM_elem_index_get(l_iter->next)); + } + else { + GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(l_iter->e)); + } + } while ((l_iter = l_iter->next) != l_first); + } + EXTRACT_POLY_FOREACH_BM_END; +} + +static void extract_lines_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *elb) +{ + /* Using poly & loop iterator would complicate accessing the adjacent loop. */ + const MLoop *mloop = mr->mloop; + const MEdge *medge = mr->medge; + if (mr->use_hide || (mr->extract_type == MR_EXTRACT_MAPPED) || (mr->e_origindex != NULL)) { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + const int ml_index_last = mp->loopstart + (mp->totloop - 1); + int ml_index = ml_index_last, ml_index_next = mp->loopstart; + do { + const MLoop *ml = &mloop[ml_index]; + const MEdge *med = &medge[ml->e]; + if (!((mr->use_hide && (med->flag & ME_HIDE)) || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && + (mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) { + GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next); + } + else { + GPU_indexbuf_set_line_restart(elb, ml->e); + } + } while ((ml_index = ml_index_next++) != ml_index_last); + } + EXTRACT_POLY_FOREACH_MESH_END; } else { - GPU_indexbuf_set_line_restart(elb, mloop->e); + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + const int ml_index_last = mp->loopstart + (mp->totloop - 1); + int ml_index = ml_index_last, ml_index_next = mp->loopstart; + do { + const MLoop *ml = &mloop[ml_index]; + GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next); + } while ((ml_index = ml_index_next++) != ml_index_last); + } + EXTRACT_POLY_FOREACH_MESH_END; } } -static void extract_lines_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *elb) +static void extract_lines_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *elb) { - int ledge_idx = mr->edge_len + e; - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - int l = mr->loop_len + e * 2; - GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1); - } - else { - GPU_indexbuf_set_line_restart(elb, ledge_idx); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + const int l_index_offset = mr->edge_len + ledge_index; + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + const int l_index = mr->loop_len + ledge_index * 2; + GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1); + } + else { + GPU_indexbuf_set_line_restart(elb, l_index_offset); + } + /* Don't render the edge twice. */ + GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed)); } - /* Don't render the edge twice. */ - GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed)); + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_lines_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *elb) +static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *elb) { - int ledge_idx = mr->edge_len + e; - int edge_idx = mr->ledges[e]; - if (!((mr->use_hide && (medge->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[edge_idx] == ORIGINDEX_NONE)))) { - int l = mr->loop_len + e * 2; - GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1); - } - else { - GPU_indexbuf_set_line_restart(elb, ledge_idx); + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + const int l_index_offset = mr->edge_len + ledge_index; + const int e_index = mr->ledges[ledge_index]; + if (!((mr->use_hide && (med->flag & ME_HIDE)) || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && + (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) { + const int l_index = mr->loop_len + ledge_index * 2; + GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1); + } + else { + GPU_indexbuf_set_line_restart(elb, l_index_offset); + } + /* Don't render the edge twice. */ + GPU_indexbuf_set_line_restart(elb, e_index); } - /* Don't render the edge twice. */ - GPU_indexbuf_set_line_restart(elb, edge_idx); + EXTRACT_LEDGE_FOREACH_MESH_END; } static void extract_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb) @@ -765,18 +1046,14 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, vo } static const MeshExtract extract_lines = { - extract_lines_init, - NULL, - NULL, - extract_lines_loop_bmesh, - extract_lines_loop_mesh, - extract_lines_ledge_bmesh, - extract_lines_ledge_mesh, - NULL, - NULL, - extract_lines_finish, - 0, - false, + .init = extract_lines_init, + .iter_poly_bm = extract_lines_iter_poly_bm, + .iter_poly_mesh = extract_lines_iter_poly_mesh, + .iter_ledge_bm = extract_lines_iter_ledge_bm, + .iter_ledge_mesh = extract_lines_iter_ledge_mesh, + .finish = extract_lines_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -803,18 +1080,14 @@ static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, void } static const MeshExtract extract_lines_with_lines_loose = { - extract_lines_init, - NULL, - NULL, - extract_lines_loop_bmesh, - extract_lines_loop_mesh, - extract_lines_ledge_bmesh, - extract_lines_ledge_mesh, - NULL, - NULL, - extract_lines_with_lines_loose_finish, - 0, - false, + .init = extract_lines_init, + .iter_poly_bm = extract_lines_iter_poly_bm, + .iter_poly_mesh = extract_lines_iter_poly_mesh, + .iter_ledge_bm = extract_lines_iter_ledge_bm, + .iter_ledge_mesh = extract_lines_iter_ledge_mesh, + .finish = extract_lines_with_lines_loose_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -830,77 +1103,101 @@ static void *extract_points_init(const MeshRenderData *mr, void *UNUSED(buf)) return elb; } -BLI_INLINE void vert_set_bmesh(GPUIndexBufBuilder *elb, BMVert *eve, int loop) +BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, BMVert *eve, int l_index) { - int vert_idx = BM_elem_index_get(eve); + const int v_index = BM_elem_index_get(eve); if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_point_vert(elb, vert_idx, loop); + GPU_indexbuf_set_point_vert(elb, v_index, l_index); } else { - GPU_indexbuf_set_point_restart(elb, vert_idx); + GPU_indexbuf_set_point_restart(elb, v_index); } } BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb, const MeshRenderData *mr, - int vert_idx, - int loop) + const int v_index, + const int l_index) { - const MVert *mvert = &mr->mvert[vert_idx]; - if (!((mr->use_hide && (mvert->flag & ME_HIDE)) || + const MVert *mv = &mr->mvert[v_index]; + if (!((mr->use_hide && (mv->flag & ME_HIDE)) || ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[vert_idx] == ORIGINDEX_NONE)))) { - GPU_indexbuf_set_point_vert(elb, vert_idx, loop); + (mr->v_origindex[v_index] == ORIGINDEX_NONE)))) { + GPU_indexbuf_set_point_vert(elb, v_index, l_index); } else { - GPU_indexbuf_set_point_restart(elb, vert_idx); + GPU_indexbuf_set_point_restart(elb, v_index); } } -static void extract_points_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *elb) +static void extract_points_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *elb) { - vert_set_bmesh(elb, loop->v, l); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + vert_set_bm(elb, l->v, l_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_points_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *elb) +static void extract_points_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *elb) { - vert_set_mesh(elb, mr, mloop->v, l); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + vert_set_mesh(elb, mr, ml->v, ml_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_points_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *elb) +static void extract_points_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *elb) { - vert_set_bmesh(elb, eed->v1, mr->loop_len + e * 2); - vert_set_bmesh(elb, eed->v2, mr->loop_len + e * 2 + 1); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + vert_set_bm(elb, eed->v1, mr->loop_len + (ledge_index * 2)); + vert_set_bm(elb, eed->v2, mr->loop_len + (ledge_index * 2) + 1); + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_points_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *elb) +static void extract_points_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *elb) { - vert_set_mesh(elb, mr, medge->v1, mr->loop_len + e * 2); - vert_set_mesh(elb, mr, medge->v2, mr->loop_len + e * 2 + 1); + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + vert_set_mesh(elb, mr, med->v1, mr->loop_len + (ledge_index * 2)); + vert_set_mesh(elb, mr, med->v2, mr->loop_len + (ledge_index * 2) + 1); + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_points_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *elb) +static void extract_points_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *elb) { - vert_set_bmesh(elb, eve, mr->loop_len + mr->edge_loose_len * 2 + v); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + vert_set_bm(elb, eve, offset + lvert_index); + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_points_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *UNUSED(mvert), - void *elb) +static void extract_points_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *elb) { - vert_set_mesh(elb, mr, mr->lverts[v], mr->loop_len + mr->edge_loose_len * 2 + v); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index); + } + EXTRACT_LVERT_FOREACH_MESH_END; } static void extract_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb) @@ -910,18 +1207,16 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, v } static const MeshExtract extract_points = { - extract_points_init, - NULL, - NULL, - extract_points_loop_bmesh, - extract_points_loop_mesh, - extract_points_ledge_bmesh, - extract_points_ledge_mesh, - extract_points_lvert_bmesh, - extract_points_lvert_mesh, - extract_points_finish, - 0, - false, + .init = extract_points_init, + .iter_poly_bm = extract_points_iter_poly_bm, + .iter_poly_mesh = extract_points_iter_poly_mesh, + .iter_ledge_bm = extract_points_iter_ledge_bm, + .iter_ledge_mesh = extract_points_iter_ledge_mesh, + .iter_lvert_bm = extract_points_iter_lvert_bm, + .iter_lvert_mesh = extract_points_iter_lvert_mesh, + .finish = extract_points_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -937,34 +1232,51 @@ static void *extract_fdots_init(const MeshRenderData *mr, void *UNUSED(buf)) return elb; } -static void extract_fdots_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *elb) +static void extract_fdots_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *elb) { - int face_idx = BM_elem_index_get(loop->f); - if (!BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_point_vert(elb, face_idx, face_idx); - } - else { - GPU_indexbuf_set_point_restart(elb, face_idx); + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + GPU_indexbuf_set_point_vert(elb, f_index, f_index); + } + else { + GPU_indexbuf_set_point_restart(elb, f_index); + } } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_fdots_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *mloop, - int p, - const MPoly *mpoly, - void *elb) +static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *elb) { - const MVert *mvert = &mr->mvert[mloop->v]; - if ((!mr->use_subsurf_fdots || (mvert->flag & ME_VERT_FACEDOT)) && - !(mr->use_hide && (mpoly->flag & ME_HIDE))) { - GPU_indexbuf_set_point_vert(elb, p, p); + if (mr->use_subsurf_fdots) { + /* Check #ME_VERT_FACEDOT. */ + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MVert *mv = &mr->mvert[ml->v]; + if ((mv->flag & ME_VERT_FACEDOT) && !(mr->use_hide && (mp->flag & ME_HIDE))) { + GPU_indexbuf_set_point_vert(elb, mp_index, mp_index); + } + else { + GPU_indexbuf_set_point_restart(elb, mp_index); + } + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - GPU_indexbuf_set_point_restart(elb, p); + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + GPU_indexbuf_set_point_vert(elb, mp_index, mp_index); + } + else { + GPU_indexbuf_set_point_restart(elb, mp_index); + } + } + EXTRACT_POLY_FOREACH_MESH_END; } } @@ -975,18 +1287,12 @@ static void extract_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, vo } static const MeshExtract extract_fdots = { - extract_fdots_init, - NULL, - NULL, - extract_fdots_loop_bmesh, - extract_fdots_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_fdots_finish, - 0, - false, + .init = extract_fdots_init, + .iter_poly_bm = extract_fdots_iter_poly_bm, + .iter_poly_mesh = extract_fdots_iter_poly_mesh, + .finish = extract_fdots_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1009,66 +1315,60 @@ static void *extract_lines_paint_mask_init(const MeshRenderData *mr, void *UNUSE return data; } -static void extract_lines_paint_mask_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *_data) -{ - MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data; - const int edge_idx = mloop->e; - const MEdge *medge = &mr->medge[edge_idx]; - if (!((mr->use_hide && (medge->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[edge_idx] == ORIGINDEX_NONE)))) { - - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1); - if (mpoly->flag & ME_FACE_SEL) { - if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, edge_idx)) { - /* Hide edge as it has more than 2 selected loop. */ - GPU_indexbuf_set_line_restart(&data->elb, edge_idx); +static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) +{ + MeshExtract_LinePaintMask_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const int e_index = ml->e; + const MEdge *me = &mr->medge[e_index]; + if (!((mr->use_hide && (me->flag & ME_HIDE)) || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && + (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) { + + const int ml_index_last = mp->totloop + mp->loopstart - 1; + const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); + if (mp->flag & ME_FACE_SEL) { + if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, e_index)) { + /* Hide edge as it has more than 2 selected loop. */ + GPU_indexbuf_set_line_restart(&data->elb, e_index); + } + else { + /* First selected loop. Set edge visible, overwriting any unselected loop. */ + GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other); + } } else { - /* First selected loop. Set edge visible, overwritting any unsel loop. */ - GPU_indexbuf_set_line_verts(&data->elb, edge_idx, l, other_loop); + /* Set theses unselected loop only if this edge has no other selected loop. */ + if (!BLI_BITMAP_TEST(data->select_map, e_index)) { + GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other); + } } } else { - /* Set theses unselected loop only if this edge has no other selected loop. */ - if (!BLI_BITMAP_TEST(data->select_map, edge_idx)) { - GPU_indexbuf_set_line_verts(&data->elb, edge_idx, l, other_loop); - } + GPU_indexbuf_set_line_restart(&data->elb, e_index); } } - else { - GPU_indexbuf_set_line_restart(&data->elb, edge_idx); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *_data) { - MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data; + MeshExtract_LinePaintMask_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); MEM_freeN(data); } static const MeshExtract extract_lines_paint_mask = { - extract_lines_paint_mask_init, - NULL, - NULL, - NULL, - extract_lines_paint_mask_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_lines_paint_mask_finish, - 0, - false, + .init = extract_lines_paint_mask_init, + .iter_poly_mesh = extract_lines_paint_mask_iter_poly_mesh, + .finish = extract_lines_paint_mask_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1090,7 +1390,7 @@ typedef struct MeshExtract_LineAdjacency_Data { static void *extract_lines_adjacency_init(const MeshRenderData *mr, void *UNUSED(buf)) { /* Similar to poly_to_tri_count(). - * There is always loop + tri - 1 edges inside a polygon. + * There is always (loop + triangle - 1) edges inside a polygon. * Accumulate for all polys and you get : */ uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len; @@ -1107,7 +1407,7 @@ BLI_INLINE void lines_adjacency_triangle( uint v1, uint v2, uint v3, uint l1, uint l2, uint l3, MeshExtract_LineAdjacency_Data *data) { GPUIndexBufBuilder *elb = &data->elb; - /* Iter around the triangle's edges. */ + /* Iterate around the triangle's edges. */ for (int e = 0; e < 3; e++) { SHIFT3(uint, v3, v2, v1); SHIFT3(uint, l3, l2, l1); @@ -1118,7 +1418,7 @@ BLI_INLINE void lines_adjacency_triangle( int v_data = POINTER_AS_INT(*pval); if (!value_is_init || v_data == NO_EDGE) { /* Save the winding order inside the sign bit. Because the - * edgehash sort the keys and we need to compare winding later. */ + * Edge-hash sort the keys and we need to compare winding later. */ int value = (int)l1 + 1; /* 0 cannot be signed so add one. */ *pval = POINTER_FROM_INT((inv_indices) ? -value : value); /* Store loop indices for remaining non-manifold edges. */ @@ -1130,7 +1430,7 @@ BLI_INLINE void lines_adjacency_triangle( *pval = POINTER_FROM_INT(NO_EDGE); bool inv_opposite = (v_data < 0); uint l_opposite = (uint)abs(v_data) - 1; - /* TODO Make this part threadsafe. */ + /* TODO Make this part thread-safe. */ if (inv_opposite == inv_indices) { /* Don't share edge if triangles have non matching winding. */ GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l1); @@ -1144,42 +1444,48 @@ BLI_INLINE void lines_adjacency_triangle( } } -static void extract_lines_adjacency_looptri_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(t), - BMLoop **elt, - void *data) +static void extract_lines_adjacency_iter_looptri_bm(const MeshRenderData *UNUSED(mr), + const struct ExtractTriBMesh_Params *params, + void *data) { - if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { - lines_adjacency_triangle(BM_elem_index_get(elt[0]->v), - BM_elem_index_get(elt[1]->v), - BM_elem_index_get(elt[2]->v), - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2]), - data); + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) + { + if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { + lines_adjacency_triangle(BM_elem_index_get(elt[0]->v), + BM_elem_index_get(elt[1]->v), + BM_elem_index_get(elt[2]->v), + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2]), + data); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } -static void extract_lines_adjacency_looptri_mesh(const MeshRenderData *mr, - int UNUSED(t), - const MLoopTri *mlt, - void *data) +static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr, + const struct ExtractTriMesh_Params *params, + void *data) { - const MPoly *mpoly = &mr->mpoly[mlt->poly]; - if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) { - lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v, - mr->mloop[mlt->tri[1]].v, - mr->mloop[mlt->tri[2]].v, - mlt->tri[0], - mlt->tri[1], - mlt->tri[2], - data); + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) + { + const MPoly *mp = &mr->mpoly[mlt->poly]; + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v, + mr->mloop[mlt->tri[1]].v, + mr->mloop[mlt->tri[2]].v, + mlt->tri[0], + mlt->tri[1], + mlt->tri[2], + data); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_lines_adjacency_finish(const MeshRenderData *mr, void *ibo, void *_data) { - MeshExtract_LineAdjacency_Data *data = (MeshExtract_LineAdjacency_Data *)_data; + MeshExtract_LineAdjacency_Data *data = _data; /* Create edges for remaining non manifold edges. */ EdgeHashIterator *ehi = BLI_edgehashIterator_new(data->eh); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { @@ -1209,18 +1515,12 @@ static void extract_lines_adjacency_finish(const MeshRenderData *mr, void *ibo, #undef NO_EDGE static const MeshExtract extract_lines_adjacency = { - extract_lines_adjacency_init, - extract_lines_adjacency_looptri_bmesh, - extract_lines_adjacency_looptri_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_lines_adjacency_finish, - 0, - false, + .init = extract_lines_adjacency_init, + .iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm, + .iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh, + .finish = extract_lines_adjacency_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1250,53 +1550,53 @@ BLI_INLINE void edituv_tri_add( } } -static void extract_edituv_tris_looptri_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(t), - BMLoop **elt, - void *data) +static void extract_edituv_tris_iter_looptri_bm(const MeshRenderData *UNUSED(mr), + const struct ExtractTriBMesh_Params *params, + void *data) { - edituv_tri_add(data, - BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT), - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2])); + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) + { + edituv_tri_add(data, + BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN), + BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT), + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2])); + } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } -static void extract_edituv_tris_looptri_mesh(const MeshRenderData *mr, - int UNUSED(t), - const MLoopTri *mlt, - void *data) +static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr, + const struct ExtractTriMesh_Params *params, + void *data) { - const MPoly *mpoly = &mr->mpoly[mlt->poly]; - edituv_tri_add(data, - (mpoly->flag & ME_HIDE) != 0, - (mpoly->flag & ME_FACE_SEL) != 0, - mlt->tri[0], - mlt->tri[1], - mlt->tri[2]); + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) + { + const MPoly *mp = &mr->mpoly[mlt->poly]; + edituv_tri_add(data, + (mp->flag & ME_HIDE) != 0, + (mp->flag & ME_FACE_SEL) != 0, + mlt->tri[0], + mlt->tri[1], + mlt->tri[2]); + } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data) { - MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data; + MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } static const MeshExtract extract_edituv_tris = { - extract_edituv_tris_init, - extract_edituv_tris_looptri_bmesh, - extract_edituv_tris_looptri_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_edituv_tris_finish, - 0, - false, + .init = extract_edituv_tris_init, + .iter_looptri_bm = extract_edituv_tris_iter_looptri_bm, + .iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh, + .finish = extract_edituv_tris_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1322,55 +1622,53 @@ BLI_INLINE void edituv_edge_add( } } -static void extract_edituv_lines_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - edituv_edge_add(data, - BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(loop->f, BM_ELEM_SELECT), - l, - BM_elem_index_get(loop->next)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr) + { + edituv_edge_add(data, + BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), + BM_elem_flag_test(loop->f, BM_ELEM_SELECT), + l_index, + BM_elem_index_get(loop->next)); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop); } -static void extract_edituv_lines_loop_mesh(const MeshRenderData *mr, - int loop_idx, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *data) +static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int loop_next_idx = (loop_idx == loopend) ? mpoly->loopstart : (loop_idx + 1); - const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[mloop->e] != ORIGINDEX_NONE); - edituv_edge_add(data, - (mpoly->flag & ME_HIDE) != 0 || !real_edge, - (mpoly->flag & ME_FACE_SEL) != 0, - loop_idx, - loop_next_idx); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const int ml_index_last = mp->totloop + mp->loopstart - 1; + const int ml_index_next = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); + const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[ml->e] != ORIGINDEX_NONE); + edituv_edge_add(data, + (mp->flag & ME_HIDE) != 0 || !real_edge, + (mp->flag & ME_FACE_SEL) != 0, + ml_index, + ml_index_next); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data) { - MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data; + MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } static const MeshExtract extract_edituv_lines = { - extract_edituv_lines_init, - NULL, - NULL, - extract_edituv_lines_loop_bmesh, - extract_edituv_lines_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_lines_finish, - 0, - false, + .init = extract_edituv_lines_init, + .iter_poly_bm = extract_edituv_lines_iter_poly_bm, + .iter_poly_mesh = extract_edituv_lines_iter_poly_mesh, + .finish = extract_edituv_lines_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1398,50 +1696,48 @@ BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data, } } -static void extract_edituv_points_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_edituv_points_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - edituv_point_add(data, - BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(loop->f, BM_ELEM_SELECT), - l); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + edituv_point_add(data, + BM_elem_flag_test(l->f, BM_ELEM_HIDDEN), + BM_elem_flag_test(l->f, BM_ELEM_SELECT), + l_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edituv_points_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *data) +static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[mloop->v] != ORIGINDEX_NONE); - edituv_point_add( - data, ((mpoly->flag & ME_HIDE) != 0) || !real_vert, (mpoly->flag & ME_FACE_SEL) != 0, l); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && + mr->v_origindex[ml->v] != ORIGINDEX_NONE); + edituv_point_add( + data, ((mp->flag & ME_HIDE) != 0) || !real_vert, (mp->flag & ME_FACE_SEL) != 0, ml_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data) { - MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data; + MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } static const MeshExtract extract_edituv_points = { - extract_edituv_points_init, - NULL, - NULL, - extract_edituv_points_loop_bmesh, - extract_edituv_points_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_points_finish, - 0, - false, + .init = extract_edituv_points_init, + .iter_poly_bm = extract_edituv_points_iter_poly_bm, + .iter_poly_mesh = extract_edituv_points_iter_poly_mesh, + .finish = extract_edituv_points_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1462,64 +1758,75 @@ static void *extract_edituv_fdots_init(const MeshRenderData *mr, void *UNUSED(ib BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, - int face_idx) + int face_index) { if (!hidden && (data->sync_selection || selected)) { - GPU_indexbuf_set_point_vert(&data->elb, face_idx, face_idx); + GPU_indexbuf_set_point_vert(&data->elb, face_index, face_index); } else { - GPU_indexbuf_set_point_restart(&data->elb, face_idx); + GPU_indexbuf_set_point_restart(&data->elb, face_index); } } -static void extract_edituv_fdots_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *data) +static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - edituv_facedot_add(data, - BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(loop->f, BM_ELEM_SELECT), - BM_elem_index_get(loop->f)); + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + edituv_facedot_add( + data, BM_elem_flag_test(f, BM_ELEM_HIDDEN), BM_elem_flag_test(f, BM_ELEM_SELECT), f_index); + } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_edituv_fdots_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *mloop, - int p, - const MPoly *mpoly, - void *data) +static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[p] != ORIGINDEX_NONE); - const bool subd_fdot = (!mr->use_subsurf_fdots || - (mr->mvert[mloop->v].flag & ME_VERT_FACEDOT) != 0); - edituv_facedot_add(data, - ((mpoly->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot, - (mpoly->flag & ME_FACE_SEL) != 0, - p); + if (mr->use_subsurf_fdots) { + /* Check #ME_VERT_FACEDOT. */ + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && + mr->p_origindex[mp_index] != ORIGINDEX_NONE); + const bool subd_fdot = (!mr->use_subsurf_fdots || + (mr->mvert[ml->v].flag & ME_VERT_FACEDOT) != 0); + edituv_facedot_add(data, + ((mp->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot, + (mp->flag & ME_FACE_SEL) != 0, + mp_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; + } + else { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && + mr->p_origindex[mp_index] != ORIGINDEX_NONE); + edituv_facedot_add(data, + ((mp->flag & ME_HIDE) != 0) || !real_fdot, + (mp->flag & ME_FACE_SEL) != 0, + mp_index); + } + EXTRACT_POLY_FOREACH_MESH_END; + } } static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *_data) { - MeshExtract_EditUvElem_Data *data = (MeshExtract_EditUvElem_Data *)_data; + MeshExtract_EditUvElem_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); MEM_freeN(data); } static const MeshExtract extract_edituv_fdots = { - extract_edituv_fdots_init, - NULL, - NULL, - extract_edituv_fdots_loop_bmesh, - extract_edituv_fdots_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_fdots_finish, - 0, - false, + .init = extract_edituv_fdots_init, + .iter_poly_bm = extract_edituv_fdots_iter_poly_bm, + .iter_poly_mesh = extract_edituv_fdots_iter_poly_mesh, + .finish = extract_edituv_fdots_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1542,7 +1849,7 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust PosNorLoop struct accordingly. */ + /* WARNING Adjust #PosNorLoop struct accordingly. */ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_alias_add(&format, "vnor"); @@ -1566,95 +1873,122 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf) } } else { - const MVert *mvert = mr->mvert; - for (int v = 0; v < mr->vert_len; v++, mvert++) { - data->packed_nor[v] = GPU_normal_convert_i10_s3(mvert->no); + const MVert *mv = mr->mvert; + for (int v = 0; v < mr->vert_len; v++, mv++) { + data->packed_nor[v] = GPU_normal_convert_i10_s3(mv->no); } } return data; } -static void extract_pos_nor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) +static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, loop->v)); - vert->nor = data->packed_nor[BM_elem_index_get(loop->v)]; - BMFace *efa = loop->f; - vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, l->v)); + vert->nor = data->packed_nor[BM_elem_index_get(l->v)]; + BMFace *efa = l->f; + vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_pos_nor_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *_data) +static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - const MVert *mvert = &mr->mvert[mloop->v]; - copy_v3_v3(vert->pos, mvert->co); - vert->nor = data->packed_nor[mloop->v]; - /* Flag for paint mode overlay. */ - if (mpoly->flag & ME_HIDE || mvert->flag & ME_HIDE || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[mloop->v] == ORIGINDEX_NONE))) { - vert->nor.w = -1; - } - else if (mvert->flag & SELECT) { - vert->nor.w = 1; - } - else { - vert->nor.w = 0; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + PosNorLoop *vert = &data->vbo_data[ml_index]; + const MVert *mv = &mr->mvert[ml->v]; + copy_v3_v3(vert->pos, mv->co); + vert->nor = data->packed_nor[ml->v]; + /* Flag for paint mode overlay. */ + if (mp->flag & ME_HIDE || mv->flag & ME_HIDE || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && + (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) { + vert->nor.w = -1; + } + else if (mv->flag & SELECT) { + vert->nor.w = 1; + } + else { + vert->nor.w = 0; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *_data) +static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *_data) { - int l = mr->loop_len + e * 2; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); - copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); - vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)]; - vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)]; + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + int l_index = mr->loop_len + ledge_index * 2; + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); + copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); + vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)]; + vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)]; + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_pos_nor_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *_data) +static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *_data) { - int l = mr->loop_len + e * 2; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert[0].pos, mr->mvert[medge->v1].co); - copy_v3_v3(vert[1].pos, mr->mvert[medge->v2].co); - vert[0].nor = data->packed_nor[medge->v1]; - vert[1].nor = data->packed_nor[medge->v2]; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + const int ml_index = mr->loop_len + ledge_index * 2; + PosNorLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co); + copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co); + vert[0].nor = data->packed_nor[med->v1]; + vert[1].nor = data->packed_nor[med->v2]; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_pos_nor_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *_data) +static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *_data) { - int l = mr->loop_len + mr->edge_loose_len * 2 + v; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); - vert->nor = data->packed_nor[BM_elem_index_get(eve)]; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + const int l_index = offset + lvert_index; + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); + vert->nor = data->packed_nor[BM_elem_index_get(eve)]; + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_pos_nor_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *mvert, - void *_data) +static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *_data) { - int l = mr->loop_len + mr->edge_loose_len * 2 + v; - int v_idx = mr->lverts[v]; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, mvert->co); - vert->nor = data->packed_nor[v_idx]; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + const int ml_index = offset + lvert_index; + const int v_index = mr->lverts[lvert_index]; + PosNorLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert->pos, mv->co); + vert->nor = data->packed_nor[v_index]; + } + EXTRACT_LVERT_FOREACH_MESH_END; } static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(vbo), void *data) @@ -1663,18 +1997,16 @@ static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), void *UNUSE } static const MeshExtract extract_pos_nor = { - extract_pos_nor_init, - NULL, - NULL, - extract_pos_nor_loop_bmesh, - extract_pos_nor_loop_mesh, - extract_pos_nor_ledge_bmesh, - extract_pos_nor_ledge_mesh, - extract_pos_nor_lvert_bmesh, - extract_pos_nor_lvert_mesh, - extract_pos_nor_finish, - 0, - true, + .init = extract_pos_nor_init, + .iter_poly_bm = extract_pos_nor_iter_poly_bm, + .iter_poly_mesh = extract_pos_nor_iter_poly_mesh, + .iter_ledge_bm = extract_pos_nor_iter_ledge_bm, + .iter_ledge_mesh = extract_pos_nor_iter_ledge_mesh, + .iter_lvert_bm = extract_pos_nor_iter_lvert_bm, + .iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh, + .finish = extract_pos_nor_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -1700,62 +2032,71 @@ static void *extract_lnor_hq_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_lnor_hq_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *data) +static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { if (mr->loop_normals) { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->loop_normals[l]); - } - else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_vert_no_get(mr, loop->v)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(_l, l_index, params, mr) + { + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, mr->loop_normals[l_index]); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(_l); } else { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_face_no_get(mr, loop->f)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) { + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l->v)); + } + else { + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, l->f)); + } + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } } -static void extract_lnor_hq_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data) +static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - gpuHQNor *lnor_data = &((gpuHQNor *)data)[l]; - if (mr->loop_normals) { - normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[l]); - } - else if (mpoly->flag & ME_SMOOTH) { - copy_v3_v3_short(&lnor_data->x, mr->mvert[mloop->v].no); - } - else { - normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[p]); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + gpuHQNor *lnor_data = &((gpuHQNor *)data)[ml_index]; + if (mr->loop_normals) { + normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]); + } + else if (mp->flag & ME_SMOOTH) { + copy_v3_v3_short(&lnor_data->x, mr->mvert[ml->v].no); + } + else { + normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]); + } - /* Flag for paint mode overlay. - * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In - * paint mode it will use the unmapped data to draw the wireframe. */ - if (mpoly->flag & ME_HIDE || - (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) { - lnor_data->w = -1; - } - else if (mpoly->flag & ME_FACE_SEL) { - lnor_data->w = 1; - } - else { - lnor_data->w = 0; + /* Flag for paint mode overlay. + * Only use #MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. + * In paint mode it will use the un-mapped data to draw the wire-frame. */ + if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && + (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { + lnor_data->w = -1; + } + else if (mp->flag & ME_FACE_SEL) { + lnor_data->w = 1; + } + else { + lnor_data->w = 0; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static const MeshExtract extract_lnor_hq = { - extract_lnor_hq_init, - NULL, - NULL, - extract_lnor_hq_loop_bmesh, - extract_lnor_hq_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_LOOP_NOR, - true, + .init = extract_lnor_hq_init, + .iter_poly_bm = extract_lnor_hq_iter_poly_bm, + .iter_poly_mesh = extract_lnor_hq_iter_poly_mesh, + .data_flag = MR_DATA_LOOP_NOR, + .use_threading = true, }; /** \} */ @@ -1777,64 +2118,75 @@ static void *extract_lnor_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_lnor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *data) +static void extract_lnor_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { if (mr->loop_normals) { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]); - } - else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, loop->v)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]); + BMFace *efa = l->f; + ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } else { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, loop->f)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) { + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, l->v)); + } + else { + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, l->f)); + } + BMFace *efa = l->f; + ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } - BMFace *efa = loop->f; - ((GPUPackedNormal *)data)[l].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; } -static void extract_lnor_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data) +static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[l]; - if (mr->loop_normals) { - *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[l]); - } - else if (mpoly->flag & ME_SMOOTH) { - *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[mloop->v].no); - } - else { - *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[p]); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[ml_index]; + if (mr->loop_normals) { + *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]); + } + else if (mp->flag & ME_SMOOTH) { + *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[ml->v].no); + } + else { + *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]); + } - /* Flag for paint mode overlay. - * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In - * paint mode it will use the unmapped data to draw the wireframe. */ - if (mpoly->flag & ME_HIDE || - (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) { - lnor_data->w = -1; - } - else if (mpoly->flag & ME_FACE_SEL) { - lnor_data->w = 1; - } - else { - lnor_data->w = 0; + /* Flag for paint mode overlay. + * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. + * In paint mode it will use the un-mapped data to draw the wire-frame. */ + if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && + (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { + lnor_data->w = -1; + } + else if (mp->flag & ME_FACE_SEL) { + lnor_data->w = 1; + } + else { + lnor_data->w = 0; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static const MeshExtract extract_lnor = { - extract_lnor_init, - NULL, - NULL, - extract_lnor_loop_bmesh, - extract_lnor_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_LOOP_NOR, - true, + .init = extract_lnor_init, + .iter_poly_bm = extract_lnor_iter_poly_bm, + .iter_poly_mesh = extract_lnor_iter_poly_mesh, + .data_flag = MR_DATA_LOOP_NOR, + .use_threading = true, }; /** \} */ @@ -1878,7 +2230,7 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) /* Active display layer name. */ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { GPU_vertformat_alias_add(&format, "au"); - /* Alias to pos for edit uvs. */ + /* Alias to `pos` for edit uvs. */ GPU_vertformat_alias_add(&format, "pos"); } /* Stencil mask uv layer name. */ @@ -1904,20 +2256,21 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) if (uv_layers & (1 << i)) { if (mr->extract_type == MR_EXTRACT_BMESH) { int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPUV, i); - BMIter f_iter, l_iter; + BMIter f_iter; BMFace *efa; - BMLoop *loop; BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs); memcpy(uv_data, luv->uv, sizeof(*uv_data)); uv_data++; - } + } while ((l_iter = l_iter->next) != l_first); } } else { MLoopUV *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i); - for (int l = 0; l < mr->loop_len; l++, uv_data++, layer_data++) { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) { memcpy(uv_data, layer_data->uv, sizeof(*uv_data)); } } @@ -1928,18 +2281,9 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_uv = { - extract_uv_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - false, + .init = extract_uv_init, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1987,7 +2331,7 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool } } if (use_orco_tan && orco == NULL) { - /* If orco is not available compute it ourselves */ + /* If `orco` is not available compute it ourselves */ orco_allocated = true; orco = MEM_mallocN(sizeof(*orco) * mr->vert_len, __func__); @@ -2001,17 +2345,18 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool } } else { - const MVert *mvert = mr->mvert; - for (int v = 0; v < mr->vert_len; v++, mvert++) { - copy_v3_v3(orco[v], mvert->co); + const MVert *mv = mr->mvert; + for (int v = 0; v < mr->vert_len; v++, mv++) { + copy_v3_v3(orco[v], mv->co); } } BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0); } /* Start Fresh */ - CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len); - + CustomData loop_data; + CustomData_reset(&loop_data); + CustomData *ldata = cd_ldata; if (tan_len != 0 || use_orco_tan) { short tangent_mask = 0; bool calc_active_tangent = false; @@ -2041,9 +2386,10 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool mr->poly_normals, mr->loop_normals, orco, - cd_ldata, + &loop_data, mr->loop_len, &tangent_mask); + ldata = &loop_data; } } @@ -2075,18 +2421,18 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool short(*tan_data)[4] = (short(*)[4])vbo->data; for (int i = 0; i < tan_len; i++) { const char *name = tangent_names[i]; - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(cd_ldata, CD_TANGENT, name); - for (int l = 0; l < mr->loop_len; l++) { - normal_float_to_short_v3(*tan_data, layer_data[l]); - (*tan_data)[3] = (layer_data[l][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(ldata, CD_TANGENT, name); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + normal_float_to_short_v3(*tan_data, layer_data[ml_index]); + (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; tan_data++; } } if (use_orco_tan) { - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0); - for (int l = 0; l < mr->loop_len; l++) { - normal_float_to_short_v3(*tan_data, layer_data[l]); - (*tan_data)[3] = (layer_data[l][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(ldata, CD_TANGENT, 0); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + normal_float_to_short_v3(*tan_data, layer_data[ml_index]); + (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; tan_data++; } } @@ -2095,24 +2441,25 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool GPUPackedNormal *tan_data = (GPUPackedNormal *)vbo->data; for (int i = 0; i < tan_len; i++) { const char *name = tangent_names[i]; - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(cd_ldata, CD_TANGENT, name); - for (int l = 0; l < mr->loop_len; l++) { - *tan_data = GPU_normal_convert_i10_v3(layer_data[l]); - tan_data->w = (layer_data[l][3] > 0.0f) ? 1 : -2; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(ldata, CD_TANGENT, name); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]); + tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2; tan_data++; } } if (use_orco_tan) { - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0); - for (int l = 0; l < mr->loop_len; l++) { - *tan_data = GPU_normal_convert_i10_v3(layer_data[l]); - tan_data->w = (layer_data[l][3] > 0.0f) ? 1 : -2; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(ldata, CD_TANGENT, 0); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]); + tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2; tan_data++; } } } - CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len); + CustomData_free_layers(ldata, CD_TANGENT, mr->loop_len); + CustomData_free(&loop_data, mr->loop_len); } static void *extract_tan_init(const MeshRenderData *mr, void *buf) @@ -2122,18 +2469,9 @@ static void *extract_tan_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_tan = { - extract_tan_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, - false, + .init = extract_tan_init, + .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, + .use_threading = false, }; /** \} */ @@ -2149,18 +2487,9 @@ static void *extract_tan_hq_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_tan_hq = { - extract_tan_hq_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, - false, + .init = extract_tan_hq_init, + .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, + .use_threading = false, }; /** \} */ @@ -2175,7 +2504,9 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) GPU_vertformat_deinterleave(&format); CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; uint32_t vcol_layers = mr->cache->cd_used.vcol; + uint32_t svcol_layers = mr->cache->cd_used.sculpt_vcol; for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { @@ -2192,14 +2523,42 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) { GPU_vertformat_alias_add(&format, "ac"); } + /* Gather number of auto layers. */ - /* We only do vcols that are not overridden by uvs */ + /* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */ + if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1 && + CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, layer_name) == -1) { + BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); + GPU_vertformat_alias_add(&format, attr_name); + } + } + } + + /* Sculpt Vertex Colors */ + for (int i = 0; i < 8; i++) { + if (svcol_layers & (1 << i)) { + char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i); + GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + + BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name); + GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + + if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) { + GPU_vertformat_alias_add(&format, "c"); + } + if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) { + GPU_vertformat_alias_add(&format, "ac"); + } + /* Gather number of auto layers. */ + /* We only do `vcols` that are not overridden by `uvs`. */ if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) { BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); GPU_vertformat_alias_add(&format, attr_name); } } } + GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -2209,27 +2568,30 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) } gpuMeshVcol; gpuMeshVcol *vcol_data = (gpuMeshVcol *)vbo->data; + MLoop *loops = CustomData_get_layer(cd_ldata, CD_MLOOP); + for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { if (mr->extract_type == MR_EXTRACT_BMESH) { int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i); - BMIter f_iter, l_iter; + BMIter f_iter; BMFace *efa; - BMLoop *loop; BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs); vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); vcol_data++; - } + } while ((l_iter = l_iter->next) != l_first); } } else { const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); - for (int l = 0; l < mr->loop_len; l++, mloopcol++, vcol_data++) { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, mloopcol++, vcol_data++) { vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); @@ -2237,22 +2599,45 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) } } } + + if (svcol_layers & (1 << i)) { + if (mr->extract_type == MR_EXTRACT_BMESH) { + int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i); + BMIter f_iter; + BMFace *efa; + BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const MPropCol *prop_col = BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs); + vcol_data->r = unit_float_to_ushort_clamp(prop_col->color[0]); + vcol_data->g = unit_float_to_ushort_clamp(prop_col->color[1]); + vcol_data->b = unit_float_to_ushort_clamp(prop_col->color[2]); + vcol_data->a = unit_float_to_ushort_clamp(prop_col->color[3]); + vcol_data++; + } while ((l_iter = l_iter->next) != l_first); + } + } + else { + MPropCol *vcol = CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vcol_data++) { + vcol_data->r = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[0]); + vcol_data->g = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[1]); + vcol_data->b = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[2]); + vcol_data->a = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[3]); + } + } + + vcol_data += mr->loop_len; + } } return NULL; } static const MeshExtract extract_vcol = { - extract_vcol_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - false, + .init = extract_vcol_init, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -2271,7 +2656,7 @@ static void *extract_orco_init(const MeshRenderData *mr, void *buf) static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex - * attributes. This is a substantial waste of Vram and should be done another way. + * attributes. This is a substantial waste of video-ram and should be done another way. * Unfortunately, at the time of writing, I did not found any other "non disruptive" * alternative. */ GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); @@ -2286,33 +2671,37 @@ static void *extract_orco_init(const MeshRenderData *mr, void *buf) MeshExtract_Orco_Data *data = MEM_mallocN(sizeof(*data), __func__); data->vbo_data = (float(*)[4])vbo->data; data->orco = CustomData_get_layer(cd_vdata, CD_ORCO); - /* Make sure orco layer was requested only if needed! */ + /* Make sure `orco` layer was requested only if needed! */ BLI_assert(data->orco); return data; } -static void extract_orco_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_orco_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; - float *loop_orco = orco_data->vbo_data[l]; - copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]); - loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr) + { + float *loop_orco = orco_data->vbo_data[l_index]; + copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]); + loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop); } -static void extract_orco_loop_mesh(const MeshRenderData *UNUSED(mr), - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *data) +static void extract_orco_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; - float *loop_orco = orco_data->vbo_data[l]; - copy_v3_v3(loop_orco, orco_data->orco[mloop->v]); - loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; + float *loop_orco = orco_data->vbo_data[ml_index]; + copy_v3_v3(loop_orco, orco_data->orco[ml->v]); + loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_orco_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data) @@ -2321,18 +2710,12 @@ static void extract_orco_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(b } static const MeshExtract extract_orco = { - extract_orco_init, - NULL, - NULL, - extract_orco_loop_bmesh, - extract_orco_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_orco_finish, - 0, - true, + .init = extract_orco_init, + .iter_poly_bm = extract_orco_iter_poly_bm, + .iter_poly_mesh = extract_orco_iter_poly_mesh, + .finish = extract_orco_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -2359,7 +2742,7 @@ static float loop_edge_factor_get(const float f_no[3], cross_v3_v3v3(enor, v_no, evec); normalize_v3(enor); float d = fabsf(dot_v3v3(enor, f_no)); - /* Rescale to the slider range. */ + /* Re-scale to the slider range. */ d *= (1.0f / 0.065f); CLAMP(d, 0.0f, 1.0f); return d; @@ -2383,9 +2766,9 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf) /* HACK(fclem) Detecting the need for edge render. * We could have a flag in the mesh instead or check the modifier stack. */ - const MEdge *medge = mr->medge; - for (int e = 0; e < mr->edge_len; e++, medge++) { - if ((medge->flag & ME_EDGERENDER) == 0) { + const MEdge *med = mr->medge; + for (int e_index = 0; e_index < mr->edge_len; e_index++, med++) { + if ((med->flag & ME_EDGERENDER) == 0) { data->use_edge_render = true; break; } @@ -2401,81 +2784,103 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_edge_fac_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) +static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - if (BM_edge_is_manifold(loop->e)) { - float ratio = loop_edge_factor_get(bm_face_no_get(mr, loop->f), - bm_vert_co_get(mr, loop->v), - bm_vert_no_get(mr, loop->v), - bm_vert_co_get(mr, loop->next->v)); - data->vbo_data[l] = ratio * 253 + 1; - } - else { - data->vbo_data[l] = 255; + MeshExtract_EdgeFac_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + if (BM_edge_is_manifold(l->e)) { + float ratio = loop_edge_factor_get(bm_face_no_get(mr, l->f), + bm_vert_co_get(mr, l->v), + bm_vert_no_get(mr, l->v), + bm_vert_co_get(mr, l->next->v)); + data->vbo_data[l_index] = ratio * 253 + 1; + } + else { + data->vbo_data[l_index] = 255; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edge_fac_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data) +static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; + if (data->use_edge_render) { - const MEdge *medge = &mr->medge[mloop->e]; - data->vbo_data[l] = (medge->flag & ME_EDGERENDER) ? 255 : 0; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MEdge *med = &mr->medge[ml->e]; + data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - /* Count loop per edge to detect non-manifold. */ - if (data->edge_loop_count[mloop->e] < 3) { - data->edge_loop_count[mloop->e]++; - } - if (data->edge_loop_count[mloop->e] == 2) { - /* Manifold */ - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1); - const MLoop *mloop_next = &mr->mloop[other_loop]; - const MVert *v1 = &mr->mvert[mloop->v]; - const MVert *v2 = &mr->mvert[mloop_next->v]; - float vnor_f[3]; - normal_short_to_float_v3(vnor_f, v1->no); - float ratio = loop_edge_factor_get(mr->poly_normals[p], v1->co, vnor_f, v2->co); - data->vbo_data[l] = ratio * 253 + 1; - } - else { - /* Non-manifold */ - data->vbo_data[l] = 255; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + /* Count loop per edge to detect non-manifold. */ + if (data->edge_loop_count[ml->e] < 3) { + data->edge_loop_count[ml->e]++; + } + if (data->edge_loop_count[ml->e] == 2) { + /* Manifold */ + const int ml_index_last = mp->totloop + mp->loopstart - 1; + const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); + const MLoop *ml_next = &mr->mloop[ml_index_other]; + const MVert *v1 = &mr->mvert[ml->v]; + const MVert *v2 = &mr->mvert[ml_next->v]; + float vnor_f[3]; + normal_short_to_float_v3(vnor_f, v1->no); + float ratio = loop_edge_factor_get(mr->poly_normals[mp_index], v1->co, vnor_f, v2->co); + data->vbo_data[ml_index] = ratio * 253 + 1; + } + else { + /* Non-manifold */ + data->vbo_data[ml_index] = 255; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } } -static void extract_edge_fac_ledge_bmesh(const MeshRenderData *mr, - int e, - BMEdge *UNUSED(eed), - void *_data) +static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - data->vbo_data[mr->loop_len + e * 2 + 0] = 255; - data->vbo_data[mr->loop_len + e * 2 + 1] = 255; + MeshExtract_EdgeFac_Data *data = _data; + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255; + data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255; + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_edge_fac_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *UNUSED(edge), - void *_data) +static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - data->vbo_data[mr->loop_len + e * 2 + 0] = 255; - data->vbo_data[mr->loop_len + e * 2 + 1] = 255; + MeshExtract_EdgeFac_Data *data = _data; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255; + data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; + MeshExtract_EdgeFac_Data *data = _data; if (GPU_crappy_amd_driver()) { GPUVertBuf *vbo = (GPUVertBuf *)buf; - /* Some AMD drivers strangely crash with VBOs with a one byte format. - * To workaround we reinit the vbo with another format and convert + /* Some AMD drivers strangely crash with VBO's with a one byte format. + * To workaround we reinitialize the VBO with another format and convert * all bytes to floats. */ static GPUVertFormat format = {0}; if (format.attr_len == 0) { @@ -2490,8 +2895,8 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_ GPU_vertbuf_data_alloc(vbo, buf_len); float *fdata = (float *)vbo->data; - for (int l = 0; l < buf_len; l++, fdata++) { - *fdata = data->vbo_data[l] / 255.0f; + for (int ml_index = 0; ml_index < buf_len; ml_index++, fdata++) { + *fdata = data->vbo_data[ml_index] / 255.0f; } /* Free old byte data. */ MEM_freeN(data->vbo_data); @@ -2500,18 +2905,14 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_ } static const MeshExtract extract_edge_fac = { - extract_edge_fac_init, - NULL, - NULL, - extract_edge_fac_loop_bmesh, - extract_edge_fac_loop_mesh, - extract_edge_fac_ledge_bmesh, - extract_edge_fac_ledge_mesh, - NULL, - NULL, - extract_edge_fac_finish, - MR_DATA_POLY_NOR, - false, + .init = extract_edge_fac_init, + .iter_poly_bm = extract_edge_fac_iter_poly_bm, + .iter_poly_mesh = extract_edge_fac_iter_poly_mesh, + .iter_ledge_bm = extract_edge_fac_iter_ledge_bm, + .iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh, + .finish = extract_edge_fac_finish, + .data_flag = MR_DATA_POLY_NOR, + .use_threading = false, }; /** \} */ @@ -2522,8 +2923,8 @@ static const MeshExtract extract_edge_fac = { typedef struct MeshExtract_Weight_Data { float *vbo_data; const DRW_MeshWeightState *wstate; - const MDeformVert *dvert; /* For Mesh. */ - int cd_ofs; /* For BMesh. */ + const MDeformVert *dvert; /* For #Mesh. */ + int cd_ofs; /* For #BMesh. */ } MeshExtract_Weight_Data; static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate) @@ -2609,27 +3010,49 @@ static void *extract_weights_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_weights_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *_data) +static void extract_weights_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_Weight_Data *data = (MeshExtract_Weight_Data *)_data; - const MDeformVert *dvert = (data->cd_ofs != -1) ? BM_ELEM_CD_GET_VOID_P(loop->v, data->cd_ofs) : - NULL; - data->vbo_data[l] = evaluate_vertex_weight(dvert, data->wstate); + MeshExtract_Weight_Data *data = _data; + if (data->cd_ofs != -1) { + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l->v, data->cd_ofs); + data->vbo_data[l_index] = evaluate_vertex_weight(dvert, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + } + else { + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + data->vbo_data[l_index] = evaluate_vertex_weight(NULL, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + } } -static void extract_weights_loop_mesh(const MeshRenderData *UNUSED(mr), - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *_data) +static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_Weight_Data *data = (MeshExtract_Weight_Data *)_data; - const MDeformVert *dvert = data->dvert ? &data->dvert[mloop->v] : NULL; - data->vbo_data[l] = evaluate_vertex_weight(dvert, data->wstate); + MeshExtract_Weight_Data *data = _data; + if (data->dvert != NULL) { + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MDeformVert *dvert = &data->dvert[ml->v]; + data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; + } + else { + const MDeformVert *dvert = NULL; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; + } } static void extract_weights_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data) @@ -2638,18 +3061,12 @@ static void extract_weights_finish(const MeshRenderData *UNUSED(mr), void *UNUSE } static const MeshExtract extract_weights = { - extract_weights_init, - NULL, - NULL, - extract_weights_loop_bmesh, - extract_weights_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_weights_finish, - 0, - true, + .init = extract_weights_init, + .iter_poly_bm = extract_weights_iter_poly_bm, + .iter_poly_mesh = extract_weights_iter_poly_mesh, + .finish = extract_weights_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -2756,31 +3173,31 @@ static void mesh_render_data_edge_flag(const MeshRenderData *mr, BMEdge *eed, Ed } static void mesh_render_data_loop_flag(const MeshRenderData *mr, - BMLoop *loop, + BMLoop *l, const int cd_ofs, EditLoopData *eattr) { if (cd_ofs == -1) { return; } - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_ofs); if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) { eattr->v_flag |= VFLAG_VERT_UV_PINNED; } - if (uvedit_uv_select_test_ex(mr->toolsettings, loop, cd_ofs)) { + if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) { eattr->v_flag |= VFLAG_VERT_UV_SELECT; } } static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, - BMLoop *loop, + BMLoop *l, const int cd_ofs, EditLoopData *eattr) { if (cd_ofs == -1) { return; } - if (uvedit_edge_select_test_ex(mr->toolsettings, loop, cd_ofs)) { + if (uvedit_edge_select_test_ex(mr->toolsettings, l, cd_ofs)) { eattr->v_flag |= VFLAG_EDGE_UV_SELECT; eattr->v_flag |= VFLAG_VERT_UV_SELECT; } @@ -2800,7 +3217,7 @@ static void *extract_edit_data_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust EditLoopData struct accordingly. */ + /* WARNING: Adjust #EditLoopData struct accordingly. */ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); GPU_vertformat_alias_add(&format, "flag"); } @@ -2810,114 +3227,130 @@ static void *extract_edit_data_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_edit_data_loop_bmesh(const MeshRenderData *mr, - int l, - BMLoop *loop, - void *_data) +static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + l; - memset(data, 0x0, sizeof(*data)); - mesh_render_data_face_flag(mr, loop->f, -1, data); - mesh_render_data_edge_flag(mr, loop->e, data); - mesh_render_data_vert_flag(mr, loop->v, data); -} -static void extract_edit_data_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int p, - const MPoly *UNUSED(mpoly), - void *_data) -{ - EditLoopData *data = (EditLoopData *)_data + l; - memset(data, 0x0, sizeof(*data)); - BMFace *efa = bm_original_face_get(mr, p); - BMEdge *eed = bm_original_edge_get(mr, mloop->e); - BMVert *eve = bm_original_vert_get(mr, mloop->v); - if (efa) { - mesh_render_data_face_flag(mr, efa, -1, data); - } - if (eed) { - mesh_render_data_edge_flag(mr, eed, data); - } - if (eve) { - mesh_render_data_vert_flag(mr, eve, data); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + EditLoopData *data = (EditLoopData *)_data + l_index; + memset(data, 0x0, sizeof(*data)); + mesh_render_data_face_flag(mr, l->f, -1, data); + mesh_render_data_edge_flag(mr, l->e, data); + mesh_render_data_vert_flag(mr, l->v, data); } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edit_data_ledge_bmesh(const MeshRenderData *mr, - int e, - BMEdge *eed, - void *_data) +static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + e * 2; - memset(data, 0x0, sizeof(*data) * 2); - mesh_render_data_edge_flag(mr, eed, &data[0]); - data[1] = data[0]; - mesh_render_data_vert_flag(mr, eed->v1, &data[0]); - mesh_render_data_vert_flag(mr, eed->v2, &data[1]); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + EditLoopData *data = (EditLoopData *)_data + ml_index; + memset(data, 0x0, sizeof(*data)); + BMFace *efa = bm_original_face_get(mr, mp_index); + BMEdge *eed = bm_original_edge_get(mr, ml->e); + BMVert *eve = bm_original_vert_get(mr, ml->v); + if (efa) { + mesh_render_data_face_flag(mr, efa, -1, data); + } + if (eed) { + mesh_render_data_edge_flag(mr, eed, data); + } + if (eve) { + mesh_render_data_vert_flag(mr, eve, data); + } + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_edit_data_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *edge, - void *_data) +static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + e * 2; - memset(data, 0x0, sizeof(*data) * 2); - int e_idx = mr->ledges[e]; - BMEdge *eed = bm_original_edge_get(mr, e_idx); - BMVert *eve1 = bm_original_vert_get(mr, edge->v1); - BMVert *eve2 = bm_original_vert_get(mr, edge->v2); - if (eed) { + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + EditLoopData *data = (EditLoopData *)_data + mr->loop_len + (ledge_index * 2); + memset(data, 0x0, sizeof(*data) * 2); mesh_render_data_edge_flag(mr, eed, &data[0]); data[1] = data[0]; + mesh_render_data_vert_flag(mr, eed->v1, &data[0]); + mesh_render_data_vert_flag(mr, eed->v2, &data[1]); + } + EXTRACT_LEDGE_FOREACH_BM_END; +} + +static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *_data) +{ + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + EditLoopData *data = (EditLoopData *)_data + mr->loop_len + ledge_index * 2; + memset(data, 0x0, sizeof(*data) * 2); + const int e_index = mr->ledges[ledge_index]; + BMEdge *eed = bm_original_edge_get(mr, e_index); + BMVert *eve1 = bm_original_vert_get(mr, med->v1); + BMVert *eve2 = bm_original_vert_get(mr, med->v2); + if (eed) { + mesh_render_data_edge_flag(mr, eed, &data[0]); + data[1] = data[0]; + } + if (eve1) { + mesh_render_data_vert_flag(mr, eve1, &data[0]); + } + if (eve2) { + mesh_render_data_vert_flag(mr, eve2, &data[1]); + } } - if (eve1) { - mesh_render_data_vert_flag(mr, eve1, &data[0]); - } - if (eve2) { - mesh_render_data_vert_flag(mr, eve2, &data[1]); - } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_edit_data_lvert_bmesh(const MeshRenderData *mr, - int v, - BMVert *eve, - void *_data) +static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + mr->edge_loose_len * 2 + v; - memset(data, 0x0, sizeof(*data)); - mesh_render_data_vert_flag(mr, eve, data); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + EditLoopData *data = (EditLoopData *)_data + offset + lvert_index; + memset(data, 0x0, sizeof(*data)); + mesh_render_data_vert_flag(mr, eve, data); + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_edit_data_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *UNUSED(mvert), - void *_data) +static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + mr->edge_loose_len * 2 + v; - memset(data, 0x0, sizeof(*data)); - int v_idx = mr->lverts[v]; - BMVert *eve = bm_original_vert_get(mr, v_idx); - if (eve) { - mesh_render_data_vert_flag(mr, eve, data); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + EditLoopData *data = (EditLoopData *)_data + offset + lvert_index; + memset(data, 0x0, sizeof(*data)); + const int v_index = mr->lverts[lvert_index]; + BMVert *eve = bm_original_vert_get(mr, v_index); + if (eve) { + mesh_render_data_vert_flag(mr, eve, data); + } } + EXTRACT_LVERT_FOREACH_MESH_END; } static const MeshExtract extract_edit_data = { - extract_edit_data_init, - NULL, - NULL, - extract_edit_data_loop_bmesh, - extract_edit_data_loop_mesh, - extract_edit_data_ledge_bmesh, - extract_edit_data_ledge_mesh, - extract_edit_data_lvert_bmesh, - extract_edit_data_lvert_mesh, - NULL, - 0, - true, + .init = extract_edit_data_init, + .iter_poly_bm = extract_edit_data_iter_poly_bm, + .iter_poly_mesh = extract_edit_data_iter_poly_mesh, + .iter_ledge_bm = extract_edit_data_iter_ledge_bm, + .iter_ledge_mesh = extract_edit_data_iter_ledge_mesh, + .iter_lvert_bm = extract_edit_data_iter_lvert_bm, + .iter_lvert_mesh = extract_edit_data_iter_lvert_mesh, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -2935,7 +3368,7 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust EditLoopData struct accordingly. */ + /* WARNING: Adjust #EditLoopData struct accordingly. */ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); GPU_vertformat_alias_add(&format, "flag"); } @@ -2952,51 +3385,59 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_edituv_data_loop_bmesh(const MeshRenderData *mr, - int l, - BMLoop *loop, - void *_data) +static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_EditUVData_Data *data = (MeshExtract_EditUVData_Data *)_data; - EditLoopData *eldata = data->vbo_data + l; - memset(eldata, 0x0, sizeof(*eldata)); - mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata); - mesh_render_data_face_flag(mr, loop->f, data->cd_ofs, eldata); - mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata); -} - -static void extract_edituv_data_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data) -{ - MeshExtract_EditUVData_Data *data = (MeshExtract_EditUVData_Data *)_data; - EditLoopData *eldata = data->vbo_data + l; - memset(eldata, 0x0, sizeof(*eldata)); - BMFace *efa = bm_original_face_get(mr, p); - if (efa) { - BMEdge *eed = bm_original_edge_get(mr, mloop->e); - BMVert *eve = bm_original_vert_get(mr, mloop->v); - if (eed && eve) { - /* Loop on an edge endpoint. */ - BMLoop *loop = BM_face_edge_share_loop(efa, eed); - mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata); - mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata); - } - else { - if (eed == NULL) { - /* Find if the loop's vert is not part of an edit edge. - * For this, we check if the previous loop was on an edge. */ - int loopend = mpoly->loopstart + mpoly->totloop - 1; - int l_prev = (l == mpoly->loopstart) ? loopend : (l - 1); - const MLoop *mloop_prev = &mr->mloop[l_prev]; - eed = bm_original_edge_get(mr, mloop_prev->e); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + MeshExtract_EditUVData_Data *data = _data; + EditLoopData *eldata = &data->vbo_data[l_index]; + memset(eldata, 0x0, sizeof(*eldata)); + mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata); + mesh_render_data_face_flag(mr, l->f, data->cd_ofs, eldata); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); +} + +static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) +{ + MeshExtract_EditUVData_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + EditLoopData *eldata = &data->vbo_data[ml_index]; + memset(eldata, 0x0, sizeof(*eldata)); + BMFace *efa = bm_original_face_get(mr, mp_index); + if (efa) { + BMEdge *eed = bm_original_edge_get(mr, ml->e); + BMVert *eve = bm_original_vert_get(mr, ml->v); + if (eed && eve) { + /* Loop on an edge endpoint. */ + BMLoop *l = BM_face_edge_share_loop(efa, eed); + mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); } - if (eed) { - /* Mapped points on an edge between two edit verts. */ - BMLoop *loop = BM_face_edge_share_loop(efa, eed); - mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata); + else { + if (eed == NULL) { + /* Find if the loop's vert is not part of an edit edge. + * For this, we check if the previous loop was on an edge. */ + const int ml_index_last = mp->loopstart + mp->totloop - 1; + const int l_prev = (ml_index == mp->loopstart) ? ml_index_last : (ml_index - 1); + const MLoop *ml_prev = &mr->mloop[l_prev]; + eed = bm_original_edge_get(mr, ml_prev->e); + } + if (eed) { + /* Mapped points on an edge between two edit verts. */ + BMLoop *l = BM_face_edge_share_loop(efa, eed); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); + } } } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr), @@ -3007,18 +3448,12 @@ static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_edituv_data = { - extract_edituv_data_init, - NULL, - NULL, - extract_edituv_data_loop_bmesh, - extract_edituv_data_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_data_finish, - 0, - true, + .init = extract_edituv_data_init, + .iter_poly_bm = extract_edituv_data_iter_poly_bm, + .iter_poly_mesh = extract_edituv_data_iter_poly_mesh, + .finish = extract_edituv_data_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -3078,13 +3513,13 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * } else if (mr->extract_type == MR_EXTRACT_MAPPED) { const MLoopUV *uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); - const MPoly *mpoly = mr->mpoly; - for (int p = 0; p < mr->poly_len; p++, mpoly++) { - float area = BKE_mesh_calc_poly_area(mpoly, &mr->mloop[mpoly->loopstart], mr->mvert); - float uvarea = BKE_mesh_calc_poly_uv_area(mpoly, uv_data); + const MPoly *mp = mr->mpoly; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + float area = BKE_mesh_calc_poly_area(mp, &mr->mloop[mp->loopstart], mr->mvert); + float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data); tot_area += area; tot_uv_area += uvarea; - area_ratio[p] = area_ratio_get(area, uvarea); + area_ratio[mp_index] = area_ratio_get(area, uvarea); } } else { @@ -3097,8 +3532,8 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * /* Convert in place to avoid an extra allocation */ uint16_t *poly_stretch = (uint16_t *)area_ratio; - for (int p = 0; p < mr->poly_len; p++) { - poly_stretch[p] = area_ratio[p] * SHRT_MAX; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { + poly_stretch[mp_index] = area_ratio[mp_index] * SHRT_MAX; } /* Copy face data for each loop. */ @@ -3108,18 +3543,18 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * if (mr->extract_type == MR_EXTRACT_BMESH) { BMFace *efa; BMIter f_iter; - int f, l = 0; + int f, l_index = 0; BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) { - for (int i = 0; i < efa->len; i++, l++) { - loop_stretch[l] = poly_stretch[f]; + for (int i = 0; i < efa->len; i++, l_index++) { + loop_stretch[l_index] = poly_stretch[f]; } } } else if (mr->extract_type == MR_EXTRACT_MAPPED) { - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { - for (int i = 0; i < mpoly->totloop; i++, l++) { - loop_stretch[l] = poly_stretch[p]; + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + for (int i = 0; i < mp->totloop; i++, l_index++) { + loop_stretch[l_index] = poly_stretch[mp_index]; } } } @@ -3132,18 +3567,10 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * } static const MeshExtract extract_stretch_area = { - extract_stretch_area_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - mesh_stretch_area_finish, - 0, - false, + .init = extract_stretch_area_init, + .finish = mesh_stretch_area_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -3190,7 +3617,7 @@ static short v2_to_short_angle(float v[2]) static void edituv_get_stretch_angle(float auv[2][2], float av[2][3], UVStretchAngle *r_stretch) { - /* Send uvs to the shader and let it compute the aspect corrected angle. */ + /* Send UV's to the shader and let it compute the aspect corrected angle. */ r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]); r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]); /* Compute 3D angle here. */ @@ -3208,7 +3635,7 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust UVStretchAngle struct accordingly. */ + /* Waning: adjust #UVStretchAngle struct accordingly. */ GPU_vertformat_attr_add(&format, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT); } @@ -3220,7 +3647,7 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) MeshExtract_StretchAngle_Data *data = MEM_callocN(sizeof(*data), __func__); data->vbo_data = (UVStretchAngle *)vbo->data; - /* Special iter nneded to save about half of the computing cost. */ + /* Special iterator needed to save about half of the computing cost. */ if (mr->extract_type == MR_EXTRACT_BMESH) { data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV); } @@ -3233,94 +3660,95 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_stretch_angle_loop_bmesh(const MeshRenderData *mr, - int l, - BMLoop *loop, - void *_data) +static void extract_stretch_angle_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_StretchAngle_Data *data = (MeshExtract_StretchAngle_Data *)_data; + MeshExtract_StretchAngle_Data *data = _data; float(*auv)[2] = data->auv, *last_auv = data->last_auv; float(*av)[3] = data->av, *last_av = data->last_av; - const MLoopUV *luv, *luv_next; - BMLoop *l_next = loop->next; - BMFace *efa = loop->f; - if (loop == efa->l_first) { - /* First loop in face. */ - BMLoop *l_tmp = loop->prev; - BMLoop *l_next_tmp = loop; - luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs); - luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs); - compute_normalize_edge_vectors(auv, - av, - luv->uv, - luv_next->uv, - bm_vert_co_get(mr, l_tmp->v), - bm_vert_co_get(mr, l_next_tmp->v)); - /* Save last edge. */ - copy_v2_v2(last_auv, auv[1]); - copy_v3_v3(last_av, av[1]); - } - if (l_next == efa->l_first) { - /* Move previous edge. */ - copy_v2_v2(auv[0], auv[1]); - copy_v3_v3(av[0], av[1]); - /* Copy already calculated last edge. */ - copy_v2_v2(auv[1], last_auv); - copy_v3_v3(av[1], last_av); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + const MLoopUV *luv, *luv_next; + BMLoop *l_next = l->next; + BMFace *efa = l->f; + if (l == BM_FACE_FIRST_LOOP(efa)) { + /* First loop in face. */ + BMLoop *l_tmp = l->prev; + BMLoop *l_next_tmp = l; + luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs); + luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs); + compute_normalize_edge_vectors(auv, + av, + luv->uv, + luv_next->uv, + bm_vert_co_get(mr, l_tmp->v), + bm_vert_co_get(mr, l_next_tmp->v)); + /* Save last edge. */ + copy_v2_v2(last_auv, auv[1]); + copy_v3_v3(last_av, av[1]); + } + if (l_next == BM_FACE_FIRST_LOOP(efa)) { + /* Move previous edge. */ + copy_v2_v2(auv[0], auv[1]); + copy_v3_v3(av[0], av[1]); + /* Copy already calculated last edge. */ + copy_v2_v2(auv[1], last_auv); + copy_v3_v3(av[1], last_av); + } + else { + luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs); + luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); + compute_normalize_edge_vectors( + auv, av, luv->uv, luv_next->uv, bm_vert_co_get(mr, l->v), bm_vert_co_get(mr, l_next->v)); + } + edituv_get_stretch_angle(auv, av, &data->vbo_data[l_index]); } - else { - luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs); - luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); - compute_normalize_edge_vectors(auv, - av, - luv->uv, - luv_next->uv, - bm_vert_co_get(mr, loop->v), - bm_vert_co_get(mr, l_next->v)); - } - edituv_get_stretch_angle(auv, av, data->vbo_data + l); -} - -static void extract_stretch_angle_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *UNUSED(mloop), - int UNUSED(p), - const MPoly *mpoly, - void *_data) + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); +} + +static void extract_stretch_angle_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_StretchAngle_Data *data = (MeshExtract_StretchAngle_Data *)_data; - float(*auv)[2] = data->auv, *last_auv = data->last_auv; - float(*av)[3] = data->av, *last_av = data->last_av; - int l_next = l + 1, loopend = mpoly->loopstart + mpoly->totloop; - const MVert *v, *v_next; - if (l == mpoly->loopstart) { - /* First loop in face. */ - int l_tmp = loopend - 1; - int l_next_tmp = mpoly->loopstart; - v = &mr->mvert[mr->mloop[l_tmp].v]; - v_next = &mr->mvert[mr->mloop[l_next_tmp].v]; - compute_normalize_edge_vectors( - auv, av, data->luv[l_tmp].uv, data->luv[l_next_tmp].uv, v->co, v_next->co); - /* Save last edge. */ - copy_v2_v2(last_auv, auv[1]); - copy_v3_v3(last_av, av[1]); - } - if (l_next == loopend) { - l_next = mpoly->loopstart; - /* Move previous edge. */ - copy_v2_v2(auv[0], auv[1]); - copy_v3_v3(av[0], av[1]); - /* Copy already calculated last edge. */ - copy_v2_v2(auv[1], last_auv); - copy_v3_v3(av[1], last_av); - } - else { - v = &mr->mvert[mr->mloop[l].v]; - v_next = &mr->mvert[mr->mloop[l_next].v]; - compute_normalize_edge_vectors( - auv, av, data->luv[l].uv, data->luv[l_next].uv, v->co, v_next->co); + MeshExtract_StretchAngle_Data *data = _data; + + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + float(*auv)[2] = data->auv, *last_auv = data->last_auv; + float(*av)[3] = data->av, *last_av = data->last_av; + int l_next = ml_index + 1, ml_index_end = mp->loopstart + mp->totloop; + const MVert *v, *v_next; + if (ml_index == mp->loopstart) { + /* First loop in face. */ + const int ml_index_last = ml_index_end - 1; + const int l_next_tmp = mp->loopstart; + v = &mr->mvert[mr->mloop[ml_index_last].v]; + v_next = &mr->mvert[mr->mloop[l_next_tmp].v]; + compute_normalize_edge_vectors( + auv, av, data->luv[ml_index_last].uv, data->luv[l_next_tmp].uv, v->co, v_next->co); + /* Save last edge. */ + copy_v2_v2(last_auv, auv[1]); + copy_v3_v3(last_av, av[1]); + } + if (l_next == ml_index_end) { + l_next = mp->loopstart; + /* Move previous edge. */ + copy_v2_v2(auv[0], auv[1]); + copy_v3_v3(av[0], av[1]); + /* Copy already calculated last edge. */ + copy_v2_v2(auv[1], last_auv); + copy_v3_v3(av[1], last_av); + } + else { + v = &mr->mvert[mr->mloop[ml_index].v]; + v_next = &mr->mvert[mr->mloop[l_next].v]; + compute_normalize_edge_vectors( + auv, av, data->luv[ml_index].uv, data->luv[l_next].uv, v->co, v_next->co); + } + edituv_get_stretch_angle(auv, av, &data->vbo_data[ml_index]); } - edituv_get_stretch_angle(auv, av, data->vbo_data + l); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_stretch_angle_finish(const MeshRenderData *UNUSED(mr), @@ -3331,18 +3759,12 @@ static void extract_stretch_angle_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_stretch_angle = { - extract_stretch_angle_init, - NULL, - NULL, - extract_stretch_angle_loop_bmesh, - extract_stretch_angle_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_stretch_angle_finish, - 0, - false, + .init = extract_stretch_angle_init, + .iter_poly_bm = extract_stretch_angle_iter_poly_bm, + .iter_poly_mesh = extract_stretch_angle_iter_poly_mesh, + .finish = extract_stretch_angle_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -3414,28 +3836,30 @@ static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang) normalize_v3(dir); if (mr->extract_type == MR_EXTRACT_BMESH) { - int l = 0; + int l_index = 0; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI; fac = overhang_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l++) { - r_overhang[l] = fac; + for (int i = 0; i < f->len; i++, l_index++) { + r_overhang[l_index] = fac; } } } else { - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { - float fac = angle_normalized_v3v3(mr->poly_normals[p], dir) / (float)M_PI; + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + float fac = angle_normalized_v3v3(mr->poly_normals[mp_index], dir) / (float)M_PI; fac = overhang_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mpoly->totloop; i++, l++) { - r_overhang[l] = fac; + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_overhang[l_index] = fac; } } } } -/* so we can use jitter values for face interpolation */ +/** + * Needed so we can use jitter values for face interpolation. + */ static void uv_from_jitter_v2(float uv[2]) { uv[0] += 0.5f; @@ -3527,12 +3951,12 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) BMIter iter; BMFace *f; - int l = 0; + int l_index = 0; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { float fac = face_dists[BM_elem_index_get(f)]; fac = thickness_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l++) { - r_thickness[l] = fac; + for (int i = 0; i < f->len; i++, l_index++) { + r_thickness[l_index] = fac; } } } @@ -3573,12 +3997,12 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) } } - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { - float fac = face_dists[p]; + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + float fac = face_dists[mp_index]; fac = thickness_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mpoly->totloop; i++, l++) { - r_thickness[l] = fac; + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_thickness[l_index] = fac; } } } @@ -3629,8 +4053,8 @@ static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) { BMEditMesh *em = mr->edit_bmesh; - for (int l = 0; l < mr->loop_len; l++) { - r_intersect[l] = -1.0f; + for (int l_index = 0; l_index < mr->loop_len; l_index++) { + r_intersect[l_index] = -1.0f; } if (mr->extract_type == MR_EXTRACT_BMESH) { @@ -3651,9 +4075,9 @@ static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) for (int j = 0; j < 2; j++) { BMFace *f_hit = f_hit_pair[j]; BMLoop *l_first = BM_FACE_FIRST_LOOP(f_hit); - int l = BM_elem_index_get(l_first); - for (int k = 0; k < f_hit->len; k++, l++) { - r_intersect[l] = 1.0f; + int l_index = BM_elem_index_get(l_first); + for (int k = 0; k < f_hit->len; k++, l_index++) { + r_intersect[l_index] = 1.0f; } } } @@ -3680,9 +4104,9 @@ static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) }; for (int j = 0; j < 2; j++) { const MPoly *f_hit = f_hit_pair[j]; - int l = f_hit->loopstart; - for (int k = 0; k < f_hit->totloop; k++, l++) { - r_intersect[l] = 1.0f; + int l_index = f_hit->loopstart; + for (int k = 0; k < f_hit->totloop; k++, l_index++) { + r_intersect[l_index] = 1.0f; } } } @@ -3725,9 +4149,9 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) BM_mesh_elem_index_ensure(em->bm, BM_VERT); } - int l = 0; - int p = 0; - BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, p) { + int l_index = 0; + int f_index = 0; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, f_index) { float fac = -1.0f; if (f->len > 3) { @@ -3739,7 +4163,7 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) const float *no_face; float no_corner[3]; if (mr->bm_vert_coords != NULL) { - no_face = mr->bm_poly_normals[p]; + no_face = mr->bm_poly_normals[f_index]; BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner); } else { @@ -3758,24 +4182,24 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) } fac = distort_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l++) { - r_distort[l] = fac; + for (int i = 0; i < f->len; i++, l_index++) { + r_distort[l_index] = fac; } } } else { - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { float fac = -1.0f; - if (mpoly->totloop > 3) { - float *f_no = mr->poly_normals[p]; + if (mp->totloop > 3) { + float *f_no = mr->poly_normals[mp_index]; fac = 0.0f; - for (int i = 1; i <= mpoly->totloop; i++) { - const MLoop *l_prev = &mr->mloop[mpoly->loopstart + (i - 1) % mpoly->totloop]; - const MLoop *l_curr = &mr->mloop[mpoly->loopstart + (i + 0) % mpoly->totloop]; - const MLoop *l_next = &mr->mloop[mpoly->loopstart + (i + 1) % mpoly->totloop]; + for (int i = 1; i <= mp->totloop; i++) { + const MLoop *l_prev = &mr->mloop[mp->loopstart + (i - 1) % mp->totloop]; + const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop]; + const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop]; float no_corner[3]; normal_tri_v3(no_corner, mr->mvert[l_prev->v].co, @@ -3791,8 +4215,8 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) } fac = distort_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mpoly->totloop; i++, l++) { - r_distort[l] = fac; + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_distort[l_index] = fac; } } } @@ -3825,11 +4249,10 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) copy_vn_fl(vert_angles, mr->vert_len, -M_PI); if (mr->extract_type == MR_EXTRACT_BMESH) { - BMIter iter, l_iter; + BMIter iter; BMesh *bm = em->bm; BMFace *efa; BMEdge *e; - BMLoop *loop; /* first assign float values to verts */ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { float angle = BM_edge_calc_face_angle_signed(e); @@ -3840,35 +4263,37 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) } /* Copy vert value to loops. */ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - int l = BM_elem_index_get(loop); - int v = BM_elem_index_get(loop->v); - r_sharp[l] = sharp_remap(vert_angles[v], min, max, minmax_irange); - } + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + int l_index = BM_elem_index_get(l_iter); + int v_index = BM_elem_index_get(l_iter->v); + r_sharp[l_index] = sharp_remap(vert_angles[v_index], min, max, minmax_irange); + } while ((l_iter = l_iter->next) != l_first); } } else { /* first assign float values to verts */ - const MPoly *mpoly = mr->mpoly; + const MPoly *mp = mr->mpoly; EdgeHash *eh = BLI_edgehash_new_ex(__func__, mr->edge_len); - for (int p = 0; p < mr->poly_len; p++, mpoly++) { - for (int i = 0; i < mpoly->totloop; i++) { - const MLoop *l_curr = &mr->mloop[mpoly->loopstart + (i + 0) % mpoly->totloop]; - const MLoop *l_next = &mr->mloop[mpoly->loopstart + (i + 1) % mpoly->totloop]; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + for (int i = 0; i < mp->totloop; i++) { + const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop]; + const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop]; const MVert *v_curr = &mr->mvert[l_curr->v]; const MVert *v_next = &mr->mvert[l_next->v]; float angle; void **pval; bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval); if (!value_is_init) { - *pval = mr->poly_normals[p]; + *pval = mr->poly_normals[mp_index]; /* non-manifold edge, yet... */ continue; } else if (*pval != NULL) { - const float *f1_no = mr->poly_normals[p]; + const float *f1_no = mr->poly_normals[mp_index]; const float *f2_no = *pval; angle = angle_normalized_v3v3(f1_no, f2_no); angle = is_edge_convex_v3(v_curr->co, v_next->co, f1_no, f2_no) ? angle : -angle; @@ -3901,9 +4326,9 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) BLI_edgehashIterator_free(ehi); BLI_edgehash_free(eh, NULL); - const MLoop *mloop = mr->mloop; - for (int l = 0; l < mr->loop_len; l++, mloop++) { - r_sharp[l] = sharp_remap(vert_angles[mloop->v], min, max, minmax_irange); + const MLoop *ml = mr->mloop; + for (int l_index = 0; l_index < mr->loop_len; l_index++, ml++) { + r_sharp[l_index] = sharp_remap(vert_angles[ml->v], min, max, minmax_irange); } } @@ -3937,20 +4362,12 @@ static void extract_mesh_analysis_finish(const MeshRenderData *mr, void *buf, vo } static const MeshExtract extract_mesh_analysis = { - extract_mesh_analysis_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_mesh_analysis_finish, - /* This is not needed for all vis type. - * Maybe split into different extract. */ - MR_DATA_POLY_NOR | MR_DATA_LOOPTRI, - false, + .init = extract_mesh_analysis_init, + .finish = extract_mesh_analysis_finish, + /* This is not needed for all visualization types. + * * Maybe split into different extract. */ + .data_flag = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI, + .use_threading = false, }; /** \} */ @@ -3975,49 +4392,46 @@ static void *extract_fdots_pos_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_fdots_pos_loop_bmesh(const MeshRenderData *mr, - int UNUSED(l), - BMLoop *loop, - void *data) +static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - float(*center)[3] = (float(*)[3])data; - float w = 1.0f / (float)loop->f->len; - madd_v3_v3fl(center[BM_elem_index_get(loop->f)], bm_vert_co_get(mr, loop->v), w); + float(*center)[3] = data; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + float w = 1.0f / (float)l->f->len; + madd_v3_v3fl(center[BM_elem_index_get(l->f)], bm_vert_co_get(mr, l->v), w); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_fdots_pos_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *mloop, - int p, - const MPoly *mpoly, - void *data) +static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { float(*center)[3] = (float(*)[3])data; - const MVert *mvert = &mr->mvert[mloop->v]; - if (mr->use_subsurf_fdots) { - if (mvert->flag & ME_VERT_FACEDOT) { - copy_v3_v3(center[p], mvert->co); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MVert *mv = &mr->mvert[ml->v]; + if (mr->use_subsurf_fdots) { + if (mv->flag & ME_VERT_FACEDOT) { + copy_v3_v3(center[mp_index], mv->co); + } + } + else { + float w = 1.0f / (float)mp->totloop; + madd_v3_v3fl(center[mp_index], mv->co, w); } } - else { - float w = 1.0f / (float)mpoly->totloop; - madd_v3_v3fl(center[p], mvert->co, w); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static const MeshExtract extract_fdots_pos = { - extract_fdots_pos_init, - NULL, - NULL, - extract_fdots_pos_loop_bmesh, - extract_fdots_pos_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_fdots_pos_init, + .iter_poly_bm = extract_fdots_pos_iter_poly_bm, + .iter_poly_mesh = extract_fdots_pos_iter_poly_mesh, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4090,18 +4504,10 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void * } static const MeshExtract extract_fdots_nor = { - extract_fdots_nor_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_fdots_nor_finish, - MR_DATA_POLY_NOR, - false, + .init = extract_fdots_nor_init, + .finish = extract_fdots_nor_finish, + .data_flag = MR_DATA_POLY_NOR, + .use_threading = false, }; /** \} */ @@ -4145,30 +4551,42 @@ static void *extract_fdots_uv_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_fdots_uv_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *_data) +static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_FdotUV_Data *data = (MeshExtract_FdotUV_Data *)_data; - float w = 1.0f / (float)loop->f->len; - const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs); - madd_v2_v2fl(data->vbo_data[BM_elem_index_get(loop->f)], luv->uv, w); + MeshExtract_FdotUV_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + float w = 1.0f / (float)l->f->len; + const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs); + madd_v2_v2fl(data->vbo_data[BM_elem_index_get(l->f)], luv->uv, w); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_fdots_uv_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data) +static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_FdotUV_Data *data = (MeshExtract_FdotUV_Data *)_data; + MeshExtract_FdotUV_Data *data = _data; if (mr->use_subsurf_fdots) { - const MVert *mvert = &mr->mvert[mloop->v]; - if (mvert->flag & ME_VERT_FACEDOT) { - copy_v2_v2(data->vbo_data[p], data->uv_data[l].uv); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MVert *mv = &mr->mvert[ml->v]; + if (mv->flag & ME_VERT_FACEDOT) { + copy_v2_v2(data->vbo_data[mp_index], data->uv_data[ml_index].uv); + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - float w = 1.0f / (float)mpoly->totloop; - madd_v2_v2fl(data->vbo_data[p], data->uv_data[l].uv, w); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + float w = 1.0f / (float)mp->totloop; + madd_v2_v2fl(data->vbo_data[mp_index], data->uv_data[ml_index].uv, w); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } } @@ -4180,18 +4598,12 @@ static void extract_fdots_uv_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_fdots_uv = { - extract_fdots_uv_init, - NULL, - NULL, - extract_fdots_uv_loop_bmesh, - extract_fdots_uv_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_fdots_uv_finish, - 0, - true, + .init = extract_fdots_uv_init, + .iter_poly_bm = extract_fdots_uv_iter_poly_bm, + .iter_poly_mesh = extract_fdots_uv_iter_poly_mesh, + .finish = extract_fdots_uv_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4220,31 +4632,35 @@ static void *extract_fdots_edituv_data_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_fdots_edituv_data_loop_bmesh(const MeshRenderData *mr, - int UNUSED(l), - BMLoop *loop, - void *_data) +static void extract_fdots_edituv_data_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_EditUVFdotData_Data *data = (MeshExtract_EditUVFdotData_Data *)_data; - EditLoopData *eldata = data->vbo_data + BM_elem_index_get(loop->f); - memset(eldata, 0x0, sizeof(*eldata)); - mesh_render_data_face_flag(mr, loop->f, data->cd_ofs, eldata); + MeshExtract_EditUVFdotData_Data *data = _data; + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + EditLoopData *eldata = &data->vbo_data[BM_elem_index_get(f)]; + memset(eldata, 0x0, sizeof(*eldata)); + mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata); + } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_fdots_edituv_data_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *UNUSED(mloop), - int p, - const MPoly *UNUSED(mpoly), - void *_data) +static void extract_fdots_edituv_data_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_EditUVFdotData_Data *data = (MeshExtract_EditUVFdotData_Data *)_data; - EditLoopData *eldata = data->vbo_data + p; - memset(eldata, 0x0, sizeof(*eldata)); - BMFace *efa = bm_original_face_get(mr, p); - if (efa) { - mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata); + MeshExtract_EditUVFdotData_Data *data = _data; + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + EditLoopData *eldata = &data->vbo_data[mp_index]; + memset(eldata, 0x0, sizeof(*eldata)); + BMFace *efa = bm_original_face_get(mr, mp_index); + if (efa) { + mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata); + } } + EXTRACT_POLY_FOREACH_MESH_END; } static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr), @@ -4255,18 +4671,12 @@ static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_fdots_edituv_data = { - extract_fdots_edituv_data_init, - NULL, - NULL, - extract_fdots_edituv_data_loop_bmesh, - extract_fdots_edituv_data_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_fdots_edituv_data_finish, - 0, - true, + .init = extract_fdots_edituv_data_init, + .iter_poly_bm = extract_fdots_edituv_data_iter_poly_bm, + .iter_poly_mesh = extract_fdots_edituv_data_iter_poly_mesh, + .finish = extract_fdots_edituv_data_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4317,18 +4727,9 @@ static void *extract_skin_roots_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_skin_roots = { - extract_skin_roots_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - false, + .init = extract_skin_roots_init, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -4350,157 +4751,183 @@ static void *extract_select_idx_init(const MeshRenderData *mr, void *buf) return vbo->data; } -/* TODO Use glVertexID to get loop index and use the data structure on the CPU to retrieve the +/* TODO Use #glVertexID to get loop index and use the data structure on the CPU to retrieve the * select element associated with this loop ID. This would remove the need for this separate - * index VBOs. We could upload the p/e/v_origindex as a buffer texture and sample it inside the + * index VBO's. We could upload the p/e/v_origindex as a buffer texture and sample it inside the * shader to output original index. */ -static void extract_poly_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_poly_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = BM_elem_index_get(loop->f); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((uint32_t *)data)[l_index] = BM_elem_index_get(l->f); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edge_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_edge_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = BM_elem_index_get(loop->e); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((uint32_t *)data)[l_index] = BM_elem_index_get(l->e); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_vert_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_vert_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = BM_elem_index_get(loop->v); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((uint32_t *)data)[l_index] = BM_elem_index_get(l->v); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edge_idx_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *data) +static void extract_edge_idx_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *data) { - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = BM_elem_index_get(eed); - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = BM_elem_index_get(eed); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed); + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed); + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_vert_idx_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *data) +static void extract_vert_idx_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *data) { - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = BM_elem_index_get(eed->v1); - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = BM_elem_index_get(eed->v2); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1); + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2); + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_vert_idx_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *data) +static void extract_vert_idx_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *data) { - ((uint32_t *)data)[mr->loop_len + mr->edge_loose_len * 2 + v] = BM_elem_index_get(eve); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + ((uint32_t *)data)[offset + lvert_index] = BM_elem_index_get(eve); + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_poly_idx_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *UNUSED(mloop), - int p, - const MPoly *UNUSED(mpoly), - void *data) +static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = (mr->p_origindex) ? mr->p_origindex[p] : p; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + ((uint32_t *)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_edge_idx_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *data) +static void extract_edge_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = (mr->e_origindex) ? mr->e_origindex[mloop->e] : mloop->e; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + ((uint32_t *)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_vert_idx_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *data) +static void extract_vert_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = (mr->v_origindex) ? mr->v_origindex[mloop->v] : mloop->v; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + ((uint32_t *)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_edge_idx_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *UNUSED(medge), - void *data) +static void extract_edge_idx_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *data) { - int e_idx = mr->ledges[e]; - int e_orig = (mr->e_origindex) ? mr->e_origindex[e_idx] : e_idx; - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = e_orig; - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = e_orig; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + const int e_index = mr->ledges[ledge_index]; + const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_vert_idx_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *data) +static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *data) { - int v1_orig = (mr->v_origindex) ? mr->v_origindex[medge->v1] : medge->v1; - int v2_orig = (mr->v_origindex) ? mr->v_origindex[medge->v2] : medge->v2; - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = v1_orig; - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = v2_orig; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1; + int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_vert_idx_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *UNUSED(mvert), - void *data) +static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *data) { - int v_idx = mr->lverts[v]; - int v_orig = (mr->v_origindex) ? mr->v_origindex[v_idx] : v_idx; - ((uint32_t *)data)[mr->loop_len + mr->edge_loose_len * 2 + v] = v_orig; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(med, lvert_index, params, mr) + { + const int v_index = mr->lverts[lvert_index]; + const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index; + ((uint32_t *)data)[offset + lvert_index] = v_orig; + } + EXTRACT_LVERT_FOREACH_MESH_END; } static const MeshExtract extract_poly_idx = { - extract_select_idx_init, - NULL, - NULL, - extract_poly_idx_loop_bmesh, - extract_poly_idx_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_select_idx_init, + .iter_poly_bm = extract_poly_idx_iter_poly_bm, + .iter_poly_mesh = extract_poly_idx_iter_poly_mesh, + .data_flag = 0, + .use_threading = true, }; static const MeshExtract extract_edge_idx = { - extract_select_idx_init, - NULL, - NULL, - extract_edge_idx_loop_bmesh, - extract_edge_idx_loop_mesh, - extract_edge_idx_ledge_bmesh, - extract_edge_idx_ledge_mesh, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_select_idx_init, + .iter_poly_bm = extract_edge_idx_iter_poly_bm, + .iter_poly_mesh = extract_edge_idx_iter_poly_mesh, + .iter_ledge_bm = extract_edge_idx_iter_ledge_bm, + .iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh, + .data_flag = 0, + .use_threading = true, }; static const MeshExtract extract_vert_idx = { - extract_select_idx_init, - NULL, - NULL, - extract_vert_idx_loop_bmesh, - extract_vert_idx_loop_mesh, - extract_vert_idx_ledge_bmesh, - extract_vert_idx_ledge_mesh, - extract_vert_idx_lvert_bmesh, - extract_vert_idx_lvert_mesh, - NULL, - 0, - true, + .init = extract_select_idx_init, + .iter_poly_bm = extract_vert_idx_iter_poly_bm, + .iter_poly_mesh = extract_vert_idx_iter_poly_mesh, + .iter_ledge_bm = extract_vert_idx_iter_ledge_bm, + .iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh, + .iter_lvert_bm = extract_vert_idx_iter_lvert_bm, + .iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh, + .data_flag = 0, + .use_threading = true, }; static void *extract_select_fdot_idx_init(const MeshRenderData *mr, void *buf) @@ -4516,37 +4943,43 @@ static void *extract_select_fdot_idx_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_fdot_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *data) +static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[BM_elem_index_get(loop->f)] = BM_elem_index_get(loop->f); + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + ((uint32_t *)data)[f_index] = f_index; + } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_fdot_idx_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *UNUSED(mloop), - int p, - const MPoly *UNUSED(mpoly), - void *data) +static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[p] = (mr->p_origindex) ? mr->p_origindex[p] : p; + if (mr->p_origindex != NULL) { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + ((uint32_t *)data)[mp_index] = mr->p_origindex[mp_index]; + } + EXTRACT_POLY_FOREACH_MESH_END; + } + else { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + ((uint32_t *)data)[mp_index] = mp_index; + } + EXTRACT_POLY_FOREACH_MESH_END; + } } static const MeshExtract extract_fdot_idx = { - extract_select_fdot_idx_init, - NULL, - NULL, - extract_fdot_idx_loop_bmesh, - extract_fdot_idx_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_select_fdot_idx_init, + .iter_poly_bm = extract_fdot_idx_iter_poly_bm, + .iter_poly_mesh = extract_fdot_idx_iter_poly_mesh, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4589,9 +5022,9 @@ static ExtractTaskData *extract_task_data_create_mesh_extract(const MeshRenderDa taskdata->extract = extract; taskdata->buf = buf; - /* ExtractUserData is shared between the iterations as it holds counters to detect if the - * extraction is finished. To make sure the duplication of the userdata does not create a new - * instance of the counters we allocate the userdata in its own container. + /* #ExtractUserData is shared between the iterations as it holds counters to detect if the + * extraction is finished. To make sure the duplication of the user_data does not create a new + * instance of the counters we allocate the user_data in its own container. * * This structure makes sure that when extract_init is called, that the user data of all * iterations are updated. */ @@ -4628,67 +5061,69 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, switch (mr->extract_type) { case MR_EXTRACT_BMESH: if (iter_type & MR_ITER_LOOPTRI) { - int t_end = min_ii(mr->tri_len, end); - for (int t = start; t < t_end; t++) { - BMLoop **elt = &mr->edit_bmesh->looptris[t][0]; - extract->iter_looptri_bm(mr, t, elt, user_data); - } + extract->iter_looptri_bm(mr, + &(const ExtractTriBMesh_Params){ + .looptris = mr->edit_bmesh->looptris, + .tri_range = {start, min_ii(mr->tri_len, end)}, + }, + user_data); } - if (iter_type & MR_ITER_LOOP) { - int l_end = min_ii(mr->poly_len, end); - for (int f = start; f < l_end; f++) { - BMFace *efa = BM_face_at_index(mr->bm, f); - BMLoop *loop; - BMIter l_iter; - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - extract->iter_loop_bm(mr, BM_elem_index_get(loop), loop, user_data); - } - } + if (iter_type & MR_ITER_POLY) { + extract->iter_poly_bm(mr, + &(const ExtractPolyBMesh_Params){ + .poly_range = {start, min_ii(mr->poly_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LEDGE) { - int le_end = min_ii(mr->edge_loose_len, end); - for (int e = start; e < le_end; e++) { - BMEdge *eed = BM_edge_at_index(mr->bm, mr->ledges[e]); - extract->iter_ledge_bm(mr, e, eed, user_data); - } + extract->iter_ledge_bm(mr, + &(const ExtractLEdgeBMesh_Params){ + .ledge = mr->ledges, + .ledge_range = {start, min_ii(mr->edge_loose_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LVERT) { - int lv_end = min_ii(mr->vert_loose_len, end); - for (int v = start; v < lv_end; v++) { - BMVert *eve = BM_vert_at_index(mr->bm, mr->lverts[v]); - extract->iter_lvert_bm(mr, v, eve, user_data); - } + extract->iter_lvert_bm(mr, + &(const ExtractLVertBMesh_Params){ + .lvert = mr->lverts, + .lvert_range = {start, min_ii(mr->vert_loose_len, end)}, + }, + user_data); } break; case MR_EXTRACT_MAPPED: case MR_EXTRACT_MESH: if (iter_type & MR_ITER_LOOPTRI) { - int t_end = min_ii(mr->tri_len, end); - for (int t = start; t < t_end; t++) { - extract->iter_looptri(mr, t, &mr->mlooptri[t], user_data); - } + extract->iter_looptri_mesh(mr, + &(const ExtractTriMesh_Params){ + .mlooptri = mr->mlooptri, + .tri_range = {start, min_ii(mr->tri_len, end)}, + }, + user_data); } - if (iter_type & MR_ITER_LOOP) { - int l_end = min_ii(mr->poly_len, end); - for (int p = start; p < l_end; p++) { - const MPoly *mpoly = &mr->mpoly[p]; - int l = mpoly->loopstart; - for (int i = 0; i < mpoly->totloop; i++, l++) { - extract->iter_loop(mr, l, &mr->mloop[l], p, mpoly, user_data); - } - } + if (iter_type & MR_ITER_POLY) { + extract->iter_poly_mesh(mr, + &(const ExtractPolyMesh_Params){ + .poly_range = {start, min_ii(mr->poly_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LEDGE) { - int le_end = min_ii(mr->edge_loose_len, end); - for (int e = start; e < le_end; e++) { - extract->iter_ledge(mr, e, &mr->medge[mr->ledges[e]], user_data); - } + extract->iter_ledge_mesh(mr, + &(const ExtractLEdgeMesh_Params){ + .ledge = mr->ledges, + .ledge_range = {start, min_ii(mr->edge_loose_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LVERT) { - int lv_end = min_ii(mr->vert_loose_len, end); - for (int v = start; v < lv_end; v++) { - extract->iter_lvert(mr, v, &mr->mvert[mr->lverts[v]], user_data); - } + extract->iter_lvert_mesh(mr, + &(const ExtractLVertMesh_Params){ + .lvert = mr->lverts, + .lvert_range = {start, min_ii(mr->vert_loose_len, end)}, + }, + user_data); } break; } @@ -4915,10 +5350,10 @@ static void extract_task_create(struct TaskGraph *task_graph, task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOPTRI, i, chunk_size); } } - if (taskdata->iter_type & MR_ITER_LOOP) { + if (taskdata->iter_type & MR_ITER_POLY) { for (int i = 0; i < mr->poly_len; i += chunk_size) { extract_range_task_create( - task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOP, i, chunk_size); + task_graph, task_node_user_data_init, taskdata, MR_ITER_POLY, i, chunk_size); } } if (taskdata->iter_type & MR_ITER_LEDGE) { @@ -4973,9 +5408,9 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, * `extract_single_threaded_task_node`. * * Other extractions will create a node for each loop exceeding 8192 items. these nodes are - * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the userdata - * needed for the extraction based on the data extracted from the mesh. counters are used to - * check if the finalize of a task has to be called. + * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the + * user_data needed for the extraction based on the data extracted from the mesh. + * counters are used to check if the finalize of a task has to be called. * * Mesh extraction sub graph * diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 191d75342d0..5cf1c24af0b 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -170,6 +170,7 @@ struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Mesh *me, struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me); /* edit-mesh drawing */ struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(struct Mesh *me); @@ -199,6 +200,11 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me); +/* For direct data access. */ +struct GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(struct Mesh *me); +struct GPUVertBuf *DRW_curve_batch_cache_pos_vertbuf_get(struct Curve *cu); +struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(struct Object *ob); + int DRW_mesh_material_count_get(struct Mesh *me); /* See 'common_globals_lib.glsl' for duplicate defines. */ diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index 8798549a416..73e0ff7ef83 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -903,6 +903,16 @@ GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu, return cache->surf_per_mat; } +GPUVertBuf *DRW_curve_batch_cache_pos_vertbuf_get(struct Curve *cu) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ + DRW_batch_request(&cache->batch.surfaces); + + DRW_vbo_request(NULL, &cache->ordered.loop_pos_nor); + return cache->ordered.loop_pos_nor; +} + GPUBatch *DRW_curve_batch_cache_get_wireframes_face(Curve *cu) { CurveBatchCache *cache = curve_batch_cache_get(cu); diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index b4974330043..53e04fb61ee 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -349,10 +349,10 @@ static void gpencil_stroke_iter_cb(bGPDlayer *UNUSED(gpl), } } -static void gp_object_verts_count_cb(bGPDlayer *UNUSED(gpl), - bGPDframe *UNUSED(gpf), - bGPDstroke *gps, - void *thunk) +static void gpencil_object_verts_count_cb(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) { gpIterData *iter = (gpIterData *)thunk; @@ -387,7 +387,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr .tri_len = 0, }; BKE_gpencil_visible_stroke_iter( - NULL, ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra); + NULL, ob, NULL, gpencil_object_verts_count_cb, &iter, do_onion, cfra); /* Create VBOs. */ GPUVertFormat *format = gpencil_stroke_format(); @@ -441,10 +441,10 @@ GPUBatch *DRW_cache_gpencil_fills_get(Object *ob, int cfra) return cache->fill_batch; } -static void gp_lines_indices_cb(bGPDlayer *UNUSED(gpl), - bGPDframe *UNUSED(gpf), - bGPDstroke *gps, - void *thunk) +static void gpencil_lines_indices_cb(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) { gpIterData *iter = (gpIterData *)thunk; int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps); @@ -477,7 +477,8 @@ GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob) /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */ bool do_onion = true; - BKE_gpencil_visible_stroke_iter(NULL, ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter( + NULL, ob, NULL, gpencil_lines_indices_cb, &iter, do_onion, cfra); GPUIndexBuf *ibo = GPU_indexbuf_build(&iter.ibo); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 99e285a18f1..ea1717f0684 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -112,6 +112,21 @@ BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) return &me->ldata; } +BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_MDATA: + return &me->vdata; + break; + case ME_WRAPPER_TYPE_BMESH: + return &me->edit_mesh->bm->vdata; + break; + } + + BLI_assert(0); + return &me->vdata; +} + static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; @@ -135,7 +150,19 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); + + int layer = CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR); + if (layer != -1) { + cd_used->sculpt_vcol |= (1 << layer); + } +} + +static void mesh_cd_calc_active_mloopcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used) +{ + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); if (layer != -1) { cd_used->vcol |= (1 << layer); @@ -148,6 +175,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); /* See: DM_vertex_attributes_from_gpu for similar logic */ DRW_MeshCDMask cd_used; @@ -175,6 +203,11 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name); type = CD_MCOL; } + + if (layer == -1) { + layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name); + type = CD_PROP_COLOR; + } #if 0 /* Tangents are always from UV's - this will never happen. */ if (layer == -1) { layer = CustomData_get_named_layer(cd_ldata, CD_TANGENT, name); @@ -222,7 +255,20 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, } break; } + case CD_PROP_COLOR: { + /* Sculpt Vertex Colors */ + if (layer == -1) { + layer = (name[0] != '\0') ? + CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name) : + CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR); + } + if (layer != -1) { + cd_used.sculpt_vcol |= (1 << layer); + } + break; + } case CD_MCOL: { + /* Vertex Color Data */ if (layer == -1) { layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name) : CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL); @@ -230,6 +276,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, if (layer != -1) { cd_used.vcol |= (1 << layer); } + break; } case CD_ORCO: { @@ -679,10 +726,22 @@ static void texpaint_request_active_vcol(MeshBatchCache *cache, Mesh *me) { DRW_MeshCDMask cd_needed; mesh_cd_layers_type_clear(&cd_needed); - mesh_cd_calc_active_vcol_layer(me, &cd_needed); + mesh_cd_calc_active_mloopcol_layer(me, &cd_needed); BLI_assert(cd_needed.vcol != 0 && - "No vcol layer available in vertpaint, but batches requested anyway!"); + "No MLOOPCOL layer available in vertpaint, but batches requested anyway!"); + + mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); +} + +static void sculpt_request_active_vcol(MeshBatchCache *cache, Mesh *me) +{ + DRW_MeshCDMask cd_needed; + mesh_cd_layers_type_clear(&cd_needed); + mesh_cd_calc_active_vcol_layer(me, &cd_needed); + + BLI_assert(cd_needed.sculpt_vcol != 0 && + "No MPropCol layer available in Sculpt, but batches requested anyway!"); mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); } @@ -799,6 +858,14 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Mesh *me) return DRW_batch_request(&cache->batch.surface); } +GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + sculpt_request_active_vcol(cache, me); + mesh_batch_cache_add_request(cache, MBC_SURFACE); + return DRW_batch_request(&cache->batch.surface); +} + int DRW_mesh_material_count_get(Mesh *me) { return mesh_render_mat_len_get(me); @@ -810,6 +877,23 @@ int DRW_mesh_material_count_get(Mesh *me) /** \name Edit Mode API * \{ */ +GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ + mesh_batch_cache_add_request(cache, MBC_SURFACE); + DRW_batch_request(&cache->batch.surface); + + DRW_vbo_request(NULL, &cache->final.vbo.pos_nor); + return cache->final.vbo.pos_nor; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Edit Mode API + * \{ */ + GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); @@ -1120,7 +1204,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if (cache->cd_used.orco != cache->cd_needed.orco) { GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.orco); } - if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) { + if (((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) || + ((cache->cd_used.sculpt_vcol & cache->cd_needed.sculpt_vcol) != + cache->cd_needed.sculpt_vcol)) { GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.vcol); } } @@ -1201,7 +1287,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if (cache->cd_used.uv != 0) { DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.uv); } - if (cache->cd_used.vcol != 0) { + if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) { DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.vcol); } } @@ -1269,7 +1355,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if ((cache->cd_used.tan != 0) || (cache->cd_used.tan_orco != 0)) { DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.tan); } - if (cache->cd_used.vcol != 0) { + if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) { DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.vcol); } if (cache->cd_used.orco != 0) { diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c index c14e66c2b47..076d32ffe1f 100644 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ b/source/blender/draw/intern/draw_cache_impl_metaball.c @@ -274,6 +274,18 @@ struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob, return cache->edge_detection; } +struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(Object *ob) +{ + if (!BKE_mball_is_basis(ob)) { + return NULL; + } + + MetaBall *mb = ob->data; + MetaBallBatchCache *cache = metaball_batch_cache_get(mb); + + return mball_batch_cache_get_pos_and_normals(ob, cache); +} + int DRW_metaball_material_count_get(MetaBall *mb) { return max_ii(1, mb->totcol); diff --git a/source/blender/draw/intern/draw_cache_inline.h b/source/blender/draw/intern/draw_cache_inline.h index a067434f3bb..67f44b5fb0c 100644 --- a/source/blender/draw/intern/draw_cache_inline.h +++ b/source/blender/draw/intern/draw_cache_inline.h @@ -90,17 +90,19 @@ BLI_INLINE void DRW_vbo_request(GPUBatch *batch, GPUVertBuf **vbo) if (*vbo == NULL) { *vbo = MEM_callocN(sizeof(GPUVertBuf), "GPUVertBuf"); } - /* HACK set first vbo if not init. */ - if (batch->verts[0] == NULL) { - GPU_batch_vao_cache_clear(batch); - batch->verts[0] = *vbo; - } - else { - /* HACK: bypass assert */ - int vbo_vert_len = (*vbo)->vertex_len; - (*vbo)->vertex_len = batch->verts[0]->vertex_len; - GPU_batch_vertbuf_add(batch, *vbo); - (*vbo)->vertex_len = vbo_vert_len; + if (batch != NULL) { + /* HACK set first vbo if not init. */ + if (batch->verts[0] == NULL) { + GPU_batch_vao_cache_clear(batch); + batch->verts[0] = *vbo; + } + else { + /* HACK: bypass assert */ + int vbo_vert_len = (*vbo)->vertex_len; + (*vbo)->vertex_len = batch->verts[0]->vertex_len; + GPU_batch_vertbuf_add(batch, *vbo); + (*vbo)->vertex_len = vbo_vert_len; + } } } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 656d72b2808..81c0e97a1a8 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -176,6 +176,13 @@ struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, struct DRWShadingGroup *shgrp); +struct GPUVertBuf *DRW_hair_pos_buffer_get(struct Object *object, + struct ParticleSystem *psys, + struct ModifierData *md); +void DRW_hair_duplimat_get(struct Object *object, + struct ParticleSystem *psys, + struct ModifierData *md, + float (*dupli_mat)[4]); void DRW_hair_init(void); void DRW_hair_update(void); diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 2fdaf0d5345..6cfba0e2a78 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -124,32 +124,109 @@ void DRW_hair_init(void) } } -DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, - ParticleSystem *psys, - ModifierData *md, - DRWShadingGroup *shgrp_parent) +static ParticleHairCache *drw_hair_particle_cache_get( + Object *object, ParticleSystem *psys, ModifierData *md, int subdiv, int thickness_res) +{ + bool update; + ParticleHairCache *cache; + if (psys) { + /* Old particle hair. */ + update = particles_ensure_procedural_data(object, psys, md, &cache, subdiv, thickness_res); + } + else { + /* New hair object. */ + update = hair_ensure_procedural_data(object, &cache, subdiv, thickness_res); + } + + if (update) { + int final_points_len = cache->final[subdiv].strands_res * cache->strands_len; + if (final_points_len > 0) { + GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); + +#ifdef USE_TRANSFORM_FEEDBACK + DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( + tf_shader, g_tf_pass, cache->final[subdiv].proc_buf); +#else + DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); + + ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__); + pr_call->next = g_tf_calls; + pr_call->vbo = cache->final[subdiv].proc_buf; + pr_call->shgrp = tf_shgrp; + pr_call->vert_len = final_points_len; + g_tf_calls = pr_call; + DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); + DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); + DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); +#endif + + DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", cache->point_tex); + DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", cache->strand_tex); + DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", cache->strand_seg_tex); + DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1); + DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len); + } + } + return cache; +} + +/* Note: Only valid after DRW_hair_update(). */ +GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md) { - /* TODO(fclem): Pass the scene as parameter */ const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - float dupli_mat[4][4]; - Object *dupli_parent = DRW_object_get_dupli_parent(object); - DupliObject *dupli_object = DRW_object_get_dupli(object); int subdiv = scene->r.hair_subdiv; int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; - ParticleHairCache *hair_cache; - bool need_ft_update; + ParticleHairCache *cache = drw_hair_particle_cache_get(object, psys, md, subdiv, thickness_res); + + return cache->final[subdiv].proc_buf; +} + +void DRW_hair_duplimat_get(Object *object, + ParticleSystem *psys, + ModifierData *UNUSED(md), + float (*dupli_mat)[4]) +{ + Object *dupli_parent = DRW_object_get_dupli_parent(object); + DupliObject *dupli_object = DRW_object_get_dupli(object); + if (psys) { - /* Old particle hair. */ - need_ft_update = particles_ensure_procedural_data( - object, psys, md, &hair_cache, subdiv, thickness_res); + if ((dupli_parent != NULL) && (dupli_object != NULL)) { + if (dupli_object->type & OB_DUPLICOLLECTION) { + copy_m4_m4(dupli_mat, dupli_parent->obmat); + } + else { + copy_m4_m4(dupli_mat, dupli_object->ob->obmat); + invert_m4(dupli_mat); + mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat); + } + } + else { + unit_m4(dupli_mat); + } } else { /* New hair object. */ - need_ft_update = hair_ensure_procedural_data(object, &hair_cache, subdiv, thickness_res); + copy_m4_m4(dupli_mat, object->obmat); } +} + +DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, + ParticleSystem *psys, + ModifierData *md, + DRWShadingGroup *shgrp_parent) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + float dupli_mat[4][4]; + + int subdiv = scene->r.hair_subdiv; + int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; + + ParticleHairCache *hair_cache = drw_hair_particle_cache_get( + object, psys, md, subdiv, thickness_res); DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); @@ -177,25 +254,7 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture); } - if (psys) { - if ((dupli_parent != NULL) && (dupli_object != NULL)) { - if (dupli_object->type & OB_DUPLICOLLECTION) { - copy_m4_m4(dupli_mat, dupli_parent->obmat); - } - else { - copy_m4_m4(dupli_mat, dupli_object->ob->obmat); - invert_m4(dupli_mat); - mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat); - } - } - else { - unit_m4(dupli_mat); - } - } - else { - /* New hair object. */ - copy_m4_m4(dupli_mat, object->obmat); - } + DRW_hair_duplimat_get(object, psys, md, dupli_mat); /* Get hair shape parameters. */ float hair_rad_shape, hair_rad_root, hair_rad_tip; @@ -229,38 +288,6 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, GPUBatch *geom = hair_cache->final[subdiv].proc_hairs[thickness_res - 1]; DRW_shgroup_call_no_cull(shgrp, geom, object); - /* Transform Feedback subdiv. */ - if (need_ft_update) { - int final_points_len = hair_cache->final[subdiv].strands_res * hair_cache->strands_len; - if (final_points_len) { - GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); - -#ifdef USE_TRANSFORM_FEEDBACK - DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( - tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf); -#else - DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); - - ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__); - pr_call->next = g_tf_calls; - pr_call->vbo = hair_cache->final[subdiv].proc_buf; - pr_call->shgrp = tf_shgrp; - pr_call->vert_len = final_points_len; - g_tf_calls = pr_call; - DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); - DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); - DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); -#endif - - DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex); - DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex); - DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex); - DRW_shgroup_uniform_int( - tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); - DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len); - } - } - return shgrp; } diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 10ef8d9c4c8..3e42c4cdb23 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -373,6 +373,8 @@ void DRW_render_viewport_size_set(int size[2]) { DST.size[0] = size[0]; DST.size[1] = size[1]; + DST.inv_size[0] = 1.0f / size[0]; + DST.inv_size[1] = 1.0f / size[1]; } const float *DRW_viewport_size_get(void) @@ -1635,13 +1637,6 @@ bool DRW_render_check_grease_pencil(Depsgraph *depsgraph) return false; } -static void drw_view_reset(void) -{ - DST.view_default = NULL; - DST.view_active = NULL; - DST.view_previous = NULL; -} - static void DRW_render_gpencil_to_image(RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect) @@ -1719,7 +1714,7 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph for (RenderView *render_view = render_result->views.first; render_view != NULL; render_view = render_view->next) { RE_SetActiveRenderView(render, render_view->name); - drw_view_reset(); + DRW_view_reset(); DST.buffer_finish_called = false; DRW_render_gpencil_to_image(engine, render_layer, &render_rect); } @@ -1827,7 +1822,7 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) for (RenderView *render_view = render_result->views.first; render_view != NULL; render_view = render_view->next) { RE_SetActiveRenderView(render, render_view->name); - drw_view_reset(); + DRW_view_reset(); engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect); DST.buffer_finish_called = false; } @@ -1949,6 +1944,28 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, #endif } +/* Used when the render engine want to redo another cache populate inside the same render frame. */ +void DRW_cache_restart(void) +{ + /* Save viewport size. */ + float size[2], inv_size[2]; + copy_v2_v2(size, DST.size); + copy_v2_v2(inv_size, DST.inv_size); + + /* Force cache to reset. */ + drw_viewport_cache_resize(); + + drw_viewport_var_init(); + + DST.buffer_finish_called = false; + + DRW_hair_init(); + + /* Restore. */ + copy_v2_v2(DST.size, size); + copy_v2_v2(DST.inv_size, inv_size); +} + static struct DRWSelectBuffer { struct GPUFrameBuffer *framebuffer_depth_only; struct GPUTexture *texture_depth; @@ -2374,6 +2391,17 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, const rcti *rect) { + SELECTID_Context *sel_ctx = DRW_select_engine_context_get(); + GPUViewport *viewport = WM_draw_region_get_viewport(region); + if (!viewport) { + /* Selection engine requires a viewport. + * TODO (germano): This should be done internally in the engine. */ + sel_ctx->is_dirty = true; + sel_ctx->objects_drawn_len = 0; + sel_ctx->index_drawn_len = 1; + return; + } + Scene *scene = DEG_get_evaluated_scene(depsgraph); ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); @@ -2394,14 +2422,13 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons drw_context_state_init(); /* Setup viewport */ - DST.viewport = WM_draw_region_get_viewport(region); + DST.viewport = viewport; drw_viewport_var_init(); /* Update ubos */ DRW_globals_update(); /* Init Select Engine */ - struct SELECTID_Context *sel_ctx = DRW_select_engine_context_get(); sel_ctx->last_rect = *rect; use_drw_engine(&draw_engine_select_type); diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 07fb97236fb..3d83b918757 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -76,7 +76,7 @@ static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_l for (int i = 1; i < ARRAY_SIZE(idx); i++) { idx[i] += idx[i - 1]; } - /* Traverse in reverse to not change the order of the resource ids. */ + /* Traverse in reverse to not change the order of the resource ID's. */ for (int src = array_len - 1; src >= 0; src--) { array_tmp[--idx[KEY(array[src])]] = array[src]; } @@ -116,7 +116,7 @@ void drw_resource_buffer_finish(ViewportMemoryPool *vmempool) vmempool->ubo_len = ubo_len; } - /* Remove unecessary buffers */ + /* Remove unnecessary buffers */ for (int i = ubo_len; i < vmempool->ubo_len; i++) { GPU_uniformbuffer_free(vmempool->matrices_ubo[i]); GPU_uniformbuffer_free(vmempool->obinfos_ubo[i]); @@ -151,7 +151,7 @@ void drw_resource_buffer_finish(ViewportMemoryPool *vmempool) BLI_memblock_iternew(vmempool->commands, &iter); while ((chunk = BLI_memblock_iterstep(&iter))) { bool sortable = true; - /* We can only sort chunks that contain DRWCommandDraw only. */ + /* We can only sort chunks that contain #DRWCommandDraw only. */ for (int i = 0; i < ARRAY_SIZE(chunk->command_type) && sortable; i++) { if (chunk->command_type[i] != 0) { sortable = false; @@ -179,7 +179,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, int arraysize) { if (loc == -1) { - /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + /* Nice to enable eventually, for now EEVEE uses uniforms that might not exist. */ // BLI_assert(0); return; } @@ -262,11 +262,19 @@ void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, con DRW_shgroup_uniform_texture_ex(shgroup, name, tex, GPU_SAMPLER_MAX); } -void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) +void DRW_shgroup_uniform_texture_ref_ex(DRWShadingGroup *shgroup, + const char *name, + GPUTexture **tex, + eGPUSamplerState sampler_state) { BLI_assert(tex != NULL); int loc = GPU_shader_get_texture_binding(shgroup->shader, name); - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE_REF, tex, GPU_SAMPLER_MAX, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE_REF, tex, sampler_state, 0, 1); +} + +void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) +{ + DRW_shgroup_uniform_texture_ref_ex(shgroup, name, tex, GPU_SAMPLER_MAX); } void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, @@ -424,7 +432,7 @@ void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, int location = GPU_shader_get_uniform(shgroup->shader, name); if (location == -1) { - /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + /* Nice to enable eventually, for now EEVEE uses uniforms that might not exist. */ // BLI_assert(0); return; } @@ -530,6 +538,11 @@ static void drw_call_culling_init(DRWCullingState *cull, Object *ob) mul_v3_m4v3(corner, ob->obmat, bbox->vec[0]); mul_m4_v3(ob->obmat, cull->bsphere.center); cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner); + + /* Bypass test for very large objects (see T67319). */ + if (UNLIKELY(cull->bsphere.radius > 1e12)) { + cull->bsphere.radius = -1.0f; + } } else { /* Bypass test. */ @@ -569,7 +582,7 @@ uint32_t DRW_object_resource_id_get(Object *UNUSED(ob)) /* Handle not yet allocated. Return next handle. */ handle = DST.resource_handle; } - return handle; + return handle & ~(1 << 31); } static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup, @@ -1786,6 +1799,14 @@ const DRWView *DRW_view_default_get(void) return DST.view_default; } +/* WARNING: Only use in render AND only if you are going to set view_default again. */ +void DRW_view_reset(void) +{ + DST.view_default = NULL; + DST.view_active = NULL; + DST.view_previous = NULL; +} + /* MUST only be called once per render and only in render mode. Sets default view. */ void DRW_view_default_set(DRWView *view) { diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c index 81c9f400f6e..558d5441136 100644 --- a/source/blender/draw/intern/draw_select_buffer.c +++ b/source/blender/draw/intern/draw_select_buffer.c @@ -122,7 +122,6 @@ uint *DRW_select_buffer_read(struct Depsgraph *depsgraph, /** * \param rect: The rectangle to sample indices from (min/max inclusive). - * \param mask: Specifies the rect pixels (optional). * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. */ uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph, @@ -165,10 +164,10 @@ uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph, } /** - * \param bitmap_len: Number of indices in the selection id buffer. * \param center: Circle center. * \param radius: Circle radius. - * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. + * \param r_bitmap_len: Number of indices in the selection id buffer. + * \returns a #BLI_bitmap the length of \a r_bitmap_len or NULL on failure. */ uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph, struct ARegion *region, @@ -338,7 +337,7 @@ uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph, /** * Find the selection id closest to \a center. - * \param dist[in,out]: Use to initialize the distance, + * \param dist: Use to initialize the distance, * when found, this value is set to the distance of the selection that's returned. */ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index bd83bdae31b..9564b662b12 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -3414,12 +3414,13 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data) /* ----------- Public API --------------- */ -/* This function filters the active data source to leave only animation channels suitable for +/** + * This function filters the active data source to leave only animation channels suitable for * usage by the caller. It will return the length of the list * - * *anim_data: is a pointer to a ListBase, to which the filtered animation channels - * will be placed for use. - * filter_mode: how should the data be filtered - bitmapping accessed flags + * \param anim_data: Is a pointer to a #ListBase, + * to which the filtered animation channels will be placed for use. + * \param filter_mode: how should the data be filtered - bit-mapping accessed flags. */ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c index 863f433c778..edc36326c57 100644 --- a/source/blender/editors/animation/time_scrub_ui.c +++ b/source/blender/editors/animation/time_scrub_ui.c @@ -92,7 +92,9 @@ static void draw_current_frame(const Scene *scene, bool display_seconds, const View2D *v2d, const rcti *scrub_region_rect, - int current_frame) + int current_frame, + float sub_frame, + bool draw_line) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; int frame_x = UI_view2d_view_to_region_x(v2d, current_frame); @@ -106,6 +108,22 @@ static void draw_current_frame(const Scene *scene, float bg_color[4]; UI_GetThemeColorShade4fv(TH_CFRAME, -5, bg_color); + if (draw_line) { + /* Draw vertical line to from the bottom of the current frame box to the bottom of the screen. + */ + const float subframe_x = UI_view2d_view_to_region_x(v2d, current_frame + sub_frame); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_CFRAME); + immRectf(pos, + subframe_x - U.pixelsize, + scrub_region_rect->ymax - box_padding, + subframe_x + U.pixelsize, + 0.0f); + immUnbindProgram(); + } + UI_draw_roundbox_corner_set(UI_CNR_ALL); UI_draw_roundbox_3fv_alpha(true, @@ -135,6 +153,28 @@ static void draw_current_frame(const Scene *scene, text_color); } +void ED_time_scrub_draw_current_frame(const ARegion *region, + const Scene *scene, + bool display_seconds, + bool draw_line) +{ + const View2D *v2d = ®ion->v2d; + GPU_matrix_push_projection(); + wmOrtho2_region_pixelspace(region); + + rcti scrub_region_rect; + get_time_scrub_region_rect(region, &scrub_region_rect); + + draw_current_frame(scene, + display_seconds, + v2d, + &scrub_region_rect, + scene->r.cfra, + scene->r.subframe, + draw_line); + GPU_matrix_pop_projection(); +} + void ED_time_scrub_draw(const ARegion *region, const Scene *scene, bool display_seconds, @@ -161,8 +201,6 @@ void ED_time_scrub_draw(const ARegion *region, region, v2d, &numbers_rect, scene, display_seconds, TH_TEXT); } - draw_current_frame(scene, display_seconds, v2d, &scrub_region_rect, scene->r.cfra); - GPU_matrix_pop_projection(); } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index a7a705a6202..a010fbd5e81 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -140,7 +140,16 @@ void ED_armature_origin_set( mul_m4_v3(ob->imat, cent); } else { - if (around == V3D_AROUND_CENTER_MEDIAN) { + if (around == V3D_AROUND_CENTER_BOUNDS) { + float min[3], max[3]; + INIT_MINMAX(min, max); + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + minmax_v3v3_v3(min, max, ebone->head); + minmax_v3v3_v3(min, max, ebone->tail); + } + mid_v3_v3v3(cent, min, max); + } + else { /* #V3D_AROUND_CENTER_MEDIAN. */ int total = 0; zero_v3(cent); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { @@ -152,15 +161,6 @@ void ED_armature_origin_set( mul_v3_fl(cent, 1.0f / (float)total); } } - else { - float min[3], max[3]; - INIT_MINMAX(min, max); - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - minmax_v3v3_v3(min, max, ebone->head); - minmax_v3v3_v3(min, max, ebone->tail); - } - mid_v3_v3v3(cent, min, max); - } } /* Do the adjustments */ diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index d3d00fc44f2..f90d781baca 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -270,7 +270,7 @@ static void joined_armature_fix_links( } /* join armature exec is exported for use in object->join objects operator... */ -int join_armature_exec(bContext *C, wmOperator *op) +int ED_armature_join_objects_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -304,10 +304,10 @@ int join_armature_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - /* Get editbones of active armature to add editbones to */ + /* Get edit-bones of active armature to add edit-bones to */ ED_armature_to_edit(arm); - /* get pose of active object and move it out of posemode */ + /* Get pose of active object and move it out of pose-mode */ pose = ob_active->pose; ob_active->mode &= ~OB_MODE_POSE; @@ -325,7 +325,7 @@ int join_armature_exec(bContext *C, wmOperator *op) afd.tarArm = ob_active; afd.names_map = BLI_ghash_str_new("join_armature_adt_fix"); - /* Make a list of editbones in current armature */ + /* Make a list of edit-bones in current armature */ ED_armature_to_edit(ob_iter->data); /* Get Pose of current armature */ @@ -549,7 +549,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n /* Helper function for armature separating - remove certain bones from the given armature * sel: remove selected bones from the armature, otherwise the unselected bones are removed - * (ob is not in editmode) + * (ob is not in edit-mode) */ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_select) { @@ -557,7 +557,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_selec bPoseChannel *pchan, *pchann; EditBone *curbone; - /* make local set of editbones to manipulate here */ + /* make local set of edit-bones to manipulate here */ ED_armature_to_edit(arm); /* go through pose-channels, checking if a bone should be removed */ @@ -591,7 +591,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_selec } } - /* free any of the extra-data this pchan might have */ + /* Free any of the extra-data this pchan might have. */ BKE_pose_channel_free(pchan); BKE_pose_channels_hash_free(ob->pose); @@ -601,7 +601,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_selec } } - /* exit editmode (recalculates pchans too) */ + /* Exit edit-mode (recalculates pose-channels too). */ ED_armature_edit_deselect_all(ob); ED_armature_from_edit(bmain, ob->data); ED_armature_edit_free(ob->data); @@ -652,15 +652,15 @@ static int separate_armature_exec(bContext *C, wmOperator *op) } /* We are going to do this as follows (unlike every other instance of separate): - * 1. Exit editmode +posemode for active armature/base. Take note of what this is. + * 1. Exit edit-mode & pose-mode for active armature/base. Take note of what this is. * 2. Duplicate base - BASACT is the new one now * 3. For each of the two armatures, - * enter editmode -> remove appropriate bones -> exit editmode + recalc. + * enter edit-mode -> remove appropriate bones -> exit edit-mode + recalculate. * 4. Fix constraint links - * 5. Make original armature active and enter editmode + * 5. Make original armature active and enter edit-mode */ - /* 1) store starting settings and exit editmode */ + /* 1) store starting settings and exit edit-mode */ ob_old->mode &= ~OB_MODE_POSE; ED_armature_from_edit(bmain, ob_old->data); @@ -700,7 +700,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op) } MEM_freeN(bases); - /* recalc/redraw + cleanup */ + /* Recalculate/redraw + cleanup */ WM_cursor_wait(0); if (ok) { @@ -754,7 +754,7 @@ static void bone_connect_to_new_parent(ListBase *edbo, float offset[3]; if ((selbone->parent) && (selbone->flag & BONE_CONNECTED)) { - selbone->parent->flag &= ~(BONE_TIPSEL); + selbone->parent->flag &= ~BONE_TIPSEL; } /* make actbone the parent of selbone */ @@ -956,7 +956,7 @@ static void editbone_clear_parent(EditBone *ebone, int mode) { if (ebone->parent) { /* for nice selection */ - ebone->parent->flag &= ~(BONE_TIPSEL); + ebone->parent->flag &= ~BONE_TIPSEL; } if (mode == 1) { diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index eb7c1bc74ea..ccd39429704 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -188,7 +188,7 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode Base *base = NULL; bool sel; - hitresult &= ~(BONESEL_ANY); + hitresult &= ~BONESEL_ANY; /* Determine what the current bone is */ if (is_editmode == false) { base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hitresult, &pchan); @@ -1302,7 +1302,7 @@ static int armature_de_select_all_exec(bContext *C, wmOperator *op) if ((ebone->flag & BONE_UNSELECTABLE) == 0) { ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); if (ebone->parent) { - ebone->parent->flag |= (BONE_TIPSEL); + ebone->parent->flag |= BONE_TIPSEL; } } break; @@ -1317,7 +1317,7 @@ static int armature_de_select_all_exec(bContext *C, wmOperator *op) if ((ebone->flag & BONE_UNSELECTABLE) == 0) { ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); if (ebone->parent) { - ebone->parent->flag |= (BONE_TIPSEL); + ebone->parent->flag |= BONE_TIPSEL; } } } diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 61d8856afbc..b3c58f2575b 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -283,11 +283,11 @@ static void add_verts_to_dgroups(ReportList *reports, * weights, either through envelopes or using a heat equilibrium. * * This function can be called both when parenting a mesh to an armature, - * or in weightpaint + posemode. In the latter case selection is taken + * or in weight-paint + pose-mode. In the latter case selection is taken * into account and vertex weights can be mirrored. * * The mesh vertex positions used are either the final deformed coords - * from the evaluated mesh in weightpaint mode, the final subsurf coords + * from the evaluated mesh in weight-paint mode, the final sub-surface coords * when parenting, or simply the original mesh coords. */ diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index d8a6a22a7df..145071522ed 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -94,9 +94,8 @@ struct LaplacianSystem { float (*verts)[3]; /* vertex coordinates */ float (*vnors)[3]; /* vertex normals */ - float (*root)[3]; /* bone root */ - float (*tip)[3]; /* bone tip */ - float (*source)[3]; /* vertex source */ + float (*root)[3]; /* bone root */ + float (*tip)[3]; /* bone tip */ int numsource; float *H; /* diagonal H matrix */ diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 4e1c07af001..a39c8261b32 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1432,7 +1432,7 @@ static int separate_exec(bContext *C, wmOperator *op) /* 2. Duplicate the object and data. */ /* Take into account user preferences for duplicating actions. */ - short dupflag = (U.dupflag & USER_DUP_ACT); + const eDupli_ID_Flags dupflag = (U.dupflag & USER_DUP_ACT); newbase = ED_object_add_duplicate(bmain, scene, view_layer, oldbase, dupflag); DEG_relations_tag_update(bmain); @@ -6895,7 +6895,7 @@ void CURVE_OT_shade_flat(wmOperatorType *ot) * This is used externally, by #OBJECT_OT_join. * TODO: shape keys - as with meshes. */ -int join_curve_exec(bContext *C, wmOperator *op) +int ED_curve_join_objects_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index 9294bc6e91b..73f970876b1 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -988,7 +988,7 @@ void CURVE_OT_select_more(wmOperatorType *ot) /* identifiers */ ot->name = "Select More"; ot->idname = "CURVE_OT_select_more"; - ot->description = "Select control points directly linked to already selected ones"; + ot->description = "Select control points at the boundary of each selection region"; /* api callbacks */ ot->exec = curve_select_more_exec; @@ -1203,7 +1203,7 @@ void CURVE_OT_select_less(wmOperatorType *ot) /* identifiers */ ot->name = "Select Less"; ot->idname = "CURVE_OT_select_less"; - ot->description = "Reduce current selection by deselecting boundary elements"; + ot->description = "Deselect control points at the boundary of each selection region"; /* api callbacks */ ot->exec = curve_select_less_exec; diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index dc5dc71106f..1bbd4b4a5bc 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1635,7 +1635,7 @@ static int insert_text_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); char *inserted_utf8; - wchar_t *inserted_text; + char32_t *inserted_text; int a, len; if (!RNA_struct_property_is_set(op->ptr, "text")) { @@ -1645,8 +1645,8 @@ static int insert_text_exec(bContext *C, wmOperator *op) inserted_utf8 = RNA_string_get_alloc(op->ptr, "text", NULL, 0); len = BLI_strlen_utf8(inserted_utf8); - inserted_text = MEM_callocN(sizeof(wchar_t) * (len + 1), "FONT_insert_text"); - BLI_strncpy_wchar_from_utf8(inserted_text, inserted_utf8, len + 1); + inserted_text = MEM_callocN(sizeof(char32_t) * (len + 1), "FONT_insert_text"); + len = BLI_str_utf8_as_utf32(inserted_text, inserted_utf8, MAXTEXT); for (a = 0; a < len; a++) { insert_into_textbuf(obedit, inserted_text[a]); @@ -2133,7 +2133,7 @@ static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event) vfont = (VFont *)idptr.owner_id; } - path = (vfont && !BKE_vfont_is_builtin(vfont)) ? vfont->name : U.fontdir; + path = (vfont && !BKE_vfont_is_builtin(vfont)) ? vfont->filepath : U.fontdir; if (RNA_struct_property_is_set(op->ptr, "filepath")) { return font_open_exec(C, op); diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 1a5b3d6ac45..0dcb8de37f1 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -713,6 +713,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES ops.mesh.bisect ops.mesh.dupli_extrude_cursor ops.mesh.extrude_faces_move + ops.mesh.extrude_manifold ops.mesh.extrude_region_move ops.mesh.extrude_region_shrink_fatten ops.mesh.inset diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 4083169d65c..735ad8bc039 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -49,6 +49,7 @@ set(SRC gpencil_fill.c gpencil_interpolate.c gpencil_merge.c + gpencil_mesh.c gpencil_ops.c gpencil_ops_versioning.c gpencil_paint.c diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index 22df7bbbf31..20307e7f809 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -172,9 +172,14 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, float oldpressure = points[0].pressure; /* draw stroke curve */ - GPU_line_width(max_ff(oldpressure * thickness, 1.0)); + immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + immUniform2fv("viewportSize", &viewport[2]); + + immUniform1f("lineWidth", max_ff(oldpressure * thickness, 1.0) * U.pixelsize); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immUniformColor3fvAlpha(ink, ink[3]); immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints); @@ -193,7 +198,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, immEnd(); draw_points = 0; - GPU_line_width(max_ff(pt->pressure * thickness, 1.0f)); + immUniform1f("lineWidth", max_ff(pt->pressure * thickness, 1.0) * U.pixelsize); immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1); /* need to roll-back one point to ensure that there are no gaps in the stroke */ @@ -327,11 +332,17 @@ static void annotation_draw_stroke_3d( GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + immUniform2fv("viewportSize", &viewport[2]); + + immUniform1f("lineWidth", max_ff(curpressure * thickness, 1.0) * U.pixelsize); + immUniformColor3fvAlpha(ink, ink[3]); /* draw stroke curve */ - GPU_line_width(max_ff(curpressure * thickness, 1.0f)); immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add); const bGPDspoint *pt = points; for (int i = 0; i < totpoints; i++, pt++) { @@ -351,7 +362,7 @@ static void annotation_draw_stroke_3d( draw_points = 0; curpressure = pt->pressure; - GPU_line_width(max_ff(curpressure * thickness, 1.0f)); + immUniform1f("lineWidth", max_ff(curpressure * thickness, 1.0) * U.pixelsize); immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1 + cyclic_add); /* need to roll-back one point to ensure that there are no gaps in the stroke */ @@ -424,11 +435,15 @@ static void annotation_draw_stroke_2d(const bGPDspoint *points, } else { /* draw stroke curve */ - GPU_line_width(max_ff(oldpressure * thickness, 1.0)); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); immUniformColor3fvAlpha(ink, ink[3]); + float viewport[4]; + GPU_viewport_size_get_f(viewport); + immUniform2fv("viewportSize", &viewport[2]); + + immUniform1f("lineWidth", max_ff(oldpressure * thickness, 1.0) * U.pixelsize); + immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints); for (int i = 0; i < totpoints; i++) { @@ -448,7 +463,8 @@ static void annotation_draw_stroke_2d(const bGPDspoint *points, immEnd(); draw_points = 0; - GPU_line_width(max_ff(pt->pressure * thickness, 1.0f)); + immUniform1f("lineWidth", max_ff(pt->pressure * thickness, 1.0) * U.pixelsize); + immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1); /* need to roll-back one point to ensure that there are no gaps in the stroke */ @@ -683,9 +699,6 @@ static void annotation_draw_data_layers( continue; } - /* set basic stroke thickness */ - GPU_line_width(lthick); - /* Add layer drawing settings to the set of "draw flags" * NOTE: If the setting doesn't apply, it *must* be cleared, * as dflag's carry over from the previous layer @@ -774,13 +787,7 @@ static void annotation_draw_data_all(Scene *scene, } } -/* ----- Grease Pencil Sketches Drawing API ------ */ - -/* ............................ - * XXX - * We need to review the calls below, since they may be/are not that suitable for - * the new ways that we intend to be drawing data... - * ............................ */ +/* ----- Annotation Sketches Drawing API ------ */ /* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */ void ED_annotation_draw_2dimage(const bContext *C) diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 5c5adb32a97..9d80a75b959 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -204,12 +204,12 @@ typedef struct tGPsdata { /* minimum length of new segment before new point can be added */ #define MIN_EUCLIDEAN_PX (U.gp_euclideandist) -static bool gp_stroke_added_check(tGPsdata *p) +static bool annotation_stroke_added_check(tGPsdata *p) { return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED); } -static void gp_stroke_added_enable(tGPsdata *p) +static void annotation_stroke_added_enable(tGPsdata *p) { BLI_assert(p->gpf->strokes.last != NULL); p->flags |= GP_PAINTFLAG_STROKEADDED; @@ -218,13 +218,13 @@ static void gp_stroke_added_enable(tGPsdata *p) /* ------ */ /* Forward defines for some functions... */ -static void gp_session_validatebuffer(tGPsdata *p); +static void annotation_session_validatebuffer(tGPsdata *p); /* ******************************************* */ /* Context Wrangling... */ /* check if context is suitable for drawing */ -static bool gpencil_draw_poll(bContext *C) +static bool annotation_draw_poll(bContext *C) { if (ED_operator_regionactive(C)) { /* check if current context can support GPencil data */ @@ -249,7 +249,7 @@ static bool gpencil_draw_poll(bContext *C) } /* check if projecting strokes into 3d-geometry in the 3D-View */ -static bool gpencil_project_check(tGPsdata *p) +static bool annotation_project_check(tGPsdata *p) { bGPdata *gpd = p->gpd; return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) && @@ -262,7 +262,7 @@ static bool gpencil_project_check(tGPsdata *p) /* Utilities --------------------------------- */ /* get the reference point for stroke-point conversions */ -static void gp_get_3d_reference(tGPsdata *p, float vec[3]) +static void annotation_get_3d_reference(tGPsdata *p, float vec[3]) { const float *fp = p->scene->cursor.location; @@ -273,7 +273,7 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3]) /* Stroke Editing ---------------------------- */ /* check if the current mouse position is suitable for adding a new point */ -static bool gp_stroke_filtermval(tGPsdata *p, const float mval[2], float pmval[2]) +static bool annotation_stroke_filtermval(tGPsdata *p, const float mval[2], float pmval[2]) { int dx = (int)fabsf(mval[0] - pmval[0]); int dy = (int)fabsf(mval[1] - pmval[1]); @@ -318,7 +318,10 @@ static bool gp_stroke_filtermval(tGPsdata *p, const float mval[2], float pmval[2 } /* convert screen-coordinates to buffer-coordinates */ -static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[3], float *depth) +static void annotation_stroke_convertcoords(tGPsdata *p, + const float mval[2], + float out[3], + float *depth) { bGPdata *gpd = p->gpd; @@ -326,7 +329,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[ if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) { int mval_i[2]; round_v2i_v2fl(mval_i, mval); - if (gpencil_project_check(p) && + if (annotation_project_check(p) && (ED_view3d_autodist_simple(p->region, mval_i, out, 0, depth))) { /* projecting onto 3D-Geometry * - nothing more needs to be done here, since view_autodist_simple() has already done it @@ -346,7 +349,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[ * reference point instead or as offset, for easier stroke matching */ - gp_get_3d_reference(p, rvec); + annotation_get_3d_reference(p, rvec); zfac = ED_view3d_calc_zfac(p->region->regiondata, rvec, NULL); if (ED_view3d_project_float_global(p->region, rvec, mval_prj, V3D_PROJ_TEST_NOP) == @@ -381,16 +384,17 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[ } } -/* Apply smooth to buffer while drawing +/** + * Apply smooth to buffer while drawing * to smooth point C, use 2 before (A, B) and current point (D): * - * A----B-----C------D + * `A----B-----C------D` * * \param p: Temp data * \param inf: Influence factor * \param idx: Index of the last point (need minimum 3 points in the array) */ -static void gp_smooth_buffer(tGPsdata *p, float inf, int idx) +static void annotation_smooth_buffer(tGPsdata *p, float inf, int idx) { bGPdata *gpd = p->gpd; short num_points = gpd->runtime.sbuffer_used; @@ -438,12 +442,12 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx) copy_v2_v2(&ptc->x, c); } -static void gp_stroke_arrow_calc_points_segment(float stroke_points[8], - const float ref_point[2], - const float dir_cw[2], - const float dir_ccw[2], - const float lenght, - const float sign) +static void annotation_stroke_arrow_calc_points_segment(float stroke_points[8], + const float ref_point[2], + const float dir_cw[2], + const float dir_ccw[2], + const float lenght, + const float sign) { stroke_points[0] = ref_point[0] + dir_cw[0] * lenght * sign; stroke_points[1] = ref_point[1] + dir_cw[1] * lenght * sign; @@ -451,11 +455,11 @@ static void gp_stroke_arrow_calc_points_segment(float stroke_points[8], stroke_points[3] = ref_point[1] + dir_ccw[1] * lenght * sign; } -static void gp_stroke_arrow_calc_points(tGPspoint *point, - const float stroke_dir[2], - float corner[2], - float stroke_points[8], - const int arrow_style) +static void annotation_stroke_arrow_calc_points(tGPspoint *point, + const float stroke_dir[2], + float corner[2], + float stroke_points[8], + const int arrow_style) { const int arrow_lenght = 8; float norm_dir[2]; @@ -473,12 +477,12 @@ static void gp_stroke_arrow_calc_points(tGPspoint *point, stroke_points[3] = corner[1] + inv_norm_dir_counterclockwise[1] * arrow_lenght + norm_dir[1]; break; case GP_STROKE_ARROWSTYLE_SEGMENT: - gp_stroke_arrow_calc_points_segment(stroke_points, - corner, - inv_norm_dir_clockwise, - inv_norm_dir_counterclockwise, - arrow_lenght, - 1.0f); + annotation_stroke_arrow_calc_points_segment(stroke_points, + corner, + inv_norm_dir_clockwise, + inv_norm_dir_counterclockwise, + arrow_lenght, + 1.0f); break; case GP_STROKE_ARROWSTYLE_CLOSED: mul_v2_fl(norm_dir, arrow_lenght); @@ -486,12 +490,12 @@ static void gp_stroke_arrow_calc_points(tGPspoint *point, add_v2_v2(&point->x, norm_dir); copy_v2_v2(corner, &point->x); } - gp_stroke_arrow_calc_points_segment(stroke_points, - corner, - inv_norm_dir_clockwise, - inv_norm_dir_counterclockwise, - arrow_lenght, - -1.0f); + annotation_stroke_arrow_calc_points_segment(stroke_points, + corner, + inv_norm_dir_clockwise, + inv_norm_dir_counterclockwise, + arrow_lenght, + -1.0f); stroke_points[4] = corner[0] - norm_dir[0]; stroke_points[5] = corner[1] - norm_dir[1]; break; @@ -501,12 +505,12 @@ static void gp_stroke_arrow_calc_points(tGPspoint *point, add_v2_v2(&point->x, norm_dir); copy_v2_v2(corner, &point->x); } - gp_stroke_arrow_calc_points_segment(stroke_points, - corner, - inv_norm_dir_clockwise, - inv_norm_dir_counterclockwise, - arrow_lenght * 0.75f, - -1.0f); + annotation_stroke_arrow_calc_points_segment(stroke_points, + corner, + inv_norm_dir_clockwise, + inv_norm_dir_counterclockwise, + arrow_lenght * 0.75f, + -1.0f); stroke_points[4] = stroke_points[0] - norm_dir[0]; stroke_points[5] = stroke_points[1] - norm_dir[1]; stroke_points[6] = stroke_points[2] - norm_dir[0]; @@ -518,7 +522,10 @@ static void gp_stroke_arrow_calc_points(tGPspoint *point, } /* add current stroke-point to buffer (returns whether point was successfully added) */ -static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime) +static short annotation_stroke_addpoint(tGPsdata *p, + const float mval[2], + float pressure, + double curtime) { bGPdata *gpd = p->gpd; tGPspoint *pt; @@ -571,14 +578,14 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure pt++; float e_heading[2] = {start[0] - end[0], start[1] - end[1]}; /* Calculate points for ending arrow. */ - gp_stroke_arrow_calc_points( + annotation_stroke_arrow_calc_points( pt, e_heading, end, gpd->runtime.arrow_end, gpd->runtime.arrow_end_style); } /* Arrow start corner. */ if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) { float s_heading[2] = {end[0] - start[0], end[1] - start[1]}; /* Calculate points for starting arrow. */ - gp_stroke_arrow_calc_points( + annotation_stroke_arrow_calc_points( NULL, s_heading, start, gpd->runtime.arrow_start, gpd->runtime.arrow_start_style); } } @@ -611,7 +618,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) { /* smooth while drawing previous points with a reduction factor for previous */ for (int s = 0; s < 3; s++) { - gp_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_used - s); + annotation_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_used - s); } } @@ -632,7 +639,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure * to stroke. This allows to draw lines more interactively (see new segment * during mouse slide, e.g.) */ - if (gp_stroke_added_check(p)) { + if (annotation_stroke_added_check(p)) { bGPDstroke *gps = p->gpf->strokes.last; bGPDspoint *pts; @@ -649,7 +656,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure * but poly lines are converting to stroke instantly, * so initialize depth buffer before converting coordinates */ - if (gpencil_project_check(p)) { + if (annotation_project_check(p)) { View3D *v3d = p->area->spacedata.first; view3d_region_operator_needs_opengl(p->win, p->region); @@ -660,7 +667,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure } /* convert screen-coordinates to appropriate coordinates (and store them) */ - gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL); + annotation_stroke_convertcoords(p, &pt->x, &pts->x, NULL); /* copy pressure and time */ pts->pressure = pt->pressure; @@ -681,115 +688,115 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure return GP_STROKEADD_INVALID; } -static void gp_stroke_arrow_init_point_default(bGPDspoint *pt) +static void annotation_stroke_arrow_init_point_default(bGPDspoint *pt) { pt->pressure = 1.0f; pt->strength = 1.0f; pt->time = 1.0f; } -static void gp_stroke_arrow_init_conv_point(bGPDspoint *pt, const float point[3]) +static void annotation_stroke_arrow_init_conv_point(bGPDspoint *pt, const float point[3]) { copy_v3_v3(&pt->x, point); - gp_stroke_arrow_init_point_default(pt); + annotation_stroke_arrow_init_point_default(pt); } -static void gp_stroke_arrow_init_point( +static void annotation_stroke_arrow_init_point( tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float co[8], const int co_idx) { /* Note: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */ float real_co[2] = {co[co_idx], co[co_idx + 1]}; copy_v2_v2(&ptc->x, real_co); - gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - gp_stroke_arrow_init_point_default(pt); + annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_arrow_init_point_default(pt); } -static void gp_stroke_arrow_allocate(bGPDstroke *gps, const int totpoints) +static void annotation_stroke_arrow_allocate(bGPDstroke *gps, const int totpoints) { /* Copy appropriate settings for stroke. */ gps->totpoints = totpoints; /* Allocate enough memory for a continuous array for storage points. */ - gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "annotation_stroke_points"); } -static void gp_arrow_create_open(tGPsdata *p, - tGPspoint *ptc, - bGPDspoint *pt, - const float corner_point[3], - const float arrow_points[8]) +static void annotation_arrow_create_open(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float corner_point[3], + const float arrow_points[8]) { - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); pt++; - gp_stroke_arrow_init_conv_point(pt, corner_point); + annotation_stroke_arrow_init_conv_point(pt, corner_point); pt++; - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); } -static void gp_arrow_create_segm(tGPsdata *p, - tGPspoint *ptc, - bGPDspoint *pt, - const float arrow_points[8]) +static void annotation_arrow_create_segm(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float arrow_points[8]) { - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); pt++; - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); } -static void gp_arrow_create_closed(tGPsdata *p, - tGPspoint *ptc, - bGPDspoint *pt, - const float arrow_points[8]) +static void annotation_arrow_create_closed(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float arrow_points[8]) { - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); pt++; - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); pt++; - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4); pt++; - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); } -static void gp_arrow_create_square(tGPsdata *p, - tGPspoint *ptc, - bGPDspoint *pt, - const float corner_point[3], - const float arrow_points[8]) +static void annotation_arrow_create_square(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float corner_point[3], + const float arrow_points[8]) { - gp_stroke_arrow_init_conv_point(pt, corner_point); + annotation_stroke_arrow_init_conv_point(pt, corner_point); pt++; - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); pt++; - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4); pt++; - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 6); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 6); pt++; - gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); + annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); pt++; - gp_stroke_arrow_init_conv_point(pt, corner_point); + annotation_stroke_arrow_init_conv_point(pt, corner_point); } -static void gp_arrow_create(tGPsdata *p, - tGPspoint *ptc, - bGPDspoint *pt, - bGPDstroke *arrow_stroke, - const float arrow_points[8], - const int style) +static void annotation_arrow_create(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + bGPDstroke *arrow_stroke, + const float arrow_points[8], + const int style) { float corner_conv[3]; copy_v3_v3(corner_conv, &pt->x); switch (style) { case GP_STROKE_ARROWSTYLE_SEGMENT: - gp_arrow_create_segm(p, ptc, pt, arrow_points); + annotation_arrow_create_segm(p, ptc, pt, arrow_points); break; case GP_STROKE_ARROWSTYLE_CLOSED: - gp_arrow_create_closed(p, ptc, pt, arrow_points); + annotation_arrow_create_closed(p, ptc, pt, arrow_points); break; case GP_STROKE_ARROWSTYLE_OPEN: - gp_arrow_create_open(p, ptc, pt, corner_conv, arrow_points); + annotation_arrow_create_open(p, ptc, pt, corner_conv, arrow_points); break; case GP_STROKE_ARROWSTYLE_SQUARE: - gp_arrow_create_square(p, ptc, pt, corner_conv, arrow_points); + annotation_arrow_create_square(p, ptc, pt, corner_conv, arrow_points); break; default: break; @@ -799,7 +806,7 @@ static void gp_arrow_create(tGPsdata *p, } /* make a new stroke from the buffer data */ -static void gp_stroke_newfrombuffer(tGPsdata *p) +static void annotation_stroke_newfrombuffer(tGPsdata *p) { bGPdata *gpd = p->gpd; bGPDlayer *gpl = p->gpl; @@ -837,13 +844,13 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) * interactive behavior */ if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { - if (gp_stroke_added_check(p)) { + if (annotation_stroke_added_check(p)) { return; } } /* allocate memory for a new stroke */ - gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); + gps = MEM_callocN(sizeof(bGPDstroke), "annotation_stroke"); /* copy appropriate settings for stroke */ gps->totpoints = totelem; @@ -857,7 +864,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) gps->tot_triangles = 0; /* allocate enough memory for a continuous array for storage points */ - gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "annotation_stroke_points"); gps->tot_triangles = 0; /* set pointer to first non-initialized point */ @@ -871,7 +878,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ - gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -889,7 +896,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1); /* Convert screen-coordinates to appropriate coordinates (and store them). */ - gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); /* Copy pressure and time. */ pt->pressure = ptc->pressure; @@ -905,18 +912,19 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* Setting up arrow stroke. */ bGPDstroke *e_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false); - gp_stroke_arrow_allocate(e_arrow_gps, totarrowpoints); + annotation_stroke_arrow_allocate(e_arrow_gps, totarrowpoints); /* Set pointer to first non-initialized point. */ pt = e_arrow_gps->points + (e_arrow_gps->totpoints - totarrowpoints); /* End point. */ ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1); - gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - gp_stroke_arrow_init_point_default(pt); + annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_arrow_init_point_default(pt); /* Fill and convert arrow points to create arrow shape. */ - gp_arrow_create(p, ptc, pt, e_arrow_gps, runtime.arrow_end, runtime.arrow_end_style); + annotation_arrow_create( + p, ptc, pt, e_arrow_gps, runtime.arrow_end, runtime.arrow_end_style); } /* Start arrow stroke. */ if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) && @@ -925,18 +933,19 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* Setting up arrow stroke. */ bGPDstroke *s_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false); - gp_stroke_arrow_allocate(s_arrow_gps, totarrowpoints); + annotation_stroke_arrow_allocate(s_arrow_gps, totarrowpoints); /* Set pointer to first non-initialized point. */ pt = s_arrow_gps->points + (s_arrow_gps->totpoints - totarrowpoints); /* Start point. */ ptc = runtime.sbuffer; - gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - gp_stroke_arrow_init_point_default(pt); + annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_arrow_init_point_default(pt); /* Fill and convert arrow points to create arrow shape. */ - gp_arrow_create(p, ptc, pt, s_arrow_gps, runtime.arrow_start, runtime.arrow_start_style); + annotation_arrow_create( + p, ptc, pt, s_arrow_gps, runtime.arrow_start, runtime.arrow_start_style); } } } @@ -945,7 +954,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ - gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -956,7 +965,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) float *depth_arr = NULL; /* get an array of depths, far depths are blended */ - if (gpencil_project_check(p)) { + if (annotation_project_check(p)) { int mval_i[2], mval_prev[2] = {0}; int interp_depth = 0; int found_depth = 0; @@ -1024,7 +1033,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc; i++, ptc++, pt++) { /* convert screen-coordinates to appropriate coordinates (and store them) */ - gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); + annotation_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -1040,7 +1049,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* add stroke to frame */ BLI_addtail(&p->gpf->strokes, gps); - gp_stroke_added_enable(p); + annotation_stroke_added_enable(p); } /* --- 'Eraser' for 'Paint' Tool ------ */ @@ -1048,7 +1057,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* helper to free a stroke * NOTE: gps->dvert and gps->triangles should be NULL, but check anyway for good measure */ -static void gp_free_stroke(bGPDframe *gpf, bGPDstroke *gps) +static void annotation_free_stroke(bGPDframe *gpf, bGPDstroke *gps) { if (gps->points) { MEM_freeN(gps->points); @@ -1066,7 +1075,9 @@ static void gp_free_stroke(bGPDframe *gpf, bGPDstroke *gps) BLI_freelinkN(&gpf->strokes, gps); } -/* which which point is infront (result should only be used for comparison) */ +/** + * Which which point is in front (result should only be used for comparison). + */ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3]) { if (rv3d->is_persp) { @@ -1078,10 +1089,10 @@ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3]) } /* only erase stroke points that are visible (3d view) */ -static bool gp_stroke_eraser_is_occluded(tGPsdata *p, - const bGPDspoint *pt, - const int x, - const int y) +static bool annotation_stroke_eraser_is_occluded(tGPsdata *p, + const bGPDspoint *pt, + const int x, + const int y) { if ((p->area->spacetype == SPACE_VIEW3D) && (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) { RegionView3D *rv3d = p->region->regiondata; @@ -1100,14 +1111,13 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, return false; } -/* eraser tool - evaluation per stroke */ -/* TODO: this could really do with some optimization (KD-Tree/BVH?) */ -static void gp_stroke_eraser_dostroke(tGPsdata *p, - bGPDframe *gpf, - bGPDstroke *gps, - const float mval[2], - const int radius, - const rcti *rect) +/* Eraser tool - evaluation per stroke. */ +static void annotation_stroke_eraser_dostroke(tGPsdata *p, + bGPDframe *gpf, + bGPDstroke *gps, + const float mval[2], + const int radius, + const rcti *rect) { bGPDspoint *pt1, *pt2; int pc1[2] = {0}; @@ -1118,19 +1128,19 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, if (gps->totpoints == 0) { /* just free stroke */ - gp_free_stroke(gpf, gps); + annotation_free_stroke(gpf, gps); } else if (gps->totpoints == 1) { /* only process if it hasn't been masked out... */ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { - gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); + gpencil_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ if (len_v2v2_int(mval_i, pc1) <= radius) { /* free stroke */ - gp_free_stroke(gpf, gps); + annotation_free_stroke(gpf, gps); } } } @@ -1164,8 +1174,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, continue; } - gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); - gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]); + gpencil_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); + gpencil_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]); /* Check that point segment of the boundbox of the eraser stroke */ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || @@ -1174,9 +1184,9 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, * eraser region (either within stroke painted, or on its lines) * - this assumes that linewidth is irrelevant */ - if (gp_stroke_inside_circle(mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { - if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) || - (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) { + if (gpencil_stroke_inside_circle(mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { + if ((annotation_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) || + (annotation_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) { /* Edge is affected - Check individual points now */ if (len_v2v2_int(mval_i, pc1) <= radius) { pt1->flag |= GP_SPOINT_TAG; @@ -1192,13 +1202,13 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, /* Second Pass: Remove any points that are tagged */ if (do_cull) { - gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); } } } /* erase strokes which fall under the eraser strokes */ -static void gp_stroke_doeraser(tGPsdata *p) +static void annotation_stroke_doeraser(tGPsdata *p) { bGPDframe *gpf = p->gpf; bGPDstroke *gps, *gpn; @@ -1227,7 +1237,7 @@ static void gp_stroke_doeraser(tGPsdata *p) * (e.g. 2D space strokes in the 3D view, if the same datablock is shared) */ if (ED_gpencil_stroke_can_use_direct(p->area, gps)) { - gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->radius, &rect); + annotation_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->radius, &rect); } } } @@ -1236,7 +1246,7 @@ static void gp_stroke_doeraser(tGPsdata *p) /* Sketching Operator */ /* clear the session buffers (call this before AND after a paint operation) */ -static void gp_session_validatebuffer(tGPsdata *p) +static void annotation_session_validatebuffer(tGPsdata *p) { bGPdata *gpd = p->gpd; @@ -1251,7 +1261,7 @@ static void gp_session_validatebuffer(tGPsdata *p) } /* (re)init new painting data */ -static bool gp_session_initdata(bContext *C, tGPsdata *p) +static bool annotation_session_initdata(bContext *C, tGPsdata *p) { Main *bmain = CTX_data_main(C); bGPdata **gpd_ptr = NULL; @@ -1422,13 +1432,13 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) } /* clear out buffer (stored in gp-data), in case something contaminated it */ - gp_session_validatebuffer(p); + annotation_session_validatebuffer(p); return 1; } /* init new painting session */ -static tGPsdata *gp_session_initpaint(bContext *C) +static tGPsdata *annotation_session_initpaint(bContext *C) { tGPsdata *p = NULL; @@ -1438,7 +1448,7 @@ static tGPsdata *gp_session_initpaint(bContext *C) /* Try to initialize context data * WARNING: This may not always succeed (e.g. using GP in an annotation-only context) */ - if (gp_session_initdata(C, p) == 0) { + if (annotation_session_initdata(C, p) == 0) { /* Invalid state - Exit * NOTE: It should be safe to just free the data, since failing context checks should * only happen when no data has been allocated. @@ -1458,7 +1468,7 @@ static tGPsdata *gp_session_initpaint(bContext *C) } /* cleanup after a painting session */ -static void gp_session_cleanup(tGPsdata *p) +static void annotation_session_cleanup(tGPsdata *p) { bGPdata *gpd = (p) ? p->gpd : NULL; @@ -1481,13 +1491,15 @@ static void gp_session_cleanup(tGPsdata *p) p->inittime = 0.0; } -static void gp_session_free(tGPsdata *p) +static void annotation_session_free(tGPsdata *p) { MEM_freeN(p); } /* init new stroke */ -static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Depsgraph *depsgraph) +static void annotation_paint_initstroke(tGPsdata *p, + eGPencil_PaintModes paintmode, + Depsgraph *depsgraph) { Scene *scene = p->scene; ToolSettings *ts = scene->toolsettings; @@ -1638,13 +1650,13 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps } /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */ -static void gp_paint_strokeend(tGPsdata *p) +static void annotation_paint_strokeend(tGPsdata *p) { ToolSettings *ts = p->scene->toolsettings; /* for surface sketching, need to set the right OpenGL context stuff so that * the conversions will project the values correctly... */ - if (gpencil_project_check(p)) { + if (annotation_project_check(p)) { View3D *v3d = p->area->spacedata.first; /* need to restore the original projection settings before packing up */ @@ -1656,22 +1668,22 @@ static void gp_paint_strokeend(tGPsdata *p) /* check if doing eraser or not */ if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) { /* transfer stroke to frame */ - gp_stroke_newfrombuffer(p); + annotation_stroke_newfrombuffer(p); } /* clean up buffer now */ - gp_session_validatebuffer(p); + annotation_session_validatebuffer(p); } /* finish off stroke painting operation */ -static void gp_paint_cleanup(tGPsdata *p) +static void annotation_paint_cleanup(tGPsdata *p) { /* p->gpd==NULL happens when stroke failed to initialize, * for example when GP is hidden in current space (sergey) */ if (p->gpd) { /* finish off a stroke */ - gp_paint_strokeend(p); + annotation_paint_strokeend(p); } /* "unlock" frame */ @@ -1683,7 +1695,7 @@ static void gp_paint_cleanup(tGPsdata *p) /* ------------------------------- */ /* Helper callback for drawing the cursor itself */ -static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) +static void annotation_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) { tGPsdata *p = (tGPsdata *)p_ptr; @@ -1729,7 +1741,7 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) } /* Turn brush cursor in 3D view on/off */ -static void gpencil_draw_toggle_eraser_cursor(tGPsdata *p, short enable) +static void annotation_draw_toggle_eraser_cursor(tGPsdata *p, short enable) { if (p->erasercursor && !enable) { /* clear cursor */ @@ -1741,11 +1753,11 @@ static void gpencil_draw_toggle_eraser_cursor(tGPsdata *p, short enable) p->erasercursor = WM_paint_cursor_activate(SPACE_TYPE_ANY, RGN_TYPE_ANY, NULL, /* XXX */ - gpencil_draw_eraser, + annotation_draw_eraser, p); } } -static void gpencil_draw_stabilizer(bContext *C, int x, int y, void *p_ptr) +static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr) { ARegion *region = CTX_wm_region(C); tGPsdata *p = (tGPsdata *)p_ptr; @@ -1793,7 +1805,7 @@ static void gpencil_draw_stabilizer(bContext *C, int x, int y, void *p_ptr) } /* Turn *stabilizer* brush cursor in 3D view on/off */ -static void gpencil_draw_toggle_stabilizer_cursor(tGPsdata *p, short enable) +static void annotation_draw_toggle_stabilizer_cursor(tGPsdata *p, short enable) { if (p->stabilizer_cursor && !enable) { /* clear cursor */ @@ -1803,19 +1815,19 @@ static void gpencil_draw_toggle_stabilizer_cursor(tGPsdata *p, short enable) else if (enable && !p->stabilizer_cursor) { /* enable cursor */ p->stabilizer_cursor = WM_paint_cursor_activate( - SPACE_TYPE_ANY, RGN_TYPE_ANY, NULL, gpencil_draw_stabilizer, p); + SPACE_TYPE_ANY, RGN_TYPE_ANY, NULL, annotation_draw_stabilizer, p); } } /* Check if tablet eraser is being used (when processing events) */ -static bool gpencil_is_tablet_eraser_active(const wmEvent *event) +static bool annotation_is_tablet_eraser_active(const wmEvent *event) { return (event->tablet.active == EVT_TABLET_ERASER); } /* ------------------------------- */ -static void gpencil_draw_exit(bContext *C, wmOperator *op) +static void annotation_draw_exit(bContext *C, wmOperator *op) { tGPsdata *p = op->customdata; @@ -1827,10 +1839,10 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op) /* check size of buffer before cleanup, to determine if anything happened here */ if (p->paintmode == GP_PAINTMODE_ERASER) { /* turn off radial brush cursor */ - gpencil_draw_toggle_eraser_cursor(p, false); + annotation_draw_toggle_eraser_cursor(p, false); } else if (p->paintmode == GP_PAINTMODE_DRAW) { - gpencil_draw_toggle_stabilizer_cursor(p, false); + annotation_draw_toggle_stabilizer_cursor(p, false); } /* always store the new eraser size to be used again next time @@ -1843,40 +1855,40 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op) gpencil_undo_finish(); /* cleanup */ - gp_paint_cleanup(p); - gp_session_cleanup(p); - gp_session_free(p); + annotation_paint_cleanup(p); + annotation_session_cleanup(p); + annotation_session_free(p); p = NULL; } op->customdata = NULL; } -static void gpencil_draw_cancel(bContext *C, wmOperator *op) +static void annotation_draw_cancel(bContext *C, wmOperator *op) { /* this is just a wrapper around exit() */ - gpencil_draw_exit(C, op); + annotation_draw_exit(C, op); } /* ------------------------------- */ -static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) +static int annotation_draw_init(bContext *C, wmOperator *op, const wmEvent *event) { tGPsdata *p; eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode"); /* check context */ - p = op->customdata = gp_session_initpaint(C); + p = op->customdata = annotation_session_initpaint(C); if ((p == NULL) || (p->status == GP_STATUS_ERROR)) { /* something wasn't set correctly in context */ - gpencil_draw_exit(C, op); + annotation_draw_exit(C, op); return 0; } /* init painting data */ - gp_paint_initstroke(p, paintmode, CTX_data_ensure_evaluated_depsgraph(C)); + annotation_paint_initstroke(p, paintmode, CTX_data_ensure_evaluated_depsgraph(C)); if (p->status == GP_STATUS_ERROR) { - gpencil_draw_exit(C, op); + annotation_draw_exit(C, op); return 0; } @@ -1894,7 +1906,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) /* ------------------------------- */ /* ensure that the correct cursor icon is set */ -static void gpencil_draw_cursor_set(tGPsdata *p) +static void annotation_draw_cursor_set(tGPsdata *p) { if (p->paintmode == GP_PAINTMODE_ERASER) { WM_cursor_modal_set(p->win, WM_CURSOR_ERASER); @@ -1905,7 +1917,7 @@ static void gpencil_draw_cursor_set(tGPsdata *p) } /* update UI indicators of status, including cursor and header prints */ -static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) +static void annotation_draw_status_indicators(bContext *C, tGPsdata *p) { /* header prints */ switch (p->status) { @@ -1970,12 +1982,12 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) /* ------------------------------- */ /* create a new stroke point at the point indicated by the painting context */ -static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph) +static void annotation_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph) { /* handle drawing/erasing -> test for erasing first */ if (p->paintmode == GP_PAINTMODE_ERASER) { /* do 'live' erasing now */ - gp_stroke_doeraser(p); + annotation_stroke_doeraser(p); /* store used values */ p->mvalo[0] = p->mval[0]; @@ -1984,7 +1996,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph } /* Only add current point to buffer if mouse moved * (even though we got an event, it might be just noise). */ - else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) { + else if (annotation_stroke_filtermval(p, p->mval, p->mvalo)) { /* If lazy mouse, interpolate the last and current mouse positions. */ if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) { float now_mouse[2]; @@ -1996,26 +2008,24 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph } /* try to add point */ - short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); + short ok = annotation_stroke_addpoint(p, p->mval, p->pressure, p->curtime); /* handle errors while adding point */ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) { /* finish off old stroke */ - gp_paint_strokeend(p); + annotation_paint_strokeend(p); /* And start a new one!!! Else, projection errors! */ - gp_paint_initstroke(p, p->paintmode, depsgraph); + annotation_paint_initstroke(p, p->paintmode, depsgraph); /* start a new stroke, starting from previous point */ - /* XXX Must manually reset inittime... */ - /* XXX We only need to reuse previous point if overflow! */ if (ok == GP_STROKEADD_OVERFLOW) { p->inittime = p->ocurtime; - gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime); + annotation_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime); } else { p->inittime = p->curtime; } - gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); + annotation_stroke_addpoint(p, p->mval, p->pressure, p->curtime); } else if (ok == GP_STROKEADD_INVALID) { /* the painting operation cannot continue... */ @@ -2053,16 +2063,16 @@ static void annotation_draw_apply_event( /* Key to toggle stabilization. */ if (event->shift > 0 && p->paintmode == GP_PAINTMODE_DRAW) { /* Using permanent stabilization, shift will deactivate the flag. */ - if (p->flags & (GP_PAINTFLAG_USE_STABILIZER)) { + if (p->flags & GP_PAINTFLAG_USE_STABILIZER) { if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) { - gpencil_draw_toggle_stabilizer_cursor(p, false); + annotation_draw_toggle_stabilizer_cursor(p, false); p->flags &= ~GP_PAINTFLAG_USE_STABILIZER_TEMP; } } /* Not using any stabilization flag. Activate temporal one. */ else if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) { p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP; - gpencil_draw_toggle_stabilizer_cursor(p, true); + annotation_draw_toggle_stabilizer_cursor(p, true); } } /* verify key status for straight lines */ @@ -2091,7 +2101,7 @@ static void annotation_draw_apply_event( so activate the temp flag back again. */ if (p->flags & GP_PAINTFLAG_USE_STABILIZER) { if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) { - gpencil_draw_toggle_stabilizer_cursor(p, true); + annotation_draw_toggle_stabilizer_cursor(p, true); p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP; } } @@ -2101,7 +2111,7 @@ static void annotation_draw_apply_event( else if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) { /* Reset temporal stabilizer flag and remove cursor. */ p->flags &= ~GP_PAINTFLAG_USE_STABILIZER_TEMP; - gpencil_draw_toggle_stabilizer_cursor(p, false); + annotation_draw_toggle_stabilizer_cursor(p, false); } } @@ -2165,7 +2175,7 @@ static void annotation_draw_apply_event( RNA_float_set(&itemptr, "time", p->curtime - p->inittime); /* apply the current latest drawing point */ - gpencil_draw_apply(op, p, depsgraph); + annotation_draw_apply(op, p, depsgraph); /* force refresh */ /* just active area for now, since doing whole screen is too slow */ @@ -2175,7 +2185,7 @@ static void annotation_draw_apply_event( /* ------------------------------- */ /* operator 'redo' (i.e. after changing some properties, but also for repeat last) */ -static int gpencil_draw_exec(bContext *C, wmOperator *op) +static int annotation_draw_exec(bContext *C, wmOperator *op) { tGPsdata *p = NULL; Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); @@ -2183,7 +2193,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) /* printf("GPencil - Starting Re-Drawing\n"); */ /* try to initialize context data needed while drawing */ - if (!gpencil_draw_init(C, op, NULL)) { + if (!annotation_draw_init(C, op, NULL)) { if (op->customdata) { MEM_freeN(op->customdata); } @@ -2217,8 +2227,8 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) */ if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) { /* TODO: both of these ops can set error-status, but we probably don't need to worry */ - gp_paint_strokeend(p); - gp_paint_initstroke(p, p->paintmode, depsgraph); + annotation_paint_strokeend(p); + annotation_paint_initstroke(p, p->paintmode, depsgraph); } } @@ -2233,14 +2243,14 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) } /* apply this data as necessary now (as per usual) */ - gpencil_draw_apply(op, p, depsgraph); + annotation_draw_apply(op, p, depsgraph); } RNA_END; /* printf("\tGP - done\n"); */ /* cleanup */ - gpencil_draw_exit(C, op); + annotation_draw_exit(C, op); /* refreshes */ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); @@ -2252,12 +2262,12 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) /* ------------------------------- */ /* start of interactive drawing part of operator */ -static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int annotation_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) { tGPsdata *p = NULL; /* support for tablets eraser pen */ - if (gpencil_is_tablet_eraser_active(event)) { + if (annotation_is_tablet_eraser_active(event)) { RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER); } @@ -2266,7 +2276,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event } /* try to initialize context data needed while drawing */ - if (!gpencil_draw_init(C, op, event)) { + if (!annotation_draw_init(C, op, event)) { if (op->customdata) { MEM_freeN(op->customdata); } @@ -2281,21 +2291,15 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event /* if empty erase capture and finish */ if (p->status == GP_STATUS_CAPTURE) { - gpencil_draw_exit(C, op); + annotation_draw_exit(C, op); BKE_report(op->reports, RPT_ERROR, "Nothing to erase"); return OPERATOR_FINISHED; } - /* TODO: set any additional settings that we can take from the events? - * TODO? if tablet is erasing, force eraser to be on? */ - - /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... - */ - /* if eraser is on, draw radial aid */ if (p->paintmode == GP_PAINTMODE_ERASER) { - gpencil_draw_toggle_eraser_cursor(p, true); + annotation_draw_toggle_eraser_cursor(p, true); } else if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { if (RNA_enum_get(op->ptr, "arrowstyle_start") != GP_STROKE_ARROWSTYLE_NONE) { @@ -2312,18 +2316,18 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event p->stabilizer_radius = RNA_int_get(op->ptr, "stabilizer_radius"); if (RNA_boolean_get(op->ptr, "use_stabilizer")) { p->flags |= GP_PAINTFLAG_USE_STABILIZER | GP_PAINTFLAG_USE_STABILIZER_TEMP; - gpencil_draw_toggle_stabilizer_cursor(p, true); + annotation_draw_toggle_stabilizer_cursor(p, true); } else if (event->shift > 0) { p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP; - gpencil_draw_toggle_stabilizer_cursor(p, true); + annotation_draw_toggle_stabilizer_cursor(p, true); } } /* set cursor * NOTE: This may change later (i.e. intentionally via brush toggle, * or unintentionally if the user scrolls outside the area)... */ - gpencil_draw_cursor_set(p); + annotation_draw_cursor_set(p); /* only start drawing immediately if we're allowed to do so... */ if (RNA_boolean_get(op->ptr, "wait_for_input") == false) { @@ -2348,13 +2352,13 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event } /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */ -static bool gpencil_area_exists(bContext *C, ScrArea *area_test) +static bool annotation_area_exists(bContext *C, ScrArea *area_test) { bScreen *screen = CTX_wm_screen(C); return (BLI_findindex(&screen->areabase, area_test) != -1); } -static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) +static tGPsdata *annotation_stroke_begin(bContext *C, wmOperator *op) { tGPsdata *p = op->customdata; @@ -2372,8 +2376,8 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) /* XXX: watch it with the paintmode! in future, * it'd be nice to allow changing paint-mode when in sketching-sessions */ - if (gp_session_initdata(C, p)) { - gp_paint_initstroke(p, p->paintmode, CTX_data_ensure_evaluated_depsgraph(C)); + if (annotation_session_initdata(C, p)) { + annotation_paint_initstroke(p, p->paintmode, CTX_data_ensure_evaluated_depsgraph(C)); } if (p->status != GP_STATUS_ERROR) { @@ -2384,15 +2388,15 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) return op->customdata; } -static void gpencil_stroke_end(wmOperator *op) +static void annotation_stroke_end(wmOperator *op) { tGPsdata *p = op->customdata; - gp_paint_cleanup(p); + annotation_paint_cleanup(p); gpencil_undo_push(p->gpd); - gp_session_cleanup(p); + annotation_session_cleanup(p); p->status = GP_STATUS_IDLING; op->flag |= OP_IS_MODAL_CURSOR_REGION; @@ -2439,7 +2443,7 @@ static void annotation_add_missing_events(bContext *C, } /* events handling during interactive drawing part of operator */ -static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) +static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) { tGPsdata *p = op->customdata; /* default exit state - pass through to support MMB view nav, etc. */ @@ -2542,7 +2546,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) if (sketch) { /* end stroke only, and then wait to resume painting soon */ /* printf("\t\tGP - end stroke only\n"); */ - gpencil_stroke_end(op); + annotation_stroke_end(op); /* If eraser mode is on, turn it off after the stroke finishes * NOTE: This just makes it nicer to work with drawing sessions @@ -2561,7 +2565,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) * Just hiding this makes it seem like * you can paint again... */ - gpencil_draw_toggle_eraser_cursor(p, false); + annotation_draw_toggle_eraser_cursor(p, false); } } @@ -2637,7 +2641,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Switch paintmode (temporarily if need be) based on which button was used * NOTE: This is to make it more convenient to erase strokes when using drawing sessions */ - if ((event->type == RIGHTMOUSE) || gpencil_is_tablet_eraser_active(event)) { + if ((event->type == RIGHTMOUSE) || annotation_is_tablet_eraser_active(event)) { /* turn on eraser */ p->paintmode = GP_PAINTMODE_ERASER; } @@ -2646,10 +2650,10 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) p->paintmode = RNA_enum_get(op->ptr, "mode"); } - gpencil_draw_toggle_eraser_cursor(p, p->paintmode == GP_PAINTMODE_ERASER); + annotation_draw_toggle_eraser_cursor(p, p->paintmode == GP_PAINTMODE_ERASER); /* not painting, so start stroke (this should be mouse-button down) */ - p = gpencil_stroke_begin(C, op); + p = annotation_stroke_begin(C, op); if (p->status == GP_STATUS_ERROR) { estate = OPERATOR_CANCELLED; @@ -2733,26 +2737,26 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */ - if (0 == gpencil_area_exists(C, p->area)) { + if (0 == annotation_area_exists(C, p->area)) { estate = OPERATOR_CANCELLED; } else { /* update status indicators - cursor, header, etc. */ - gpencil_draw_status_indicators(C, p); + annotation_draw_status_indicators(C, p); /* cursor may have changed outside our control - T44084 */ - gpencil_draw_cursor_set(p); + annotation_draw_cursor_set(p); } /* process last operations before exiting */ switch (estate) { case OPERATOR_FINISHED: /* one last flush before we're done */ - gpencil_draw_exit(C, op); + annotation_draw_exit(C, op); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); break; case OPERATOR_CANCELLED: - gpencil_draw_exit(C, op); + annotation_draw_exit(C, op); break; case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH: @@ -2811,11 +2815,11 @@ void GPENCIL_OT_annotate(wmOperatorType *ot) ot->description = "Make annotations on the active data"; /* api callbacks */ - ot->exec = gpencil_draw_exec; - ot->invoke = gpencil_draw_invoke; - ot->modal = gpencil_draw_modal; - ot->cancel = gpencil_draw_cancel; - ot->poll = gpencil_draw_poll; + ot->exec = annotation_draw_exec; + ot->invoke = annotation_draw_invoke; + ot->modal = annotation_draw_modal; + ot->cancel = annotation_draw_cancel; + ot->poll = annotation_draw_poll; /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 6d41e9bddbe..60fd52db707 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -114,10 +114,10 @@ typedef enum eDrawStrokeFlags { /* ----- Tool Buffer Drawing ------ */ /* helper functions to set color of buffer point */ -static void gp_set_point_varying_color(const bGPDspoint *pt, - const float ink[4], - uint attr_id, - bool fix_strength) +static void gpencil_set_point_varying_color(const bGPDspoint *pt, + const float ink[4], + uint attr_id, + bool fix_strength) { float alpha = ink[3] * pt->strength; if ((fix_strength) && (alpha >= 0.1f)) { @@ -130,10 +130,10 @@ static void gp_set_point_varying_color(const bGPDspoint *pt, /* ----------- Volumetric Strokes --------------- */ /* draw a 3D stroke in "volumetric" style */ -static void gp_draw_stroke_volumetric_3d(const bGPDspoint *points, - int totpoints, - short thickness, - const float ink[4]) +static void gpencil_draw_stroke_volumetric_3d(const bGPDspoint *points, + int totpoints, + short thickness, + const float ink[4]) { GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); @@ -147,7 +147,7 @@ static void gp_draw_stroke_volumetric_3d(const bGPDspoint *points, const bGPDspoint *pt = points; for (int i = 0; i < totpoints && pt; i++, pt++) { - gp_set_point_varying_color(pt, ink, color, false); + gpencil_set_point_varying_color(pt, ink, color, false); /* TODO: scale based on view transform */ immAttr1f(size, pt->pressure * thickness); /* we can adjust size in vertex shader based on view/projection! */ @@ -162,7 +162,10 @@ static void gp_draw_stroke_volumetric_3d(const bGPDspoint *points, /* ----- Existing Strokes Drawing (3D and Point) ------ */ /* draw a given stroke in 3d (i.e. in 3d-space) */ -static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4], bool cyclic) +static void gpencil_draw_stroke_3d(tGPDdraw *tgpw, + short thickness, + const float ink[4], + bool cyclic) { bGPDspoint *points = tgpw->gps->points; int totpoints = tgpw->gps->totpoints; @@ -209,7 +212,7 @@ static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4 for (int i = 0; i < totpoints; i++, pt++) { /* first point for adjacency (not drawn) */ if (i == 0) { - gp_set_point_varying_color(points, ink, attr_id.color, (bool)tgpw->is_fill_stroke); + gpencil_set_point_varying_color(points, ink, attr_id.color, (bool)tgpw->is_fill_stroke); if ((cyclic) && (totpoints > 2)) { immAttr1f(attr_id.thickness, max_ff((points + totpoints - 1)->pressure * thickness, 1.0f)); @@ -222,7 +225,7 @@ static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4 immVertex3fv(attr_id.pos, fpt); } /* set point */ - gp_set_point_varying_color(pt, ink, attr_id.color, (bool)tgpw->is_fill_stroke); + gpencil_set_point_varying_color(pt, ink, attr_id.color, (bool)tgpw->is_fill_stroke); immAttr1f(attr_id.thickness, max_ff(pt->pressure * thickness, 1.0f)); mul_v3_m4v3(fpt, tgpw->diff_mat, &pt->x); immVertex3fv(attr_id.pos, fpt); @@ -241,7 +244,7 @@ static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4 } /* last adjacency point (not drawn) */ else { - gp_set_point_varying_color( + gpencil_set_point_varying_color( points + totpoints - 2, ink, attr_id.color, (bool)tgpw->is_fill_stroke); immAttr1f(attr_id.thickness, max_ff((points + totpoints - 2)->pressure * thickness, 1.0f)); @@ -256,7 +259,7 @@ static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4 /* ----- Strokes Drawing ------ */ /* Helper for doing all the checks on whether a stroke can be drawn */ -static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag) +static bool gpencil_can_draw_stroke(const bGPDstroke *gps, const int dflag) { /* skip stroke if it isn't in the right display space for this drawing context */ /* 1) 3D Strokes */ @@ -293,7 +296,7 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag) } /* draw a set of strokes */ -static void gp_draw_strokes(tGPDdraw *tgpw) +static void gpencil_draw_strokes(tGPDdraw *tgpw) { float tcolor[4]; short sthickness; @@ -307,7 +310,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw) for (bGPDstroke *gps = gps_init; gps; gps = gps->next) { /* check if stroke can be drawn */ - if (gp_can_draw_stroke(gps, tgpw->dflag) == false) { + if (gpencil_can_draw_stroke(gps, tgpw->dflag) == false) { continue; } /* check if the color is visible */ @@ -316,7 +319,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw) if ((gp_style == NULL) || (gp_style->flag & GP_MATERIAL_HIDE) || /* if onion and ghost flag do not draw*/ - (tgpw->onion && (gp_style->flag & GP_MATERIAL_ONIONSKIN))) { + (tgpw->onion && (gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN))) { continue; } @@ -379,14 +382,14 @@ static void gp_draw_strokes(tGPDdraw *tgpw) if (gp_style->mode == GP_MATERIAL_MODE_DOT) { /* volumetric stroke drawing */ if (tgpw->disable_fill != 1) { - gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink); + gpencil_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink); } } else { /* 3D Lines - OpenGL primitives-based */ if (gps->totpoints > 1) { tgpw->gps = gps; - gp_draw_stroke_3d(tgpw, sthickness, ink, gps->flag & GP_STROKE_CYCLIC); + gpencil_draw_stroke_3d(tgpw, sthickness, ink, gps->flag & GP_STROKE_CYCLIC); } } if (no_xray) { @@ -408,7 +411,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw) /* ----- General Drawing ------ */ /* wrapper to draw strokes for filling operator */ -void ED_gp_draw_fill(tGPDdraw *tgpw) +void ED_gpencil_draw_fill(tGPDdraw *tgpw) { - gp_draw_strokes(tgpw); + gpencil_draw_strokes(tgpw); } diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index d2b1eba7d86..752b8a74f4f 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -56,7 +56,9 @@ /* Generics - Loopers */ /* Loops over the gp-frames for a gp-layer, and applies the given callback */ -bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPDframe *, Scene *)) +bool ED_gpencil_layer_frames_looper(bGPDlayer *gpl, + Scene *scene, + short (*gpf_cb)(bGPDframe *, Scene *)) { /* error checker */ if (gpl == NULL) { @@ -79,7 +81,7 @@ bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPD /* Data Conversion Tools */ /* make a listing all the gp-frames in a layer as cfraelems */ -void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel) +void ED_gpencil_layer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel) { CfraElem *ce; @@ -105,7 +107,7 @@ void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel) /* Selection Tools */ /* check if one of the frames in this layer is selected */ -bool ED_gplayer_frame_select_check(bGPDlayer *gpl) +bool ED_gpencil_layer_frame_select_check(bGPDlayer *gpl) { /* error checking */ if (gpl == NULL) { @@ -124,7 +126,7 @@ bool ED_gplayer_frame_select_check(bGPDlayer *gpl) } /* helper function - select gp-frame based on SELECT_* mode */ -static void gpframe_select(bGPDframe *gpf, short select_mode) +static void gpencil_frame_select(bGPDframe *gpf, short select_mode) { if (gpf == NULL) { return; @@ -153,12 +155,12 @@ void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode) /* handle according to mode */ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { - gpframe_select(gpf, select_mode); + gpencil_frame_select(gpf, select_mode); } } /* set all/none/invert select */ -void ED_gplayer_frame_select_set(bGPDlayer *gpl, short mode) +void ED_gpencil_layer_frame_select_set(bGPDlayer *gpl, short mode) { /* error checking */ if (gpl == NULL) { @@ -181,12 +183,12 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode) gpf = BKE_gpencil_layer_frame_find(gpl, selx); if (gpf) { - gpframe_select(gpf, select_mode); + gpencil_frame_select(gpf, select_mode); } } /* select the frames in this layer that occur within the bounds specified */ -void ED_gplayer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode) +void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode) { if (gpl == NULL) { return; @@ -195,16 +197,16 @@ void ED_gplayer_frames_select_box(bGPDlayer *gpl, float min, float max, short se /* only select those frames which are in bounds */ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { if (IN_RANGE(gpf->framenum, min, max)) { - gpframe_select(gpf, select_mode); + gpencil_frame_select(gpf, select_mode); } } } /* select the frames in this layer that occur within the lasso/circle region specified */ -void ED_gplayer_frames_select_region(KeyframeEditData *ked, - bGPDlayer *gpl, - short tool, - short select_mode) +void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked, + bGPDlayer *gpl, + short tool, + short select_mode) { if (gpl == NULL) { return; @@ -222,13 +224,13 @@ void ED_gplayer_frames_select_region(KeyframeEditData *ked, if (tool == BEZT_OK_CHANNEL_LASSO) { /* Lasso */ if (keyframe_region_lasso_test(ked->data, pt)) { - gpframe_select(gpf, select_mode); + gpencil_frame_select(gpf, select_mode); } } else if (tool == BEZT_OK_CHANNEL_CIRCLE) { /* Circle */ if (keyframe_region_circle_test(ked->data, pt)) { - gpframe_select(gpf, select_mode); + gpencil_frame_select(gpf, select_mode); } } } @@ -238,7 +240,7 @@ void ED_gplayer_frames_select_region(KeyframeEditData *ked, /* Frame Editing Tools */ /* Delete selected frames */ -bool ED_gplayer_frames_delete(bGPDlayer *gpl) +bool ED_gpencil_layer_frames_delete(bGPDlayer *gpl) { bool changed = false; @@ -259,7 +261,7 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl) } /* Duplicate selected frames from given gp-layer */ -void ED_gplayer_frames_duplicate(bGPDlayer *gpl) +void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl) { /* error checking */ if (gpl == NULL) { @@ -282,10 +284,12 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl) } } -/* Set keyframe type for selected frames from given gp-layer - * \param type: The type of keyframe (eBezTriple_KeyframeType) to set selected frames to +/** + * Set keyframe type for selected frames from given gp-layer + * + * \param type: The type of keyframe (#eBezTriple_KeyframeType) to set selected frames to. */ -void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type) +void ED_gpencil_layer_frames_keytype_set(bGPDlayer *gpl, short type) { if (gpl == NULL) { return; @@ -311,20 +315,20 @@ void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type) */ /* globals for copy/paste data (like for other copy/paste buffers) */ -static ListBase gp_anim_copybuf = {NULL, NULL}; -static int gp_anim_copy_firstframe = 999999999; -static int gp_anim_copy_lastframe = -999999999; -static int gp_anim_copy_cfra = 0; +static ListBase gpencil_anim_copybuf = {NULL, NULL}; +static int gpencil_anim_copy_firstframe = 999999999; +static int gpencil_anim_copy_lastframe = -999999999; +static int gpencil_anim_copy_cfra = 0; /* This function frees any MEM_calloc'ed copy/paste buffer data */ void ED_gpencil_anim_copybuf_free(void) { - BKE_gpencil_free_layers(&gp_anim_copybuf); - BLI_listbase_clear(&gp_anim_copybuf); + BKE_gpencil_free_layers(&gpencil_anim_copybuf); + BLI_listbase_clear(&gpencil_anim_copybuf); - gp_anim_copy_firstframe = 999999999; - gp_anim_copy_lastframe = -999999999; - gp_anim_copy_cfra = 0; + gpencil_anim_copy_firstframe = 999999999; + gpencil_anim_copy_lastframe = -999999999; + gpencil_anim_copy_cfra = 0; } /* This function adds data to the copy/paste buffer, freeing existing data first @@ -361,11 +365,11 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac) BLI_addtail(&copied_frames, new_frame); /* extend extents for keyframes encountered */ - if (gpf->framenum < gp_anim_copy_firstframe) { - gp_anim_copy_firstframe = gpf->framenum; + if (gpf->framenum < gpencil_anim_copy_firstframe) { + gpencil_anim_copy_firstframe = gpf->framenum; } - if (gpf->framenum > gp_anim_copy_lastframe) { - gp_anim_copy_lastframe = gpf->framenum; + if (gpf->framenum > gpencil_anim_copy_lastframe) { + gpencil_anim_copy_lastframe = gpf->framenum; } } } @@ -373,7 +377,7 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac) /* create a new layer in buffer if there were keyframes here */ if (BLI_listbase_is_empty(&copied_frames) == false) { bGPDlayer *new_layer = MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer"); - BLI_addtail(&gp_anim_copybuf, new_layer); + BLI_addtail(&gpencil_anim_copybuf, new_layer); /* move over copied frames */ BLI_movelisttolist(&new_layer->frames, &copied_frames); @@ -385,13 +389,13 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac) } /* in case 'relative' paste method is used */ - gp_anim_copy_cfra = CFRA; + gpencil_anim_copy_cfra = CFRA; /* clean up */ ANIM_animdata_freelist(&anim_data); /* check if anything ended up in the buffer */ - if (ELEM(NULL, gp_anim_copybuf.first, gp_anim_copybuf.last)) { + if (ELEM(NULL, gpencil_anim_copybuf.first, gpencil_anim_copybuf.last)) { BKE_report(ac->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer"); return false; } @@ -412,26 +416,26 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) int offset = 0; /* check if buffer is empty */ - if (BLI_listbase_is_empty(&gp_anim_copybuf)) { + if (BLI_listbase_is_empty(&gpencil_anim_copybuf)) { BKE_report(ac->reports, RPT_ERROR, "No data in buffer to paste"); return false; } /* check if single channel in buffer (disregard names if so) */ - if (gp_anim_copybuf.first == gp_anim_copybuf.last) { + if (gpencil_anim_copybuf.first == gpencil_anim_copybuf.last) { no_name = true; } /* methods of offset (eKeyPasteOffset) */ switch (offset_mode) { case KEYFRAME_PASTE_OFFSET_CFRA_START: - offset = (CFRA - gp_anim_copy_firstframe); + offset = (CFRA - gpencil_anim_copy_firstframe); break; case KEYFRAME_PASTE_OFFSET_CFRA_END: - offset = (CFRA - gp_anim_copy_lastframe); + offset = (CFRA - gpencil_anim_copy_lastframe); break; case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE: - offset = (CFRA - gp_anim_copy_cfra); + offset = (CFRA - gpencil_anim_copy_cfra); break; case KEYFRAME_PASTE_OFFSET_NONE: offset = 0; @@ -451,7 +455,7 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) bGPDframe *gpfs, *gpf; /* find suitable layer from buffer to use to paste from */ - for (gpls = gp_anim_copybuf.first; gpls; gpls = gpls->next) { + for (gpls = gpencil_anim_copybuf.first; gpls; gpls = gpls->next) { /* check if layer name matches */ if ((no_name) || STREQ(gpls->info, gpld->info)) { break; @@ -507,7 +511,7 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) /* -------------------------------------- */ /* Snap Tools */ -static short snap_gpf_nearest(bGPDframe *UNUSED(gpf), Scene *UNUSED(scene)) +static short gpencil_frame_snap_nearest(bGPDframe *UNUSED(gpf), Scene *UNUSED(scene)) { #if 0 /* note: gpf->framenum is already an int! */ if (gpf->flag & GP_FRAME_SELECT) { @@ -517,7 +521,7 @@ static short snap_gpf_nearest(bGPDframe *UNUSED(gpf), Scene *UNUSED(scene)) return 0; } -static short snap_gpf_nearestsec(bGPDframe *gpf, Scene *scene) +static short gpencil_frame_snap_nearestsec(bGPDframe *gpf, Scene *scene) { float secf = (float)FPS; if (gpf->flag & GP_FRAME_SELECT) { @@ -526,7 +530,7 @@ static short snap_gpf_nearestsec(bGPDframe *gpf, Scene *scene) return 0; } -static short snap_gpf_cframe(bGPDframe *gpf, Scene *scene) +static short gpencil_frame_snap_cframe(bGPDframe *gpf, Scene *scene) { if (gpf->flag & GP_FRAME_SELECT) { gpf->framenum = (int)CFRA; @@ -534,7 +538,7 @@ static short snap_gpf_cframe(bGPDframe *gpf, Scene *scene) return 0; } -static short snap_gpf_nearmarker(bGPDframe *gpf, Scene *scene) +static short gpencil_frame_snap_nearmarker(bGPDframe *gpf, Scene *scene) { if (gpf->flag & GP_FRAME_SELECT) { gpf->framenum = (int)ED_markers_find_nearest_marker_time(&scene->markers, @@ -544,20 +548,20 @@ static short snap_gpf_nearmarker(bGPDframe *gpf, Scene *scene) } /* snap selected frames to ... */ -void ED_gplayer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode) +void ED_gpencil_layer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode) { switch (mode) { case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */ - ED_gplayer_frames_looper(gpl, scene, snap_gpf_nearest); + ED_gpencil_layer_frames_looper(gpl, scene, gpencil_frame_snap_nearest); break; case SNAP_KEYS_CURFRAME: /* snap to current frame */ - ED_gplayer_frames_looper(gpl, scene, snap_gpf_cframe); + ED_gpencil_layer_frames_looper(gpl, scene, gpencil_frame_snap_cframe); break; case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */ - ED_gplayer_frames_looper(gpl, scene, snap_gpf_nearmarker); + ED_gpencil_layer_frames_looper(gpl, scene, gpencil_frame_snap_nearmarker); break; case SNAP_KEYS_NEARSEC: /* snap to nearest second */ - ED_gplayer_frames_looper(gpl, scene, snap_gpf_nearestsec); + ED_gpencil_layer_frames_looper(gpl, scene, gpencil_frame_snap_nearestsec); break; default: /* just in case */ break; @@ -567,7 +571,7 @@ void ED_gplayer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode) /* -------------------------------------- */ /* Mirror Tools */ -static short mirror_gpf_cframe(bGPDframe *gpf, Scene *scene) +static short gpencil_frame_mirror_cframe(bGPDframe *gpf, Scene *scene) { int diff; @@ -579,7 +583,7 @@ static short mirror_gpf_cframe(bGPDframe *gpf, Scene *scene) return 0; } -static short mirror_gpf_yaxis(bGPDframe *gpf, Scene *UNUSED(scene)) +static short gpencil_frame_mirror_yaxis(bGPDframe *gpf, Scene *UNUSED(scene)) { int diff; @@ -591,7 +595,7 @@ static short mirror_gpf_yaxis(bGPDframe *gpf, Scene *UNUSED(scene)) return 0; } -static short mirror_gpf_xaxis(bGPDframe *gpf, Scene *UNUSED(scene)) +static short gpencil_frame_mirror_xaxis(bGPDframe *gpf, Scene *UNUSED(scene)) { int diff; @@ -604,7 +608,7 @@ static short mirror_gpf_xaxis(bGPDframe *gpf, Scene *UNUSED(scene)) return 0; } -static short mirror_gpf_marker(bGPDframe *gpf, Scene *scene) +static short gpencil_frame_mirror_marker(bGPDframe *gpf, Scene *scene) { static TimeMarker *marker; static short initialized = 0; @@ -646,25 +650,25 @@ static short mirror_gpf_marker(bGPDframe *gpf, Scene *scene) /* mirror selected gp-frames on... */ // TODO: mirror over a specific time -void ED_gplayer_mirror_frames(bGPDlayer *gpl, Scene *scene, short mode) +void ED_gpencil_layer_mirror_frames(bGPDlayer *gpl, Scene *scene, short mode) { switch (mode) { case MIRROR_KEYS_CURFRAME: /* mirror over current frame */ - ED_gplayer_frames_looper(gpl, scene, mirror_gpf_cframe); + ED_gpencil_layer_frames_looper(gpl, scene, gpencil_frame_mirror_cframe); break; case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */ - ED_gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis); + ED_gpencil_layer_frames_looper(gpl, scene, gpencil_frame_mirror_yaxis); break; case MIRROR_KEYS_XAXIS: /* mirror over value 0 */ - ED_gplayer_frames_looper(gpl, scene, mirror_gpf_xaxis); + ED_gpencil_layer_frames_looper(gpl, scene, gpencil_frame_mirror_xaxis); break; case MIRROR_KEYS_MARKER: /* mirror over marker */ - mirror_gpf_marker(NULL, scene); - ED_gplayer_frames_looper(gpl, scene, mirror_gpf_marker); - mirror_gpf_marker(NULL, scene); + gpencil_frame_mirror_marker(NULL, scene); + ED_gpencil_layer_frames_looper(gpl, scene, gpencil_frame_mirror_marker); + gpencil_frame_mirror_marker(NULL, scene); break; default: /* just in case */ - ED_gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis); + ED_gpencil_layer_frames_looper(gpl, scene, gpencil_frame_mirror_yaxis); break; } } diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c index 60a4404beaf..39a2d594c13 100644 --- a/source/blender/editors/gpencil/gpencil_add_stroke.c +++ b/source/blender/editors/gpencil/gpencil_add_stroke.c @@ -49,7 +49,10 @@ typedef struct ColorTemplate { } ColorTemplate; /* Add color an ensure duplications (matched by name) */ -static int gp_stroke_material(Main *bmain, Object *ob, const ColorTemplate *pct, const bool fill) +static int gpencil_stroke_material(Main *bmain, + Object *ob, + const ColorTemplate *pct, + const bool fill) { short *totcol = BKE_object_material_len_p(ob); Material *ma = NULL; @@ -224,12 +227,12 @@ void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4]) bGPDstroke *gps; /* create colors */ - int color_black = gp_stroke_material(bmain, ob, &gp_stroke_material_black, false); - gp_stroke_material(bmain, ob, &gp_stroke_material_white, false); - gp_stroke_material(bmain, ob, &gp_stroke_material_red, false); - gp_stroke_material(bmain, ob, &gp_stroke_material_green, false); - gp_stroke_material(bmain, ob, &gp_stroke_material_blue, false); - gp_stroke_material(bmain, ob, &gp_stroke_material_grey, true); + int color_black = gpencil_stroke_material(bmain, ob, &gp_stroke_material_black, false); + gpencil_stroke_material(bmain, ob, &gp_stroke_material_white, false); + gpencil_stroke_material(bmain, ob, &gp_stroke_material_red, false); + gpencil_stroke_material(bmain, ob, &gp_stroke_material_green, false); + gpencil_stroke_material(bmain, ob, &gp_stroke_material_blue, false); + gpencil_stroke_material(bmain, ob, &gp_stroke_material_grey, true); /* set first color as active and in brushes */ ob->actcol = color_black + 1; diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 78a34cda2f5..e111ce44bc4 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -54,8 +54,11 @@ #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" +#include "BKE_image.h" #include "BKE_layer.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -151,12 +154,12 @@ static const EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), /* convert the coordinates from the given stroke point into 3d-coordinates * - assumes that the active space is the 3D-View */ -static void gp_strokepoint_convertcoords(bContext *C, - bGPDlayer *gpl, - bGPDstroke *gps, - bGPDspoint *source_pt, - float p3d[3], - const rctf *subrect) +static void gpencil_strokepoint_convertcoords(bContext *C, + bGPDlayer *gpl, + bGPDstroke *gps, + bGPDspoint *source_pt, + float p3d[3], + const rctf *subrect) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -240,7 +243,7 @@ typedef struct tGpTimingData { /* Init point buffers for timing data. * Note this assumes we only grow those arrays! */ -static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr) +static void gpencil_timing_data_set_nbr(tGpTimingData *gtd, const int nbr) { float *tmp; @@ -266,10 +269,10 @@ static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr) } /* add stroke point to timing buffers */ -static void gp_timing_data_add_point(tGpTimingData *gtd, - const double stroke_inittime, - const float time, - const float delta_dist) +static void gpencil_timing_data_add_point(tGpTimingData *gtd, + const double stroke_inittime, + const float time, + const float delta_dist) { float delta_time = 0.0f; const int cur_point = gtd->cur_point; @@ -305,14 +308,14 @@ static void gp_timing_data_add_point(tGpTimingData *gtd, #define MIN_TIME_DELTA 0.02f /* Loop over next points to find the end of the stroke, and compute */ -static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, - RNG *rng, - const int idx, - const int nbr_gaps, - int *nbr_done_gaps, - const float tot_gaps_time, - const float delta_time, - float *next_delta_time) +static int gpencil_find_end_of_stroke_idx(tGpTimingData *gtd, + RNG *rng, + const int idx, + const int nbr_gaps, + int *nbr_done_gaps, + const float tot_gaps_time, + const float delta_time, + float *next_delta_time) { int j; @@ -362,10 +365,10 @@ static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, return j - 1; } -static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, - RNG *rng, - int *nbr_gaps, - float *tot_gaps_time) +static void gpencil_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, + RNG *rng, + int *nbr_gaps, + float *tot_gaps_time) { int i; float delta_time = 0.0f; @@ -393,16 +396,16 @@ static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, } } -static void gp_stroke_path_animation_add_keyframes(ReportList *reports, - PointerRNA ptr, - PropertyRNA *prop, - FCurve *fcu, - Curve *cu, - tGpTimingData *gtd, - RNG *rng, - const float time_range, - const int nbr_gaps, - const float tot_gaps_time) +static void gpencil_stroke_path_animation_add_keyframes(ReportList *reports, + PointerRNA ptr, + PropertyRNA *prop, + FCurve *fcu, + Curve *cu, + tGpTimingData *gtd, + RNG *rng, + const float time_range, + const int nbr_gaps, + const float tot_gaps_time) { /* Use actual recorded timing! */ const float time_start = (float)gtd->start_frame; @@ -428,7 +431,7 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, start_stroke_idx = i; delta_time = next_delta_time; /* find end of that new stroke */ - end_stroke_idx = gp_find_end_of_stroke_idx( + end_stroke_idx = gpencil_find_end_of_stroke_idx( gtd, rng, i, nbr_gaps, &nbr_done_gaps, tot_gaps_time, delta_time, &next_delta_time); /* This one should *never* be negative! */ end_stroke_time = time_start + @@ -486,10 +489,10 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, } } -static void gp_stroke_path_animation(bContext *C, - ReportList *reports, - Curve *cu, - tGpTimingData *gtd) +static void gpencil_stroke_path_animation(bContext *C, + ReportList *reports, + Curve *cu, + tGpTimingData *gtd) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -557,7 +560,7 @@ static void gp_stroke_path_animation(bContext *C, /* Pre-process gaps, in case we don't want to keep their original timing */ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { - gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time); + gpencil_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time); } if (gtd->realtime) { @@ -571,7 +574,7 @@ static void gp_stroke_path_animation(bContext *C, printf("GP Stroke Path Conversion: Starting keying!\n"); } - gp_stroke_path_animation_add_keyframes( + gpencil_stroke_path_animation_add_keyframes( reports, ptr, prop, fcu, cu, gtd, rng, time_range, nbr_gaps, tot_gaps_time); BLI_rng_free(rng); @@ -603,16 +606,16 @@ static void gp_stroke_path_animation(bContext *C, /* convert stroke to 3d path */ /* helper */ -static void gp_stroke_to_path_add_point(tGpTimingData *gtd, - BPoint *bp, - const float p[3], - const float prev_p[3], - const bool do_gtd, - const double inittime, - const float time, - const float width, - const float rad_fac, - float minmax_weights[2]) +static void gpencil_stroke_to_path_add_point(tGpTimingData *gtd, + BPoint *bp, + const float p[3], + const float prev_p[3], + const bool do_gtd, + const double inittime, + const float time, + const float width, + const float rad_fac, + float minmax_weights[2]) { copy_v3_v3(bp->vec, p); bp->vec[3] = 1.0f; @@ -631,22 +634,22 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd, /* Update timing data */ if (do_gtd) { - gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p)); + gpencil_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p)); } } -static void gp_stroke_to_path(bContext *C, - bGPDlayer *gpl, - bGPDstroke *gps, - Curve *cu, - rctf *subrect, - Nurb **curnu, - float minmax_weights[2], - const float rad_fac, - bool stitch, - const bool add_start_point, - const bool add_end_point, - tGpTimingData *gtd) +static void gpencil_stroke_to_path(bContext *C, + bGPDlayer *gpl, + bGPDstroke *gps, + Curve *cu, + rctf *subrect, + Nurb **curnu, + float minmax_weights[2], + const float rad_fac, + bool stitch, + const bool add_start_point, + const bool add_end_point, + tGpTimingData *gtd) { bGPDspoint *pt; Nurb *nu = (curnu) ? *curnu : NULL; @@ -682,7 +685,7 @@ static void gp_stroke_to_path(bContext *C, } if (do_gtd) { - gp_timing_data_set_nbr(gtd, nu->pntsu); + gpencil_timing_data_set_nbr(gtd, nu->pntsu); } /* If needed, make the link between both strokes with two zero-radius additional points */ @@ -710,7 +713,7 @@ static void gp_stroke_to_path(bContext *C, bp = &nu->bp[old_nbp - 1]; /* First point */ - gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect); + gpencil_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect); if (prev_bp) { interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC); if (do_gtd) { @@ -725,21 +728,21 @@ static void gp_stroke_to_path(bContext *C, } } bp++; - gp_stroke_to_path_add_point(gtd, - bp, - p1, - (bp - 1)->vec, - do_gtd, - gps->prev->inittime, - dt1, - 0.0f, - rad_fac, - minmax_weights); + gpencil_stroke_to_path_add_point(gtd, + bp, + p1, + (bp - 1)->vec, + do_gtd, + gps->prev->inittime, + dt1, + 0.0f, + rad_fac, + minmax_weights); /* Second point */ /* Note dt2 is always negative, which marks the gap. */ if (gps->totpoints > 1) { - gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect); + gpencil_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect); interp_v3_v3v3(p2, p, next_p, -GAP_DFAC); if (do_gtd) { dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC); @@ -752,7 +755,7 @@ static void gp_stroke_to_path(bContext *C, } } bp++; - gp_stroke_to_path_add_point( + gpencil_stroke_to_path_add_point( gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights); old_nbp += 2; @@ -761,9 +764,9 @@ static void gp_stroke_to_path(bContext *C, float p[3], next_p[3]; float dt = 0.0f; - gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect); + gpencil_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect); if (gps->totpoints > 1) { - gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect); + gpencil_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect); interp_v3_v3v3(p, p, next_p, -GAP_DFAC); if (do_gtd) { dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC); @@ -778,7 +781,7 @@ static void gp_stroke_to_path(bContext *C, * (which would be expected value) would not work * (it would be *before* gtd->inittime, which is not supported currently). */ - gp_stroke_to_path_add_point( + gpencil_stroke_to_path_add_point( gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); old_nbp++; @@ -796,18 +799,18 @@ static void gp_stroke_to_path(bContext *C, float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC; /* get coordinates to add at */ - gp_strokepoint_convertcoords(C, gpl, gps, pt, p, subrect); - - gp_stroke_to_path_add_point(gtd, - bp, - p, - (prev_bp) ? prev_bp->vec : p, - do_gtd, - gps->inittime, - pt->time, - width, - rad_fac, - minmax_weights); + gpencil_strokepoint_convertcoords(C, gpl, gps, pt, p, subrect); + + gpencil_stroke_to_path_add_point(gtd, + bp, + p, + (prev_bp) ? prev_bp->vec : p, + do_gtd, + gps->inittime, + pt->time, + width, + rad_fac, + minmax_weights); prev_bp = bp; } @@ -829,7 +832,7 @@ static void gp_stroke_to_path(bContext *C, dt = GAP_DFAC; /* Rather arbitrary too! */ } /* Note bp has already been incremented in main loop above, so it points to the right place. */ - gp_stroke_to_path_add_point( + gpencil_stroke_to_path_add_point( gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); } @@ -847,18 +850,18 @@ static void gp_stroke_to_path(bContext *C, /* convert stroke to 3d bezier */ /* helper */ -static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, - BezTriple *bezt, - const float p[3], - const float h1[3], - const float h2[3], - const float prev_p[3], - const bool do_gtd, - const double inittime, - const float time, - const float width, - const float rad_fac, - float minmax_weights[2]) +static void gpencil_stroke_to_bezier_add_point(tGpTimingData *gtd, + BezTriple *bezt, + const float p[3], + const float h1[3], + const float h2[3], + const float prev_p[3], + const bool do_gtd, + const double inittime, + const float time, + const float width, + const float rad_fac, + float minmax_weights[2]) { copy_v3_v3(bezt->vec[0], h1); copy_v3_v3(bezt->vec[1], p); @@ -879,22 +882,22 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, /* Update timing data */ if (do_gtd) { - gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p)); + gpencil_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p)); } } -static void gp_stroke_to_bezier(bContext *C, - bGPDlayer *gpl, - bGPDstroke *gps, - Curve *cu, - rctf *subrect, - Nurb **curnu, - float minmax_weights[2], - const float rad_fac, - bool stitch, - const bool add_start_point, - const bool add_end_point, - tGpTimingData *gtd) +static void gpencil_stroke_to_bezier(bContext *C, + bGPDlayer *gpl, + bGPDstroke *gps, + Curve *cu, + rctf *subrect, + Nurb **curnu, + float minmax_weights[2], + const float rad_fac, + bool stitch, + const bool add_start_point, + const bool add_end_point, + tGpTimingData *gtd) { bGPDspoint *pt; Nurb *nu = (curnu) ? *curnu : NULL; @@ -927,7 +930,7 @@ static void gp_stroke_to_bezier(bContext *C, } if (do_gtd) { - gp_timing_data_set_nbr(gtd, nu->pntsu); + gpencil_timing_data_set_nbr(gtd, nu->pntsu); } tot = gps->totpoints; @@ -935,12 +938,13 @@ static void gp_stroke_to_bezier(bContext *C, /* get initial coordinates */ pt = gps->points; if (tot) { - gp_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect); + gpencil_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect); if (tot > 1) { - gp_strokepoint_convertcoords(C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect); + gpencil_strokepoint_convertcoords( + C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect); } if (stitch && tot > 2) { - gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect); + gpencil_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect); } } @@ -1017,24 +1021,24 @@ static void gp_stroke_to_bezier(bContext *C, interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC); bezt++; - gp_stroke_to_bezier_add_point(gtd, - bezt, - p1, - h1, - h2, - (bezt - 1)->vec[1], - do_gtd, - gps->prev->inittime, - dt1, - 0.0f, - rad_fac, - minmax_weights); + gpencil_stroke_to_bezier_add_point(gtd, + bezt, + p1, + h1, + h2, + (bezt - 1)->vec[1], + do_gtd, + gps->prev->inittime, + dt1, + 0.0f, + rad_fac, + minmax_weights); /* Second point */ interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC); bezt++; - gp_stroke_to_bezier_add_point( + gpencil_stroke_to_bezier_add_point( gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights); old_nbezt += 2; @@ -1059,7 +1063,7 @@ static void gp_stroke_to_bezier(bContext *C, interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC); bezt = &nu->bezt[old_nbezt]; - gp_stroke_to_bezier_add_point( + gpencil_stroke_to_bezier_add_point( gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); old_nbezt++; @@ -1088,25 +1092,25 @@ static void gp_stroke_to_bezier(bContext *C, interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC); } - gp_stroke_to_bezier_add_point(gtd, - bezt, - p3d_cur, - h1, - h2, - prev_bezt ? prev_bezt->vec[1] : p3d_cur, - do_gtd, - gps->inittime, - pt->time, - width, - rad_fac, - minmax_weights); + gpencil_stroke_to_bezier_add_point(gtd, + bezt, + p3d_cur, + h1, + h2, + prev_bezt ? prev_bezt->vec[1] : p3d_cur, + do_gtd, + gps->inittime, + pt->time, + width, + rad_fac, + minmax_weights); /* shift coord vects */ copy_v3_v3(p3d_prev, p3d_cur); copy_v3_v3(p3d_cur, p3d_next); if (i + 2 < tot) { - gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect); + gpencil_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect); } prev_bezt = bezt; @@ -1138,18 +1142,18 @@ static void gp_stroke_to_bezier(bContext *C, interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC); /* Note bezt has already been incremented in main loop above, * so it points to the right place. */ - gp_stroke_to_bezier_add_point(gtd, - bezt, - p, - h1, - h2, - prev_bezt->vec[1], - do_gtd, - gps->inittime, - dt, - 0.0f, - rad_fac, - minmax_weights); + gpencil_stroke_to_bezier_add_point(gtd, + bezt, + p, + h1, + h2, + prev_bezt->vec[1], + do_gtd, + gps->inittime, + dt, + 0.0f, + rad_fac, + minmax_weights); } /* must calculate handles or else we crash */ @@ -1167,7 +1171,7 @@ static void gp_stroke_to_bezier(bContext *C, #undef WIDTH_CORR_FAC #undef BEZT_HANDLE_FAC -static void gp_stroke_finalize_curve_endpoints(Curve *cu) +static void gpencil_stroke_finalize_curve_endpoints(Curve *cu) { /* start */ Nurb *nu = cu->nurb.first; @@ -1202,7 +1206,7 @@ static void gp_stroke_finalize_curve_endpoints(Curve *cu) } } -static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2]) +static void gpencil_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2]) { Nurb *nu; const float delta = minmax_weights[0]; @@ -1233,7 +1237,7 @@ static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2 } } -static int gp_camera_view_subrect(bContext *C, rctf *subrect) +static int gpencil_camera_view_subrect(bContext *C, rctf *subrect) { View3D *v3d = CTX_wm_view3d(C); ARegion *region = CTX_wm_region(C); @@ -1255,15 +1259,15 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect) /* convert a given grease-pencil layer to a 3d-curve representation * (using current view if appropriate) */ -static void gp_layer_to_curve(bContext *C, - ReportList *reports, - bGPdata *gpd, - bGPDlayer *gpl, - const int mode, - const bool norm_weights, - const float rad_fac, - const bool link_strokes, - tGpTimingData *gtd) +static void gpencil_layer_to_curve(bContext *C, + ReportList *reports, + bGPdata *gpd, + bGPDlayer *gpl, + const int mode, + const bool norm_weights, + const float rad_fac, + const bool link_strokes, + tGpTimingData *gtd) { struct Main *bmain = CTX_data_main(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -1292,7 +1296,7 @@ static void gp_layer_to_curve(bContext *C, } /* initialize camera framing */ - if (gp_camera_view_subrect(C, &subrect)) { + if (gpencil_camera_view_subrect(C, &subrect)) { subrect_ptr = &subrect; } @@ -1335,33 +1339,33 @@ static void gp_layer_to_curve(bContext *C, switch (mode) { case GP_STROKECONVERT_PATH: - gp_stroke_to_path(C, - gpl, - gps, - cu, - subrect_ptr, - &nu, - minmax_weights, - rad_fac, - stitch, - add_start_point, - add_end_point, - gtd); + gpencil_stroke_to_path(C, + gpl, + gps, + cu, + subrect_ptr, + &nu, + minmax_weights, + rad_fac, + stitch, + add_start_point, + add_end_point, + gtd); break; case GP_STROKECONVERT_CURVE: case GP_STROKECONVERT_POLY: /* convert after */ - gp_stroke_to_bezier(C, - gpl, - gps, - cu, - subrect_ptr, - &nu, - minmax_weights, - rad_fac, - stitch, - add_start_point, - add_end_point, - gtd); + gpencil_stroke_to_bezier(C, + gpl, + gps, + cu, + subrect_ptr, + &nu, + minmax_weights, + rad_fac, + stitch, + add_start_point, + add_end_point, + gtd); break; default: BLI_assert(!"invalid mode"); @@ -1372,16 +1376,16 @@ static void gp_layer_to_curve(bContext *C, /* If link_strokes, be sure first and last points have a zero weight/size! */ if (link_strokes) { - gp_stroke_finalize_curve_endpoints(cu); + gpencil_stroke_finalize_curve_endpoints(cu); } /* Update curve's weights, if needed */ if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) { - gp_stroke_norm_curve_weights(cu, minmax_weights); + gpencil_stroke_norm_curve_weights(cu, minmax_weights); } /* Create the path animation, if needed */ - gp_stroke_path_animation(C, reports, cu, gtd); + gpencil_stroke_path_animation(C, reports, cu, gtd); if (mode == GP_STROKECONVERT_POLY) { for (nu = cu->nurb.first; nu; nu = nu->next) { @@ -1399,7 +1403,7 @@ static void gp_layer_to_curve(bContext *C, /* Check a GP layer has valid timing data! Else, most timing options are hidden in the operator. * op may be NULL. */ -static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op) +static bool gpencil_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -1447,9 +1451,9 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe } /* Check end_frame is always > start frame! */ -static void gp_convert_set_end_frame(struct Main *UNUSED(main), - struct Scene *UNUSED(scene), - struct PointerRNA *ptr) +static void gpencil_convert_set_end_frame(struct Main *UNUSED(main), + struct Scene *UNUSED(scene), + struct PointerRNA *ptr) { int start_frame = RNA_int_get(ptr, "start_frame"); int end_frame = RNA_int_get(ptr, "end_frame"); @@ -1459,7 +1463,7 @@ static void gp_convert_set_end_frame(struct Main *UNUSED(main), } } -static bool gp_convert_poll(bContext *C) +static bool gpencil_convert_poll(bContext *C) { Object *ob = CTX_data_active_object(C); Scene *scene = CTX_data_scene(C); @@ -1481,7 +1485,7 @@ static bool gp_convert_poll(bContext *C) (gpf->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd))); } -static int gp_convert_layer_exec(bContext *C, wmOperator *op) +static int gpencil_convert_layer_exec(bContext *C, wmOperator *op) { PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data"); Object *ob = CTX_data_active_object(C); @@ -1502,7 +1506,7 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) { + if (!RNA_property_is_set(op->ptr, prop) && !gpencil_convert_check_has_valid_timing(C, gpl, op)) { BKE_report(op->reports, RPT_WARNING, "Current Grease Pencil strokes have no valid timing data, most timing options will " @@ -1539,7 +1543,8 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) gtd.offset_time = 0.0f; /* perform conversion */ - gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, >d); + gpencil_layer_to_curve( + C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, >d); /* free temp memory */ if (gtd.dists) { @@ -1560,9 +1565,9 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static bool gp_convert_poll_property(const bContext *UNUSED(C), - wmOperator *op, - const PropertyRNA *prop) +static bool gpencil_convert_poll_property(const bContext *UNUSED(C), + wmOperator *op, + const PropertyRNA *prop) { PointerRNA *ptr = op->ptr; const char *prop_id = RNA_property_identifier(prop); @@ -1641,9 +1646,9 @@ void GPENCIL_OT_convert(wmOperatorType *ot) /* callbacks */ ot->invoke = WM_menu_invoke; - ot->exec = gp_convert_layer_exec; - ot->poll = gp_convert_poll; - ot->poll_property = gp_convert_poll_property; + ot->exec = gpencil_convert_layer_exec; + ot->poll = gpencil_convert_poll; + ot->poll_property = gpencil_convert_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1725,7 +1730,7 @@ void GPENCIL_OT_convert(wmOperatorType *ot) "The end frame of the path control curve (if Realtime is not set)", 1, 100000); - RNA_def_property_update_runtime(prop, gp_convert_set_end_frame); + RNA_def_property_update_runtime(prop, gpencil_convert_set_end_frame); RNA_def_float(ot->srna, "gap_duration", @@ -1771,7 +1776,10 @@ static bool image_to_gpencil_poll(bContext *C) { SpaceLink *sl = CTX_wm_space_data(C); if ((sl != NULL) && (sl->spacetype == SPACE_IMAGE)) { - return true; + SpaceImage *sima = CTX_wm_space_image(C); + Image *image = sima->image; + ImageUser iuser = sima->iuser; + return BKE_image_has_ibuf(image, &iuser); } return false; @@ -1811,7 +1819,7 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op) if (done) { /* Delete any selected point. */ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { - gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); } BKE_reportf(op->reports, RPT_INFO, "Object created"); diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 8c80334bf8a..44b866d81d7 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -90,7 +90,7 @@ /* Datablock Operators */ /* ******************* Add New Data ************************ */ -static bool gp_data_add_poll(bContext *C) +static bool gpencil_data_add_poll(bContext *C) { /* the base line we have is that we have somewhere to add Grease Pencil data */ @@ -98,7 +98,7 @@ static bool gp_data_add_poll(bContext *C) } /* add new datablock - wrapper around API */ -static int gp_data_add_exec(bContext *C, wmOperator *op) +static int gpencil_data_add_exec(bContext *C, wmOperator *op) { PointerRNA gpd_owner = {NULL}; bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, &gpd_owner); @@ -145,14 +145,14 @@ void GPENCIL_OT_annotation_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_data_add_exec; - ot->poll = gp_data_add_poll; + ot->exec = gpencil_data_add_exec; + ot->poll = gpencil_data_add_poll; } /* ******************* Unlink Data ************************ */ /* poll callback for adding data/layers - special */ -static bool gp_data_unlink_poll(bContext *C) +static bool gpencil_data_unlink_poll(bContext *C) { bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, NULL); @@ -168,7 +168,7 @@ static bool gp_data_unlink_poll(bContext *C) } /* unlink datablock - wrapper around API */ -static int gp_data_unlink_exec(bContext *C, wmOperator *op) +static int gpencil_data_unlink_exec(bContext *C, wmOperator *op) { bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, NULL); @@ -199,8 +199,8 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_data_unlink_exec; - ot->poll = gp_data_unlink_poll; + ot->exec = gpencil_data_unlink_exec; + ot->poll = gpencil_data_unlink_poll; } /* ************************************************ */ @@ -209,7 +209,7 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot) /* ******************* Add New Layer ************************ */ /* add new layer - wrapper around API */ -static int gp_layer_add_exec(bContext *C, wmOperator *op) +static int gpencil_layer_add_exec(bContext *C, wmOperator *op) { const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_add"); @@ -268,11 +268,11 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_layer_add_exec; - ot->poll = gp_add_poll; + ot->exec = gpencil_layer_add_exec; + ot->poll = gpencil_add_poll; } -static bool gp_add_annotation_poll(bContext *C) +static bool gpencil_add_annotation_poll(bContext *C) { return ED_annotation_data_get_pointers(C, NULL) != NULL; } @@ -287,12 +287,12 @@ void GPENCIL_OT_layer_annotation_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_layer_add_exec; - ot->poll = gp_add_annotation_poll; + ot->exec = gpencil_layer_add_exec; + ot->poll = gpencil_add_annotation_poll; } /* ******************* Remove Active Layer ************************* */ -static int gp_layer_remove_exec(bContext *C, wmOperator *op) +static int gpencil_layer_remove_exec(bContext *C, wmOperator *op) { const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_remove"); @@ -345,11 +345,11 @@ void GPENCIL_OT_layer_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_layer_remove_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_layer_remove_exec; + ot->poll = gpencil_active_layer_poll; } -static bool gp_active_layer_annotation_poll(bContext *C) +static bool gpencil_active_layer_annotation_poll(bContext *C) { bGPdata *gpd = ED_annotation_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); @@ -367,8 +367,8 @@ void GPENCIL_OT_layer_annotation_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_layer_remove_exec; - ot->poll = gp_active_layer_annotation_poll; + ot->exec = gpencil_layer_remove_exec; + ot->poll = gpencil_active_layer_annotation_poll; } /* ******************* Move Layer Up/Down ************************** */ @@ -377,7 +377,7 @@ enum { GP_LAYER_MOVE_DOWN = 1, }; -static int gp_layer_move_exec(bContext *C, wmOperator *op) +static int gpencil_layer_move_exec(bContext *C, wmOperator *op) { const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_move"); @@ -418,8 +418,8 @@ void GPENCIL_OT_layer_move(wmOperatorType *ot) ot->description = "Move the active Grease Pencil layer up/down in the list"; /* api callbacks */ - ot->exec = gp_layer_move_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_layer_move_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -441,8 +441,8 @@ void GPENCIL_OT_layer_annotation_move(wmOperatorType *ot) ot->description = "Move the active Annotation layer up/down in the list"; /* api callbacks */ - ot->exec = gp_layer_move_exec; - ot->poll = gp_active_layer_annotation_poll; + ot->exec = gpencil_layer_move_exec; + ot->poll = gpencil_active_layer_annotation_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -451,7 +451,7 @@ void GPENCIL_OT_layer_annotation_move(wmOperatorType *ot) } /* ********************* Duplicate Layer ************************** */ -static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_layer_copy_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); @@ -491,8 +491,8 @@ void GPENCIL_OT_layer_duplicate(wmOperatorType *ot) ot->description = "Make a copy of the active Grease Pencil layer"; /* callbacks */ - ot->exec = gp_layer_copy_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_layer_copy_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -504,7 +504,7 @@ enum { GP_LAYER_COPY_OBJECT_ACT_FRAME = 1, }; -static bool gp_layer_duplicate_object_poll(bContext *C) +static bool gpencil_layer_duplicate_object_poll(bContext *C) { ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = CTX_data_active_object(C); @@ -529,7 +529,7 @@ static bool gp_layer_duplicate_object_poll(bContext *C) return false; } -static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op) +static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -622,8 +622,8 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot) ot->description = "Make a copy of the active Grease Pencil layer to new object"; /* callbacks */ - ot->exec = gp_layer_duplicate_object_exec; - ot->poll = gp_layer_duplicate_object_poll; + ot->exec = gpencil_layer_duplicate_object_exec; + ot->poll = gpencil_layer_duplicate_object_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -641,7 +641,7 @@ enum { GP_FRAME_DUP_ALL = 1, }; -static int gp_frame_duplicate_exec(bContext *C, wmOperator *op) +static int gpencil_frame_duplicate_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd); @@ -685,8 +685,8 @@ void GPENCIL_OT_frame_duplicate(wmOperatorType *ot) ot->description = "Make a copy of the active Grease Pencil Frame"; /* callbacks */ - ot->exec = gp_frame_duplicate_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_frame_duplicate_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -700,7 +700,7 @@ enum { GP_FRAME_CLEAN_FILL_ALL = 1, }; -static int gp_frame_clean_fill_exec(bContext *C, wmOperator *op) +static int gpencil_frame_clean_fill_exec(bContext *C, wmOperator *op) { bool changed = false; bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -770,8 +770,8 @@ void GPENCIL_OT_frame_clean_fill(wmOperatorType *ot) ot->description = "Remove 'no fill' boundary strokes"; /* callbacks */ - ot->exec = gp_frame_clean_fill_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_frame_clean_fill_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -780,7 +780,7 @@ void GPENCIL_OT_frame_clean_fill(wmOperatorType *ot) } /* ********************* Clean Loose Boundaries on Frame ************************** */ -static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op) +static int gpencil_frame_clean_loose_exec(bContext *C, wmOperator *op) { bool changed = false; bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -846,8 +846,8 @@ void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot) ot->description = "Remove loose points"; /* callbacks */ - ot->exec = gp_frame_clean_loose_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_frame_clean_loose_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -865,7 +865,7 @@ void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot) /* *********************** Hide Layers ******************************** */ -static int gp_hide_exec(bContext *C, wmOperator *op) +static int gpencil_hide_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *layer = BKE_gpencil_layer_active_get(gpd); @@ -908,8 +908,8 @@ void GPENCIL_OT_hide(wmOperatorType *ot) ot->description = "Hide selected/unselected Grease Pencil layers"; /* callbacks */ - ot->exec = gp_hide_exec; - ot->poll = gp_active_layer_poll; /* NOTE: we need an active layer to play with */ + ot->exec = gpencil_hide_exec; + ot->poll = gpencil_active_layer_poll; /* NOTE: we need an active layer to play with */ /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -922,12 +922,12 @@ void GPENCIL_OT_hide(wmOperatorType *ot) /* ********************** Show All Layers ***************************** */ /* poll callback for showing layers */ -static bool gp_reveal_poll(bContext *C) +static bool gpencil_reveal_poll(bContext *C) { return ED_gpencil_data_get_active(C) != NULL; } -static void gp_reveal_select_frame(bContext *C, bGPDframe *frame, bool select) +static void gpencil_reveal_select_frame(bContext *C, bGPDframe *frame, bool select) { bGPDstroke *gps; for (gps = frame->strokes.first; gps; gps = gps->next) { @@ -948,7 +948,7 @@ static void gp_reveal_select_frame(bContext *C, bGPDframe *frame, bool select) } } -static int gp_reveal_exec(bContext *C, wmOperator *op) +static int gpencil_reveal_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); const bool select = RNA_boolean_get(op->ptr, "select"); @@ -967,14 +967,14 @@ static int gp_reveal_exec(bContext *C, wmOperator *op) if (select) { /* select all strokes on active frame only (same as select all operator) */ if (gpl->actframe) { - gp_reveal_select_frame(C, gpl->actframe, true); + gpencil_reveal_select_frame(C, gpl->actframe, true); } } else { /* deselect strokes on all frames (same as deselect all operator) */ bGPDframe *gpf; for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - gp_reveal_select_frame(C, gpf, false); + gpencil_reveal_select_frame(C, gpf, false); } } } @@ -996,8 +996,8 @@ void GPENCIL_OT_reveal(wmOperatorType *ot) ot->description = "Show all Grease Pencil layers"; /* callbacks */ - ot->exec = gp_reveal_exec; - ot->poll = gp_reveal_poll; + ot->exec = gpencil_reveal_exec; + ot->poll = gpencil_reveal_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1008,7 +1008,7 @@ void GPENCIL_OT_reveal(wmOperatorType *ot) /* ***************** Lock/Unlock All Layers ************************ */ -static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -1038,8 +1038,8 @@ void GPENCIL_OT_lock_all(wmOperatorType *ot) "Lock all Grease Pencil layers to prevent them from being accidentally modified"; /* callbacks */ - ot->exec = gp_lock_all_exec; - ot->poll = gp_reveal_poll; + ot->exec = gpencil_lock_all_exec; + ot->poll = gpencil_reveal_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1047,7 +1047,7 @@ void GPENCIL_OT_lock_all(wmOperatorType *ot) /* -------------------------- */ -static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -1076,8 +1076,8 @@ void GPENCIL_OT_unlock_all(wmOperatorType *ot) ot->description = "Unlock all Grease Pencil layers so that they can be edited"; /* callbacks */ - ot->exec = gp_unlock_all_exec; - ot->poll = gp_reveal_poll; + ot->exec = gpencil_unlock_all_exec; + ot->poll = gpencil_reveal_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1085,7 +1085,7 @@ void GPENCIL_OT_unlock_all(wmOperatorType *ot) /* ********************** Isolate Layer **************************** */ -static int gp_isolate_layer_exec(bContext *C, wmOperator *op) +static int gpencil_isolate_layer_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *layer = BKE_gpencil_layer_active_get(gpd); @@ -1153,8 +1153,8 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot) "Toggle whether the active layer is the only one that can be edited and/or visible"; /* callbacks */ - ot->exec = gp_isolate_layer_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_isolate_layer_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1169,7 +1169,7 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot) /* ********************** Merge Layer with the next layer **************************** */ -static int gp_merge_layer_exec(bContext *C, wmOperator *op) +static int gpencil_merge_layer_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl_next = BKE_gpencil_layer_active_get(gpd); @@ -1242,8 +1242,8 @@ void GPENCIL_OT_layer_merge(wmOperatorType *ot) ot->description = "Merge the current layer with the layer below"; /* callbacks */ - ot->exec = gp_merge_layer_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_merge_layer_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1251,7 +1251,7 @@ void GPENCIL_OT_layer_merge(wmOperatorType *ot) /* ********************** Change Layer ***************************** */ -static int gp_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt)) +static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt)) { uiPopupMenu *pup; uiLayout *layout; @@ -1265,7 +1265,7 @@ static int gp_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UN return OPERATOR_INTERFACE; } -static int gp_layer_change_exec(bContext *C, wmOperator *op) +static int gpencil_layer_change_exec(bContext *C, wmOperator *op) { bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *gpl = NULL; @@ -1306,9 +1306,9 @@ void GPENCIL_OT_layer_change(wmOperatorType *ot) ot->description = "Change active Grease Pencil layer"; /* callbacks */ - ot->invoke = gp_layer_change_invoke; - ot->exec = gp_layer_change_exec; - ot->poll = gp_active_layer_poll; + ot->invoke = gpencil_layer_change_invoke; + ot->exec = gpencil_layer_change_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1318,7 +1318,7 @@ void GPENCIL_OT_layer_change(wmOperatorType *ot) RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf); } -static int gp_layer_active_exec(bContext *C, wmOperator *op) +static int gpencil_layer_active_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -1352,8 +1352,8 @@ void GPENCIL_OT_layer_active(wmOperatorType *ot) ot->description = "Active Grease Pencil layer"; /* callbacks */ - ot->exec = gp_layer_active_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_layer_active_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1373,7 +1373,7 @@ enum { GP_STROKE_MOVE_BOTTOM = 3, }; -static int gp_stroke_arrange_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -1503,8 +1503,8 @@ void GPENCIL_OT_stroke_arrange(wmOperatorType *ot) ot->description = "Arrange selected strokes up/down in the drawing order of the active layer"; /* callbacks */ - ot->exec = gp_stroke_arrange_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_arrange_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1515,7 +1515,7 @@ void GPENCIL_OT_stroke_arrange(wmOperatorType *ot) /* ******************* Move Stroke to new color ************************** */ -static int gp_stroke_change_color_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_change_color_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Material *ma = NULL; @@ -1599,8 +1599,8 @@ void GPENCIL_OT_stroke_change_color(wmOperatorType *ot) ot->description = "Move selected strokes to active material"; /* callbacks */ - ot->exec = gp_stroke_change_color_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_change_color_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1610,7 +1610,7 @@ void GPENCIL_OT_stroke_change_color(wmOperatorType *ot) /* ******************* Lock color of non selected Strokes colors ************************** */ -static int gp_material_lock_unsused_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_material_lock_unsused_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -1674,8 +1674,8 @@ void GPENCIL_OT_material_lock_unused(wmOperatorType *ot) ot->description = "Lock any material not used in any selected stroke"; /* api callbacks */ - ot->exec = gp_material_lock_unsused_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_material_lock_unsused_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1685,7 +1685,7 @@ void GPENCIL_OT_material_lock_unused(wmOperatorType *ot) /* Drawing Brushes Operators */ /* ******************* Brush resets ************************** */ -static int gp_brush_reset_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_brush_reset_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); ToolSettings *ts = CTX_data_tool_settings(C); @@ -1743,16 +1743,16 @@ void GPENCIL_OT_brush_reset(wmOperatorType *ot) ot->description = "Reset Brush to default parameters"; /* api callbacks */ - ot->exec = gp_brush_reset_exec; + ot->exec = gpencil_brush_reset_exec; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static Brush *gp_brush_get_first_by_mode(Main *bmain, - Paint *UNUSED(paint), - const enum eContextObjectMode mode, - char tool) +static Brush *gpencil_brush_get_first_by_mode(Main *bmain, + Paint *UNUSED(paint), + const enum eContextObjectMode mode, + char tool) { Brush *brush_next = NULL; for (Brush *brush = bmain->brushes.first; brush; brush = brush_next) { @@ -1782,9 +1782,9 @@ static Brush *gp_brush_get_first_by_mode(Main *bmain, return NULL; } -static void gp_brush_delete_mode_brushes(Main *bmain, - Paint *paint, - const enum eContextObjectMode mode) +static void gpencil_brush_delete_mode_brushes(Main *bmain, + Paint *paint, + const enum eContextObjectMode mode) { Brush *brush_active = paint->brush; Brush *brush_next = NULL; @@ -1847,7 +1847,7 @@ static void gp_brush_delete_mode_brushes(Main *bmain, } } -static int gp_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); ToolSettings *ts = CTX_data_tool_settings(C); @@ -1903,7 +1903,7 @@ static int gp_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op)) } } - gp_brush_delete_mode_brushes(bmain, paint, mode); + gpencil_brush_delete_mode_brushes(bmain, paint, mode); switch (mode) { case CTX_MODE_PAINT_GPENCIL: { @@ -1930,7 +1930,7 @@ static int gp_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op)) BKE_paint_toolslots_brush_validate(bmain, paint); /* Set Again the first brush of the mode. */ - Brush *deft_brush = gp_brush_get_first_by_mode(bmain, paint, mode, tool); + Brush *deft_brush = gpencil_brush_get_first_by_mode(bmain, paint, mode, tool); if (deft_brush) { BKE_paint_brush_set(paint, deft_brush); } @@ -1950,7 +1950,7 @@ void GPENCIL_OT_brush_reset_all(wmOperatorType *ot) ot->description = "Delete all mode brushes and recreate a default set"; /* api callbacks */ - ot->exec = gp_brush_reset_all_exec; + ot->exec = gpencil_brush_reset_all_exec; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2496,7 +2496,7 @@ typedef struct tJoinGPencil_AdtFixData { * Callback to pass to #BKE_fcurves_main_cb() * for RNA Paths attached to each F-Curve used in the #AnimData. */ -static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data) +static void gpencil_joined_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data) { tJoinGPencil_AdtFixData *afd = (tJoinGPencil_AdtFixData *)user_data; ID *src_id = &afd->src_gpd->id; @@ -2534,8 +2534,8 @@ static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data) if (dtar->id == src_id) { dtar->id = dst_id; - /* Also check on the subtarget... - * We duplicate the logic from drivers_path_rename_fix() here, with our own + /* Also check on the sub-target. + * We duplicate the logic from #drivers_path_rename_fix() here, with our own * little twists so that we know that it isn't going to clobber the wrong data */ if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) { @@ -2721,7 +2721,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) } /* Fix all the animation data */ - BKE_fcurves_main_cb(bmain, joined_gpencil_fix_animdata_cb, &afd); + BKE_fcurves_main_cb(bmain, gpencil_joined_fix_animdata_cb, &afd); BLI_ghash_free(afd.names_map, MEM_freeN, NULL); /* Only copy over animdata now, after all the remapping has been done, @@ -2856,7 +2856,7 @@ void GPENCIL_OT_lock_layer(wmOperatorType *ot) /* api callbacks */ ot->exec = gpencil_lock_layer_exec; - ot->poll = gp_active_layer_poll; + ot->poll = gpencil_active_layer_poll; } /* ********************** Isolate gpencil_ color **************************** */ @@ -3415,7 +3415,7 @@ bool ED_gpencil_add_lattice_modifier(const bContext *C, } /* Masking operators */ -static int gp_layer_mask_add_exec(bContext *C, wmOperator *op) +static int gpencil_layer_mask_add_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); if ((ob == NULL) || (ob->type != OB_GPENCIL)) { @@ -3476,14 +3476,14 @@ void GPENCIL_OT_layer_mask_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_layer_mask_add_exec; - ot->poll = gp_add_poll; + ot->exec = gpencil_layer_mask_add_exec; + ot->poll = gpencil_add_poll; /* properties */ RNA_def_string(ot->srna, "name", NULL, 128, "Layer", "Name of the layer"); } -static int gp_layer_mask_remove_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_layer_mask_remove_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = CTX_data_active_object(C); if ((ob == NULL) || (ob->type != OB_GPENCIL)) { @@ -3525,6 +3525,6 @@ void GPENCIL_OT_layer_mask_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_layer_mask_remove_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_layer_mask_remove_exec; + ot->poll = gpencil_active_layer_poll; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 76776b5c23c..78e2812fdef 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -95,7 +95,7 @@ * \{ */ /* poll callback for all stroke editing operators */ -static bool gp_stroke_edit_poll(bContext *C) +static bool gpencil_stroke_edit_poll(bContext *C) { /* edit only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); @@ -108,7 +108,7 @@ static bool gp_stroke_edit_poll(bContext *C) } /* poll callback to verify edit mode in 3D view only */ -static bool gp_strokes_edit3d_poll(bContext *C) +static bool gpencil_strokes_edit3d_poll(bContext *C) { /* edit only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); @@ -120,7 +120,7 @@ static bool gp_strokes_edit3d_poll(bContext *C) * - 1) Editable GP data * - 2) 3D View only */ - return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C)); + return (gpencil_stroke_edit_poll(C) && ED_operator_view3d_active(C)); } static bool gpencil_editmode_toggle_poll(bContext *C) @@ -789,7 +789,7 @@ void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot) /* callbacks */ ot->exec = gpencil_hideselect_toggle_exec; - ot->poll = gp_stroke_edit_poll; + ot->poll = gpencil_stroke_edit_poll; /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; @@ -802,9 +802,9 @@ void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot) * \{ */ /* Make copies of selected point segments in a selected stroke */ -static void gp_duplicate_points(const bGPDstroke *gps, - ListBase *new_strokes, - const char *layername) +static void gpencil_duplicate_points(const bGPDstroke *gps, + ListBase *new_strokes, + const char *layername) { bGPDspoint *pt; int i; @@ -880,7 +880,7 @@ static void gp_duplicate_points(const bGPDstroke *gps, } } -static int gp_duplicate_exec(bContext *C, wmOperator *op) +static int gpencil_duplicate_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -933,7 +933,7 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op) } else { /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */ - gp_duplicate_points(gps, &new_strokes, gpl->info); + gpencil_duplicate_points(gps, &new_strokes, gpl->info); } /* deselect original stroke, or else the originals get moved too @@ -969,8 +969,8 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot) ot->description = "Duplicate the selected Grease Pencil strokes"; /* callbacks */ - ot->exec = gp_duplicate_exec; - ot->poll = gp_stroke_edit_poll; + ot->exec = gpencil_duplicate_exec; + ot->poll = gpencil_stroke_edit_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -983,12 +983,12 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot) * \{ */ /* helper to copy a point to temp area */ -static void copy_move_point(bGPDstroke *gps, - bGPDspoint *temp_points, - MDeformVert *temp_dverts, - int from_idx, - int to_idx, - const bool copy) +static void gpencil_copy_move_point(bGPDstroke *gps, + bGPDspoint *temp_points, + MDeformVert *temp_dverts, + int from_idx, + int to_idx, + const bool copy) { bGPDspoint *pt = &temp_points[from_idx]; bGPDspoint *pt_final = &gps->points[to_idx]; @@ -1053,7 +1053,7 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps) BLI_insertlinkafter(&gpf->strokes, gps, gps_new); /* copy selected point data to new stroke */ - copy_move_point(gps_new, gps->points, gps->dvert, i, 0, true); + gpencil_copy_move_point(gps_new, gps->points, gps->dvert, i, 0, true); /* Calc geometry data. */ BKE_gpencil_stroke_geometry_update(gps); @@ -1098,13 +1098,13 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps) /* move points to new position */ for (int i = 0; i < oldtotpoints; i++) { - copy_move_point(gps, temp_points, temp_dverts, i, i2, false); + gpencil_copy_move_point(gps, temp_points, temp_dverts, i, i2, false); i2++; } /* If first point, add new point at the beginning. */ if (do_first) { - copy_move_point(gps, temp_points, temp_dverts, 0, 0, true); + gpencil_copy_move_point(gps, temp_points, temp_dverts, 0, 0, true); /* deselect old */ pt = &gps->points[1]; pt->flag &= ~GP_SPOINT_SELECT; @@ -1115,7 +1115,8 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps) /* if last point, add new point at the end */ if (do_last) { - copy_move_point(gps, temp_points, temp_dverts, oldtotpoints - 1, gps->totpoints - 1, true); + gpencil_copy_move_point( + gps, temp_points, temp_dverts, oldtotpoints - 1, gps->totpoints - 1, true); /* deselect old */ pt = &gps->points[gps->totpoints - 2]; @@ -1138,7 +1139,7 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps) } } -static int gp_extrude_exec(bContext *C, wmOperator *op) +static int gpencil_extrude_exec(bContext *C, wmOperator *op) { Object *obact = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)obact->data; @@ -1194,8 +1195,8 @@ void GPENCIL_OT_extrude(wmOperatorType *ot) ot->description = "Extrude the selected Grease Pencil points"; /* callbacks */ - ot->exec = gp_extrude_exec; - ot->poll = gp_stroke_edit_poll; + ot->exec = gpencil_extrude_exec; + ot->poll = gpencil_stroke_edit_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1216,16 +1217,16 @@ void GPENCIL_OT_extrude(wmOperatorType *ot) /* list of bGPDstroke instances */ /* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */ -ListBase gp_strokes_copypastebuf = {NULL, NULL}; +ListBase gpencil_strokes_copypastebuf = {NULL, NULL}; /* Hash for hanging on to all the colors used by strokes in the buffer * * This is needed to prevent dangling and unsafe pointers when pasting across data-blocks, * or after a color used by a stroke in the buffer gets deleted (via user action or undo). */ -static GHash *gp_strokes_copypastebuf_colors = NULL; +static GHash *gpencil_strokes_copypastebuf_colors = NULL; -static GHash *gp_strokes_copypastebuf_colors_material_to_name_create(Main *bmain) +static GHash *gpencil_strokes_copypastebuf_colors_material_to_name_create(Main *bmain) { GHash *ma_to_name = BLI_ghash_ptr_new(__func__); @@ -1237,12 +1238,12 @@ static GHash *gp_strokes_copypastebuf_colors_material_to_name_create(Main *bmain return ma_to_name; } -static void gp_strokes_copypastebuf_colors_material_to_name_free(GHash *ma_to_name) +static void gpencil_strokes_copypastebuf_colors_material_to_name_free(GHash *ma_to_name) { BLI_ghash_free(ma_to_name, NULL, MEM_freeN); } -static GHash *gp_strokes_copypastebuf_colors_name_to_material_create(Main *bmain) +static GHash *gpencil_strokes_copypastebuf_colors_name_to_material_create(Main *bmain) { GHash *name_to_ma = BLI_ghash_str_new(__func__); @@ -1254,7 +1255,7 @@ static GHash *gp_strokes_copypastebuf_colors_name_to_material_create(Main *bmain return name_to_ma; } -static void gp_strokes_copypastebuf_colors_name_to_material_free(GHash *name_to_ma) +static void gpencil_strokes_copypastebuf_colors_name_to_material_free(GHash *name_to_ma) { BLI_ghash_free(name_to_ma, MEM_freeN, NULL); } @@ -1267,13 +1268,13 @@ void ED_gpencil_strokes_copybuf_free(void) /* Free the colors buffer * NOTE: This is done before the strokes so that the ptrs are still safe */ - if (gp_strokes_copypastebuf_colors) { - BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, MEM_freeN); - gp_strokes_copypastebuf_colors = NULL; + if (gpencil_strokes_copypastebuf_colors) { + BLI_ghash_free(gpencil_strokes_copypastebuf_colors, NULL, MEM_freeN); + gpencil_strokes_copypastebuf_colors = NULL; } /* Free the stroke buffer */ - for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) { + for (gps = gpencil_strokes_copypastebuf.first; gps; gps = gpsn) { gpsn = gps->next; if (gps->points) { @@ -1286,17 +1287,17 @@ void ED_gpencil_strokes_copybuf_free(void) MEM_SAFE_FREE(gps->triangles); - BLI_freelinkN(&gp_strokes_copypastebuf, gps); + BLI_freelinkN(&gpencil_strokes_copypastebuf, gps); } - gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL; + gpencil_strokes_copypastebuf.first = gpencil_strokes_copypastebuf.last = NULL; } /** * Ensure that destination datablock has all the colors the pasted strokes need. * Helper function for copy-pasting strokes */ -GHash *gp_copybuf_validate_colormap(bContext *C) +GHash *gpencil_copybuf_validate_colormap(bContext *C) { Main *bmain = CTX_data_main(C); Object *ob = CTX_data_active_object(C); @@ -1304,9 +1305,9 @@ GHash *gp_copybuf_validate_colormap(bContext *C) GHashIterator gh_iter; /* For each color, check if exist and add if not */ - GHash *name_to_ma = gp_strokes_copypastebuf_colors_name_to_material_create(bmain); + GHash *name_to_ma = gpencil_strokes_copypastebuf_colors_name_to_material_create(bmain); - GHASH_ITER (gh_iter, gp_strokes_copypastebuf_colors) { + GHASH_ITER (gh_iter, gpencil_strokes_copypastebuf_colors) { int *key = BLI_ghashIterator_getKey(&gh_iter); char *ma_name = BLI_ghashIterator_getValue(&gh_iter); Material *ma = BLI_ghash_lookup(name_to_ma, ma_name); @@ -1319,7 +1320,7 @@ GHash *gp_copybuf_validate_colormap(bContext *C) } } - gp_strokes_copypastebuf_colors_name_to_material_free(name_to_ma); + gpencil_strokes_copypastebuf_colors_name_to_material_free(name_to_ma); return new_colors; } @@ -1330,7 +1331,7 @@ GHash *gp_copybuf_validate_colormap(bContext *C) /** \name Copy Selected Strokes Operator * \{ */ -static int gp_strokes_copy_exec(bContext *C, wmOperator *op) +static int gpencil_strokes_copy_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Object *ob = CTX_data_active_object(C); @@ -1389,11 +1390,11 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) /* add to temp buffer */ gpsd->next = gpsd->prev = NULL; - BLI_addtail(&gp_strokes_copypastebuf, gpsd); + BLI_addtail(&gpencil_strokes_copypastebuf, gpsd); } else { /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */ - gp_duplicate_points(gps, &gp_strokes_copypastebuf, gpl->info); + gpencil_duplicate_points(gps, &gpencil_strokes_copypastebuf, gpl->info); } } } @@ -1401,10 +1402,10 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* Build up hash of material colors used in these strokes */ - if (gp_strokes_copypastebuf.first) { - gp_strokes_copypastebuf_colors = BLI_ghash_int_new("GPencil CopyBuf Colors"); - GHash *ma_to_name = gp_strokes_copypastebuf_colors_material_to_name_create(bmain); - LISTBASE_FOREACH (bGPDstroke *, gps, &gp_strokes_copypastebuf) { + if (gpencil_strokes_copypastebuf.first) { + gpencil_strokes_copypastebuf_colors = BLI_ghash_int_new("GPencil CopyBuf Colors"); + GHash *ma_to_name = gpencil_strokes_copypastebuf_colors_material_to_name_create(bmain); + LISTBASE_FOREACH (bGPDstroke *, gps, &gpencil_strokes_copypastebuf) { if (ED_gpencil_stroke_can_use(C, gps)) { Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1); /* Avoid default material. */ @@ -1414,13 +1415,13 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) char **ma_name_val; if (!BLI_ghash_ensure_p( - gp_strokes_copypastebuf_colors, &gps->mat_nr, (void ***)&ma_name_val)) { + gpencil_strokes_copypastebuf_colors, &gps->mat_nr, (void ***)&ma_name_val)) { char *ma_name = BLI_ghash_lookup(ma_to_name, ma); *ma_name_val = MEM_dupallocN(ma_name); } } } - gp_strokes_copypastebuf_colors_material_to_name_free(ma_to_name); + gpencil_strokes_copypastebuf_colors_material_to_name_free(ma_to_name); } /* updates (to ensure operator buttons are refreshed, when used via hotkeys) */ @@ -1438,8 +1439,8 @@ void GPENCIL_OT_copy(wmOperatorType *ot) ot->description = "Copy selected Grease Pencil points and strokes"; /* callbacks */ - ot->exec = gp_strokes_copy_exec; - ot->poll = gp_stroke_edit_poll; + ot->exec = gpencil_strokes_copy_exec; + ot->poll = gpencil_stroke_edit_poll; /* flags */ // ot->flag = OPTYPE_REGISTER; @@ -1451,7 +1452,7 @@ void GPENCIL_OT_copy(wmOperatorType *ot) /** \name Paste Selected Strokes Operator * \{ */ -static bool gp_strokes_paste_poll(bContext *C) +static bool gpencil_strokes_paste_poll(bContext *C) { ScrArea *area = CTX_wm_area(C); if (!((area != NULL) && (area->spacetype == SPACE_VIEW3D))) { @@ -1464,7 +1465,7 @@ static bool gp_strokes_paste_poll(bContext *C) * 2) Copy buffer must at least have something (though it may be the wrong sort...). */ return (ED_gpencil_data_get_active(C) != NULL) && - (!BLI_listbase_is_empty(&gp_strokes_copypastebuf)); + (!BLI_listbase_is_empty(&gpencil_strokes_copypastebuf)); } typedef enum eGP_PasteMode { @@ -1472,7 +1473,7 @@ typedef enum eGP_PasteMode { GP_COPY_TO_ACTIVE = 1, } eGP_PasteMode; -static int gp_strokes_paste_exec(bContext *C, wmOperator *op) +static int gpencil_strokes_paste_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -1489,7 +1490,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition"); return OPERATOR_CANCELLED; } - else if (BLI_listbase_is_empty(&gp_strokes_copypastebuf)) { + else if (BLI_listbase_is_empty(&gpencil_strokes_copypastebuf)) { BKE_report(op->reports, RPT_ERROR, "No strokes to paste, select and copy some points before trying again"); @@ -1509,7 +1510,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) bGPDstroke *gps; bool ok = false; - for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { + for (gps = gpencil_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { ok = true; break; @@ -1535,10 +1536,11 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* Ensure that all the necessary colors exist */ - new_colors = gp_copybuf_validate_colormap(C); + new_colors = gpencil_copybuf_validate_colormap(C); /* Copy over the strokes from the buffer (and adjust the colors) */ - bGPDstroke *gps_init = (!on_back) ? gp_strokes_copypastebuf.first : gp_strokes_copypastebuf.last; + bGPDstroke *gps_init = (!on_back) ? gpencil_strokes_copypastebuf.first : + gpencil_strokes_copypastebuf.last; for (bGPDstroke *gps = gps_init; gps; gps = (!on_back) ? gps->next : gps->prev) { if (ED_gpencil_stroke_can_use(C, gps)) { /* Need to verify if layer exists */ @@ -1606,8 +1608,8 @@ void GPENCIL_OT_paste(wmOperatorType *ot) ot->description = "Paste previously copied strokes to active layer or to original layer"; /* callbacks */ - ot->exec = gp_strokes_paste_exec; - ot->poll = gp_strokes_paste_poll; + ot->exec = gpencil_strokes_paste_exec; + ot->poll = gpencil_strokes_paste_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1626,7 +1628,7 @@ void GPENCIL_OT_paste(wmOperatorType *ot) /** \name Move To Layer Operator * \{ */ -static int gp_move_to_layer_exec(bContext *C, wmOperator *op) +static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -1732,8 +1734,8 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot) "Move selected strokes to another layer"; // XXX: allow moving individual points too? /* callbacks */ - ot->exec = gp_move_to_layer_exec; - ot->poll = gp_stroke_edit_poll; // XXX? + ot->exec = gpencil_move_to_layer_exec; + ot->poll = gpencil_stroke_edit_poll; // XXX? /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1750,7 +1752,7 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot) /** \name Add Blank Frame Operator * \{ */ -static int gp_blank_frame_add_exec(bContext *C, wmOperator *op) +static int gpencil_blank_frame_add_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); Scene *scene = CTX_data_scene(C); @@ -1808,8 +1810,8 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot) "(all subsequently existing frames, if any, are shifted right by one frame)"; /* callbacks */ - ot->exec = gp_blank_frame_add_exec; - ot->poll = gp_add_poll; + ot->exec = gpencil_blank_frame_add_exec; + ot->poll = gpencil_add_poll; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1828,7 +1830,7 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot) /** \name Delete Active Frame Operator * \{ */ -static bool gp_actframe_delete_poll(bContext *C) +static bool gpencil_actframe_delete_poll(bContext *C) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); @@ -1837,7 +1839,7 @@ static bool gp_actframe_delete_poll(bContext *C) return (gpl && gpl->actframe); } -static bool gp_annotation_actframe_delete_poll(bContext *C) +static bool annotation_actframe_delete_poll(bContext *C) { bGPdata *gpd = ED_annotation_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); @@ -1847,7 +1849,7 @@ static bool gp_annotation_actframe_delete_poll(bContext *C) } /* delete active frame - wrapper around API calls */ -static int gp_actframe_delete_exec(bContext *C, wmOperator *op) +static int gpencil_actframe_delete_exec(bContext *C, wmOperator *op) { const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_annotation_active_frame_delete"); @@ -1890,8 +1892,8 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_actframe_delete_exec; - ot->poll = gp_actframe_delete_poll; + ot->exec = gpencil_actframe_delete_exec; + ot->poll = gpencil_actframe_delete_poll; } void GPENCIL_OT_annotation_active_frame_delete(wmOperatorType *ot) @@ -1904,8 +1906,8 @@ void GPENCIL_OT_annotation_active_frame_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_actframe_delete_exec; - ot->poll = gp_annotation_actframe_delete_poll; + ot->exec = gpencil_actframe_delete_exec; + ot->poll = annotation_actframe_delete_poll; } /** \} */ @@ -1914,7 +1916,7 @@ void GPENCIL_OT_annotation_active_frame_delete(wmOperatorType *ot) /** \name Delete All Active Frames * \{ */ -static bool gp_actframe_delete_all_poll(bContext *C) +static bool gpencil_actframe_delete_all_poll(bContext *C) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -1924,7 +1926,7 @@ static bool gp_actframe_delete_all_poll(bContext *C) return (gpd && gpd->layers.first); } -static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op) +static int gpencil_actframe_delete_all_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); Scene *scene = CTX_data_scene(C); @@ -1969,8 +1971,8 @@ void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* callbacks */ - ot->exec = gp_actframe_delete_all_exec; - ot->poll = gp_actframe_delete_all_poll; + ot->exec = gpencil_actframe_delete_all_exec; + ot->poll = gpencil_actframe_delete_all_poll; } /** \} */ @@ -1998,7 +2000,7 @@ typedef enum eGP_DissolveMode { } eGP_DissolveMode; /* Delete selected strokes */ -static int gp_delete_selected_strokes(bContext *C) +static int gpencil_delete_selected_strokes(bContext *C) { bool changed = false; bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -2056,7 +2058,7 @@ static int gp_delete_selected_strokes(bContext *C) /* ----------------------------------- */ /* Delete selected points but keep the stroke */ -static int gp_dissolve_selected_points(bContext *C, eGP_DissolveMode mode) +static int gpencil_dissolve_selected_points(bContext *C, eGP_DissolveMode mode) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -2282,7 +2284,9 @@ typedef struct tGPDeleteIsland { int end_idx; } tGPDeleteIsland; -static void gp_stroke_join_islands(bGPDframe *gpf, bGPDstroke *gps_first, bGPDstroke *gps_last) +static void gpencil_stroke_join_islands(bGPDframe *gpf, + bGPDstroke *gps_first, + bGPDstroke *gps_last) { bGPDspoint *pt = NULL; bGPDspoint *pt_final = NULL; @@ -2382,12 +2386,12 @@ static void gp_stroke_join_islands(bGPDframe *gpf, bGPDstroke *gps_first, bGPDst * 2) Each island gets converted to a new stroke * If the number of points is <= limit, the stroke is deleted */ -void gp_stroke_delete_tagged_points(bGPDframe *gpf, - bGPDstroke *gps, - bGPDstroke *next_stroke, - int tag_flags, - bool select, - int limit) +void gpencil_stroke_delete_tagged_points(bGPDframe *gpf, + bGPDstroke *gps, + bGPDstroke *next_stroke, + int tag_flags, + bool select, + int limit) { tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands"); @@ -2517,7 +2521,7 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, } /* if cyclic, need to join last stroke with first stroke */ if ((is_cyclic) && (gps_first != NULL) && (gps_first != new_stroke)) { - gp_stroke_join_islands(gpf, gps_first, new_stroke); + gpencil_stroke_join_islands(gpf, gps_first, new_stroke); } } @@ -2530,7 +2534,7 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, } /* Split selected strokes into segments, splitting on selected points */ -static int gp_delete_selected_points(bContext *C) +static int gpencil_delete_selected_points(bContext *C) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -2564,7 +2568,7 @@ static int gp_delete_selected_points(bContext *C) gps->flag &= ~GP_STROKE_SELECT; /* delete unwanted points by splitting stroke into several smaller ones */ - gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); changed = true; } @@ -2585,9 +2589,9 @@ static int gp_delete_selected_points(bContext *C) } /* simple wrapper to external call */ -int gp_delete_selected_point_wrap(bContext *C) +int gpencil_delete_selected_point_wrap(bContext *C) { - return gp_delete_selected_points(C); + return gpencil_delete_selected_points(C); } /** \} */ @@ -2596,22 +2600,22 @@ int gp_delete_selected_point_wrap(bContext *C) /** \name Delete Operator * \{ */ -static int gp_delete_exec(bContext *C, wmOperator *op) +static int gpencil_delete_exec(bContext *C, wmOperator *op) { eGP_DeleteMode mode = RNA_enum_get(op->ptr, "type"); int result = OPERATOR_CANCELLED; switch (mode) { case GP_DELETEOP_STROKES: /* selected strokes */ - result = gp_delete_selected_strokes(C); + result = gpencil_delete_selected_strokes(C); break; case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */ - result = gp_delete_selected_points(C); + result = gpencil_delete_selected_points(C); break; case GP_DELETEOP_FRAME: /* active frame */ - result = gp_actframe_delete_exec(C, op); + result = gpencil_actframe_delete_exec(C, op); break; } @@ -2638,8 +2642,8 @@ void GPENCIL_OT_delete(wmOperatorType *ot) /* callbacks */ ot->invoke = WM_menu_invoke; - ot->exec = gp_delete_exec; - ot->poll = gp_stroke_edit_poll; + ot->exec = gpencil_delete_exec; + ot->poll = gpencil_stroke_edit_poll; /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; @@ -2659,11 +2663,11 @@ void GPENCIL_OT_delete(wmOperatorType *ot) /** \name Dissolve Operator * \{ */ -static int gp_dissolve_exec(bContext *C, wmOperator *op) +static int gpencil_dissolve_exec(bContext *C, wmOperator *op) { eGP_DissolveMode mode = RNA_enum_get(op->ptr, "type"); - return gp_dissolve_selected_points(C, mode); + return gpencil_dissolve_selected_points(C, mode); } void GPENCIL_OT_dissolve(wmOperatorType *ot) @@ -2686,8 +2690,8 @@ void GPENCIL_OT_dissolve(wmOperatorType *ot) /* callbacks */ ot->invoke = WM_menu_invoke; - ot->exec = gp_dissolve_exec; - ot->poll = gp_stroke_edit_poll; + ot->exec = gpencil_dissolve_exec; + ot->poll = gpencil_stroke_edit_poll; /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; @@ -2711,7 +2715,7 @@ void GPENCIL_OT_dissolve(wmOperatorType *ot) /* NOTE: For now, we only allow these in the 3D view, as other editors do not * define a cursor or gridstep which can be used */ -static bool gp_snap_poll(bContext *C) +static bool gpencil_snap_poll(bContext *C) { ScrArea *area = CTX_wm_area(C); Object *ob = CTX_data_active_object(C); @@ -2720,7 +2724,7 @@ static bool gp_snap_poll(bContext *C) ((area != NULL) && (area->spacetype == SPACE_VIEW3D)); } -static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); RegionView3D *rv3d = CTX_wm_region_data(C); @@ -2766,7 +2770,7 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) /* return data */ copy_v3_v3(&pt->x, fpt); - gp_apply_parent_point(depsgraph, obact, gpl, pt); + gpencil_apply_parent_point(depsgraph, obact, gpl, pt); } } } @@ -2787,8 +2791,8 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot) ot->description = "Snap selected points to the nearest grid points"; /* callbacks */ - ot->exec = gp_snap_to_grid; - ot->poll = gp_snap_poll; + ot->exec = gpencil_snap_to_grid; + ot->poll = gpencil_snap_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2800,7 +2804,7 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot) /** \name Snapping Selection to Cursor Operator * \{ */ -static int gp_snap_to_cursor(bContext *C, wmOperator *op) +static int gpencil_snap_to_cursor(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -2854,7 +2858,7 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { copy_v3_v3(&pt->x, cursor_global); - gp_apply_parent_point(depsgraph, obact, gpl, pt); + gpencil_apply_parent_point(depsgraph, obact, gpl, pt); } } } @@ -2876,8 +2880,8 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot) ot->description = "Snap selected points/strokes to the cursor"; /* callbacks */ - ot->exec = gp_snap_to_cursor; - ot->poll = gp_snap_poll; + ot->exec = gpencil_snap_to_cursor; + ot->poll = gpencil_snap_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2896,7 +2900,7 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot) /** \name Snapping Cursor to Selection Operator * \{ */ -static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *obact = CTX_data_active_object(C); @@ -2956,13 +2960,16 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) } } - if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN && count) { - mul_v3_fl(centroid, 1.0f / (float)count); - copy_v3_v3(cursor, centroid); - } - else { + if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_BOUNDS) { mid_v3_v3v3(cursor, min, max); } + else { /* #V3D_AROUND_CENTER_MEDIAN. */ + zero_v3(cursor); + if (count) { + mul_v3_fl(centroid, 1.0f / (float)count); + copy_v3_v3(cursor, centroid); + } + } DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); @@ -2978,8 +2985,8 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot) ot->description = "Snap cursor to center of selected points"; /* callbacks */ - ot->exec = gp_snap_cursor_to_sel; - ot->poll = gp_snap_poll; + ot->exec = gpencil_snap_cursor_to_sel; + ot->poll = gpencil_snap_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2991,7 +2998,7 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot) /** \name Apply Layer Thickness Change to Strokes Operator * \{ */ -static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); @@ -3032,8 +3039,8 @@ void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot) ot->description = "Apply the thickness change of the layer to its strokes"; /* api callbacks */ - ot->exec = gp_stroke_apply_thickness_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_apply_thickness_exec; + ot->poll = gpencil_active_layer_poll; } /** \} */ @@ -3048,7 +3055,7 @@ enum { GP_STROKE_CYCLIC_TOGGLE = 3, }; -static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_cyclical_set_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); Object *ob = CTX_data_active_object(C); @@ -3147,8 +3154,8 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot) ot->description = "Close or open the selected stroke adding an edge from last to first point"; /* api callbacks */ - ot->exec = gp_stroke_cyclical_set_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_cyclical_set_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3173,7 +3180,7 @@ enum { GP_STROKE_CAPS_TOGGLE_DEFAULT = 3, }; -static int gp_stroke_caps_set_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); Object *ob = CTX_data_active_object(C); @@ -3250,8 +3257,8 @@ void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot) ot->description = "Change Stroke caps mode (rounded or flat)"; /* api callbacks */ - ot->exec = gp_stroke_caps_set_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_caps_set_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3422,7 +3429,7 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, } } -static int gp_stroke_join_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_join_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *activegpl = BKE_gpencil_layer_active_get(gpd); @@ -3549,8 +3556,8 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot) ot->description = "Join selected strokes (optionally as new stroke)"; /* api callbacks */ - ot->exec = gp_stroke_join_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_join_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3570,7 +3577,7 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot) /** \name Stroke Flip Operator * \{ */ -static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); Object *ob = CTX_data_active_object(C); @@ -3620,8 +3627,8 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot) ot->description = "Change direction of the points of the selected strokes"; /* api callbacks */ - ot->exec = gp_stroke_flip_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_flip_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3633,7 +3640,7 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot) /** \name Stroke Re-project Operator * \{ */ -static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) +static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); Scene *scene = CTX_data_scene(C); @@ -3647,7 +3654,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) /* Init space conversion stuff. */ GP_SpaceConversion gsc = {NULL}; SnapObjectContext *sctx = NULL; - gp_point_conversion_init(C, &gsc); + gpencil_point_conversion_init(C, &gsc); /* Init snap context for geometry projection. */ sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C)); @@ -3718,8 +3725,8 @@ void GPENCIL_OT_reproject(wmOperatorType *ot) /* callbacks */ ot->invoke = WM_menu_invoke; - ot->exec = gp_strokes_reproject_exec; - ot->poll = gp_strokes_edit3d_poll; + ot->exec = gpencil_strokes_reproject_exec; + ot->poll = gpencil_strokes_edit3d_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3736,7 +3743,7 @@ void GPENCIL_OT_reproject(wmOperatorType *ot) "Keep original strokes and create a copy before reprojecting instead of reproject them"); } -static int gp_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = CTX_data_active_object(C); if ((ob == NULL) || (ob->type != OB_GPENCIL)) { @@ -3765,8 +3772,8 @@ void GPENCIL_OT_recalc_geometry(wmOperatorType *ot) ot->description = "Update all internal geometry data"; /* callbacks */ - ot->exec = gp_recalc_geometry_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_recalc_geometry_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3779,7 +3786,7 @@ void GPENCIL_OT_recalc_geometry(wmOperatorType *ot) * \{ */ /* helper to smooth */ -static void gp_smooth_stroke(bContext *C, wmOperator *op) +static void gpencil_smooth_stroke(bContext *C, wmOperator *op) { const int repeat = RNA_int_get(op->ptr, "repeat"); float factor = RNA_float_get(op->ptr, "factor"); @@ -3826,7 +3833,7 @@ static void gp_smooth_stroke(bContext *C, wmOperator *op) } /* helper: Count how many points need to be inserted */ -static int gp_count_subdivision_cuts(bGPDstroke *gps) +static int gpencil_count_subdivision_cuts(bGPDstroke *gps) { bGPDspoint *pt; int i; @@ -3844,7 +3851,7 @@ static int gp_count_subdivision_cuts(bGPDstroke *gps) return totnewpoints; } -static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_subdivide_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDspoint *temp_points; @@ -3863,7 +3870,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) if (gps->flag & GP_STROKE_SELECT) { /* loop as many times as cuts */ for (int s = 0; s < cuts; s++) { - totnewpoints = gp_count_subdivision_cuts(gps); + totnewpoints = gpencil_count_subdivision_cuts(gps); if (totnewpoints == 0) { continue; } @@ -3963,7 +3970,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) GP_EDITABLE_STROKES_END(gpstroke_iter); /* smooth stroke */ - gp_smooth_stroke(C, op); + gpencil_smooth_stroke(C, op); /* notifiers */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -3984,8 +3991,8 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot) "them"; /* api callbacks */ - ot->exec = gp_stroke_subdivide_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_subdivide_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -4011,7 +4018,7 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot) } /* ** simplify stroke *** */ -static int gp_stroke_simplify_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_simplify_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); float factor = RNA_float_get(op->ptr, "factor"); @@ -4047,8 +4054,8 @@ void GPENCIL_OT_stroke_simplify(wmOperatorType *ot) ot->description = "Simplify selected stroked reducing number of points"; /* api callbacks */ - ot->exec = gp_stroke_simplify_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_simplify_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -4060,7 +4067,7 @@ void GPENCIL_OT_stroke_simplify(wmOperatorType *ot) } /* ** simplify stroke using fixed algorithm *** */ -static int gp_stroke_simplify_fixed_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_simplify_fixed_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); int steps = RNA_int_get(op->ptr, "step"); @@ -4097,8 +4104,8 @@ void GPENCIL_OT_stroke_simplify_fixed(wmOperatorType *ot) ot->description = "Simplify selected stroked reducing number of points using fixed algorithm"; /* api callbacks */ - ot->exec = gp_stroke_simplify_fixed_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_simplify_fixed_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -4111,7 +4118,7 @@ void GPENCIL_OT_stroke_simplify_fixed(wmOperatorType *ot) } /* ** Resample stroke *** */ -static int gp_stroke_sample_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_sample_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); const float length = RNA_float_get(op->ptr, "length"); @@ -4146,8 +4153,8 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot) ot->description = "Sample stroke points to predefined segment length"; /* api callbacks */ - ot->exec = gp_stroke_sample_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_sample_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -4164,7 +4171,7 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot) /** \name Stroke Trim Operator * \{ */ -static int gp_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -4221,8 +4228,8 @@ void GPENCIL_OT_stroke_trim(wmOperatorType *ot) ot->description = "Trim selected stroke to first loop or intersection"; /* api callbacks */ - ot->exec = gp_stroke_trim_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_trim_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -4243,7 +4250,7 @@ typedef enum eGP_SeparateModes { GP_SEPARATE_LAYER, } eGP_SeparateModes; -static int gp_stroke_separate_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op) { Base *base_new; Main *bmain = CTX_data_main(C); @@ -4277,7 +4284,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op) /* Create a new object. */ /* Take into account user preferences for duplicating actions. */ - short dupflag = (U.dupflag & USER_DUP_ACT); + const eDupli_ID_Flags dupflag = (U.dupflag & USER_DUP_ACT); base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_prev, dupflag); ob_dst = base_new->object; @@ -4347,10 +4354,12 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op) } /* delete selected points from destination stroke */ - gp_stroke_delete_tagged_points(gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0); + gpencil_stroke_delete_tagged_points( + gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0); /* delete selected points from origin stroke */ - gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpencil_stroke_delete_tagged_points( + gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); } /* selected strokes mode */ else if (mode == GP_SEPARATE_STROKE) { @@ -4441,8 +4450,8 @@ void GPENCIL_OT_stroke_separate(wmOperatorType *ot) /* callbacks */ ot->invoke = WM_menu_invoke; - ot->exec = gp_stroke_separate_exec; - ot->poll = gp_strokes_edit3d_poll; + ot->exec = gpencil_stroke_separate_exec; + ot->poll = gpencil_strokes_edit3d_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -4457,7 +4466,7 @@ void GPENCIL_OT_stroke_separate(wmOperatorType *ot) /** \name Stroke Split Operator * \{ */ -static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_stroke_split_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -4505,10 +4514,10 @@ static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op)) } /* delete selected points from destination stroke */ - gp_stroke_delete_tagged_points(gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0); + gpencil_stroke_delete_tagged_points(gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0); /* delete selected points from origin stroke */ - gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); } } /* select again tagged points */ @@ -4546,8 +4555,8 @@ void GPENCIL_OT_stroke_split(wmOperatorType *ot) ot->description = "Split selected points as new stroke on same frame"; /* callbacks */ - ot->exec = gp_stroke_split_exec; - ot->poll = gp_strokes_edit3d_poll; + ot->exec = gpencil_stroke_split_exec; + ot->poll = gpencil_strokes_edit3d_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -4559,7 +4568,7 @@ void GPENCIL_OT_stroke_split(wmOperatorType *ot) /** \name Stroke Smooth Operator * \{ */ -static int gp_stroke_smooth_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_smooth_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -4568,7 +4577,7 @@ static int gp_stroke_smooth_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - gp_smooth_stroke(C, op); + gpencil_smooth_stroke(C, op); /* notifiers */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -4587,8 +4596,8 @@ void GPENCIL_OT_stroke_smooth(wmOperatorType *ot) ot->description = "Smooth selected strokes"; /* api callbacks */ - ot->exec = gp_stroke_smooth_exec; - ot->poll = gp_active_layer_poll; + ot->exec = gpencil_stroke_smooth_exec; + ot->poll = gpencil_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -4631,8 +4640,8 @@ static bool gpencil_test_lasso(bGPDstroke *gps, const struct GP_SelectLassoUserData *data = user_data; bGPDspoint pt2; int x0, y0; - gp_point_to_parent_space(pt, diff_mat, &pt2); - gp_point_to_xy(gsc, gps, &pt2, &x0, &y0); + gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_xy(gsc, gps, &pt2, &x0, &y0); /* test if in lasso */ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) && BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX)); @@ -4688,7 +4697,8 @@ static void gpencil_cutter_dissolve(bGPDlayer *hit_layer, bGPDstroke *hit_stroke pt->flag &= ~GP_SPOINT_TAG; } } - gp_stroke_delete_tagged_points(hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1); + gpencil_stroke_delete_tagged_points( + hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1); } } @@ -4715,7 +4725,7 @@ static int gpencil_cutter_lasso_select(bContext *C, } /* init space conversion stuff */ - gp_point_conversion_init(C, &gsc); + gpencil_point_conversion_init(C, &gsc); /* deselect all strokes first */ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) { @@ -4877,7 +4887,7 @@ bool ED_object_gpencil_exit(struct Main *bmain, Object *ob) /** \name Merge By Distance Operator * \{ */ -static bool gp_merge_by_distance_poll(bContext *C) +static bool gpencil_merge_by_distance_poll(bContext *C) { Object *ob = CTX_data_active_object(C); if ((ob == NULL) || (ob->type != OB_GPENCIL)) { @@ -4893,7 +4903,7 @@ static bool gp_merge_by_distance_poll(bContext *C) return ((gpl != NULL) && (ob->mode == OB_MODE_EDIT_GPENCIL)); } -static int gp_merge_by_distance_exec(bContext *C, wmOperator *op) +static int gpencil_merge_by_distance_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -4930,8 +4940,8 @@ void GPENCIL_OT_stroke_merge_by_distance(wmOperatorType *ot) ot->description = "Merge points by distance"; /* api callbacks */ - ot->exec = gp_merge_by_distance_exec; - ot->poll = gp_merge_by_distance_poll; + ot->exec = gpencil_merge_by_distance_exec; + ot->poll = gpencil_merge_by_distance_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 502097a0678..168693ff517 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -162,13 +162,13 @@ typedef struct tGPDfill { } tGPDfill; /* draw a given stroke using same thickness and color for all points */ -static void gp_draw_basic_stroke(tGPDfill *tgpf, - bGPDstroke *gps, - const float diff_mat[4][4], - const bool cyclic, - const float ink[4], - const int flag, - const float thershold) +static void gpencil_draw_basic_stroke(tGPDfill *tgpf, + bGPDstroke *gps, + const float diff_mat[4][4], + const bool cyclic, + const float ink[4], + const int flag, + const float thershold) { bGPDspoint *points = gps->points; @@ -223,7 +223,7 @@ static void gp_draw_basic_stroke(tGPDfill *tgpf, } /* loop all layers */ -static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) +static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4]) { /* duplicated: etempFlags */ enum { @@ -298,19 +298,19 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) /* normal strokes */ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) || (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) { - ED_gp_draw_fill(&tgpw); + ED_gpencil_draw_fill(&tgpw); } /* 3D Lines with basic shapes and invisible lines */ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) || (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) { - gp_draw_basic_stroke(tgpf, - gps, - tgpw.diff_mat, - gps->flag & GP_STROKE_CYCLIC, - ink, - tgpf->flag, - tgpf->fill_threshold); + gpencil_draw_basic_stroke(tgpf, + gps, + tgpw.diff_mat, + gps->flag & GP_STROKE_CYCLIC, + ink, + tgpf->flag, + tgpf->fill_threshold); } } } @@ -319,7 +319,7 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) } /* draw strokes in offscreen buffer */ -static bool gp_render_offscreen(tGPDfill *tgpf) +static bool gpencil_render_offscreen(tGPDfill *tgpf) { bool is_ortho = false; float winmat[4][4]; @@ -410,7 +410,7 @@ static bool gp_render_offscreen(tGPDfill *tgpf) /* draw strokes */ float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f}; - gp_draw_datablock(tgpf, ink); + gpencil_draw_datablock(tgpf, ink); GPU_matrix_pop_projection(); GPU_matrix_pop(); @@ -472,15 +472,16 @@ static void set_pixel(ImBuf *ibuf, int idx, const float col[4]) } } -/* check if the size of the leak is narrow to determine if the stroke is closed +/** + * Check if the size of the leak is narrow to determine if the stroke is closed * this is used for strokes with small gaps between them to get a full fill * and do not get a full screen fill. * - * \param ibuf: Image pixel data - * \param maxpixel: Maximum index - * \param limit: Limit of pixels to analyze - * \param index: Index of current pixel - * \param type: 0-Horizontal 1-Vertical + * \param ibuf: Image pixel data. + * \param maxpixel: Maximum index. + * \param limit: Limit of pixels to analyze. + * \param index: Index of current pixel. + * \param type: 0-Horizontal 1-Vertical. */ static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index, int type) { @@ -576,11 +577,12 @@ static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index return (bool)(t_a && t_b); } -/* Boundary fill inside strokes +/** + * Boundary fill inside strokes * Fills the space created by a set of strokes using the stroke color as the boundary * of the shape to fill. * - * \param tgpf: Temporary fill data + * \param tgpf: Temporary fill data. */ static void gpencil_boundaryfill_area(tGPDfill *tgpf) { @@ -665,62 +667,6 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf) BLI_stack_free(stack); } -/* Check if there are some pixel not filled with green. If no points, means nothing to fill. */ -static bool UNUSED_FUNCTION(gpencil_check_borders)(tGPDfill *tgpf) -{ - ImBuf *ibuf; - void *lock; - ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); - int idx; - int pixel = 0; - float color[4]; - bool found = false; - - /* horizontal lines */ - for (idx = 0; idx < ibuf->x; idx++) { - /* bottom line */ - get_pixel(ibuf, idx, color); - if (color[1] != 1.0f) { - found = true; - break; - } - /* top line */ - pixel = idx + (ibuf->x * (ibuf->y - 1)); - get_pixel(ibuf, pixel, color); - if (color[1] != 1.0f) { - found = true; - break; - } - } - if (!found) { - /* vertical lines */ - for (idx = 0; idx < ibuf->y; idx++) { - /* left line */ - get_pixel(ibuf, ibuf->x * idx, color); - if (color[1] != 1.0f) { - found = true; - break; - } - /* right line */ - pixel = ibuf->x * idx + (ibuf->x - 1); - get_pixel(ibuf, pixel, color); - if (color[1] != 1.0f) { - found = true; - break; - } - } - } - - /* release ibuf */ - if (ibuf) { - BKE_image_release_ibuf(tgpf->ima, ibuf, lock); - } - - tgpf->ima->id.tag |= LIB_TAG_DOIT; - - return found; -} - /* Set a border to create image limits. */ static void gpencil_set_borders(tGPDfill *tgpf, const bool transparent) { @@ -1137,12 +1083,12 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) for (int i = 0; i < tgpf->sbuffer_used && point2D; i++, point2D++, pt++) { /* convert screen-coordinates to 3D coordinates */ - gp_stroke_convertcoords_tpoint(tgpf->scene, - tgpf->region, - tgpf->ob, - point2D, - tgpf->depth_arr ? tgpf->depth_arr + i : NULL, - &pt->x); + gpencil_stroke_convertcoords_tpoint(tgpf->scene, + tgpf->region, + tgpf->ob, + point2D, + tgpf->depth_arr ? tgpf->depth_arr + i : NULL, + &pt->x); pt->pressure = 1.0f; pt->strength = 1.0f; @@ -1183,14 +1129,14 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) { float origin[3]; ED_gpencil_drawing_reference_get(tgpf->scene, tgpf->ob, ts->gpencil_v3d_align, origin); - ED_gp_project_stroke_to_plane( + ED_gpencil_project_stroke_to_plane( tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1); } /* if parented change position relative to parent object */ for (int a = 0; a < tgpf->sbuffer_used; a++) { pt = &gps->points[a]; - gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt); + gpencil_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt); } /* if camera view, reproject flat to view to avoid perspective effect */ @@ -1223,7 +1169,7 @@ static void gpencil_draw_boundary_lines(const bContext *UNUSED(C), tGPDfill *tgp return; } const float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f}; - gp_draw_datablock(tgpf, ink); + gpencil_draw_datablock(tgpf, ink); } /* Drawing callback for modal operator in 3d mode */ @@ -1266,7 +1212,7 @@ static bool gpencil_fill_poll(bContext *C) } /* Allocate memory and initialize values */ -static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op)) +static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *UNUSED(op)) { tGPDfill *tgpf = MEM_callocN(sizeof(tGPDfill), "GPencil Fill Data"); @@ -1399,7 +1345,7 @@ static int gpencil_fill_init(bContext *C, wmOperator *op) } /* check context */ - tgpf = op->customdata = gp_session_init_fill(C, op); + tgpf = op->customdata = gpencil_session_init_fill(C, op); if (tgpf == NULL) { /* something wasn't set correctly in context */ gpencil_fill_exit(C, op); @@ -1499,7 +1445,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) tgpf->active_cfra = CFRA; /* render screen to temp image */ - if (gp_render_offscreen(tgpf)) { + if (gpencil_render_offscreen(tgpf)) { /* Set red borders to create a external limit. */ gpencil_set_borders(tgpf, true); diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 473913c5459..bd697dbc768 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -248,7 +248,7 @@ typedef struct tGPDprimitive { } tGPDprimitive; /* Modal Operator Drawing Callbacks ------------------------ */ -void ED_gp_draw_fill(struct tGPDdraw *tgpw); +void ED_gpencil_draw_fill(struct tGPDdraw *tgpw); /* ***************************************************** */ /* Internal API */ @@ -272,83 +272,85 @@ typedef struct GP_SpaceConversion { float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */ } GP_SpaceConversion; -bool gp_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1); +bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1); -void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc); +void gpencil_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc); -void gp_point_to_xy(const GP_SpaceConversion *gsc, - const struct bGPDstroke *gps, - const struct bGPDspoint *pt, - int *r_x, - int *r_y); +void gpencil_point_to_xy(const GP_SpaceConversion *gsc, + const struct bGPDstroke *gps, + const struct bGPDspoint *pt, + int *r_x, + int *r_y); -void gp_point_to_xy_fl(const GP_SpaceConversion *gsc, - const bGPDstroke *gps, - const bGPDspoint *pt, - float *r_x, - float *r_y); +void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc, + const bGPDstroke *gps, + const bGPDspoint *pt, + float *r_x, + float *r_y); -void gp_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], bGPDspoint *r_pt); +void gpencil_point_to_parent_space(const bGPDspoint *pt, + const float diff_mat[4][4], + bGPDspoint *r_pt); /** * Change points position relative to parent object */ -void gp_apply_parent(struct Depsgraph *depsgraph, - struct Object *obact, - bGPDlayer *gpl, - bGPDstroke *gps); +void gpencil_apply_parent(struct Depsgraph *depsgraph, + struct Object *obact, + bGPDlayer *gpl, + bGPDstroke *gps); /** * Change point position relative to parent object */ -void gp_apply_parent_point(struct Depsgraph *depsgraph, - struct Object *obact, - bGPDlayer *gpl, - bGPDspoint *pt); +void gpencil_apply_parent_point(struct Depsgraph *depsgraph, + struct Object *obact, + bGPDlayer *gpl, + bGPDspoint *pt); -void gp_point_3d_to_xy(const GP_SpaceConversion *gsc, - const short flag, - const float pt[3], - float xy[2]); +void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc, + const short flag, + const float pt[3], + float xy[2]); -bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc, - struct Scene *scene, - const float screen_co[2], - float r_out[3]); +bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc, + struct Scene *scene, + const float screen_co[2], + float r_out[3]); /* helper to convert 2d to 3d */ -void gp_stroke_convertcoords_tpoint(struct Scene *scene, - struct ARegion *region, - struct Object *ob, - const struct tGPspoint *point2D, - float *depth, - float out[3]); +void gpencil_stroke_convertcoords_tpoint(struct Scene *scene, + struct ARegion *region, + struct Object *ob, + const struct tGPspoint *point2D, + float *depth, + float out[3]); /* Poll Callbacks ------------------------------------ */ /* gpencil_utils.c */ -bool gp_add_poll(struct bContext *C); -bool gp_active_layer_poll(struct bContext *C); -bool gp_active_brush_poll(struct bContext *C); -bool gp_brush_crt_presets_poll(bContext *C); +bool gpencil_add_poll(struct bContext *C); +bool gpencil_active_layer_poll(struct bContext *C); +bool gpencil_active_brush_poll(struct bContext *C); +bool gpencil_brush_create_presets_poll(bContext *C); /* Copy/Paste Buffer --------------------------------- */ /* gpencil_edit.c */ -extern ListBase gp_strokes_copypastebuf; +extern ListBase gpencil_strokes_copypastebuf; /* Build a map for converting between old colornames and destination-color-refs */ -struct GHash *gp_copybuf_validate_colormap(struct bContext *C); +struct GHash *gpencil_copybuf_validate_colormap(struct bContext *C); /* Stroke Editing ------------------------------------ */ -void gp_stroke_delete_tagged_points(bGPDframe *gpf, - bGPDstroke *gps, - bGPDstroke *next_stroke, - int tag_flags, - bool select, - int limit); -int gp_delete_selected_point_wrap(bContext *C); +void gpencil_stroke_delete_tagged_points(bGPDframe *gpf, + bGPDstroke *gps, + bGPDstroke *next_stroke, + int tag_flags, + bool select, + int limit); +int gpencil_delete_selected_point_wrap(bContext *C); -void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide); +void gpencil_subdivide_stroke(bGPDstroke *gps, const int subdivide); /* Layers Enums -------------------------------------- */ @@ -485,6 +487,8 @@ void GPENCIL_OT_frame_clean_fill(struct wmOperatorType *ot); void GPENCIL_OT_frame_clean_loose(struct wmOperatorType *ot); void GPENCIL_OT_convert(struct wmOperatorType *ot); +void GPENCIL_OT_bake_mesh_animation(struct wmOperatorType *ot); + void GPENCIL_OT_image_to_grease_pencil(struct wmOperatorType *ot); enum { diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 5cb49600d05..5e653187edb 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -100,10 +100,10 @@ static bool gpencil_view3d_poll(bContext *C) } /* Perform interpolation */ -static void gp_interpolate_update_points(const bGPDstroke *gps_from, - const bGPDstroke *gps_to, - bGPDstroke *new_stroke, - float factor) +static void gpencil_interpolate_update_points(const bGPDstroke *gps_from, + const bGPDstroke *gps_to, + bGPDstroke *new_stroke, + float factor) { /* update points */ for (int i = 0; i < new_stroke->totpoints; i++) { @@ -121,7 +121,7 @@ static void gp_interpolate_update_points(const bGPDstroke *gps_from, /* ****************** Interpolate Interactive *********************** */ /* Helper: free all temp strokes for display. */ -static void gp_interpolate_free_temp_strokes(bGPDframe *gpf) +static void gpencil_interpolate_free_temp_strokes(bGPDframe *gpf) { if (gpf == NULL) { return; @@ -136,9 +136,11 @@ static void gp_interpolate_free_temp_strokes(bGPDframe *gpf) } /* Helper: Untag all strokes. */ -static void gp_interpolate_untag_strokes(bGPDframe *gpf) +static void gpencil_interpolate_untag_strokes(bGPDframe *gpf) { - BLI_assert(gpf != NULL); + if (gpf == NULL) { + return; + } LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (gps->flag & GP_STROKE_TAG) { @@ -148,7 +150,7 @@ static void gp_interpolate_untag_strokes(bGPDframe *gpf) } /* Helper: Update all strokes interpolated */ -static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) +static void gpencil_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) { bGPdata *gpd = tgpi->gpd; const float shift = tgpi->shift; @@ -158,7 +160,7 @@ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) bGPDframe *gpf = tgpil->gpl->actframe; /* Free temp strokes. */ - gp_interpolate_free_temp_strokes(gpf); + gpencil_interpolate_free_temp_strokes(gpf); LISTBASE_FOREACH (bGPDstroke *, new_stroke, &tgpil->interFrame->strokes) { bGPDstroke *gps_from, *gps_to; @@ -176,7 +178,7 @@ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) /* update points position */ if ((gps_from) && (gps_to)) { - gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); + gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor); /* Add temp strokes. */ if (gpf) { @@ -193,7 +195,7 @@ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) } /* Helper: Verify valid strokes for interpolation */ -static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) +static bool gpencil_interpolate_check_todo(bContext *C, bGPdata *gpd) { Object *ob = CTX_data_active_object(C); ToolSettings *ts = CTX_data_tool_settings(C); @@ -243,7 +245,7 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) } /* Helper: Create internal strokes interpolated */ -static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) +static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) { bGPdata *gpd = tgpi->gpd; bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); @@ -262,6 +264,14 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { tGPDinterpolate_layer *tgpil; + /* Untag strokes to be sure nothing is pending. This must be done for + * all layer because it could be anything tagged and it would be removed + * at the end of the process when all tagged strokes are removed. */ + if (gpl->actframe != NULL) { + gpencil_interpolate_untag_strokes(gpl->actframe); + gpencil_interpolate_untag_strokes(gpl->actframe->next); + } + /* all layers or only active */ if (!(tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && (gpl != active_gpl)) { continue; @@ -278,10 +288,6 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) tgpil->prevFrame = gpl->actframe; tgpil->nextFrame = gpl->actframe->next; - /* Untag interpolated strokes to be sure nothing is pending. */ - gp_interpolate_untag_strokes(tgpil->prevFrame); - gp_interpolate_untag_strokes(tgpil->nextFrame); - BLI_addtail(&tgpi->ilayers, tgpil); /* create a new temporary frame */ @@ -337,7 +343,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) new_stroke->totpoints = gps_to->totpoints; } /* update points position */ - gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor); + gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor); } else { /* need an empty stroke to keep index correct for lookup, but resize to smallest size */ @@ -413,7 +419,7 @@ static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpol /* apply... */ tgpi->shift = RNA_float_get(op->ptr, "shift"); /* update points position */ - gp_interpolate_update_strokes(C, tgpi); + gpencil_interpolate_update_strokes(C, tgpi); } /* ----------------------- */ @@ -433,7 +439,7 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) /* Clear any temp stroke. */ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { - gp_interpolate_free_temp_strokes(gpf); + gpencil_interpolate_free_temp_strokes(gpf); } } @@ -454,7 +460,7 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) } /* Init new temporary interpolation data */ -static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) +static bool gpencil_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) { ToolSettings *ts = CTX_data_tool_settings(C); bGPdata *gpd = CTX_data_gpencil_data(C); @@ -475,18 +481,18 @@ static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinte /* set interpolation weight */ tgpi->shift = RNA_float_get(op->ptr, "shift"); /* set layers */ - gp_interpolate_set_points(C, tgpi); + gpencil_interpolate_set_points(C, tgpi); return 1; } /* Allocate memory and initialize values */ -static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op) +static tGPDinterpolate *gpencil_session_init_interpolation(bContext *C, wmOperator *op) { tGPDinterpolate *tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data"); /* define initial values */ - gp_interpolate_set_init_values(C, op, tgpi); + gpencil_interpolate_set_init_values(C, op, tgpi); /* return context data for running operator */ return tgpi; @@ -498,7 +504,7 @@ static int gpencil_interpolate_init(bContext *C, wmOperator *op) tGPDinterpolate *tgpi; /* check context */ - tgpi = op->customdata = gp_session_init_interpolation(C, op); + tgpi = op->customdata = gpencil_session_init_interpolation(C, op); if (tgpi == NULL) { /* something wasn't set correctly in context */ gpencil_interpolate_exit(C, op); @@ -540,7 +546,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent } /* need editable strokes */ - if (!gp_interpolate_check_todo(C, gpd)) { + if (!gpencil_interpolate_check_todo(C, gpd)) { BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable strokes"); return OPERATOR_CANCELLED; } @@ -731,7 +737,7 @@ void GPENCIL_OT_interpolate(wmOperatorType *ot) /* ****************** Interpolate Sequence *********************** */ /* Helper: Perform easing equation calculations for GP interpolation operator */ -static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_settings, float time) +static float gpencil_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_settings, float time) { const float begin = 0.0f; const float change = 1.0f; @@ -1008,7 +1014,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } else if (ipo_settings->type >= GP_IPO_BACK) { /* easing equation... */ - factor = gp_interpolate_seq_easing_calc(ipo_settings, factor); + factor = gpencil_interpolate_seq_easing_calc(ipo_settings, factor); } /* create new strokes data with interpolated points reading original stroke */ @@ -1064,7 +1070,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } /* update points position */ - gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); + gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor); /* Calc geometry data. */ BKE_gpencil_stroke_geometry_update(new_stroke); diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index e71bf2098dd..cf806e68837 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -132,7 +132,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode); /* stroke */ - bGPDstroke *gps = BKE_gpencil_stroke_new(ob->actcol - 1, totpoints, brush->size); + bGPDstroke *gps = BKE_gpencil_stroke_new(MAX2(ob->actcol - 1, 0), totpoints, brush->size); gps->flag |= GP_STROKE_SELECT; if (cyclic) { @@ -178,7 +178,7 @@ static void gpencil_dissolve_points(bContext *C) } LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { - gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); } } CTX_DATA_END; @@ -431,7 +431,7 @@ static int gpencil_analyze_strokes(tGPencilPointCache *src_array, return last; } -static bool gp_strokes_merge_poll(bContext *C) +static bool gpencil_strokes_merge_poll(bContext *C) { /* only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); @@ -462,7 +462,7 @@ static bool gp_strokes_merge_poll(bContext *C) return (CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0) && ED_operator_view3d_active(C); } -static int gp_stroke_merge_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_merge_exec(bContext *C, wmOperator *op) { const int mode = RNA_enum_get(op->ptr, "mode"); const bool clear_point = RNA_boolean_get(op->ptr, "clear_point"); @@ -546,8 +546,8 @@ void GPENCIL_OT_stroke_merge(wmOperatorType *ot) ot->description = "Create a new stroke with the selected stroke points"; /* api callbacks */ - ot->exec = gp_stroke_merge_exec; - ot->poll = gp_strokes_merge_poll; + ot->exec = gpencil_stroke_merge_exec; + ot->poll = gpencil_strokes_merge_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -563,7 +563,7 @@ void GPENCIL_OT_stroke_merge(wmOperatorType *ot) } /* Merge similar materials. */ -static bool gp_stroke_merge_material_poll(bContext *C) +static bool gpencil_stroke_merge_material_poll(bContext *C) { /* only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); @@ -574,7 +574,7 @@ static bool gp_stroke_merge_material_poll(bContext *C) return true; } -static int gp_stroke_merge_material_exec(bContext *C, wmOperator *op) +static int gpencil_stroke_merge_material_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -642,8 +642,8 @@ void GPENCIL_OT_stroke_merge_material(wmOperatorType *ot) ot->description = "Replace materials in strokes merging similar"; /* api callbacks */ - ot->exec = gp_stroke_merge_material_exec; - ot->poll = gp_stroke_merge_material_poll; + ot->exec = gpencil_stroke_merge_material_exec; + ot->poll = gpencil_stroke_merge_material_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c new file mode 100644 index 00000000000..763f5687edf --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_mesh.c @@ -0,0 +1,404 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008, Blender Foundation + * This is a new part of Blender + * Operator for converting Grease Pencil data to geometry + */ + +/** \file + * \ingroup edgpencil + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" + +#include "DNA_gpencil_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" + +#include "BKE_context.h" +#include "BKE_duplilist.h" +#include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_report.h" +#include "BKE_scene.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_gpencil.h" +#include "ED_transform_snap_object_context.h" + +#include "gpencil_intern.h" + +/* Check frame_end is always > start frame! */ +static void gpencil_bake_set_frame_end(struct Main *UNUSED(main), + struct Scene *UNUSED(scene), + struct PointerRNA *ptr) +{ + int frame_start = RNA_int_get(ptr, "frame_start"); + int frame_end = RNA_int_get(ptr, "frame_end"); + + if (frame_end <= frame_start) { + RNA_int_set(ptr, "frame_end", frame_start + 1); + } +} + +/* Extract mesh animation to Grease Pencil. */ +static bool gpencil_bake_mesh_animation_poll(bContext *C) +{ + if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT) { + return false; + } + + /* Only if the current view is 3D View. */ + ScrArea *area = CTX_wm_area(C); + return (area && area->spacetype); +} + +typedef struct GpBakeOb { + struct GPBakelist *next, *prev; + Object *ob; +} GpBakeOb; + +static void gpencil_bake_duplilist(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *list) +{ + GpBakeOb *elem = NULL; + ListBase *lb; + DupliObject *dob; + lb = object_duplilist(depsgraph, scene, ob); + for (dob = lb->first; dob; dob = dob->next) { + if (dob->ob->type != OB_MESH) { + continue; + } + elem = MEM_callocN(sizeof(GpBakeOb), __func__); + elem->ob = dob->ob; + BLI_addtail(list, elem); + } + + free_object_duplilist(lb); +} + +static void gpencil_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene, ListBase *list) +{ + GpBakeOb *elem = NULL; + + /* Add active object. In some files this could not be in selected array. */ + Object *obact = CTX_data_active_object(C); + + if (obact->type == OB_MESH) { + elem = MEM_callocN(sizeof(GpBakeOb), __func__); + elem->ob = obact; + BLI_addtail(list, elem); + } + /* Add duplilist. */ + else if (obact->type == OB_EMPTY) { + gpencil_bake_duplilist(depsgraph, scene, obact, list); + } + + /* Add other selected objects. */ + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + if (ob == obact) { + continue; + } + /* Add selected meshes.*/ + if (ob->type == OB_MESH) { + elem = MEM_callocN(sizeof(GpBakeOb), __func__); + elem->ob = ob; + BLI_addtail(list, elem); + } + + /* Add duplilist. */ + if (ob->type == OB_EMPTY) { + gpencil_bake_duplilist(depsgraph, scene, obact, list); + } + } + CTX_DATA_END; +} + +static void gpencil_bake_free_ob_list(ListBase *list) +{ + LISTBASE_FOREACH_MUTABLE (GpBakeOb *, elem, list) { + MEM_SAFE_FREE(elem); + } +} + +static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + ARegion *region = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + Object *ob_gpencil = NULL; + + ListBase list = {NULL, NULL}; + gpencil_bake_ob_list(C, depsgraph, scene, &list); + + /* Cannot check this in poll because the active object changes. */ + if (list.first == NULL) { + BKE_report(op->reports, RPT_INFO, "No valid object selected"); + gpencil_bake_free_ob_list(&list); + return OPERATOR_CANCELLED; + } + + /* Grab all relevant settings. */ + const int step = RNA_int_get(op->ptr, "step"); + + const int frame_start = (scene->r.sfra > RNA_int_get(op->ptr, "frame_start")) ? + scene->r.sfra : + RNA_int_get(op->ptr, "frame_start"); + + const int frame_end = (scene->r.efra < RNA_int_get(op->ptr, "frame_end")) ? + scene->r.efra : + RNA_int_get(op->ptr, "frame_end"); + + const float angle = RNA_float_get(op->ptr, "angle"); + const int thickness = RNA_int_get(op->ptr, "thickness"); + const bool use_seams = RNA_boolean_get(op->ptr, "seams"); + const bool use_faces = RNA_boolean_get(op->ptr, "faces"); + const float offset = RNA_float_get(op->ptr, "offset"); + const int frame_offset = RNA_int_get(op->ptr, "frame_target") - frame_start; + char target[64]; + RNA_string_get(op->ptr, "target", target); + const int project_type = RNA_enum_get(op->ptr, "project_type"); + + /* Create a new grease pencil object in origin. */ + bool newob = false; + if (STREQ(target, "*NEW")) { + ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; + float loc[3] = {0.0f, 0.0f, 0.0f}; + ob_gpencil = ED_gpencil_add_object(C, loc, local_view_bits); + newob = true; + } + else { + ob_gpencil = BLI_findstring(&bmain->objects, target, offsetof(ID, name) + 2); + } + + if ((ob_gpencil == NULL) || (ob_gpencil->type != OB_GPENCIL)) { + BKE_report(op->reports, RPT_ERROR, "Target grease pencil object not valid"); + gpencil_bake_free_ob_list(&list); + return OPERATOR_CANCELLED; + } + + bGPdata *gpd = (bGPdata *)ob_gpencil->data; + gpd->draw_mode = (project_type == GP_REPROJECT_KEEP) ? GP_DRAWMODE_3D : GP_DRAWMODE_2D; + + /* Set cursor to indicate working. */ + WM_cursor_wait(1); + + GP_SpaceConversion gsc = {NULL}; + SnapObjectContext *sctx = NULL; + if (project_type != GP_REPROJECT_KEEP) { + /* Init space conversion stuff. */ + gpencil_point_conversion_init(C, &gsc); + /* Init snap context for geometry projection. */ + sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C)); + + /* Tag all existing strokes to avoid reprojections. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + gps->flag |= GP_STROKE_TAG; + } + } + } + } + + /* Loop all frame range. */ + int oldframe = (int)DEG_get_ctime(depsgraph); + int key = -1; + for (int i = frame_start; i < frame_end + 1; i++) { + key++; + /* Jump if not step limit but include last frame always. */ + if ((key % step != 0) && (i != frame_end)) { + continue; + } + + /* Move scene to new frame. */ + CFRA = i; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); + + /* Loop all objects in the list. */ + LISTBASE_FOREACH (GpBakeOb *, elem, &list) { + Object *ob_eval = (Object *)DEG_get_evaluated_object(depsgraph, elem->ob); + + /* Generate strokes. */ + BKE_gpencil_convert_mesh(bmain, + depsgraph, + scene, + ob_gpencil, + elem->ob, + angle, + thickness, + offset, + ob_eval->obmat, + frame_offset, + use_seams, + use_faces); + + /* Reproject all untaged created strokes. */ + if (project_type != GP_REPROJECT_KEEP) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + bGPDframe *gpf = gpl->actframe; + if (gpf != NULL) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if ((gps->flag & GP_STROKE_TAG) == 0) { + ED_gpencil_stroke_reproject( + depsgraph, &gsc, sctx, gpl, gpf, gps, project_type, false); + gps->flag |= GP_STROKE_TAG; + } + } + } + } + } + } + } + + /* Return scene frame state and DB to original state. */ + CFRA = oldframe; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); + + /* Remove unused materials. */ + int actcol = ob_gpencil->actcol; + for (int slot = 1; slot <= ob_gpencil->totcol; slot++) { + while (slot <= ob_gpencil->totcol && !BKE_object_material_slot_used(ob_gpencil->data, slot)) { + ob_gpencil->actcol = slot; + BKE_object_material_slot_remove(CTX_data_main(C), ob_gpencil); + + if (actcol >= slot) { + actcol--; + } + } + } + ob_gpencil->actcol = actcol; + + /* Untag all strokes. */ + if (project_type != GP_REPROJECT_KEEP) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + gps->flag &= ~GP_STROKE_TAG; + } + } + } + } + + /* Free memory. */ + gpencil_bake_free_ob_list(&list); + if (sctx != NULL) { + ED_transform_snap_object_context_destroy(sctx); + } + + /* notifiers */ + if (newob) { + DEG_relations_tag_update(bmain); + } + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + + /* Reset cursor. */ + WM_cursor_wait(0); + + /* done */ + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_bake_mesh_animation(wmOperatorType *ot) +{ + static const EnumPropertyItem reproject_type[] = { + {GP_REPROJECT_KEEP, "KEEP", 0, "No Reproject", ""}, + {GP_REPROJECT_FRONT, "FRONT", 0, "Front", "Reproject the strokes using the X-Z plane"}, + {GP_REPROJECT_SIDE, "SIDE", 0, "Side", "Reproject the strokes using the Y-Z plane"}, + {GP_REPROJECT_TOP, "TOP", 0, "Top", "Reproject the strokes using the X-Y plane"}, + {GP_REPROJECT_VIEW, + "VIEW", + 0, + "View", + "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint " + "using 'Cursor' Stroke Placement"}, + {GP_REPROJECT_CURSOR, + "CURSOR", + 0, + "Cursor", + "Reproject the strokes using the orientation of 3D cursor"}, + {0, NULL, 0, NULL, NULL}, + }; + + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Bake Mesh Animation to Grease Pencil"; + ot->idname = "GPENCIL_OT_bake_mesh_animation"; + ot->description = "Bake Mesh Animation to Grease Pencil strokes"; + + /* callbacks */ + ot->exec = gpencil_bake_mesh_animation_exec; + ot->poll = gpencil_bake_mesh_animation_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_int( + ot->srna, "frame_start", 1, 1, 100000, "Start Frame", "The start frame", 1, 100000); + + prop = RNA_def_int( + ot->srna, "frame_end", 250, 1, 100000, "End Frame", "The end frame of animation", 1, 100000); + RNA_def_property_update_runtime(prop, gpencil_bake_set_frame_end); + + prop = RNA_def_int(ot->srna, "step", 1, 1, 100, "Step", "Step between generated frames", 1, 100); + + prop = RNA_def_float_rotation(ot->srna, + "angle", + 0, + NULL, + DEG2RADF(0.0f), + DEG2RADF(180.0f), + "Threshold Angle", + "Threshold to determine ends of the strokes", + DEG2RADF(0.0f), + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(70.0f)); + + RNA_def_int(ot->srna, "thickness", 1, 1, 100, "Thickness", "", 1, 100); + RNA_def_boolean(ot->srna, "seams", 0, "Only Seam Edges", "Convert only seam edges"); + RNA_def_boolean(ot->srna, "faces", 1, "Export Faces", "Export faces as filled strokes"); + RNA_def_float_distance( + ot->srna, "offset", 0.001f, 0.0, 100.0, "Offset", "Offset strokes from fill", 0.0, 100.00); + RNA_def_int(ot->srna, "frame_target", 1, 1, 100000, "Frame Target", "", 1, 100000); + RNA_def_string(ot->srna, + "target", + "*NEW", + 64, + "Target Object", + "Target grease pencil object name. Leave empty for new object"); + + RNA_def_enum(ot->srna, "project_type", reproject_type, GP_REPROJECT_VIEW, "Projection Type", ""); +} diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 94c86572fd3..e645668ef1c 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -63,21 +63,21 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) /* ==================== */ /* Poll callback for stroke editing mode */ -static bool gp_stroke_editmode_poll(bContext *C) +static bool gpencil_stroke_editmode_poll(bContext *C) { bGPdata *gpd = CTX_data_gpencil_data(C); return (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)); } /* Poll callback for stroke painting mode */ -static bool gp_stroke_paintmode_poll(bContext *C) +static bool gpencil_stroke_paintmode_poll(bContext *C) { /* TODO: limit this to mode, but review 2D editors */ bGPdata *gpd = CTX_data_gpencil_data(C); return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE)); } -static bool gp_stroke_paintmode_poll_with_tool(bContext *C, const char gpencil_tool) +static bool gpencil_stroke_paintmode_poll_with_tool(bContext *C, const char gpencil_tool) { /* TODO: limit this to mode, but review 2D editors */ bGPdata *gpd = CTX_data_gpencil_data(C); @@ -95,7 +95,7 @@ static bool gp_stroke_paintmode_poll_with_tool(bContext *C, const char gpencil_t WM_toolsystem_active_tool_is_brush(C) && (brush->gpencil_tool == gpencil_tool)); } -static bool gp_stroke_vertexmode_poll_with_tool(bContext *C, const char gpencil_vertex_tool) +static bool gpencil_stroke_vertexmode_poll_with_tool(bContext *C, const char gpencil_vertex_tool) { bGPdata *gpd = CTX_data_gpencil_data(C); if (!gpd) { @@ -113,7 +113,7 @@ static bool gp_stroke_vertexmode_poll_with_tool(bContext *C, const char gpencil_ (brush->gpencil_vertex_tool == gpencil_vertex_tool)); } -static bool gp_stroke_sculptmode_poll_with_tool(bContext *C, const char gpencil_sculpt_tool) +static bool gpencil_stroke_sculptmode_poll_with_tool(bContext *C, const char gpencil_sculpt_tool) { bGPdata *gpd = CTX_data_gpencil_data(C); if (!gpd) { @@ -131,7 +131,7 @@ static bool gp_stroke_sculptmode_poll_with_tool(bContext *C, const char gpencil_ (brush->gpencil_sculpt_tool == gpencil_sculpt_tool)); } -static bool gp_stroke_weightmode_poll_with_tool(bContext *C, const char gpencil_weight_tool) +static bool gpencil_stroke_weightmode_poll_with_tool(bContext *C, const char gpencil_weight_tool) { bGPdata *gpd = CTX_data_gpencil_data(C); if (!gpd) { @@ -150,31 +150,31 @@ static bool gp_stroke_weightmode_poll_with_tool(bContext *C, const char gpencil_ } /* Poll callback for stroke painting (draw brush) */ -static bool gp_stroke_paintmode_draw_poll(bContext *C) +static bool gpencil_stroke_paintmode_draw_poll(bContext *C) { - return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_DRAW); + return gpencil_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_DRAW); } /* Poll callback for stroke painting (erase brush) */ -static bool gp_stroke_paintmode_erase_poll(bContext *C) +static bool gpencil_stroke_paintmode_erase_poll(bContext *C) { - return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_ERASE); + return gpencil_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_ERASE); } /* Poll callback for stroke painting (fill) */ -static bool gp_stroke_paintmode_fill_poll(bContext *C) +static bool gpencil_stroke_paintmode_fill_poll(bContext *C) { - return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_FILL); + return gpencil_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_FILL); } /* Poll callback for stroke painting (tint) */ -static bool gp_stroke_paintmode_tint_poll(bContext *C) +static bool gpencil_stroke_paintmode_tint_poll(bContext *C) { - return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_TINT); + return gpencil_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_TINT); } /* Poll callback for stroke sculpting mode */ -static bool gp_stroke_sculptmode_poll(bContext *C) +static bool gpencil_stroke_sculptmode_poll(bContext *C) { bGPdata *gpd = CTX_data_gpencil_data(C); Object *ob = CTX_data_active_object(C); @@ -194,7 +194,7 @@ static bool gp_stroke_sculptmode_poll(bContext *C) } /* Poll callback for stroke weight paint mode */ -static bool gp_stroke_weightmode_poll(bContext *C) +static bool gpencil_stroke_weightmode_poll(bContext *C) { bGPdata *gpd = CTX_data_gpencil_data(C); Object *ob = CTX_data_active_object(C); @@ -207,7 +207,7 @@ static bool gp_stroke_weightmode_poll(bContext *C) } /* Poll callback for stroke vertex paint mode */ -static bool gp_stroke_vertexmode_poll(bContext *C) +static bool gpencil_stroke_vertexmode_poll(bContext *C) { bGPdata *gpd = CTX_data_gpencil_data(C); Object *ob = CTX_data_active_object(C); @@ -220,91 +220,91 @@ static bool gp_stroke_vertexmode_poll(bContext *C) } /* Poll callback for vertex painting (draw) */ -static bool gp_stroke_vertexmode_draw_poll(bContext *C) +static bool gpencil_stroke_vertexmode_draw_poll(bContext *C) { - return gp_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_DRAW); + return gpencil_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_DRAW); } /* Poll callback for vertex painting (blur) */ -static bool gp_stroke_vertexmode_blur_poll(bContext *C) +static bool gpencil_stroke_vertexmode_blur_poll(bContext *C) { - return gp_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_BLUR); + return gpencil_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_BLUR); } /* Poll callback for vertex painting (average) */ -static bool gp_stroke_vertexmode_average_poll(bContext *C) +static bool gpencil_stroke_vertexmode_average_poll(bContext *C) { - return gp_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_AVERAGE); + return gpencil_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_AVERAGE); } /* Poll callback for vertex painting (smear) */ -static bool gp_stroke_vertexmode_smear_poll(bContext *C) +static bool gpencil_stroke_vertexmode_smear_poll(bContext *C) { - return gp_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_SMEAR); + return gpencil_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_SMEAR); } /* Poll callback for vertex painting (replace) */ -static bool gp_stroke_vertexmode_replace_poll(bContext *C) +static bool gpencil_stroke_vertexmode_replace_poll(bContext *C) { - return gp_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_REPLACE); + return gpencil_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_REPLACE); } /* Poll callback for sculpt (Smooth) */ -static bool gp_stroke_sculptmode_smooth_poll(bContext *C) +static bool gpencil_stroke_sculptmode_smooth_poll(bContext *C) { - return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_SMOOTH); + return gpencil_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_SMOOTH); } /* Poll callback for sculpt (Thickness) */ -static bool gp_stroke_sculptmode_thickness_poll(bContext *C) +static bool gpencil_stroke_sculptmode_thickness_poll(bContext *C) { - return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_THICKNESS); + return gpencil_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_THICKNESS); } /* Poll callback for sculpt (Strength) */ -static bool gp_stroke_sculptmode_strength_poll(bContext *C) +static bool gpencil_stroke_sculptmode_strength_poll(bContext *C) { - return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_STRENGTH); + return gpencil_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_STRENGTH); } /* Poll callback for sculpt (Grab) */ -static bool gp_stroke_sculptmode_grab_poll(bContext *C) +static bool gpencil_stroke_sculptmode_grab_poll(bContext *C) { - return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_GRAB); + return gpencil_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_GRAB); } /* Poll callback for sculpt (Push) */ -static bool gp_stroke_sculptmode_push_poll(bContext *C) +static bool gpencil_stroke_sculptmode_push_poll(bContext *C) { - return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_PUSH); + return gpencil_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_PUSH); } /* Poll callback for sculpt (Twist) */ -static bool gp_stroke_sculptmode_twist_poll(bContext *C) +static bool gpencil_stroke_sculptmode_twist_poll(bContext *C) { - return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_TWIST); + return gpencil_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_TWIST); } /* Poll callback for sculpt (Pinch) */ -static bool gp_stroke_sculptmode_pinch_poll(bContext *C) +static bool gpencil_stroke_sculptmode_pinch_poll(bContext *C) { - return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_PINCH); + return gpencil_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_PINCH); } /* Poll callback for sculpt (Randomize) */ -static bool gp_stroke_sculptmode_randomize_poll(bContext *C) +static bool gpencil_stroke_sculptmode_randomize_poll(bContext *C) { - return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_RANDOMIZE); + return gpencil_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_RANDOMIZE); } /* Poll callback for sculpt (Clone) */ -static bool gp_stroke_sculptmode_clone_poll(bContext *C) +static bool gpencil_stroke_sculptmode_clone_poll(bContext *C) { - return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_CLONE); + return gpencil_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_CLONE); } /* Poll callback for weight paint (Draw) */ -static bool gp_stroke_weightmode_draw_poll(bContext *C) +static bool gpencil_stroke_weightmode_draw_poll(bContext *C) { - return gp_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_DRAW); + return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_DRAW); } /* Stroke Editing Keymap - Only when editmode is enabled */ @@ -313,35 +313,35 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0); /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */ - keymap->poll = gp_stroke_editmode_poll; + keymap->poll = gpencil_stroke_editmode_poll; } /* keys for draw with a drawing brush (no fill) */ static void ed_keymap_gpencil_painting_draw(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Draw brush)", 0, 0); - keymap->poll = gp_stroke_paintmode_draw_poll; + keymap->poll = gpencil_stroke_paintmode_draw_poll; } /* keys for draw with a eraser brush (erase) */ static void ed_keymap_gpencil_painting_erase(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Erase)", 0, 0); - keymap->poll = gp_stroke_paintmode_erase_poll; + keymap->poll = gpencil_stroke_paintmode_erase_poll; } /* keys for draw with a fill brush */ static void ed_keymap_gpencil_painting_fill(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Fill)", 0, 0); - keymap->poll = gp_stroke_paintmode_fill_poll; + keymap->poll = gpencil_stroke_paintmode_fill_poll; } /* keys for draw with a tint brush */ static void ed_keymap_gpencil_painting_tint(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Tint)", 0, 0); - keymap->poll = gp_stroke_paintmode_tint_poll; + keymap->poll = gpencil_stroke_paintmode_tint_poll; } /* Stroke Painting Keymap - Only when paintmode is enabled */ @@ -349,7 +349,7 @@ static void ed_keymap_gpencil_painting(wmKeyConfig *keyconf) { /* set poll callback - so that this keymap only gets enabled when stroke paintmode is enabled */ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint Mode", 0, 0); - keymap->poll = gp_stroke_paintmode_poll; + keymap->poll = gpencil_stroke_paintmode_poll; } /* Stroke Sculpting Keymap - Only when sculptmode is enabled */ @@ -357,7 +357,7 @@ static void ed_keymap_gpencil_sculpting(wmKeyConfig *keyconf) { /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt Mode", 0, 0); - keymap->poll = gp_stroke_sculptmode_poll; + keymap->poll = gpencil_stroke_sculptmode_poll; } /* Stroke Weight Paint Keymap - Only when weight is enabled */ @@ -365,106 +365,106 @@ static void ed_keymap_gpencil_weightpainting(wmKeyConfig *keyconf) { /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight Mode", 0, 0); - keymap->poll = gp_stroke_weightmode_poll; + keymap->poll = gpencil_stroke_weightmode_poll; } static void ed_keymap_gpencil_vertexpainting(wmKeyConfig *keyconf) { /* set poll callback - so that this keymap only gets enabled when stroke vertex is enabled */ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex Mode", 0, 0); - keymap->poll = gp_stroke_vertexmode_poll; + keymap->poll = gpencil_stroke_vertexmode_poll; } /* keys for vertex with a draw brush */ static void ed_keymap_gpencil_vertexpainting_draw(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex (Draw)", 0, 0); - keymap->poll = gp_stroke_vertexmode_draw_poll; + keymap->poll = gpencil_stroke_vertexmode_draw_poll; } /* keys for vertex with a blur brush */ static void ed_keymap_gpencil_vertexpainting_blur(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex (Blur)", 0, 0); - keymap->poll = gp_stroke_vertexmode_blur_poll; + keymap->poll = gpencil_stroke_vertexmode_blur_poll; } /* keys for vertex with a average brush */ static void ed_keymap_gpencil_vertexpainting_average(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex (Average)", 0, 0); - keymap->poll = gp_stroke_vertexmode_average_poll; + keymap->poll = gpencil_stroke_vertexmode_average_poll; } /* keys for vertex with a smear brush */ static void ed_keymap_gpencil_vertexpainting_smear(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex (Smear)", 0, 0); - keymap->poll = gp_stroke_vertexmode_smear_poll; + keymap->poll = gpencil_stroke_vertexmode_smear_poll; } /* keys for vertex with a replace brush */ static void ed_keymap_gpencil_vertexpainting_replace(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex (Replace)", 0, 0); - keymap->poll = gp_stroke_vertexmode_replace_poll; + keymap->poll = gpencil_stroke_vertexmode_replace_poll; } /* keys for sculpt with a smooth brush */ static void ed_keymap_gpencil_sculptpainting_smooth(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Smooth)", 0, 0); - keymap->poll = gp_stroke_sculptmode_smooth_poll; + keymap->poll = gpencil_stroke_sculptmode_smooth_poll; } /* keys for sculpt with a thickness brush */ static void ed_keymap_gpencil_sculptpainting_thickness(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Thickness)", 0, 0); - keymap->poll = gp_stroke_sculptmode_thickness_poll; + keymap->poll = gpencil_stroke_sculptmode_thickness_poll; } /* keys for sculpt with a strength brush */ static void ed_keymap_gpencil_sculptpainting_strength(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Strength)", 0, 0); - keymap->poll = gp_stroke_sculptmode_strength_poll; + keymap->poll = gpencil_stroke_sculptmode_strength_poll; } /* keys for sculpt with a grab brush */ static void ed_keymap_gpencil_sculptpainting_grab(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Grab)", 0, 0); - keymap->poll = gp_stroke_sculptmode_grab_poll; + keymap->poll = gpencil_stroke_sculptmode_grab_poll; } /* keys for sculpt with a push brush */ static void ed_keymap_gpencil_sculptpainting_push(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Push)", 0, 0); - keymap->poll = gp_stroke_sculptmode_push_poll; + keymap->poll = gpencil_stroke_sculptmode_push_poll; } /* keys for sculpt with a twist brush */ static void ed_keymap_gpencil_sculptpainting_twist(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Twist)", 0, 0); - keymap->poll = gp_stroke_sculptmode_twist_poll; + keymap->poll = gpencil_stroke_sculptmode_twist_poll; } /* keys for sculpt with a pinch brush */ static void ed_keymap_gpencil_sculptpainting_pinch(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Pinch)", 0, 0); - keymap->poll = gp_stroke_sculptmode_pinch_poll; + keymap->poll = gpencil_stroke_sculptmode_pinch_poll; } /* keys for sculpt with a randomize brush */ static void ed_keymap_gpencil_sculptpainting_randomize(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Randomize)", 0, 0); - keymap->poll = gp_stroke_sculptmode_randomize_poll; + keymap->poll = gpencil_stroke_sculptmode_randomize_poll; } /* keys for sculpt with a clone brush */ static void ed_keymap_gpencil_sculptpainting_clone(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Clone)", 0, 0); - keymap->poll = gp_stroke_sculptmode_clone_poll; + keymap->poll = gpencil_stroke_sculptmode_clone_poll; } /* keys for weight with a draw brush */ static void ed_keymap_gpencil_weightpainting_draw(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Draw)", 0, 0); - keymap->poll = gp_stroke_weightmode_draw_poll; + keymap->poll = gpencil_stroke_weightmode_draw_poll; } /* ==================== */ @@ -603,6 +603,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_frame_clean_loose); WM_operatortype_append(GPENCIL_OT_convert); + WM_operatortype_append(GPENCIL_OT_bake_mesh_animation); WM_operatortype_append(GPENCIL_OT_image_to_grease_pencil); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index a9eb94498ad..95133244dfb 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -272,7 +272,7 @@ typedef struct tGPsdata { /* minimum length of new segment before new point can be added */ #define MIN_EUCLIDEAN_PX (U.gp_euclideandist) -static void gp_update_cache(bGPdata *gpd) +static void gpencil_update_cache(bGPdata *gpd) { if (gpd) { DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -280,19 +280,19 @@ static void gp_update_cache(bGPdata *gpd) } } -static void gp_stroke_added_enable(tGPsdata *p) +static void gpencil_stroke_added_enable(tGPsdata *p) { BLI_assert(p->gpf->strokes.last != NULL); p->flags |= GP_PAINTFLAG_STROKEADDED; /* drawing batch cache is dirty now */ - gp_update_cache(p->gpd); + gpencil_update_cache(p->gpd); } /* ------ */ /* Forward defines for some functions... */ -static void gp_session_validatebuffer(tGPsdata *p); +static void gpencil_session_validatebuffer(tGPsdata *p); /* ******************************************* */ /* Context Wrangling... */ @@ -352,7 +352,7 @@ static bool gpencil_project_check(tGPsdata *p) /* Utilities --------------------------------- */ /* get the reference point for stroke-point conversions */ -static void gp_get_3d_reference(tGPsdata *p, float vec[3]) +static void gpencil_get_3d_reference(tGPsdata *p, float vec[3]) { Object *ob = NULL; if (p->ownerPtr.type == &RNA_Object) { @@ -363,7 +363,7 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3]) /* Stroke Editing ---------------------------- */ /* check if the current mouse position is suitable for adding a new point */ -static bool gp_stroke_filtermval(tGPsdata *p, const float mval[2], float mvalo[2]) +static bool gpencil_stroke_filtermval(tGPsdata *p, const float mval[2], float mvalo[2]) { Brush *brush = p->brush; int dx = (int)fabsf(mval[0] - mvalo[0]); @@ -410,7 +410,7 @@ static bool gp_stroke_filtermval(tGPsdata *p, const float mval[2], float mvalo[2 } /* reproject stroke to plane locked to axis in 3d cursor location */ -static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps) +static void gpencil_reproject_toplane(tGPsdata *p, bGPDstroke *gps) { bGPdata *gpd = p->gpd; Object *obact = (Object *)p->ownerPtr.data; @@ -430,13 +430,15 @@ static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps) } /* get drawing origin */ - gp_get_3d_reference(p, origin); - ED_gp_project_stroke_to_plane(p->scene, obact, rv3d, gps, origin, p->lock_axis - 1); + gpencil_get_3d_reference(p, origin); + ED_gpencil_project_stroke_to_plane(p->scene, obact, rv3d, gps, origin, p->lock_axis - 1); } /* convert screen-coordinates to buffer-coordinates */ -/* XXX this method needs a total overhaul! */ -static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[3], float *depth) +static void gpencil_stroke_convertcoords(tGPsdata *p, + const float mval[2], + float out[3], + float *depth) { bGPdata *gpd = p->gpd; @@ -476,7 +478,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[ * 3D-coordinates using the 3D-cursor as reference. In general, this * works OK, but it could of course be improved. */ - gp_get_3d_reference(p, rvec); + gpencil_get_3d_reference(p, rvec); zfac = ED_view3d_calc_zfac(p->region->regiondata, rvec, NULL); if (ED_view3d_project_float_global(p->region, rvec, mval_prj, V3D_PROJ_TEST_NOP) == @@ -492,7 +494,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[ } /* Apply jitter to stroke point. */ -static void gp_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude) +static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude) { const float axis[2] = {0.0f, 1.0f}; /* Jitter is applied perpendicular to the mouse movement vector (2D space). */ @@ -513,8 +515,8 @@ static void gp_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude) } } -/* apply pressure change depending of the angle of the stroke to simulate a pen with shape */ -static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const float mval[2]) +/* Apply pressure change depending of the angle of the stroke to simulate a pen with shape */ +static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const float mval[2]) { float mvec[2]; float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */ @@ -551,16 +553,17 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa } } -/* Apply smooth to buffer while drawing +/** + * Apply smooth to buffer while drawing * to smooth point C, use 2 before (A, B) and current point (D): * - * A----B-----C------D + * `A----B-----C------D` * * \param p: Temp data * \param inf: Influence factor * \param idx: Index of the last point (need minimum 3 points in the array) */ -static void gp_smooth_buffer(tGPsdata *p, float inf, int idx) +static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx) { bGPdata *gpd = p->gpd; GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide; @@ -624,7 +627,7 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx) } /* Helper: Apply smooth to segment from Index to Index */ -static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int to_idx) +static void gpencil_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int to_idx) { const short num_points = to_idx - from_idx; /* Do nothing if not enough points to smooth out */ @@ -691,12 +694,12 @@ static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int t } } -static void gp_apply_randomness(tGPsdata *p, - BrushGpencilSettings *brush_settings, - tGPspoint *pt, - const bool press, - const bool strength, - const bool uv) +static void gpencil_apply_randomness(tGPsdata *p, + BrushGpencilSettings *brush_settings, + tGPspoint *pt, + const bool press, + const bool strength, + const bool uv) { bGPdata *gpd = p->gpd; GpRandomSettings random_settings = p->random_settings; @@ -764,7 +767,10 @@ static void gp_apply_randomness(tGPsdata *p, } /* add current stroke-point to buffer (returns whether point was successfully added) */ -static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime) +static short gpencil_stroke_addpoint(tGPsdata *p, + const float mval[2], + float pressure, + double curtime) { bGPdata *gpd = p->gpd; Brush *brush = p->brush; @@ -860,16 +866,16 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure /* FIXME the +2 means minimum jitter is 4 which is a bit strange for UX. */ const float exp_factor = brush_settings->draw_jitter + 2.0f; const float fac = rand * square_f(exp_factor) * jitpress; - gp_brush_jitter(gpd, pt, fac); + gpencil_brush_jitter(gpd, pt, fac); } /* Apply other randomness. */ - gp_apply_randomness(p, brush_settings, pt, true, true, true); + gpencil_apply_randomness(p, brush_settings, pt, true, true, true); } /* apply angle of stroke to brush size */ if (brush_settings->draw_angle_factor != 0.0f) { - gp_brush_angle(gpd, brush, pt, mval); + gpencil_brush_angle(gpd, brush, pt, mval); } /* point time */ @@ -882,14 +888,14 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure /* get origin to reproject point */ float origin[3]; - gp_get_3d_reference(p, origin); + gpencil_get_3d_reference(p, origin); /* reproject current */ ED_gpencil_tpoint_to_point(p->region, origin, pt, &spt); - ED_gp_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt); + ED_gpencil_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt); /* reproject previous */ ED_gpencil_tpoint_to_point(p->region, origin, ptb, &spt2); - ED_gp_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt2); + ED_gpencil_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt2); p->totpixlen += len_v3v3(&spt.x, &spt2.x); pt->uv_fac = p->totpixlen; } @@ -904,9 +910,9 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure /* Smooth while drawing previous points with a reduction factor for previous. */ if (brush->gpencil_settings->active_smooth > 0.0f) { for (int s = 0; s < 3; s++) { - gp_smooth_buffer(p, - brush->gpencil_settings->active_smooth * ((3.0f - s) / 3.0f), - gpd->runtime.sbuffer_used - s); + gpencil_smooth_buffer(p, + brush->gpencil_settings->active_smooth * ((3.0f - s) / 3.0f), + gpd->runtime.sbuffer_used - s); } } @@ -920,7 +926,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure } /* make a new stroke from the buffer data */ -static void gp_stroke_newfrombuffer(tGPsdata *p) +static void gpencil_stroke_newfrombuffer(tGPsdata *p) { bGPdata *gpd = p->gpd; bGPDlayer *gpl = p->gpl; @@ -1000,7 +1006,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) gps->dvert = NULL; /* drawing batch cache is dirty now */ - gp_update_cache(p->gpd); + gpencil_update_cache(p->gpd); /* set pointer to first non-initialized point */ pt = gps->points + (gps->totpoints - totelem); if (gps->dvert != NULL) { @@ -1018,7 +1024,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ - gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; @@ -1052,7 +1058,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1); /* convert screen-coordinates to appropriate coordinates (and store them) */ - gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; @@ -1077,11 +1083,11 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) } /* reproject to plane (only in 3d space) */ - gp_reproject_toplane(p, gps); + gpencil_reproject_toplane(p, gps); pt = gps->points; for (i = 0; i < gps->totpoints; i++, pt++) { /* if parented change position relative to parent object */ - gp_apply_parent_point(depsgraph, obact, gpl, pt); + gpencil_apply_parent_point(depsgraph, obact, gpl, pt); } /* if camera view, reproject flat to view to avoid perspective effect */ @@ -1172,7 +1178,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc; i++, ptc++, pt++) { /* convert screen-coordinates to appropriate coordinates (and store them) */ - gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); + gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -1194,7 +1200,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* subdivide and smooth the stroke */ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && (subdivide > 0)) { - gp_subdivide_stroke(gps, subdivide); + gpencil_subdivide_stroke(gps, subdivide); } /* Smooth stroke after subdiv - only if there's something to do for each iteration, @@ -1229,9 +1235,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) } /* reproject to plane (only in 3d space) */ - gp_reproject_toplane(p, gps); + gpencil_reproject_toplane(p, gps); /* change position relative to parent object */ - gp_apply_parent(depsgraph, obact, gpl, gps); + gpencil_apply_parent(depsgraph, obact, gpl, gps); /* if camera view, reproject flat to view to avoid perspective effect */ if (is_camera) { ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps); @@ -1284,12 +1290,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* Calc geometry data. */ BKE_gpencil_stroke_geometry_update(gps); - gp_stroke_added_enable(p); + gpencil_stroke_added_enable(p); } /* --- 'Eraser' for 'Paint' Tool ------ */ -/* which which point is infront (result should only be used for comparison) */ +/** + * Which which point is in front (result should only be used for comparison). + */ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3]) { if (rv3d->is_persp) { @@ -1301,10 +1309,10 @@ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3]) } /* only erase stroke points that are visible */ -static bool gp_stroke_eraser_is_occluded(tGPsdata *p, - const bGPDspoint *pt, - const int x, - const int y) +static bool gpencil_stroke_eraser_is_occluded(tGPsdata *p, + const bGPDspoint *pt, + const int x, + const int y) { Object *obact = (Object *)p->ownerPtr.data; Brush *brush = p->brush; @@ -1346,10 +1354,10 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, } /* apply a falloff effect to brush strength, based on distance */ -static float gp_stroke_eraser_calc_influence(tGPsdata *p, - const float mval[2], - const int radius, - const int co[2]) +static float gpencil_stroke_eraser_calc_influence(tGPsdata *p, + const float mval[2], + const int radius, + const int co[2]) { Brush *brush = p->brush; /* Linear Falloff... */ @@ -1373,7 +1381,7 @@ static float gp_stroke_eraser_calc_influence(tGPsdata *p, } /* helper to free a stroke */ -static void gp_free_stroke(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps) +static void gpencil_free_stroke(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps) { if (gps->points) { MEM_freeN(gps->points); @@ -1388,7 +1396,7 @@ static void gp_free_stroke(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps) MEM_freeN(gps->triangles); } BLI_freelinkN(&gpf->strokes, gps); - gp_update_cache(gpd); + gpencil_update_cache(gpd); } /** @@ -1396,7 +1404,7 @@ static void gp_free_stroke(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps) * to avoid that segments gets the end points rounded. * The round caps breaks the artistic effect. */ -static void gp_stroke_soft_refine(bGPDstroke *gps) +static void gpencil_stroke_soft_refine(bGPDstroke *gps) { bGPDspoint *pt = NULL; bGPDspoint *pt2 = NULL; @@ -1431,12 +1439,12 @@ static void gp_stroke_soft_refine(bGPDstroke *gps) } /* eraser tool - evaluation per stroke */ -static void gp_stroke_eraser_dostroke(tGPsdata *p, - bGPDframe *gpf, - bGPDstroke *gps, - const float mval[2], - const int radius, - const rcti *rect) +static void gpencil_stroke_eraser_dostroke(tGPsdata *p, + bGPDframe *gpf, + bGPDstroke *gps, + const float mval[2], + const int radius, + const rcti *rect) { Brush *eraser = p->eraser; bGPDspoint *pt0, *pt1, *pt2; @@ -1449,20 +1457,20 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, if (gps->totpoints == 0) { /* just free stroke */ - gp_free_stroke(p->gpd, gpf, gps); + gpencil_free_stroke(p->gpd, gpf, gps); } else if (gps->totpoints == 1) { /* only process if it hasn't been masked out... */ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { bGPDspoint pt_temp; - gp_point_to_parent_space(gps->points, p->diff_mat, &pt_temp); - gp_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]); + gpencil_point_to_parent_space(gps->points, p->diff_mat, &pt_temp); + gpencil_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]); /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ if (len_v2v2_int(mval_i, pc1) <= radius) { /* free stroke */ - gp_free_stroke(p->gpd, gpf, gps); + gpencil_free_stroke(p->gpd, gpf, gps); } } } @@ -1479,15 +1487,15 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, /* get points to work with */ pt1 = gps->points + i; bGPDspoint npt; - gp_point_to_parent_space(pt1, p->diff_mat, &npt); - gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); + gpencil_point_to_parent_space(pt1, p->diff_mat, &npt); + gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ if (len_v2v2_int(mval_i, pc1) <= radius) { /* free stroke */ - gp_free_stroke(p->gpd, gpf, gps); + gpencil_free_stroke(p->gpd, gpf, gps); return; } } @@ -1531,19 +1539,19 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, bGPDspoint npt; if (pt0) { - gp_point_to_parent_space(pt0, p->diff_mat, &npt); - gp_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]); + gpencil_point_to_parent_space(pt0, p->diff_mat, &npt); + gpencil_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]); } else { /* avoid null values */ copy_v2_v2_int(pc0, pc1); } - gp_point_to_parent_space(pt1, p->diff_mat, &npt); - gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); + gpencil_point_to_parent_space(pt1, p->diff_mat, &npt); + gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); - gp_point_to_parent_space(pt2, p->diff_mat, &npt); - gp_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); + gpencil_point_to_parent_space(pt2, p->diff_mat, &npt); + gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); /* Check that point segment of the boundbox of the eraser stroke */ if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) || @@ -1553,10 +1561,10 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, * eraser region (either within stroke painted, or on its lines) * - this assumes that linewidth is irrelevant */ - if (gp_stroke_inside_circle(mval, radius, pc0[0], pc0[1], pc2[0], pc2[1])) { - if ((gp_stroke_eraser_is_occluded(p, pt0, pc0[0], pc0[1]) == false) || - (gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) || - (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) { + if (gpencil_stroke_inside_circle(mval, radius, pc0[0], pc0[1], pc2[0], pc2[1])) { + if ((gpencil_stroke_eraser_is_occluded(p, pt0, pc0[0], pc0[1]) == false) || + (gpencil_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) || + (gpencil_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) { /* Point is affected: */ /* Adjust thickness * - Influence of eraser falls off with distance from the middle of the eraser @@ -1570,18 +1578,18 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, float influence = 0.0f; if (pt0) { - influence = gp_stroke_eraser_calc_influence(p, mval, radius, pc0); + influence = gpencil_stroke_eraser_calc_influence(p, mval, radius, pc0); pt0->strength -= influence * strength * f_strength * 0.5f; CLAMP_MIN(pt0->strength, 0.0f); pt0->pressure -= influence * strength * f_thickness * 0.5f; } - influence = gp_stroke_eraser_calc_influence(p, mval, radius, pc1); + influence = gpencil_stroke_eraser_calc_influence(p, mval, radius, pc1); pt1->strength -= influence * strength * f_strength; CLAMP_MIN(pt1->strength, 0.0f); pt1->pressure -= influence * strength * f_thickness; - influence = gp_stroke_eraser_calc_influence(p, mval, radius, pc2); + influence = gpencil_stroke_eraser_calc_influence(p, mval, radius, pc2); pt2->strength -= influence * strength * f_strength * 0.5f; CLAMP_MIN(pt2->strength, 0.0f); pt2->pressure -= influence * strength * f_thickness * 0.5f; @@ -1604,9 +1612,10 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, } } else { - pt1->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc1) * strength; - pt2->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength * - 0.5f; + pt1->pressure -= gpencil_stroke_eraser_calc_influence(p, mval, radius, pc1) * + strength; + pt2->pressure -= gpencil_stroke_eraser_calc_influence(p, mval, radius, pc2) * + strength * 0.5f; } /* 2) Tag any point with overly low influence for removal in the next pass */ @@ -1630,17 +1639,17 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, /* if soft eraser, must analyze points to be sure the stroke ends * don't get rounded */ if (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_SOFT) { - gp_stroke_soft_refine(gps); + gpencil_stroke_soft_refine(gps); } - gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); } - gp_update_cache(p->gpd); + gpencil_update_cache(p->gpd); } } /* erase strokes which fall under the eraser strokes */ -static void gp_stroke_doeraser(tGPsdata *p) +static void gpencil_stroke_doeraser(tGPsdata *p) { rcti rect; Brush *brush = p->brush; @@ -1710,7 +1719,7 @@ static void gp_stroke_doeraser(tGPsdata *p) * (e.g. 2D space strokes in the 3D view, if the same datablock is shared) */ if (ED_gpencil_stroke_can_use_direct(p->area, gps)) { - gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, calc_radius, &rect); + gpencil_stroke_eraser_dostroke(p, gpf, gps, p->mval, calc_radius, &rect); } } } @@ -1720,7 +1729,7 @@ static void gp_stroke_doeraser(tGPsdata *p) /* Sketching Operator */ /* clear the session buffers (call this before AND after a paint operation) */ -static void gp_session_validatebuffer(tGPsdata *p) +static void gpencil_session_validatebuffer(tGPsdata *p) { bGPdata *gpd = p->gpd; Brush *brush = p->brush; @@ -1742,7 +1751,7 @@ static void gp_session_validatebuffer(tGPsdata *p) } /* helper to get default eraser and create one if no eraser brush */ -static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts) +static Brush *gpencil_get_default_eraser(Main *bmain, ToolSettings *ts) { Brush *brush_dft = NULL; Paint *paint = &ts->gp_paint->paint; @@ -1784,7 +1793,7 @@ static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts) } /* helper to set default eraser and disable others */ -static void gp_set_default_eraser(Main *bmain, Brush *brush_dft) +static void gpencil_set_default_eraser(Main *bmain, Brush *brush_dft) { if (brush_dft == NULL) { return; @@ -1803,7 +1812,7 @@ static void gp_set_default_eraser(Main *bmain, Brush *brush_dft) } /* initialize a drawing brush */ -static void gp_init_drawing_brush(bContext *C, tGPsdata *p) +static void gpencil_init_drawing_brush(bContext *C, tGPsdata *p) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -1831,13 +1840,13 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p) /* assign to temp tGPsdata */ p->brush = paint->brush; if (paint->brush->gpencil_tool != GPAINT_TOOL_ERASE) { - p->eraser = gp_get_default_eraser(p->bmain, ts); + p->eraser = gpencil_get_default_eraser(p->bmain, ts); } else { p->eraser = paint->brush; } /* set new eraser as default */ - gp_set_default_eraser(p->bmain, p->eraser); + gpencil_set_default_eraser(p->bmain, p->eraser); /* use radius of eraser */ p->radius = (short)p->eraser->size; @@ -1849,7 +1858,7 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p) } /* initialize a paint brush and a default color if not exist */ -static void gp_init_colors(tGPsdata *p) +static void gpencil_init_colors(tGPsdata *p) { bGPdata *gpd = p->gpd; Brush *brush = p->brush; @@ -1862,7 +1871,7 @@ static void gp_init_colors(tGPsdata *p) } /* (re)init new painting data */ -static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) +static bool gpencil_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) { Main *bmain = CTX_data_main(C); bGPdata **gpd_ptr = NULL; @@ -1959,15 +1968,15 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) } /* clear out buffer (stored in gp-data), in case something contaminated it */ - gp_session_validatebuffer(p); + gpencil_session_validatebuffer(p); /* set brush and create a new one if null */ - gp_init_drawing_brush(C, p); + gpencil_init_drawing_brush(C, p); /* setup active color */ /* region where paint was originated */ int totcol = p->ob->totcol; - gp_init_colors(p); + gpencil_init_colors(p); /* check whether the material was newly added */ if (totcol != p->ob->totcol) { @@ -1987,7 +1996,7 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) } /* init new painting session */ -static tGPsdata *gp_session_initpaint(bContext *C, wmOperator *op) +static tGPsdata *gpencil_session_initpaint(bContext *C, wmOperator *op) { tGPsdata *p = NULL; @@ -1997,7 +2006,7 @@ static tGPsdata *gp_session_initpaint(bContext *C, wmOperator *op) /* Try to initialize context data * WARNING: This may not always succeed (e.g. using GP in an annotation-only context) */ - if (gp_session_initdata(C, op, p) == 0) { + if (gpencil_session_initdata(C, op, p) == 0) { /* Invalid state - Exit * NOTE: It should be safe to just free the data, since failing context checks should * only happen when no data has been allocated. @@ -2016,7 +2025,7 @@ static tGPsdata *gp_session_initpaint(bContext *C, wmOperator *op) } /* cleanup after a painting session */ -static void gp_session_cleanup(tGPsdata *p) +static void gpencil_session_cleanup(tGPsdata *p) { bGPdata *gpd = (p) ? p->gpd : NULL; @@ -2038,7 +2047,7 @@ static void gp_session_cleanup(tGPsdata *p) p->inittime = 0.0; } -static void gp_session_free(tGPsdata *p) +static void gpencil_session_free(tGPsdata *p) { if (p->rng != NULL) { BLI_rng_free(p->rng); @@ -2048,7 +2057,9 @@ static void gp_session_free(tGPsdata *p) } /* init new stroke */ -static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Depsgraph *depsgraph) +static void gpencil_paint_initstroke(tGPsdata *p, + eGPencil_PaintModes paintmode, + Depsgraph *depsgraph) { Scene *scene = p->scene; ToolSettings *ts = scene->toolsettings; @@ -2209,12 +2220,12 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps gpd_eval->runtime.sbuffer_brush = p->gpd->runtime.sbuffer_brush; } else { - gp_update_cache(p->gpd); + gpencil_update_cache(p->gpd); } } /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */ -static void gp_paint_strokeend(tGPsdata *p) +static void gpencil_paint_strokeend(tGPsdata *p) { ToolSettings *ts = p->scene->toolsettings; /* for surface sketching, need to set the right OpenGL context stuff so that @@ -2232,22 +2243,22 @@ static void gp_paint_strokeend(tGPsdata *p) /* check if doing eraser or not */ if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) { /* transfer stroke to frame */ - gp_stroke_newfrombuffer(p); + gpencil_stroke_newfrombuffer(p); } /* clean up buffer now */ - gp_session_validatebuffer(p); + gpencil_session_validatebuffer(p); } /* finish off stroke painting operation */ -static void gp_paint_cleanup(tGPsdata *p) +static void gpencil_paint_cleanup(tGPsdata *p) { /* p->gpd==NULL happens when stroke failed to initialize, * for example when GP is hidden in current space (sergey) */ if (p->gpd) { /* finish off a stroke */ - gp_paint_strokeend(p); + gpencil_paint_strokeend(p); } /* "unlock" frame */ @@ -2357,19 +2368,19 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op) else { /* drawing batch cache is dirty now */ bGPdata *gpd = CTX_data_gpencil_data(C); - gp_update_cache(gpd); + gpencil_update_cache(gpd); } /* clear undo stack */ gpencil_undo_finish(); /* cleanup */ - gp_paint_cleanup(p); - gp_session_cleanup(p); + gpencil_paint_cleanup(p); + gpencil_session_cleanup(p); ED_gpencil_toggle_brush_cursor(C, true, NULL); /* finally, free the temp data */ - gp_session_free(p); + gpencil_session_free(p); p = NULL; } @@ -2399,7 +2410,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) } /* check context */ - p = op->customdata = gp_session_initpaint(C, op); + p = op->customdata = gpencil_session_initpaint(C, op); if ((p == NULL) || (p->status == GP_STATUS_ERROR)) { /* something wasn't set correctly in context */ gpencil_draw_exit(C, op); @@ -2407,7 +2418,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) } /* init painting data */ - gp_paint_initstroke(p, paintmode, CTX_data_ensure_evaluated_depsgraph(C)); + gpencil_paint_initstroke(p, paintmode, CTX_data_ensure_evaluated_depsgraph(C)); if (p->status == GP_STATUS_ERROR) { gpencil_draw_exit(C, op); return 0; @@ -2493,10 +2504,10 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) /* ------------------------------- */ /* Helper to rotate point around origin */ -static void gp_rotate_v2_v2v2fl(float v[2], - const float p[2], - const float origin[2], - const float angle) +static void gpencil_rotate_v2_v2v2fl(float v[2], + const float p[2], + const float origin[2], + const float angle) { float pt[2]; float r[2]; @@ -2506,7 +2517,7 @@ static void gp_rotate_v2_v2v2fl(float v[2], } /* Helper to snap value to grid */ -static float gp_snap_to_grid_fl(float v, const float offset, const float spacing) +static float gpencil_snap_to_grid_fl(float v, const float offset, const float spacing) { if (spacing > 0.0f) { v -= spacing * 0.5f; @@ -2521,25 +2532,25 @@ static float gp_snap_to_grid_fl(float v, const float offset, const float spacing } /* Helper to snap value to grid */ -static void gp_snap_to_rotated_grid_fl(float v[2], - const float origin[2], - const float spacing, - const float angle) +static void gpencil_snap_to_rotated_grid_fl(float v[2], + const float origin[2], + const float spacing, + const float angle) { - gp_rotate_v2_v2v2fl(v, v, origin, -angle); - v[1] = gp_snap_to_grid_fl(v[1], origin[1], spacing); - gp_rotate_v2_v2v2fl(v, v, origin, angle); + gpencil_rotate_v2_v2v2fl(v, v, origin, -angle); + v[1] = gpencil_snap_to_grid_fl(v[1], origin[1], spacing); + gpencil_rotate_v2_v2v2fl(v, v, origin, angle); } /* get reference point - screen coords to buffer coords */ -static void gp_origin_set(wmOperator *op, const int mval[2]) +static void gpencil_origin_set(wmOperator *op, const int mval[2]) { tGPsdata *p = op->customdata; GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide; float origin[2]; float point[3]; copy_v2fl_v2i(origin, mval); - gp_stroke_convertcoords(p, origin, point, NULL); + gpencil_stroke_convertcoords(p, origin, point, NULL); if (guide->reference_point == GP_GUIDE_REF_CUSTOM) { copy_v3_v3(guide->location, point); } @@ -2549,7 +2560,7 @@ static void gp_origin_set(wmOperator *op, const int mval[2]) } /* get reference point - buffer coords to screen coords */ -static void gp_origin_get(tGPsdata *p, float origin[2]) +static void gpencil_origin_get(tGPsdata *p, float origin[2]) { GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide; float location[3]; @@ -2563,7 +2574,7 @@ static void gp_origin_get(tGPsdata *p, float origin[2]) copy_v3_v3(location, p->scene->cursor.location); } GP_SpaceConversion *gsc = &p->gsc; - gp_point_3d_to_xy(gsc, p->gpd->runtime.sbuffer_sflag, location, origin); + gpencil_point_3d_to_xy(gsc, p->gpd->runtime.sbuffer_sflag, location, origin); } /* speed guide initial values */ @@ -2574,7 +2585,7 @@ static void gpencil_speed_guide_init(tGPsdata *p, GP_Sculpt_Guide *guide) float scale = 1.0f; if (rv3d->is_persp) { float vec[3]; - gp_get_3d_reference(p, vec); + gpencil_get_3d_reference(p, vec); mul_m4_v3(rv3d->persmat, vec); scale = vec[2] * rv3d->pixsize; } @@ -2583,7 +2594,7 @@ static void gpencil_speed_guide_init(tGPsdata *p, GP_Sculpt_Guide *guide) } p->guide.spacing = guide->spacing / scale; p->guide.half_spacing = p->guide.spacing * 0.5f; - gp_origin_get(p, p->guide.origin); + gpencil_origin_get(p, p->guide.origin); /* reference for angled snap */ copy_v2_v2(p->guide.unit, p->mvali); @@ -2595,7 +2606,7 @@ static void gpencil_speed_guide_init(tGPsdata *p, GP_Sculpt_Guide *guide) p->guide.origin_distance = len_v2v2(p->mvali, p->guide.origin); if (guide->use_snapping && (guide->spacing > 0.0f)) { - p->guide.origin_distance = gp_snap_to_grid_fl( + p->guide.origin_distance = gpencil_snap_to_grid_fl( p->guide.origin_distance, 0.0f, p->guide.spacing); } @@ -2605,10 +2616,10 @@ static void gpencil_speed_guide_init(tGPsdata *p, GP_Sculpt_Guide *guide) angle = p->guide.origin_angle + guide->angle; angle = fmodf(angle + half_angle, guide->angle_snap); angle -= half_angle; - gp_rotate_v2_v2v2fl(p->guide.rot_point, p->mvali, p->guide.origin, -angle); + gpencil_rotate_v2_v2v2fl(p->guide.rot_point, p->mvali, p->guide.origin, -angle); } else { - gp_rotate_v2_v2v2fl(p->guide.rot_point, p->guide.unit, p->mvali, guide->angle); + gpencil_rotate_v2_v2v2fl(p->guide.rot_point, p->guide.unit, p->mvali, guide->angle); } } @@ -2633,14 +2644,15 @@ static void gpencil_snap_to_guide(const tGPsdata *p, const GP_Sculpt_Guide *guid case GP_GUIDE_PARALLEL: { closest_to_line_v2(point, point, p->mvali, p->guide.rot_point); if (guide->use_snapping && (guide->spacing > 0.0f)) { - gp_snap_to_rotated_grid_fl(point, p->guide.origin, p->guide.spacing, guide->angle); + gpencil_snap_to_rotated_grid_fl(point, p->guide.origin, p->guide.spacing, guide->angle); } break; } case GP_GUIDE_ISO: { closest_to_line_v2(point, point, p->mvali, p->guide.rot_point); if (guide->use_snapping && (guide->spacing > 0.0f)) { - gp_snap_to_rotated_grid_fl(point, p->guide.origin, p->guide.spacing, p->guide.rot_angle); + gpencil_snap_to_rotated_grid_fl( + point, p->guide.origin, p->guide.spacing, p->guide.rot_angle); } break; } @@ -2648,10 +2660,10 @@ static void gpencil_snap_to_guide(const tGPsdata *p, const GP_Sculpt_Guide *guid if (guide->use_snapping && (guide->spacing > 0.0f)) { closest_to_line_v2(point, point, p->mvali, p->guide.rot_point); if (p->straight == STROKE_HORIZONTAL) { - point[1] = gp_snap_to_grid_fl(point[1], p->guide.origin[1], p->guide.spacing); + point[1] = gpencil_snap_to_grid_fl(point[1], p->guide.origin[1], p->guide.spacing); } else { - point[0] = gp_snap_to_grid_fl(point[0], p->guide.origin[0], p->guide.spacing); + point[0] = gpencil_snap_to_grid_fl(point[0], p->guide.origin[0], p->guide.spacing); } } else if (p->straight == STROKE_HORIZONTAL) { @@ -2674,7 +2686,7 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra /* handle drawing/erasing -> test for erasing first */ if (p->paintmode == GP_PAINTMODE_ERASER) { /* do 'live' erasing now */ - gp_stroke_doeraser(p); + gpencil_stroke_doeraser(p); /* store used values */ copy_v2_v2(p->mvalo, p->mval); @@ -2682,7 +2694,7 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra } /* Only add current point to buffer if mouse moved * (even though we got an event, it might be just noise). */ - else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) { + else if (gpencil_stroke_filtermval(p, p->mval, p->mvalo)) { /* if lazy mouse, interpolate the last and current mouse positions */ if (GPENCIL_LAZY_MODE(p->brush, p->shift)) { @@ -2702,26 +2714,26 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra } /* try to add point */ - short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); + short ok = gpencil_stroke_addpoint(p, p->mval, p->pressure, p->curtime); /* handle errors while adding point */ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) { /* finish off old stroke */ - gp_paint_strokeend(p); + gpencil_paint_strokeend(p); /* And start a new one!!! Else, projection errors! */ - gp_paint_initstroke(p, p->paintmode, depsgraph); + gpencil_paint_initstroke(p, p->paintmode, depsgraph); /* start a new stroke, starting from previous point */ /* XXX Must manually reset inittime... */ /* XXX We only need to reuse previous point if overflow! */ if (ok == GP_STROKEADD_OVERFLOW) { p->inittime = p->ocurtime; - gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime); + gpencil_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime); } else { p->inittime = p->curtime; } - gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); + gpencil_stroke_addpoint(p, p->mval, p->pressure, p->curtime); } else if (ok == GP_STROKEADD_INVALID) { /* the painting operation cannot continue... */ @@ -2889,13 +2901,13 @@ static void gpencil_draw_apply_event(bContext *C, else { p->guide.rot_angle = DEG2RAD(90); } - gp_rotate_v2_v2v2fl(p->guide.rot_point, p->guide.unit, p->mvali, p->guide.rot_angle); + gpencil_rotate_v2_v2v2fl(p->guide.rot_point, p->guide.unit, p->mvali, p->guide.rot_angle); } else if (ELEM(guide->type, GP_GUIDE_GRID)) { - gp_rotate_v2_v2v2fl(p->guide.rot_point, - p->guide.unit, - p->mvali, - (p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f); + gpencil_rotate_v2_v2v2fl(p->guide.rot_point, + p->guide.unit, + p->mvali, + (p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f); } } @@ -2968,8 +2980,8 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) */ if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) { /* TODO: both of these ops can set error-status, but we probably don't need to worry */ - gp_paint_strokeend(p); - gp_paint_initstroke(p, p->paintmode, depsgraph); + gpencil_paint_strokeend(p); + gpencil_paint_initstroke(p, p->paintmode, depsgraph); } } @@ -3227,8 +3239,8 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) } /* we may need to set up paint env again if we're resuming */ - if (gp_session_initdata(C, op, p)) { - gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph_pointer(C)); + if (gpencil_session_initdata(C, op, p)) { + gpencil_paint_initstroke(p, p->paintmode, CTX_data_depsgraph_pointer(C)); } if (p->status != GP_STATUS_ERROR) { @@ -3240,7 +3252,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) } /* Apply pressure change depending of the angle of the stroke for a segment. */ -static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *pt) +static void gpencil_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *pt) { Brush *brush = p->brush; /* Sensitivity. */ @@ -3284,7 +3296,7 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) /* Apply other randomness to first points. */ for (int i = 0; i < gpd->runtime.sbuffer_used; i++) { tGPspoint *pt = &points[i]; - gp_apply_randomness(p, brush_settings, pt, false, false, true); + gpencil_apply_randomness(p, brush_settings, pt, false, false, true); } return; } @@ -3359,14 +3371,14 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) /* Apply angle of stroke to brush size to interpolated points but slightly attenuated.. */ if (brush_settings->draw_angle_factor != 0.0f) { - gp_brush_angle_segment(p, pt_step, pt); + gpencil_brush_angle_segment(p, pt_step, pt); CLAMP(pt->pressure, pt_prev->pressure * 0.5f, 1.0f); /* Use the previous interpolated point for next segment. */ pt_step = pt; } /* Apply other randomness. */ - gp_apply_randomness(p, brush_settings, pt, false, false, true); + gpencil_apply_randomness(p, brush_settings, pt, false, false, true); a += step; } @@ -3411,7 +3423,7 @@ static void gpencil_add_guide_points(const tGPsdata *p, for (int i = 0; i < segments; i++) { pt = &points[idx_prev + i - 1]; - gp_rotate_v2_v2v2fl(&pt->x, start, p->guide.origin, -a); + gpencil_rotate_v2_v2v2fl(&pt->x, start, p->guide.origin, -a); gpencil_snap_to_guide(p, guide, &pt->x); a += step; @@ -3547,7 +3559,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* set */ case LEFTMOUSE: { if (ELEM(event->val, KM_RELEASE)) { - gp_origin_set(op, event->mval); + gpencil_origin_set(op, event->mval); drawmode = true; } break; @@ -3750,7 +3762,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) * the 0.15 value gets a good result in Windows and Linux. */ if (!is_speed_guide && (size_after - size_before > 1)) { for (int r = 0; r < 5; r++) { - gp_smooth_segment(p->gpd, 0.15f, size_before - 1, size_after - 1); + gpencil_smooth_segment(p->gpd, 0.15f, size_before - 1, size_after - 1); } } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 82ae99b30be..6bb9f9628fa 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -111,7 +111,7 @@ /* Core/Shared Utilities */ /* clear the session buffers (call this before AND after a paint operation) */ -static void gp_session_validatebuffer(tGPDprimitive *p) +static void gpencil_session_validatebuffer(tGPDprimitive *p) { bGPdata *gpd = p->gpd; @@ -137,7 +137,7 @@ static void gp_session_validatebuffer(tGPDprimitive *p) } } -static void gp_init_colors(tGPDprimitive *p) +static void gpencil_init_colors(tGPDprimitive *p) { bGPdata *gpd = p->gpd; Brush *brush = p->brush; @@ -196,10 +196,10 @@ static void gpencil_primitive_constrain(tGPDprimitive *tgpi, bool line_mode) } /* Helper to rotate point around origin */ -static void gp_rotate_v2_v2v2fl(float v[2], - const float p[2], - const float origin[2], - const float angle) +static void gpencil_rotate_v2_v2v2fl(float v[2], + const float p[2], + const float origin[2], + const float angle) { float pt[2]; float r[2]; @@ -209,17 +209,17 @@ static void gp_rotate_v2_v2v2fl(float v[2], } /* Helper to rotate line around line center. */ -static void gp_primitive_rotate_line( +static void gpencil_primitive_rotate_line( float va[2], float vb[2], const float a[2], const float b[2], const float angle) { float midpoint[2]; mid_v2_v2v2(midpoint, a, b); - gp_rotate_v2_v2v2fl(va, a, midpoint, angle); - gp_rotate_v2_v2v2fl(vb, b, midpoint, angle); + gpencil_rotate_v2_v2v2fl(va, a, midpoint, angle); + gpencil_rotate_v2_v2v2fl(vb, b, midpoint, angle); } /* Helper to update cps */ -static void gp_primitive_update_cps(tGPDprimitive *tgpi) +static void gpencil_primitive_update_cps(tGPDprimitive *tgpi) { if (!tgpi->curve) { mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end); @@ -233,10 +233,10 @@ static void gp_primitive_update_cps(tGPDprimitive *tgpi) } else if (tgpi->type == GP_STROKE_ARC) { if (tgpi->flip) { - gp_primitive_rotate_line(tgpi->cp1, tgpi->cp2, tgpi->start, tgpi->end, M_PI_2); + gpencil_primitive_rotate_line(tgpi->cp1, tgpi->cp2, tgpi->start, tgpi->end, M_PI_2); } else { - gp_primitive_rotate_line(tgpi->cp1, tgpi->cp2, tgpi->end, tgpi->start, M_PI_2); + gpencil_primitive_rotate_line(tgpi->cp1, tgpi->cp2, tgpi->end, tgpi->start, M_PI_2); } } } @@ -294,7 +294,7 @@ static void gpencil_primitive_allocate_memory(tGPDprimitive *tgpi) /* ****************** Primitive Interactive *********************** */ /* Helper: Create internal strokes primitives data */ -static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) +static void gpencil_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; @@ -378,7 +378,7 @@ static void gpencil_primitive_add_segment(tGPDprimitive *tgpi) } /* Helper: set control point */ -static void gp_primitive_set_cp(tGPDprimitive *tgpi, float p[2], float color[4], int size) +static void gpencil_primitive_set_cp(tGPDprimitive *tgpi, float p[2], float color[4], int size) { if (tgpi->flag == IN_PROGRESS) { return; @@ -500,7 +500,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi } /* create a rectangle */ -static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D) +static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D) { float coords[5][2]; @@ -531,20 +531,20 @@ static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D) mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end); float color[4]; UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); - gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); if (tgpi->tot_stored_edges) { UI_GetThemeColor4fv(TH_REDALERT, color); - gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); } else { - gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); } UI_GetThemeColor4fv(TH_REDALERT, color); - gp_primitive_set_cp(tgpi, tgpi->midpoint, color, SMALL_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->midpoint, color, SMALL_SIZE_CTL); } /* create a line */ -static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, bool editable) +static void gpencil_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, bool editable) { const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges); const float step = 1.0f / (float)(tgpi->tot_edges - 1); @@ -559,24 +559,24 @@ static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, bool edi if (editable) { float color[4]; UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); - gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); if (tgpi->tot_stored_edges) { UI_GetThemeColor4fv(TH_REDALERT, color); - gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); } else { - gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); } } else { float color[4]; UI_GetThemeColor4fv(TH_REDALERT, color); - gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); } } /* create an arc */ -static void gp_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D) +static void gpencil_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D) { const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges); const float step = M_PI_2 / (float)(tgpi->tot_edges - 1); @@ -604,20 +604,20 @@ static void gp_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D) } float color[4]; UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); - gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); if (tgpi->tot_stored_edges) { UI_GetThemeColor4fv(TH_REDALERT, color); - gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); } else { - gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); } UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color); - gp_primitive_set_cp(tgpi, tgpi->cp1, color, BIG_SIZE_CTL * 0.9f); + gpencil_primitive_set_cp(tgpi, tgpi->cp1, color, BIG_SIZE_CTL * 0.9f); } /* create a bezier */ -static void gp_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D) +static void gpencil_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D) { const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges); const float step = 1.0f / (float)(tgpi->tot_edges - 1); @@ -639,21 +639,21 @@ static void gp_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D) } float color[4]; UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); - gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); if (tgpi->tot_stored_edges) { UI_GetThemeColor4fv(TH_REDALERT, color); - gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); } else { - gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); } UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color); - gp_primitive_set_cp(tgpi, tgpi->cp1, color, BIG_SIZE_CTL * 0.9f); - gp_primitive_set_cp(tgpi, tgpi->cp2, color, BIG_SIZE_CTL * 0.9f); + gpencil_primitive_set_cp(tgpi, tgpi->cp1, color, BIG_SIZE_CTL * 0.9f); + gpencil_primitive_set_cp(tgpi, tgpi->cp2, color, BIG_SIZE_CTL * 0.9f); } /* create a circle */ -static void gp_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D) +static void gpencil_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D) { const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges); const float step = (2.0f * M_PI) / (float)(tgpi->tot_edges); @@ -674,14 +674,14 @@ static void gp_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D) } float color[4]; UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); - gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); - gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); UI_GetThemeColor4fv(TH_REDALERT, color); - gp_primitive_set_cp(tgpi, center, color, SMALL_SIZE_CTL); + gpencil_primitive_set_cp(tgpi, center, color, SMALL_SIZE_CTL); } /* Helper: Update shape of the stroke */ -static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) +static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) { ToolSettings *ts = tgpi->scene->toolsettings; bGPdata *gpd = tgpi->gpd; @@ -715,30 +715,30 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) if (tgpi->tot_edges > 1) { switch (tgpi->type) { case GP_STROKE_BOX: - gp_primitive_rectangle(tgpi, points2D); + gpencil_primitive_rectangle(tgpi, points2D); break; case GP_STROKE_LINE: - gp_primitive_line(tgpi, points2D, true); + gpencil_primitive_line(tgpi, points2D, true); break; case GP_STROKE_POLYLINE: - gp_primitive_line(tgpi, points2D, false); + gpencil_primitive_line(tgpi, points2D, false); break; case GP_STROKE_CIRCLE: - gp_primitive_circle(tgpi, points2D); + gpencil_primitive_circle(tgpi, points2D); break; case GP_STROKE_ARC: - gp_primitive_arc(tgpi, points2D); + gpencil_primitive_arc(tgpi, points2D); break; case GP_STROKE_CURVE: - gp_primitive_bezier(tgpi, points2D); + gpencil_primitive_bezier(tgpi, points2D); default: break; } } /* convert screen-coordinates to 3D coordinates */ - gp_session_validatebuffer(tgpi); - gp_init_colors(tgpi); + gpencil_session_validatebuffer(tgpi); + gpencil_init_colors(tgpi); if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) { BKE_curvemapping_initialize(ts->gp_sculpt.cur_primitive); } @@ -982,12 +982,12 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) ED_gpencil_drawing_reference_get(tgpi->scene, tgpi->ob, ts->gpencil_v3d_align, origin); /* reproject current */ ED_gpencil_tpoint_to_point(tgpi->region, origin, tpt, &spt); - ED_gp_project_point_to_plane( + ED_gpencil_project_point_to_plane( tgpi->scene, tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt); /* reproject previous */ ED_gpencil_tpoint_to_point(tgpi->region, origin, tptb, &spt2); - ED_gp_project_point_to_plane( + ED_gpencil_project_point_to_plane( tgpi->scene, tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt2); tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x); tpt->uv_fac = tgpi->totpixlen; @@ -1011,7 +1011,7 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) } /* convert screen-coordinates to 3D coordinates */ - gp_stroke_convertcoords_tpoint( + gpencil_stroke_convertcoords_tpoint( tgpi->scene, tgpi->region, tgpi->ob, p2d, depth_arr ? depth_arr + i : NULL, &pt->x); pt->pressure = pressure; @@ -1036,7 +1036,7 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) bGPDcontrolpoint *cps = tgpi->gpd->runtime.cp_points; for (int i = 0; i < tgpi->gpd->runtime.tot_cp_points; i++) { bGPDcontrolpoint *cp = &cps[i]; - gp_stroke_convertcoords_tpoint( + gpencil_stroke_convertcoords_tpoint( tgpi->scene, tgpi->region, tgpi->ob, (tGPspoint *)cp, NULL, &cp->x); } } @@ -1045,14 +1045,14 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) if (!is_depth) { float origin[3]; ED_gpencil_drawing_reference_get(tgpi->scene, tgpi->ob, ts->gpencil_v3d_align, origin); - ED_gp_project_stroke_to_plane( + ED_gpencil_project_stroke_to_plane( tgpi->scene, tgpi->ob, tgpi->rv3d, gps, origin, ts->gp_sculpt.lock_axis - 1); } /* if parented change position relative to parent object */ for (int i = 0; i < gps->totpoints; i++) { bGPDspoint *pt = &gps->points[i]; - gp_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt); + gpencil_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt); } /* if camera view, reproject flat to view to avoid perspective effect */ @@ -1082,7 +1082,7 @@ static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive tgpi->type = RNA_enum_get(op->ptr, "type"); tgpi->tot_edges = RNA_int_get(op->ptr, "edges"); /* update points position */ - gp_primitive_update_strokes(C, tgpi); + gpencil_primitive_update_strokes(C, tgpi); } /* Initialise mouse points */ @@ -1237,7 +1237,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) tgpi->lock_axis = ts->gp_sculpt.lock_axis; /* set temp layer, frame and stroke */ - gp_primitive_set_initdata(C, tgpi); + gpencil_primitive_set_initdata(C, tgpi); } /* Invoke handler: Initialize the operator */ @@ -1396,14 +1396,14 @@ static void gpencil_primitive_edit_event_handling( gpencil_primitive_add_segment(tgpi); copy_v2_v2(tgpi->start, tgpi->end); copy_v2_v2(tgpi->origin, tgpi->start); - gp_primitive_update_cps(tgpi); + gpencil_primitive_update_cps(tgpi); tgpi->flag = IN_POLYLINE; WM_cursor_modal_set(win, WM_CURSOR_CROSS); } else { tgpi->flag = IN_CURVE_EDIT; - gp_primitive_update_cps(tgpi); + gpencil_primitive_update_cps(tgpi); gpencil_primitive_update(C, op, tgpi); } } @@ -1460,7 +1460,7 @@ static void gpencil_primitive_edit_event_handling( case EVT_MKEY: { if ((event->val == KM_PRESS) && (tgpi->curve) && (ELEM(tgpi->orign_type, GP_STROKE_ARC))) { tgpi->flip ^= 1; - gp_primitive_update_cps(tgpi); + gpencil_primitive_update_cps(tgpi); gpencil_primitive_update(C, op, tgpi); } break; @@ -1472,7 +1472,7 @@ static void gpencil_primitive_edit_event_handling( gpencil_primitive_add_segment(tgpi); copy_v2_v2(tgpi->start, tgpi->end); copy_v2_v2(tgpi->origin, tgpi->start); - gp_primitive_update_cps(tgpi); + gpencil_primitive_update_cps(tgpi); } break; } @@ -1625,7 +1625,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e if (event->val == KM_PRESS) { tgpi->flag = IDLE; tgpi->tot_edges = tgpi->tot_stored_edges ? 1 : 0; - gp_primitive_update_strokes(C, tgpi); + gpencil_primitive_update_strokes(C, tgpi); gpencil_primitive_interaction_end(C, op, win, tgpi); return OPERATOR_FINISHED; } @@ -1749,7 +1749,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e (!ELEM(tgpi->type, GP_STROKE_POLYLINE))) { /* set control points and enter edit mode */ tgpi->flag = IN_CURVE_EDIT; - gp_primitive_update_cps(tgpi); + gpencil_primitive_update_cps(tgpi); gpencil_primitive_update(C, op, tgpi); } else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) && @@ -1792,7 +1792,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e if (tgpi->tot_stored_edges > 0) { tgpi->flag = IDLE; tgpi->tot_edges = tgpi->tot_stored_edges ? 1 : 0; - gp_primitive_update_strokes(C, tgpi); + gpencil_primitive_update_strokes(C, tgpi); gpencil_primitive_interaction_end(C, op, win, tgpi); /* done! */ return OPERATOR_FINISHED; @@ -1871,7 +1871,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e } RNA_enum_set(op->ptr, "type", tgpi->type); - gp_primitive_update_cps(tgpi); + gpencil_primitive_update_cps(tgpi); gpencil_primitive_update(C, op, tgpi); } break; @@ -1880,7 +1880,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e if (tgpi->flag == IN_CURVE_EDIT) { tgpi->flag = IN_PROGRESS; WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); - gp_primitive_update_cps(tgpi); + gpencil_primitive_update_cps(tgpi); gpencil_primitive_update(C, op, tgpi); } break; @@ -1908,7 +1908,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e tgpi->start[0] = tgpi->origin[0] - (tgpi->end[0] - tgpi->origin[0]); tgpi->start[1] = tgpi->origin[1] - (tgpi->end[1] - tgpi->origin[1]); } - gp_primitive_update_cps(tgpi); + gpencil_primitive_update_cps(tgpi); /* update screen */ gpencil_primitive_update(C, op, tgpi); } diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 6bd945160a6..d0adcea25c1 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -172,9 +172,9 @@ typedef bool (*GP_BrushApplyCb)(tGP_BrushEditData *gso, /* Utility Functions */ /* apply lock axis reset */ -static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, - bGPDspoint *pt, - const float save_pt[3]) +static void gpencil_sculpt_compute_lock_axis(tGP_BrushEditData *gso, + bGPDspoint *pt, + const float save_pt[3]) { const ToolSettings *ts = gso->scene->toolsettings; const View3DCursor *cursor = &gso->scene->cursor; @@ -221,7 +221,7 @@ static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, /* Context ---------------------------------------- */ /* Get the sculpting settings */ -static GP_Sculpt_Settings *gpsculpt_get_settings(Scene *scene) +static GP_Sculpt_Settings *gpencil_sculpt_get_settings(Scene *scene) { return &scene->toolsettings->gp_sculpt; } @@ -229,7 +229,7 @@ static GP_Sculpt_Settings *gpsculpt_get_settings(Scene *scene) /* Brush Operations ------------------------------- */ /* Invert behavior of brush? */ -static bool gp_brush_invert_check(tGP_BrushEditData *gso) +static bool gpencil_brush_invert_check(tGP_BrushEditData *gso) { /* The basic setting is the brush's setting (from the panel) */ bool invert = ((gso->brush->gpencil_settings->sculpt_flag & GP_SCULPT_FLAG_INVERT) != 0) || @@ -251,7 +251,9 @@ static bool gp_brush_invert_check(tGP_BrushEditData *gso) } /* Compute strength of effect */ -static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2]) +static float gpencil_brush_influence_calc(tGP_BrushEditData *gso, + const int radius, + const int co[2]) { Brush *brush = gso->brush; @@ -322,14 +324,14 @@ static void gpencil_update_geometry(bGPdata *gpd) /* A simple (but slower + inaccurate) * smooth-brush implementation to test the algorithm for stroke smoothing. */ -static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, - bGPDstroke *gps, - float UNUSED(rot_eval), - int pt_index, - const int radius, - const int co[2]) +static bool gpencil_brush_smooth_apply(tGP_BrushEditData *gso, + bGPDstroke *gps, + float UNUSED(rot_eval), + int pt_index, + const int radius, + const int co[2]) { - float inf = gp_brush_influence_calc(gso, radius, co); + float inf = gpencil_brush_influence_calc(gso, radius, co); /* perform smoothing */ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) { @@ -352,12 +354,12 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, /* Line Thickness Brush */ /* Make lines thicker or thinner by the specified amounts */ -static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, - bGPDstroke *gps, - float UNUSED(rot_eval), - int pt_index, - const int radius, - const int co[2]) +static bool gpencil_brush_thickness_apply(tGP_BrushEditData *gso, + bGPDstroke *gps, + float UNUSED(rot_eval), + int pt_index, + const int radius, + const int co[2]) { bGPDspoint *pt = gps->points + pt_index; float inf; @@ -366,12 +368,12 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, * - We divide the strength by 10, so that users can set "sane" values. * Otherwise, good default values are in the range of 0.093 */ - inf = gp_brush_influence_calc(gso, radius, co) / 10.0f; + inf = gpencil_brush_influence_calc(gso, radius, co) / 10.0f; /* apply */ /* XXX: this is much too strong, * and it should probably do some smoothing with the surrounding stuff. */ - if (gp_brush_invert_check(gso)) { + if (gpencil_brush_invert_check(gso)) { /* make line thinner - reduce stroke pressure */ pt->pressure -= inf; } @@ -396,21 +398,21 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, /* Color Strength Brush */ /* Make color more or less transparent by the specified amounts */ -static bool gp_brush_strength_apply(tGP_BrushEditData *gso, - bGPDstroke *gps, - float UNUSED(rot_eval), - int pt_index, - const int radius, - const int co[2]) +static bool gpencil_brush_strength_apply(tGP_BrushEditData *gso, + bGPDstroke *gps, + float UNUSED(rot_eval), + int pt_index, + const int radius, + const int co[2]) { bGPDspoint *pt = gps->points + pt_index; float inf; /* Compute strength of effect */ - inf = gp_brush_influence_calc(gso, radius, co) * 0.125f; + inf = gpencil_brush_influence_calc(gso, radius, co) * 0.125f; /* Invert effect. */ - if (gp_brush_invert_check(gso)) { + if (gpencil_brush_invert_check(gso)) { inf *= -1.0f; } @@ -443,7 +445,7 @@ typedef struct tGPSB_Grab_StrokeData { } tGPSB_Grab_StrokeData; /* initialise custom data for handling this stroke */ -static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps) +static void gpencil_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps) { tGPSB_Grab_StrokeData *data = NULL; @@ -481,15 +483,15 @@ static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps) } /* store references to stroke points in the initial stage */ -static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, - bGPDstroke *gps, - float rot_eval, - int pt_index, - const int radius, - const int co[2]) +static bool gpencil_brush_grab_store_points(tGP_BrushEditData *gso, + bGPDstroke *gps, + float rot_eval, + int pt_index, + const int radius, + const int co[2]) { tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps); - float inf = gp_brush_influence_calc(gso, radius, co); + float inf = gpencil_brush_influence_calc(gso, radius, co); BLI_assert(data != NULL); BLI_assert(data->size < data->capacity); @@ -505,7 +507,7 @@ static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, } /* Compute effect vector for grab brush */ -static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso) +static void gpencil_brush_grab_calc_dvec(tGP_BrushEditData *gso) { /* Convert mouse-movements to movement vector */ RegionView3D *rv3d = gso->region->regiondata; @@ -532,9 +534,9 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso) } /* Apply grab transform to all relevant points of the affected strokes */ -static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, - bGPDstroke *gps, - const float diff_mat[4][4]) +static void gpencil_brush_grab_apply_cached(tGP_BrushEditData *gso, + bGPDstroke *gps, + const float diff_mat[4][4]) { tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps); /* If a new frame is created, could be impossible find the stroke. */ @@ -553,7 +555,7 @@ static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, /* get evaluated transformation */ gso->rot_eval = data->rot_eval[i]; - gp_brush_grab_calc_dvec(gso); + gpencil_brush_grab_calc_dvec(gso); /* adjust the amount of displacement to apply */ mul_v3_v3fl(delta, gso->dvec, data->weights[i]); @@ -569,12 +571,12 @@ static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, mul_m4_v3(inverse_diff_mat, &pt->x); /* compute lock axis */ - gpsculpt_compute_lock_axis(gso, pt, save_pt); + gpencil_sculpt_compute_lock_axis(gso, pt, save_pt); } } /* free customdata used for handling this stroke */ -static void gp_brush_grab_stroke_free(void *ptr) +static void gpencil_brush_grab_stroke_free(void *ptr) { tGPSB_Grab_StrokeData *data = (tGPSB_Grab_StrokeData *)ptr; @@ -589,19 +591,19 @@ static void gp_brush_grab_stroke_free(void *ptr) /* ----------------------------------------------- */ /* Push Brush */ -/* NOTE: Depends on gp_brush_grab_calc_dvec() */ -static bool gp_brush_push_apply(tGP_BrushEditData *gso, - bGPDstroke *gps, - float UNUSED(rot_eval), - int pt_index, - const int radius, - const int co[2]) +/* NOTE: Depends on gpencil_brush_grab_calc_dvec() */ +static bool gpencil_brush_push_apply(tGP_BrushEditData *gso, + bGPDstroke *gps, + float UNUSED(rot_eval), + int pt_index, + const int radius, + const int co[2]) { bGPDspoint *pt = gps->points + pt_index; float save_pt[3]; copy_v3_v3(save_pt, &pt->x); - float inf = gp_brush_influence_calc(gso, radius, co); + float inf = gpencil_brush_influence_calc(gso, radius, co); float delta[3] = {0.0f}; /* adjust the amount of displacement to apply */ @@ -612,7 +614,7 @@ static bool gp_brush_push_apply(tGP_BrushEditData *gso, add_v3_v3(&pt->x, delta); /* compute lock axis */ - gpsculpt_compute_lock_axis(gso, pt, save_pt); + gpencil_sculpt_compute_lock_axis(gso, pt, save_pt); /* done */ return true; @@ -621,10 +623,10 @@ static bool gp_brush_push_apply(tGP_BrushEditData *gso, /* ----------------------------------------------- */ /* Pinch Brush */ /* Compute reference midpoint for the brush - this is what we'll be moving towards */ -static void gp_brush_calc_midpoint(tGP_BrushEditData *gso) +static void gpencil_brush_calc_midpoint(tGP_BrushEditData *gso) { /* Convert mouse position to 3D space - * See: gpencil_paint.c :: gp_stroke_convertcoords() + * See: gpencil_paint.c :: gpencil_stroke_convertcoords() */ RegionView3D *rv3d = gso->region->regiondata; const float *rvec = gso->object->loc; @@ -647,12 +649,12 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso) } /* Shrink distance between midpoint and this point... */ -static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, - bGPDstroke *gps, - float UNUSED(rot_eval), - int pt_index, - const int radius, - const int co[2]) +static bool gpencil_brush_pinch_apply(tGP_BrushEditData *gso, + bGPDstroke *gps, + float UNUSED(rot_eval), + int pt_index, + const int radius, + const int co[2]) { bGPDspoint *pt = gps->points + pt_index; float fac, inf; @@ -665,7 +667,7 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, * - Div 10 = Not enough effect * - Div 5 = Happy medium... (by trial and error) */ - inf = gp_brush_influence_calc(gso, radius, co) / 5.0f; + inf = gpencil_brush_influence_calc(gso, radius, co) / 5.0f; /* 1) Make this point relative to the cursor/midpoint (dvec) */ float fpt[3]; @@ -677,7 +679,7 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, * OR * Increase the distance (if inverting the brush action!) */ - if (gp_brush_invert_check(gso)) { + if (gpencil_brush_invert_check(gso)) { /* Inflate (inverse) */ fac = 1.0f + (inf * inf); /* squared to temper the effect... */ } @@ -692,7 +694,7 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, mul_v3_m4v3(&pt->x, gso->object->imat, fpt); /* compute lock axis */ - gpsculpt_compute_lock_axis(gso, pt, save_pt); + gpencil_sculpt_compute_lock_axis(gso, pt, save_pt); /* done */ return true; @@ -704,12 +706,12 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, * convert the rotated point and convert it into "data" space */ -static bool gp_brush_twist_apply(tGP_BrushEditData *gso, - bGPDstroke *gps, - float UNUSED(rot_eval), - int pt_index, - const int radius, - const int co[2]) +static bool gpencil_brush_twist_apply(tGP_BrushEditData *gso, + bGPDstroke *gps, + float UNUSED(rot_eval), + int pt_index, + const int radius, + const int co[2]) { bGPDspoint *pt = gps->points + pt_index; float angle, inf; @@ -717,10 +719,10 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, copy_v3_v3(save_pt, &pt->x); /* Angle to rotate by */ - inf = gp_brush_influence_calc(gso, radius, co); + inf = gpencil_brush_influence_calc(gso, radius, co); angle = DEG2RADF(1.0f) * inf; - if (gp_brush_invert_check(gso)) { + if (gpencil_brush_invert_check(gso)) { /* invert angle that we rotate by */ angle *= -1; } @@ -749,7 +751,7 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, mul_v3_m4v3(&pt->x, gso->object->imat, fpt); /* compute lock axis */ - gpsculpt_compute_lock_axis(gso, pt, save_pt); + gpencil_sculpt_compute_lock_axis(gso, pt, save_pt); } else { const float axis[3] = {0.0f, 0.0f, 1.0f}; @@ -787,12 +789,12 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, /* ----------------------------------------------- */ /* Randomize Brush */ /* Apply some random jitter to the point */ -static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, - bGPDstroke *gps, - float UNUSED(rot_eval), - int pt_index, - const int radius, - const int co[2]) +static bool gpencil_brush_randomize_apply(tGP_BrushEditData *gso, + bGPDstroke *gps, + float UNUSED(rot_eval), + int pt_index, + const int radius, + const int co[2]) { bGPDspoint *pt = gps->points + pt_index; float save_pt[3]; @@ -801,7 +803,7 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, /* Amount of jitter to apply depends on the distance of the point to the cursor, * as well as the strength of the brush */ - const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f; + const float inf = gpencil_brush_influence_calc(gso, radius, co) / 2.0f; const float fac = BLI_rng_get_float(gso->rng) * inf; /* apply random to position */ @@ -840,7 +842,7 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, ED_view3d_win_to_delta(gso->gsc.region, svec, dvec, zfac); add_v3_v3(&pt->x, dvec); /* compute lock axis */ - gpsculpt_compute_lock_axis(gso, pt, save_pt); + gpencil_sculpt_compute_lock_axis(gso, pt, save_pt); } } } @@ -909,7 +911,7 @@ typedef struct tGPSB_CloneBrushData { } tGPSB_CloneBrushData; /* Initialise "clone" brush data */ -static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso) +static void gpencil_brush_clone_init(bContext *C, tGP_BrushEditData *gso) { tGPSB_CloneBrushData *data; bGPDstroke *gps; @@ -918,7 +920,7 @@ static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso) gso->customdata = data = MEM_callocN(sizeof(tGPSB_CloneBrushData), "CloneBrushData"); /* compute midpoint of strokes on clipboard */ - for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { + for (gps = gpencil_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { const float dfac = 1.0f / ((float)gps->totpoints); float mid[3] = {0.0f}; @@ -954,11 +956,11 @@ static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso) /* Init colormap for mapping between the pasted stroke's source color (names) * and the final colors that will be used here instead. */ - data->new_colors = gp_copybuf_validate_colormap(C); + data->new_colors = gpencil_copybuf_validate_colormap(C); } /* Free custom data used for "clone" brush */ -static void gp_brush_clone_free(tGP_BrushEditData *gso) +static void gpencil_brush_clone_free(tGP_BrushEditData *gso) { tGPSB_CloneBrushData *data = gso->customdata; @@ -980,7 +982,7 @@ static void gp_brush_clone_free(tGP_BrushEditData *gso) } /* Create new copies of the strokes on the clipboard */ -static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) +static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso) { tGPSB_CloneBrushData *data = gso->customdata; @@ -995,11 +997,11 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) /* Compute amount to offset the points by */ /* NOTE: This assumes that screenspace strokes are NOT used in the 3D view... */ - gp_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */ + gpencil_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */ sub_v3_v3v3(delta, gso->dvec, data->buffer_midpoint); /* Copy each stroke into the layer */ - for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { + for (gps = gpencil_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { bGPDstroke *new_stroke; bGPDspoint *pt; @@ -1051,14 +1053,14 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) } /* Move newly-added strokes around - "Stamp" mode of the Clone brush */ -static void gp_brush_clone_adjust(tGP_BrushEditData *gso) +static void gpencil_brush_clone_adjust(tGP_BrushEditData *gso) { tGPSB_CloneBrushData *data = gso->customdata; size_t snum; /* Compute the amount of movement to apply (overwrites dvec) */ gso->rot_eval = 0.0f; - gp_brush_grab_calc_dvec(gso); + gpencil_brush_grab_calc_dvec(gso); /* For each of the stored strokes, apply the offset to each point */ /* NOTE: Again this assumes that in the 3D view, @@ -1075,8 +1077,8 @@ static void gp_brush_clone_adjust(tGP_BrushEditData *gso) float influence; /* compute influence on point */ - gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]); - influence = gp_brush_influence_calc(gso, gso->brush->size, sco); + gpencil_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]); + influence = gpencil_brush_influence_calc(gso, gso->brush->size, sco); /* adjust the amount of displacement to apply */ mul_v3_v3fl(delta, gso->dvec, influence); @@ -1088,24 +1090,24 @@ static void gp_brush_clone_adjust(tGP_BrushEditData *gso) } /* Entrypoint for applying "clone" brush */ -static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso) +static bool gpencil_sculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso) { /* Which "mode" are we operating in? */ if (gso->first) { /* Create initial clones */ - gp_brush_clone_add(C, gso); + gpencil_brush_clone_add(C, gso); } else { /* Stamp or Continuous Mode */ if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) { /* Stamp - Proceed to translate the newly added strokes */ - gp_brush_clone_adjust(gso); + gpencil_brush_clone_adjust(gso); } else { /* Continuous - Just keep pasting everytime we move */ /* TODO: The spacing of repeat should be controlled using a * "stepsize" or similar property? */ - gp_brush_clone_add(C, gso); + gpencil_brush_clone_add(C, gso); } } @@ -1115,7 +1117,7 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso) /* ************************************************ */ /* Header Info for GPencil Sculpt */ -static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso) +static void gpencil_sculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso) { Brush *brush = gso->brush; char str[UI_MAX_DRAW_STR] = ""; @@ -1135,7 +1137,7 @@ static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso) /* Init/Exit ----------------------------------------------- */ -static bool gpsculpt_brush_init(bContext *C, wmOperator *op) +static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; @@ -1151,7 +1153,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) gso->depsgraph = CTX_data_ensure_evaluated_depsgraph(C); gso->bmain = CTX_data_main(C); /* store state */ - gso->settings = gpsculpt_get_settings(scene); + gso->settings = gpencil_sculpt_get_settings(scene); /* Random generator, only init once. */ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX); @@ -1209,7 +1211,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) bool found = false; /* check that there are some usable strokes in the buffer */ - for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { + for (gps = gpencil_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { found = true; break; @@ -1229,7 +1231,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) } else { /* initialise customdata */ - gp_brush_clone_init(C, gso); + gpencil_brush_clone_init(C, gso); } break; } @@ -1246,15 +1248,15 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) } /* setup space conversions */ - gp_point_conversion_init(C, &gso->gsc); + gpencil_point_conversion_init(C, &gso->gsc); /* update header */ - gpsculpt_brush_header_set(C, gso); + gpencil_sculpt_brush_header_set(C, gso); return true; } -static void gpsculpt_brush_exit(bContext *C, wmOperator *op) +static void gpencil_sculpt_brush_exit(bContext *C, wmOperator *op) { tGP_BrushEditData *gso = op->customdata; wmWindow *win = CTX_wm_window(C); @@ -1267,13 +1269,13 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op) * - Keys don't need to be freed, as those are the strokes * - Values assigned to those keys do, as they are custom structs */ - BLI_ghash_free(gso->stroke_customdata, NULL, gp_brush_grab_stroke_free); + BLI_ghash_free(gso->stroke_customdata, NULL, gpencil_brush_grab_stroke_free); break; } case GPSCULPT_TOOL_CLONE: { /* Free customdata */ - gp_brush_clone_free(gso); + gpencil_brush_clone_free(gso); break; } @@ -1305,7 +1307,7 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op) } /* poll callback for stroke sculpting operator(s) */ -static bool gpsculpt_brush_poll(bContext *C) +static bool gpencil_sculpt_brush_poll(bContext *C) { ScrArea *area = CTX_wm_area(C); if (area && area->spacetype != SPACE_VIEW3D) { @@ -1318,7 +1320,7 @@ static bool gpsculpt_brush_poll(bContext *C) /* Init Sculpt Stroke ---------------------------------- */ -static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso) +static void gpencil_sculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso) { bGPdata *gpd = gso->gpd; @@ -1360,10 +1362,10 @@ static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso) * For strokes with one point only this is impossible to calculate because there isn't a * valid reference point. */ -static float gpsculpt_rotation_eval_get(tGP_BrushEditData *gso, - bGPDstroke *gps_eval, - bGPDspoint *pt_eval, - int idx_eval) +static float gpencil_sculpt_rotation_eval_get(tGP_BrushEditData *gso, + bGPDstroke *gps_eval, + bGPDspoint *pt_eval, + int idx_eval) { /* If multiframe or no modifiers, return 0. */ if ((GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd)) || (!gso->is_transformed)) { @@ -1402,22 +1404,22 @@ static float gpsculpt_rotation_eval_get(tGP_BrushEditData *gso, /* create 2D vectors of the stroke segments */ float v_orig_a[2], v_orig_b[2], v_eval_a[2], v_eval_b[2]; - gp_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_orig->x, v_orig_a); - gp_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_orig_prev->x, v_orig_b); + gpencil_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_orig->x, v_orig_a); + gpencil_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_orig_prev->x, v_orig_b); sub_v2_v2(v_orig_a, v_orig_b); - gp_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_eval->x, v_eval_a); - gp_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_prev_eval->x, v_eval_b); + gpencil_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_eval->x, v_eval_a); + gpencil_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_prev_eval->x, v_eval_b); sub_v2_v2(v_eval_a, v_eval_b); return angle_v2v2(v_orig_a, v_eval_a); } /* Apply brush operation to points in this stroke */ -static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, - bGPDstroke *gps, - const float diff_mat[4][4], - GP_BrushApplyCb apply) +static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, + bGPDstroke *gps, + const float diff_mat[4][4], + GP_BrushApplyCb apply) { GP_SpaceConversion *gsc = &gso->gsc; rcti *rect = &gso->brush_rect; @@ -1447,8 +1449,8 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, if (gps->totpoints == 1) { bGPDspoint pt_temp; pt = &gps->points[0]; - gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); - gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); + gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp); + gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; /* do boundbox check first */ @@ -1459,7 +1461,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, if (len_v2v2_int(mval_i, pc1) <= radius) { /* apply operation to this point */ if (pt_active != NULL) { - rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, 0); + rot_eval = gpencil_sculpt_rotation_eval_get(gso, gps, pt, 0); changed = apply(gso, gps_active, rot_eval, 0, radius, pc1); } } @@ -1483,11 +1485,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, } } bGPDspoint npt; - gp_point_to_parent_space(pt1, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); + gpencil_point_to_parent_space(pt1, diff_mat, &npt); + gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); - gp_point_to_parent_space(pt2, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); + gpencil_point_to_parent_space(pt2, diff_mat, &npt); + gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); /* Check that point segment of the boundbox of the selection stroke */ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || @@ -1496,7 +1498,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, * brush region (either within stroke painted, or on its lines) * - this assumes that linewidth is irrelevant */ - if (gp_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { + if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { /* Apply operation to these points */ bool ok = false; @@ -1513,7 +1515,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, } index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if ((pt_active != NULL) && (index < gps_active->totpoints)) { - rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i); + rot_eval = gpencil_sculpt_rotation_eval_get(gso, gps, pt, i); ok = apply(gso, gps_active, rot_eval, index, radius, pc1); } @@ -1530,7 +1532,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1; if ((pt_active != NULL) && (index < gps_active->totpoints)) { - rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i + 1); + rot_eval = gpencil_sculpt_rotation_eval_get(gso, gps, pt, i + 1); ok |= apply(gso, gps_active, rot_eval, index, radius, pc2); include_last = false; } @@ -1551,7 +1553,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if ((pt_active != NULL) && (index < gps_active->totpoints)) { - rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i); + rot_eval = gpencil_sculpt_rotation_eval_get(gso, gps, pt, i); changed |= apply(gso, gps_active, rot_eval, index, radius, pc1); include_last = false; } @@ -1564,11 +1566,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, } /* Apply sculpt brushes to strokes in the given frame */ -static bool gpsculpt_brush_do_frame(bContext *C, - tGP_BrushEditData *gso, - bGPDlayer *gpl, - bGPDframe *gpf, - const float diff_mat[4][4]) +static bool gpencil_sculpt_brush_do_frame(bContext *C, + tGP_BrushEditData *gso, + bGPDlayer *gpl, + bGPDframe *gpf, + const float diff_mat[4][4]) { bool changed = false; bool redo_geom = false; @@ -1588,20 +1590,22 @@ static bool gpsculpt_brush_do_frame(bContext *C, switch (tool) { case GPSCULPT_TOOL_SMOOTH: /* Smooth strokes */ { - changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply); + changed |= gpencil_sculpt_brush_do_stroke(gso, gps, diff_mat, gpencil_brush_smooth_apply); redo_geom |= changed; break; } case GPSCULPT_TOOL_THICKNESS: /* Adjust stroke thickness */ { - changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply); + changed |= gpencil_sculpt_brush_do_stroke( + gso, gps, diff_mat, gpencil_brush_thickness_apply); break; } case GPSCULPT_TOOL_STRENGTH: /* Adjust stroke color strength */ { - changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply); + changed |= gpencil_sculpt_brush_do_stroke( + gso, gps, diff_mat, gpencil_brush_strength_apply); break; } @@ -1614,13 +1618,13 @@ static bool gpsculpt_brush_do_frame(bContext *C, * 1) Prepare data buffers (init/clear) for this stroke * 2) Use the points now under the cursor */ - gp_brush_grab_stroke_init(gso, gps_active); - changed |= gpsculpt_brush_do_stroke( - gso, gps_active, diff_mat, gp_brush_grab_store_points); + gpencil_brush_grab_stroke_init(gso, gps_active); + changed |= gpencil_sculpt_brush_do_stroke( + gso, gps_active, diff_mat, gpencil_brush_grab_store_points); } else { /* Apply effect to the stored points */ - gp_brush_grab_apply_cached(gso, gps_active, diff_mat); + gpencil_brush_grab_apply_cached(gso, gps_active, diff_mat); changed |= true; } } @@ -1630,28 +1634,29 @@ static bool gpsculpt_brush_do_frame(bContext *C, case GPSCULPT_TOOL_PUSH: /* Push points */ { - changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply); + changed |= gpencil_sculpt_brush_do_stroke(gso, gps, diff_mat, gpencil_brush_push_apply); redo_geom |= changed; break; } case GPSCULPT_TOOL_PINCH: /* Pinch points */ { - changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply); + changed |= gpencil_sculpt_brush_do_stroke(gso, gps, diff_mat, gpencil_brush_pinch_apply); redo_geom |= changed; break; } case GPSCULPT_TOOL_TWIST: /* Twist points around midpoint */ { - changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply); + changed |= gpencil_sculpt_brush_do_stroke(gso, gps, diff_mat, gpencil_brush_twist_apply); redo_geom |= changed; break; } case GPSCULPT_TOOL_RANDOMIZE: /* Apply jitter */ { - changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply); + changed |= gpencil_sculpt_brush_do_stroke( + gso, gps, diff_mat, gpencil_brush_randomize_apply); redo_geom |= changed; break; } @@ -1685,7 +1690,7 @@ static bool gpsculpt_brush_do_frame(bContext *C, } /* Perform two-pass brushes which modify the existing strokes */ -static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) +static bool gpencil_sculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) { ToolSettings *ts = gso->scene->toolsettings; Depsgraph *depsgraph = gso->depsgraph; @@ -1703,7 +1708,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) { /* calculate amount of displacement to apply */ gso->rot_eval = 0.0f; - gp_brush_grab_calc_dvec(gso); + gpencil_brush_grab_calc_dvec(gso); break; } @@ -1711,7 +1716,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) case GPSCULPT_TOOL_TWIST: /* Twist points around midpoint */ { /* calculate midpoint of the brush (in data space) */ - gp_brush_calc_midpoint(gso); + gpencil_brush_calc_midpoint(gso); break; } @@ -1719,7 +1724,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) { /* compute the displacement vector for the cursor (in data space) */ gso->rot_eval = 0.0f; - gp_brush_grab_calc_dvec(gso); + gpencil_brush_grab_calc_dvec(gso); break; } @@ -1764,7 +1769,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) } /* affect strokes in this frame */ - changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat); + changed |= gpencil_sculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat); } } } @@ -1772,7 +1777,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) if (gpl->actframe != NULL) { /* Apply to active frame's strokes */ gso->mf_falloff = 1.0f; - changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); + changed |= gpencil_sculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); } } } @@ -1781,7 +1786,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) } /* Calculate settings for applying brush */ -static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) +static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) { tGP_BrushEditData *gso = op->customdata; Brush *brush = gso->brush; @@ -1821,10 +1826,10 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt /* Apply brush */ char tool = gso->brush->gpencil_sculpt_tool; if (tool == GPSCULPT_TOOL_CLONE) { - changed = gpsculpt_brush_apply_clone(C, gso); + changed = gpencil_sculpt_brush_apply_clone(C, gso); } else { - changed = gpsculpt_brush_apply_standard(C, gso); + changed = gpencil_sculpt_brush_apply_standard(C, gso); } /* Updates */ @@ -1841,7 +1846,7 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt } /* Running --------------------------------------------- */ -static Brush *gpsculpt_get_smooth_brush(tGP_BrushEditData *gso) +static Brush *gpencil_sculpt_get_smooth_brush(tGP_BrushEditData *gso) { Main *bmain = gso->bmain; Brush *brush = BLI_findstring(&bmain->brushes, "Smooth Stroke", offsetof(ID, name) + 2); @@ -1850,7 +1855,7 @@ static Brush *gpsculpt_get_smooth_brush(tGP_BrushEditData *gso) } /* helper - a record stroke, and apply paint event */ -static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event) +static void gpencil_sculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event) { tGP_BrushEditData *gso = op->customdata; PointerRNA itemptr; @@ -1878,7 +1883,7 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven if (event->shift) { gso->brush_prev = gso->brush; - gso->brush = gpsculpt_get_smooth_brush(gso); + gso->brush = gpencil_sculpt_get_smooth_brush(gso); if (gso->brush == NULL) { gso->brush = gso->brush_prev; } @@ -1890,28 +1895,28 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven } /* apply */ - gpsculpt_brush_apply(C, op, &itemptr); + gpencil_sculpt_brush_apply(C, op, &itemptr); } /* reapply */ -static int gpsculpt_brush_exec(bContext *C, wmOperator *op) +static int gpencil_sculpt_brush_exec(bContext *C, wmOperator *op) { - if (!gpsculpt_brush_init(C, op)) { + if (!gpencil_sculpt_brush_init(C, op)) { return OPERATOR_CANCELLED; } RNA_BEGIN (op->ptr, itemptr, "stroke") { - gpsculpt_brush_apply(C, op, &itemptr); + gpencil_sculpt_brush_apply(C, op, &itemptr); } RNA_END; - gpsculpt_brush_exit(C, op); + gpencil_sculpt_brush_exit(C, op); return OPERATOR_FINISHED; } /* start modal painting */ -static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int gpencil_sculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event) { tGP_BrushEditData *gso = NULL; const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input"); @@ -1927,7 +1932,7 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve } /* init painting data */ - if (!gpsculpt_brush_init(C, op)) { + if (!gpencil_sculpt_brush_init(C, op)) { return OPERATOR_CANCELLED; } @@ -1974,11 +1979,11 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve ARegion *region = CTX_wm_region(C); /* ensure that we'll have a new frame to draw on */ - gpsculpt_brush_init_stroke(C, gso); + gpencil_sculpt_brush_init_stroke(C, gso); /* apply first dab... */ gso->is_painting = true; - gpsculpt_brush_apply_event(C, op, event); + gpencil_sculpt_brush_apply_event(C, op, event); /* redraw view with feedback */ ED_region_tag_redraw(region); @@ -1988,7 +1993,7 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve } /* painting - handle events */ -static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *event) +static int gpencil_sculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *event) { tGP_BrushEditData *gso = op->customdata; const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input"); @@ -2003,7 +2008,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even case MOUSEMOVE: case INBETWEEN_MOUSEMOVE: /* apply brush effect at new position */ - gpsculpt_brush_apply_event(C, op, event); + gpencil_sculpt_brush_apply_event(C, op, event); /* force redraw, so that the cursor will at least be valid */ redraw_region = true; @@ -2013,7 +2018,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even case TIMER: if (event->customdata == gso->timer) { gso->timerTick = true; - gpsculpt_brush_apply_event(C, op, event); + gpencil_sculpt_brush_apply_event(C, op, event); gso->timerTick = false; } break; @@ -2029,7 +2034,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even /* end sculpt session, since we're not modal */ gso->is_painting = false; - gpsculpt_brush_exit(C, op); + gpencil_sculpt_brush_exit(C, op); return OPERATOR_FINISHED; } break; @@ -2038,7 +2043,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even case MIDDLEMOUSE: case RIGHTMOUSE: case EVT_ESCKEY: - gpsculpt_brush_exit(C, op); + gpencil_sculpt_brush_exit(C, op); return OPERATOR_FINISHED; } } @@ -2053,14 +2058,14 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even gso->is_painting = true; gso->first = true; - gpsculpt_brush_init_stroke(C, gso); - gpsculpt_brush_apply_event(C, op, event); + gpencil_sculpt_brush_init_stroke(C, gso); + gpencil_sculpt_brush_apply_event(C, op, event); break; /* Exit modal operator, based on the "standard" ops */ case RIGHTMOUSE: case EVT_ESCKEY: - gpsculpt_brush_exit(C, op); + gpencil_sculpt_brush_exit(C, op); return OPERATOR_FINISHED; /* MMB is often used for view manipulations */ @@ -2124,11 +2129,11 @@ void GPENCIL_OT_sculpt_paint(wmOperatorType *ot) ot->description = "Apply tweaks to strokes by painting over the strokes"; // XXX /* api callbacks */ - ot->exec = gpsculpt_brush_exec; - ot->invoke = gpsculpt_brush_invoke; - ot->modal = gpsculpt_brush_modal; - ot->cancel = gpsculpt_brush_exit; - ot->poll = gpsculpt_brush_poll; + ot->exec = gpencil_sculpt_brush_exec; + ot->invoke = gpencil_sculpt_brush_invoke; + ot->modal = gpencil_sculpt_brush_modal; + ot->cancel = gpencil_sculpt_brush_exit; + ot->poll = gpencil_sculpt_brush_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index c41b2993a80..ea6f53d24bb 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -369,7 +369,7 @@ typedef enum eGP_SelectGrouped { /* ----------------------------------- */ /* On each visible layer, check for selected strokes - if found, select all others */ -static void gp_select_same_layer(bContext *C) +static void gpencil_select_same_layer(bContext *C) { Scene *scene = CTX_data_scene(C); @@ -412,7 +412,7 @@ static void gp_select_same_layer(bContext *C) } /* Select all strokes with same colors as selected ones */ -static void gp_select_same_material(bContext *C) +static void gpencil_select_same_material(bContext *C) { /* First, build set containing all the colors of selected strokes */ GSet *selected_colors = BLI_gset_str_new("GP Selected Colors"); @@ -462,10 +462,10 @@ static int gpencil_select_grouped_exec(bContext *C, wmOperator *op) switch (mode) { case GP_SEL_SAME_LAYER: - gp_select_same_layer(C); + gpencil_select_same_layer(C); break; case GP_SEL_SAME_MATERIAL: - gp_select_same_material(C); + gpencil_select_same_material(C); break; default: @@ -853,142 +853,87 @@ void GPENCIL_OT_select_less(wmOperatorType *ot) * Helper to check if a given stroke is within the area. * * \note Code here is adapted (i.e. copied directly) - * from gpencil_paint.c #gp_stroke_eraser_dostroke(). + * from gpencil_paint.c #gpencil_stroke_eraser_dostroke(). * It would be great to de-duplicate the logic here sometime, but that can wait. */ -static bool gp_stroke_do_circle_sel(bGPdata *UNUSED(gpd), - bGPDlayer *gpl, - bGPDstroke *gps, - GP_SpaceConversion *gsc, - const int mx, - const int my, - const int radius, - const bool select, - rcti *rect, - const float diff_mat[4][4], - const int selectmode, - const float scale) +static bool gpencil_stroke_do_circle_sel(bGPdata *UNUSED(gpd), + bGPDlayer *gpl, + bGPDstroke *gps, + GP_SpaceConversion *gsc, + const int mx, + const int my, + const int radius, + const bool select, + rcti *rect, + const float diff_mat[4][4], + const int selectmode, + const float scale) { - bGPDspoint *pt1 = NULL; - bGPDspoint *pt2 = NULL; - int x0 = 0, y0 = 0, x1 = 0, y1 = 0; + bGPDspoint *pt = NULL; + int x0 = 0, y0 = 0; int i; bool changed = false; bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt_active = NULL; + bool hit = false; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; - if (gps->totpoints == 1) { bGPDspoint pt_temp; - gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); - gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0); + gpencil_point_to_parent_space(pt_active, diff_mat, &pt_temp); + gpencil_point_to_xy(gsc, gps, &pt_temp, &x0, &y0); /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) { /* only check if point is inside */ if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) { + hit = true; + /* change selection */ if (select) { - gps_active->points->flag |= GP_SPOINT_SELECT; + pt_active->flag |= GP_SPOINT_SELECT; gps_active->flag |= GP_STROKE_SELECT; } else { - gps_active->points->flag &= ~GP_SPOINT_SELECT; + pt_active->flag &= ~GP_SPOINT_SELECT; gps_active->flag &= ~GP_STROKE_SELECT; } + changed = true; + /* if stroke mode, don't check more points */ + if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) { + break; + } - return true; - } - } - } - else { - /* Loop over the points in the stroke, checking for intersections - * - an intersection means that we touched the stroke - */ - bool hit = false; - for (i = 0; (i + 1) < gps->totpoints; i++) { - /* get points to work with */ - pt1 = gps->points + i; - pt2 = gps->points + i + 1; - bGPDspoint npt; - gp_point_to_parent_space(pt1, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &x0, &y0); - - gp_point_to_parent_space(pt2, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &x1, &y1); - - /* check that point segment of the boundbox of the selection stroke */ - if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) || - ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1))) { - float mval[2] = {(float)mx, (float)my}; - - /* check if point segment of stroke had anything to do with - * eraser region (either within stroke painted, or on its lines) - * - this assumes that linewidth is irrelevant - */ - if (gp_stroke_inside_circle(mval, radius, x0, y0, x1, y1)) { - /* change selection of stroke, and then of both points - * (as the last point otherwise wouldn't get selected - * as we only do n-1 loops through). - */ - hit = true; - if (select) { - pt_active = pt1->runtime.pt_orig; - if (pt_active != NULL) { - pt_active->flag |= GP_SPOINT_SELECT; - } - pt_active = pt2->runtime.pt_orig; - if (pt_active != NULL) { - pt_active->flag |= GP_SPOINT_SELECT; - } - changed = true; - } - else { - pt_active = pt1->runtime.pt_orig; - if (pt_active != NULL) { - pt_active->flag &= ~GP_SPOINT_SELECT; - } - pt_active = pt2->runtime.pt_orig; - if (pt_active != NULL) { - pt_active->flag &= ~GP_SPOINT_SELECT; - } - changed = true; - } + /* Expand selection to segment. */ + if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) && (pt_active != NULL)) { + float r_hita[3], r_hitb[3]; + bool hit_select = (bool)(pt_active->flag & GP_SPOINT_SELECT); + ED_gpencil_select_stroke_segment( + gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb); } } - /* if stroke mode, don't check more points */ - if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) { - break; - } } + } - /* if stroke mode expand selection */ - if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) { - for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) { - pt_active = (pt1->runtime.pt_orig) ? pt1->runtime.pt_orig : pt1; - if (pt_active != NULL) { - if (select) { - pt_active->flag |= GP_SPOINT_SELECT; - } - else { - pt_active->flag &= ~GP_SPOINT_SELECT; - } + /* If stroke mode expand selection. */ + if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) { + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; + if (pt_active != NULL) { + if (select) { + pt_active->flag |= GP_SPOINT_SELECT; + } + else { + pt_active->flag &= ~GP_SPOINT_SELECT; } } } - - /* expand selection to segment */ - pt_active = (pt1->runtime.pt_orig) ? pt1->runtime.pt_orig : pt1; - if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) && (pt_active != NULL)) { - float r_hita[3], r_hitb[3]; - bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT); - ED_gpencil_select_stroke_segment( - gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb); - } - - /* Ensure that stroke selection is in sync with its points */ - BKE_gpencil_stroke_sync_selection(gps_active); } + /* Ensure that stroke selection is in sync with its points. */ + BKE_gpencil_stroke_sync_selection(gps_active); + return changed; } @@ -1043,7 +988,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op) } /* init space conversion stuff */ - gp_point_conversion_init(C, &gsc); + gpencil_point_conversion_init(C, &gsc); /* rect is rectangle of selection circle */ rect.xmin = mx - radius; @@ -1053,18 +998,18 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op) /* find visible strokes, and select if hit */ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { - changed |= gp_stroke_do_circle_sel(gpd, - gpl, - gps, - &gsc, - mx, - my, - radius, - select, - &rect, - gpstroke_iter.diff_mat, - selectmode, - scale); + changed |= gpencil_stroke_do_circle_sel(gpd, + gpl, + gps, + &gsc, + mx, + my, + radius, + select, + &rect, + gpstroke_iter.diff_mat, + selectmode, + scale); } GP_EVALUATED_STROKES_END(gpstroke_iter); @@ -1157,7 +1102,7 @@ static int gpencil_generic_select_exec( } /* init space conversion stuff */ - gp_point_conversion_init(C, &gsc); + gpencil_point_conversion_init(C, &gsc); /* deselect all strokes first? */ if (SEL_OP_USE_PRE_DESELECT(sel_op) || (GPENCIL_PAINT_MODE(gpd))) { @@ -1255,7 +1200,7 @@ static int gpencil_generic_select_exec( /* if paint mode,delete selected points */ if (GPENCIL_PAINT_MODE(gpd)) { - gp_delete_selected_point_wrap(C); + gpencil_delete_selected_point_wrap(C); changed = true; DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); } @@ -1292,8 +1237,8 @@ static bool gpencil_test_box(bGPDstroke *gps, const struct GP_SelectBoxUserData *data = user_data; bGPDspoint pt2; int x0, y0; - gp_point_to_parent_space(pt, diff_mat, &pt2); - gp_point_to_xy(gsc, gps, &pt2, &x0, &y0); + gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_xy(gsc, gps, &pt2, &x0, &y0); return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0)); } @@ -1349,8 +1294,8 @@ static bool gpencil_test_lasso(bGPDstroke *gps, const struct GP_SelectLassoUserData *data = user_data; bGPDspoint pt2; int x0, y0; - gp_point_to_parent_space(pt, diff_mat, &pt2); - gp_point_to_xy(gsc, gps, &pt2, &x0, &y0); + gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_xy(gsc, gps, &pt2, &x0, &y0); /* test if in lasso boundbox + within the lasso noose */ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) && BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX)); @@ -1431,7 +1376,6 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) bGPdata *gpd = ED_gpencil_data_get_active(C); ToolSettings *ts = CTX_data_tool_settings(C); const float scale = ts->gp_sculpt.isect_threshold; - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */ const float radius = 0.4f * U.widget_unit; @@ -1473,7 +1417,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) } /* init space conversion stuff */ - gp_point_conversion_init(C, &gsc); + gpencil_point_conversion_init(C, &gsc); /* get mouse location */ RNA_int_get_array(op->ptr, "location", mval); @@ -1484,24 +1428,13 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) bGPDspoint *pt; int i; - /* Check boundbox to speedup. */ - float fmval[2]; - copy_v2fl_v2i(fmval, mval); - if (!ED_gpencil_stroke_check_collision( - &gsc, gps_active, fmval, radius, gpstroke_iter.diff_mat)) { - continue; - } - /* firstly, check for hit-point */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { int xy[2]; - if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) { - continue; - } bGPDspoint pt2; - gp_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2); - gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]); + gpencil_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2); + gpencil_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]); /* do boundbox check first */ if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) { @@ -1513,27 +1446,12 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) if (pt_distance < hit_distance) { hit_layer = gpl; hit_stroke = gps_active; - hit_point = (!is_multiedit) ? pt->runtime.pt_orig : pt; + hit_point = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; hit_distance = pt_distance; } } } } - if (ELEM(NULL, hit_stroke, hit_point)) { - /* If nothing hit, check if the mouse is inside any filled stroke. - * Only check filling materials. */ - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); - if ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0) { - continue; - } - bool hit_fill = ED_gpencil_stroke_point_is_inside(gps, &gsc, mval, gpstroke_iter.diff_mat); - if (hit_fill) { - hit_stroke = gps_active; - hit_point = &gps_active->points[0]; - /* Extend selection to all stroke. */ - whole = true; - } - } } GP_EVALUATED_STROKES_END(gpstroke_iter); diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 467b7ee86bf..7f77999a17b 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -94,7 +94,7 @@ /* Context Wrangling... */ /** - * Get pointer to active Grease Pencil datablock, + * Get pointer to active Grease Pencil data-block, * and an RNA-pointer to trace back to whatever owns it, * when context info is not available. */ @@ -107,7 +107,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, Pointer switch (area->spacetype) { case SPACE_PROPERTIES: /* properties */ case SPACE_INFO: /* header info */ - case SPACE_TOPBAR: /* Topbar */ + case SPACE_TOPBAR: /* Top-bar */ case SPACE_VIEW3D: /* 3D-View */ { if (ob && (ob->type == OB_GPENCIL)) { @@ -132,7 +132,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, Pointer } /** - * Get pointer to active Grease Pencil datablock for annotations, + * Get pointer to active Grease Pencil data-block for annotations, * and an RNA-pointer to trace back to whatever owns it, * when context info is not available. */ @@ -154,7 +154,7 @@ bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id, break; } - case SPACE_TOPBAR: /* Topbar */ + case SPACE_TOPBAR: /* Top-bar */ case SPACE_VIEW3D: /* 3D-View */ { if (r_ptr) { @@ -237,8 +237,10 @@ bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id, return NULL; } -/* Get pointer to active Grease Pencil datablock, - * and an RNA-pointer to trace back to whatever owns it. */ +/** + * Get pointer to active Grease Pencil data-block, + * and an RNA-pointer to trace back to whatever owns it. + */ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr) { ScrArea *area = CTX_wm_area(C); @@ -247,8 +249,10 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr) return ED_gpencil_data_get_pointers_direct(area, ob, r_ptr); } -/* Get pointer to active Grease Pencil datablock, - * and an RNA-pointer to trace back to whatever owns it. */ +/** + * Get pointer to active Grease Pencil data-block, + * and an RNA-pointer to trace back to whatever owns it. + */ bGPdata **ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr) { ID *screen_id = (ID *)CTX_wm_screen(C); @@ -259,14 +263,14 @@ bGPdata **ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr) } /* -------------------------------------------------------- */ -/* Get the active Grease Pencil datablock, when context is not available */ +/* Get the active Grease Pencil data-block, when context is not available */ bGPdata *ED_gpencil_data_get_active_direct(ScrArea *area, Object *ob) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(area, ob, NULL); return (gpd_ptr) ? *(gpd_ptr) : NULL; } -/* Get the active Grease Pencil datablock, when context is not available */ +/* Get the active Grease Pencil data-block, when context is not available */ bGPdata *ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *area, Scene *scene) { bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct(screen_id, area, scene, NULL); @@ -274,7 +278,7 @@ bGPdata *ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *area, Scen } /** - * Get the active Grease Pencil datablock + * Get the active Grease Pencil data-block */ bGPdata *ED_gpencil_data_get_active(const bContext *C) { @@ -285,9 +289,10 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C) return ob->data; } -/* Get the active Grease Pencil datablock - * \note This is the original (bmain) copy of the datablock, stored in files. - * Do not use for reading evaluated copies of GP Objects data +/** + * Get the active Grease Pencil data-block + * \note This is the original (#G.main) copy of the data-block, stored in files. + * Do not use for reading evaluated copies of GP Objects data. */ bGPdata *ED_annotation_data_get_active(const bContext *C) { @@ -295,11 +300,11 @@ bGPdata *ED_annotation_data_get_active(const bContext *C) return (gpd_ptr) ? *(gpd_ptr) : NULL; } /** - * Get the evaluated copy of the active Grease Pencil datablock (where applicable) - * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP datablock - * (i.e. a copy of the active GP datablock for the active object, where modifiers have been + * Get the evaluated copy of the active Grease Pencil data-block (where applicable) + * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP data-block + * (i.e. a copy of the active GP data-block for the active object, where modifiers have been * applied). This is needed to correctly work with "Copy-on-Write". - * - For all other editors (i.e. "GP Annotations"), this just gives the active datablock + * - For all other editors (i.e. "GP Annotations"), this just gives the active data-block * like for #ED_gpencil_data_get_active() */ bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C) @@ -322,8 +327,7 @@ bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C) bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr) { /* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data. - * Otherwise, the GP datablock is being used for annotations (i.e. everywhere else) - */ + * Otherwise, the GP data-block is being used for annotations (i.e. everywhere else). */ return ((owner_ptr) && (owner_ptr->type != &RNA_Object)); } @@ -354,7 +358,7 @@ bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra) /* Poll Callbacks */ /* poll callback for adding data/layers - special */ -bool gp_add_poll(bContext *C) +bool gpencil_add_poll(bContext *C) { Object *ob = CTX_data_active_object(C); if (ob == NULL) { @@ -366,7 +370,7 @@ bool gp_add_poll(bContext *C) } /* poll callback for checking if there is an active layer */ -bool gp_active_layer_poll(bContext *C) +bool gpencil_active_layer_poll(bContext *C) { Object *ob = CTX_data_active_object(C); if ((ob == NULL) || (ob->type != OB_GPENCIL)) { @@ -379,7 +383,7 @@ bool gp_active_layer_poll(bContext *C) } /* poll callback for checking if there is an active brush */ -bool gp_active_brush_poll(bContext *C) +bool gpencil_active_brush_poll(bContext *C) { ToolSettings *ts = CTX_data_tool_settings(C); Paint *paint = &ts->gp_paint->paint; @@ -527,13 +531,12 @@ const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C, * Check whether a given stroke segment is inside a circular brush * * \param mval: The current screen-space coordinates (midpoint) of the brush - * \param mvalo: The previous screen-space coordinates (midpoint) of the brush (NOT CURRENTLY USED) * \param rad: The radius of the brush * * \param x0, y0: The screen-space x and y coordinates of the start of the stroke segment * \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment */ -bool gp_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1) +bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1) { /* simple within-radius check for now */ const float screen_co_a[2] = {x0, y0}; @@ -611,7 +614,7 @@ bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstr * * \param r_gsc: [out] The space conversion settings struct, populated with necessary params */ -void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) +void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) { ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); @@ -658,7 +661,9 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) * \param diff_mat: Matrix with the difference between original parent matrix * \param[out] r_pt: Pointer to new point after apply matrix */ -void gp_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], bGPDspoint *r_pt) +void gpencil_point_to_parent_space(const bGPDspoint *pt, + const float diff_mat[4][4], + bGPDspoint *r_pt) { float fpt[3]; @@ -669,7 +674,7 @@ void gp_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], /** * Change position relative to parent object */ -void gp_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDstroke *gps) +void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDstroke *gps) { bGPDspoint *pt; int i; @@ -692,7 +697,10 @@ void gp_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDst /** * Change point position relative to parent object */ -void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDspoint *pt) +void gpencil_apply_parent_point(Depsgraph *depsgraph, + Object *obact, + bGPDlayer *gpl, + bGPDspoint *pt) { /* undo matrix */ float diff_mat[4][4]; @@ -715,7 +723,7 @@ void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, * \warning This assumes that the caller has already checked * whether the stroke in question can be drawn. */ -void gp_point_to_xy( +void gpencil_point_to_xy( const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt, int *r_x, int *r_y) { const ARegion *region = gsc->region; @@ -760,21 +768,21 @@ void gp_point_to_xy( /** * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D). * - * Just like #gp_point_to_xy(), except the resulting coordinates are floats not ints. + * Just like #gpencil_point_to_xy(), except the resulting coordinates are floats not ints. * Use this version to solve "stair-step" artifacts which may arise when * roundtripping the calculations. * - * \param r_x[out]: The screen-space x-coordinate of the point. - * \param r_y[out]: The screen-space y-coordinate of the point. + * \param r_x: The screen-space x-coordinate of the point. + * \param r_y: The screen-space y-coordinate of the point. * * \warning This assumes that the caller has already checked * whether the stroke in question can be drawn. */ -void gp_point_to_xy_fl(const GP_SpaceConversion *gsc, - const bGPDstroke *gps, - const bGPDspoint *pt, - float *r_x, - float *r_y) +void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc, + const bGPDstroke *gps, + const bGPDspoint *pt, + float *r_x, + float *r_y) { const ARegion *region = gsc->region; const View2D *v2d = gsc->v2d; @@ -828,12 +836,12 @@ void gp_point_to_xy_fl(const GP_SpaceConversion *gsc, } /** - * generic based on gp_point_to_xy_fl + * generic based on gpencil_point_to_xy_fl */ -void gp_point_3d_to_xy(const GP_SpaceConversion *gsc, - const short flag, - const float pt[3], - float xy[2]) +void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc, + const short flag, + const float pt[3], + float xy[2]) { const ARegion *region = gsc->region; const View2D *v2d = gsc->v2d; @@ -899,10 +907,10 @@ void gp_point_3d_to_xy(const GP_SpaceConversion *gsc, * * \warning Assumes that it is getting called in a 3D view only. */ -bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc, - Scene *scene, - const float screen_co[2], - float r_out[3]) +bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc, + Scene *scene, + const float screen_co[2], + float r_out[3]) { const RegionView3D *rv3d = gsc->region->regiondata; float rvec[3]; @@ -935,16 +943,16 @@ bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc, * Convert tGPspoint (temporary 2D/screenspace point data used by GP modal operators) * to 3D coordinates. * - * \param point2D: The screenspace 2D point data to convert. + * \param point2D: The screen-space 2D point data to convert. * \param depth: Depth array (via #ED_view3d_autodist_depth()). - * \param[out] r_out: The resulting 2D point data. + * \param r_out: The resulting 2D point data. */ -void gp_stroke_convertcoords_tpoint(Scene *scene, - ARegion *region, - Object *ob, - const tGPspoint *point2D, - float *depth, - float r_out[3]) +void gpencil_stroke_convertcoords_tpoint(Scene *scene, + ARegion *region, + Object *ob, + const tGPspoint *point2D, + float *depth, + float r_out[3]) { ToolSettings *ts = scene->toolsettings; @@ -982,7 +990,7 @@ void gp_stroke_convertcoords_tpoint(Scene *scene, /** * Get drawing reference point for conversion or projection of the stroke - * \param[out] r_vec : Reference point found + * \param r_vec: Reference point found */ void ED_gpencil_drawing_reference_get(const Scene *scene, const Object *ob, @@ -1024,7 +1032,7 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke * float inverse_diff_mat[4][4]; /* init space conversion stuff */ - gp_point_conversion_init(C, &gsc); + gpencil_point_conversion_init(C, &gsc); BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); @@ -1034,11 +1042,11 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke * float xy[2]; bGPDspoint pt2; - gp_point_to_parent_space(pt, diff_mat, &pt2); - gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]); + gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]); /* Planar - All on same plane parallel to the viewplane */ - gp_point_xy_to_3d(&gsc, scene, xy, &pt->x); + gpencil_point_xy_to_3d(&gsc, scene, xy, &pt->x); /* Unapply parent corrections */ mul_m4_v3(inverse_diff_mat, &pt->x); @@ -1048,12 +1056,12 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke * /** * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset */ -void ED_gp_project_stroke_to_plane(const Scene *scene, - const Object *ob, - const RegionView3D *rv3d, - bGPDstroke *gps, - const float origin[3], - const int axis) +void ED_gpencil_project_stroke_to_plane(const Scene *scene, + const Object *ob, + const RegionView3D *rv3d, + bGPDstroke *gps, + const float origin[3], + const int axis) { const ToolSettings *ts = scene->toolsettings; const View3DCursor *cursor = &scene->cursor; @@ -1165,13 +1173,13 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, float xy[2]; /* 3D to Screen-space */ - /* Note: We can't use gp_point_to_xy() here because that uses ints for the screen-space + /* Note: We can't use gpencil_point_to_xy() here because that uses ints for the screen-space * coordinates, resulting in lost precision, which in turn causes stair-stepping * artifacts in the final points. */ bGPDspoint pt2; - gp_point_to_parent_space(pt, diff_mat, &pt2); - gp_point_to_xy_fl(gsc, gps_active, &pt2, &xy[0], &xy[1]); + gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_xy_fl(gsc, gps_active, &pt2, &xy[0], &xy[1]); /* Project stroke in one axis */ if (ELEM(mode, GP_REPROJECT_FRONT, GP_REPROJECT_SIDE, GP_REPROJECT_TOP, GP_REPROJECT_CURSOR)) { @@ -1199,18 +1207,18 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, } } - ED_gp_project_point_to_plane(gsc->scene, gsc->ob, rv3d, origin, axis, &pt2); + ED_gpencil_project_point_to_plane(gsc->scene, gsc->ob, rv3d, origin, axis, &pt2); copy_v3_v3(&pt->x, &pt2.x); /* apply parent again */ - gp_apply_parent_point(depsgraph, gsc->ob, gpl, pt); + gpencil_apply_parent_point(depsgraph, gsc->ob, gpl, pt); } /* Project screen-space back to 3D space (from current perspective) * so that all points have been treated the same way. */ else if (mode == GP_REPROJECT_VIEW) { /* Planar - All on same plane parallel to the view-plane. */ - gp_point_xy_to_3d(gsc, gsc->scene, xy, &pt->x); + gpencil_point_xy_to_3d(gsc, gsc->scene, xy, &pt->x); } else { /* Geometry - Snap to surfaces of visible geometry */ @@ -1238,7 +1246,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, } else { /* Default to planar */ - gp_point_xy_to_3d(gsc, gsc->scene, xy, &pt->x); + gpencil_point_xy_to_3d(gsc, gsc->scene, xy, &pt->x); } } @@ -1251,14 +1259,14 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, /** * Reproject given point to a plane locked to axis to avoid stroke offset - * \param[in,out] pt: Point to affect + * \param pt: Point to affect (used for input & output). */ -void ED_gp_project_point_to_plane(const Scene *scene, - const Object *ob, - const RegionView3D *rv3d, - const float origin[3], - const int axis, - bGPDspoint *pt) +void ED_gpencil_project_point_to_plane(const Scene *scene, + const Object *ob, + const RegionView3D *rv3d, + const float origin[3], + const int axis, + bGPDspoint *pt) { const ToolSettings *ts = scene->toolsettings; const View3DCursor *cursor = &scene->cursor; @@ -1330,7 +1338,7 @@ void ED_gp_project_point_to_plane(const Scene *scene, * \param gps: Stroke data * \param subdivide: Number of times to subdivide */ -void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide) +void gpencil_subdivide_stroke(bGPDstroke *gps, const int subdivide) { bGPDspoint *temp_points; int totnewpoints, oldtotpoints; @@ -1730,7 +1738,7 @@ void ED_gpencil_vgroup_deselect(bContext *C, Object *ob) /* Cursor drawing */ /* check if cursor is in drawing region */ -static bool gp_check_cursor_region(bContext *C, int mval_i[2]) +static bool gpencil_check_cursor_region(bContext *C, int mval_i[2]) { ARegion *region = CTX_wm_region(C); ScrArea *area = CTX_wm_area(C); @@ -1802,7 +1810,7 @@ void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y) GPU_line_smooth(false); } -static bool gp_brush_cursor_poll(bContext *C) +static bool gpencil_brush_cursor_poll(bContext *C) { if (WM_toolsystem_active_tool_is_brush(C)) { return true; @@ -1810,8 +1818,10 @@ static bool gp_brush_cursor_poll(bContext *C) return false; } -/* Helper callback for drawing the cursor itself */ -static void gp_brush_cursor_draw(bContext *C, int x, int y, void *customdata) +/** + * Helper callback for drawing the cursor itself. + */ +static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdata) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); @@ -1830,8 +1840,8 @@ static void gp_brush_cursor_draw(bContext *C, int x, int y, void *customdata) float radius = 3.0f; int mval_i[2] = {x, y}; - /* check if cursor is in drawing region and has valid datablock */ - if ((!gp_check_cursor_region(C, mval_i)) || (gpd == NULL)) { + /* Check if cursor is in drawing region and has valid data-block. */ + if ((!gpencil_check_cursor_region(C, mval_i)) || (gpd == NULL)) { return; } @@ -2016,8 +2026,8 @@ void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata) /* enable cursor */ gset->paintcursor = WM_paint_cursor_activate(SPACE_TYPE_ANY, RGN_TYPE_ANY, - gp_brush_cursor_poll, - gp_brush_cursor_draw, + gpencil_brush_cursor_poll, + gpencil_brush_cursor_draw, (lastpost) ? customdata : NULL); } } @@ -2081,7 +2091,9 @@ void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode) } } -/* helper to convert 2d to 3d for simple drawing buffer */ +/** + * Helper to convert 2d to 3d for simple drawing buffer. + */ static void gpencil_stroke_convertcoords(ARegion *region, const tGPspoint *point2D, const float origin[3], @@ -2107,7 +2119,9 @@ static void gpencil_stroke_convertcoords(ARegion *region, } } -/* convert 2d tGPspoint to 3d bGPDspoint */ +/** + * Convert 2d #tGPspoint to 3d #bGPDspoint. + */ void ED_gpencil_tpoint_to_point(ARegion *region, float origin[3], const tGPspoint *tpt, @@ -2125,7 +2139,9 @@ void ED_gpencil_tpoint_to_point(ARegion *region, pt->uv_rot = tpt->uv_rot; } -/* recalc uv for any stroke using the material */ +/** + * Recalculate UV for any stroke using the material. + */ void ED_gpencil_update_color_uv(Main *bmain, Material *mat) { Material *gps_ma = NULL; @@ -2212,7 +2228,8 @@ static bool gpencil_check_collision(bGPDstroke *gps, return hit; } -static void gp_copy_points(bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final, int i, int i2) +static void gpencil_copy_points( + bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final, int i, int i2) { /* don't copy same point */ if (i == i2) { @@ -2244,7 +2261,7 @@ static void gp_copy_points(bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final } } -static void gp_insert_point( +static void gpencil_insert_point( bGPDstroke *gps, bGPDspoint *a_pt, bGPDspoint *b_pt, const float co_a[3], float co_b[3]) { bGPDspoint *temp_points; @@ -2287,16 +2304,16 @@ static void gp_insert_point( for (int i = 0; i < oldtotpoints; i++) { bGPDspoint *pt = &temp_points[i]; bGPDspoint *pt_final = &gps->points[i2]; - gp_copy_points(gps, pt, pt_final, i, i2); + gpencil_copy_points(gps, pt, pt_final, i, i2); /* create new point duplicating point and copy location */ if ((i == a_idx) || (i == b_idx)) { i2++; pt_final = &gps->points[i2]; - gp_copy_points(gps, pt, pt_final, i, i2); + gpencil_copy_points(gps, pt, pt_final, i, i2); copy_v3_v3(&pt_final->x, (i == a_idx) ? co_a : co_b); - /* unselect */ + /* Un-select. */ pt_final->flag &= ~GP_SPOINT_SELECT; /* tag to avoid more checking with this point */ pt_final->flag |= GP_SPOINT_TAG; @@ -2304,13 +2321,13 @@ static void gp_insert_point( i2++; } - /* Calc geometry data. */ + /* Calculate geometry data. */ BKE_gpencil_stroke_geometry_update(gps); MEM_SAFE_FREE(temp_points); } -static float gp_calc_factor(float p2d_a1[2], float p2d_a2[2], float r_hit2d[2]) +static float gpencil_calc_factor(float p2d_a1[2], float p2d_a2[2], float r_hit2d[2]) { float dist1 = len_squared_v2v2(p2d_a1, p2d_a2); float dist2 = len_squared_v2v2(p2d_a1, r_hit2d); @@ -2435,7 +2452,7 @@ int ED_gpencil_select_stroke_segment(bGPDlayer *gpl, } if (hit_a) { - f = gp_calc_factor(p2d_a1, p2d_a2, r_hit2d); + f = gpencil_calc_factor(p2d_a1, p2d_a2, r_hit2d); interp_v3_v3v3(r_hita, &pta1->x, &pta2->x, f); if (f > min_factor) { hit_pointa = pta2; /* first point is second (inverted loop) */ @@ -2468,7 +2485,7 @@ int ED_gpencil_select_stroke_segment(bGPDlayer *gpl, } if (hit_b) { - f = gp_calc_factor(p2d_a1, p2d_a2, r_hit2d); + f = gpencil_calc_factor(p2d_a1, p2d_a2, r_hit2d); interp_v3_v3v3(r_hitb, &pta1->x, &pta2->x, f); if (f > min_factor) { hit_pointb = pta1; @@ -2482,7 +2499,7 @@ int ED_gpencil_select_stroke_segment(bGPDlayer *gpl, /* insert new point in the collision points */ if (insert) { - gp_insert_point(gps, hit_pointa, hit_pointb, r_hita, r_hitb); + gpencil_insert_point(gps, hit_pointa, hit_pointb, r_hita, r_hitb); } /* free memory */ @@ -2610,7 +2627,10 @@ void ED_gpencil_select_toggle_all(bContext *C, int action) } } -/* Ensure the SBuffer (while drawing stroke) size is enough to save all points of the stroke */ +/** + * Ensure the #tGPspoint buffer (while drawing stroke) + * size is enough to save all points of the stroke. + */ tGPspoint *ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array, int *buffer_size, int *buffer_used, @@ -2661,10 +2681,12 @@ void ED_gpencil_sbuffer_update_eval(bGPdata *gpd, Object *ob_eval) gpd_eval->runtime.cp_points = gpd->runtime.cp_points; } -/* Tag all scene grease pencil object to update. */ +/** + * Tag all scene grease pencil object to update. + */ void ED_gpencil_tag_scene_gpencil(Scene *scene) { - /* mark all grease pencil datablocks of the scene */ + /* Mark all grease pencil data-blocks of the scene. */ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) { if (ob->type == OB_GPENCIL) { @@ -2748,7 +2770,7 @@ void ED_gpencil_init_random_settings(Brush *brush, random_settings->pressure = BLI_hash_int_01(BLI_hash_int_2d(ix + iz, iy + iz)) * 2.0f - 1.0f; } - /* Randomn to color strength. */ + /* Random to color strength. */ if (brush_settings->draw_random_strength) { random_settings->strength = BLI_hash_int_01(BLI_hash_int_2d(ix + iy, iy + iz + ix)) * 2.0f - 1.0f; @@ -2881,8 +2903,8 @@ void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph, /* Random Color. */ gpencil_sbuffer_vertex_color_random(gpd, brush, tpt, random_color, pen_pressure); - /* Copy to eval data because paint operators don't tag refresh until end for speedup - painting. */ + /* Copy to evaluate data because paint operators don't tag refresh until end for speedup + * painting. */ if (gpd_eval != NULL) { copy_v4_v4(gpd_eval->runtime.vert_color_fill, gpd->runtime.vert_color_fill); gpd_eval->runtime.matid = gpd->runtime.matid; @@ -2908,12 +2930,12 @@ bool ED_gpencil_stroke_check_collision(GP_SpaceConversion *gsc, /* Convert bound box to 2d */ copy_v3_v3(&pt_dummy.x, gps->boundbox_min); - gp_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps); - gp_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &boundbox_min[0], &boundbox_min[1]); + gpencil_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps); + gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &boundbox_min[0], &boundbox_min[1]); copy_v3_v3(&pt_dummy.x, gps->boundbox_max); - gp_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps); - gp_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &boundbox_max[0], &boundbox_max[1]); + gpencil_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps); + gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &boundbox_max[0], &boundbox_max[1]); /* Ensure the bounding box is oriented to axis. */ if (boundbox_max[0] < boundbox_min[0]) { @@ -2925,7 +2947,7 @@ bool ED_gpencil_stroke_check_collision(GP_SpaceConversion *gsc, rcti rect_stroke = {boundbox_min[0], boundbox_max[0], boundbox_min[1], boundbox_max[1]}; - /* For mouse, add a small offet to avoid false negative in corners. */ + /* For mouse, add a small offset to avoid false negative in corners. */ rcti rect_mouse = {mouse[0] - offset, mouse[0] + offset, mouse[1] - offset, mouse[1] + offset}; /* Check collision between both rectangles. */ @@ -2933,12 +2955,13 @@ bool ED_gpencil_stroke_check_collision(GP_SpaceConversion *gsc, } /** - * Check if a point is inside of the stroke - * \param gps: Stroke to check - * \param gsc: SpaceConversion data - * \param mouse: Mouse position - * \param diff_mat: View matrix - * \return True if the point is inside + * Check if a point is inside of the stroke. + * + * \param gps: Stroke to check. + * \param gsc: Space conversion data. + * \param mouse: Mouse position. + * \param diff_mat: View matrix. + * \return True if the point is inside. */ bool ED_gpencil_stroke_point_is_inside(bGPDstroke *gps, GP_SpaceConversion *gsc, @@ -2959,11 +2982,11 @@ bool ED_gpencil_stroke_point_is_inside(bGPDstroke *gps, int i; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { bGPDspoint pt2; - gp_point_to_parent_space(pt, diff_mat, &pt2); - gp_point_to_xy(gsc, gps, &pt2, &mcoords[i][0], &mcoords[i][1]); + gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_xy(gsc, gps, &pt2, &mcoords[i][0], &mcoords[i][1]); } - /* Compute boundbox of lasso (for faster testing later). */ + /* Compute bound-box of lasso (for faster testing later). */ rcti rect; BLI_lasso_boundbox(&rect, mcoords, len); diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c index 0dfc7e0728e..e21b2049028 100644 --- a/source/blender/editors/gpencil/gpencil_uv.c +++ b/source/blender/editors/gpencil/gpencil_uv.c @@ -148,7 +148,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op) opdata->ob = CTX_data_active_object(C); opdata->gpd = (bGPdata *)opdata->ob->data; - gp_point_conversion_init(C, &opdata->gsc); + gpencil_point_conversion_init(C, &opdata->gsc); opdata->array_loc = NULL; opdata->array_rot = NULL; opdata->array_scale = NULL; @@ -197,7 +197,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op) GP_EDITABLE_STROKES_END(gpstroke_iter); } /* Convert to 2D. */ - gp_point_3d_to_xy(&opdata->gsc, GP_STROKE_3DSPACE, center, opdata->mcenter); + gpencil_point_3d_to_xy(&opdata->gsc, GP_STROKE_3DSPACE, center, opdata->mcenter); return true; } diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index 4db88bd552f..36ce7d3dc47 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -74,7 +74,7 @@ static const EnumPropertyItem gpencil_modesEnumPropertyItem_mode[] = { }; /* Poll callback for stroke vertex paint operator. */ -static bool gp_vertexpaint_mode_poll(bContext *C) +static bool gpencil_vertexpaint_mode_poll(bContext *C) { ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); @@ -97,7 +97,7 @@ static bool gp_vertexpaint_mode_poll(bContext *C) return false; } -static int gp_vertexpaint_brightness_contrast_exec(bContext *C, wmOperator *op) +static int gpencil_vertexpaint_brightness_contrast_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -178,8 +178,8 @@ void GPENCIL_OT_vertex_color_brightness_contrast(wmOperatorType *ot) ot->description = "Adjust vertex color brightness/contrast"; /* api callbacks */ - ot->exec = gp_vertexpaint_brightness_contrast_exec; - ot->poll = gp_vertexpaint_mode_poll; + ot->exec = gpencil_vertexpaint_brightness_contrast_exec; + ot->poll = gpencil_vertexpaint_mode_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -192,7 +192,7 @@ void GPENCIL_OT_vertex_color_brightness_contrast(wmOperatorType *ot) RNA_def_property_ui_range(prop, min, max, 1, 1); } -static int gp_vertexpaint_hsv_exec(bContext *C, wmOperator *op) +static int gpencil_vertexpaint_hsv_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -273,8 +273,8 @@ void GPENCIL_OT_vertex_color_hsv(wmOperatorType *ot) ot->description = "Adjust vertex color HSV values"; /* api callbacks */ - ot->exec = gp_vertexpaint_hsv_exec; - ot->poll = gp_vertexpaint_mode_poll; + ot->exec = gpencil_vertexpaint_hsv_exec; + ot->poll = gpencil_vertexpaint_mode_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -286,7 +286,7 @@ void GPENCIL_OT_vertex_color_hsv(wmOperatorType *ot) RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f); } -static int gp_vertexpaint_invert_exec(bContext *C, wmOperator *op) +static int gpencil_vertexpaint_invert_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -344,8 +344,8 @@ void GPENCIL_OT_vertex_color_invert(wmOperatorType *ot) ot->description = "Invert RGB values"; /* api callbacks */ - ot->exec = gp_vertexpaint_invert_exec; - ot->poll = gp_vertexpaint_mode_poll; + ot->exec = gpencil_vertexpaint_invert_exec; + ot->poll = gpencil_vertexpaint_mode_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -354,7 +354,7 @@ void GPENCIL_OT_vertex_color_invert(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", ""); } -static int gp_vertexpaint_levels_exec(bContext *C, wmOperator *op) +static int gpencil_vertexpaint_levels_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -413,8 +413,8 @@ void GPENCIL_OT_vertex_color_levels(wmOperatorType *ot) ot->description = "Adjust levels of vertex colors"; /* api callbacks */ - ot->exec = gp_vertexpaint_levels_exec; - ot->poll = gp_vertexpaint_mode_poll; + ot->exec = gpencil_vertexpaint_levels_exec; + ot->poll = gpencil_vertexpaint_mode_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -428,13 +428,13 @@ void GPENCIL_OT_vertex_color_levels(wmOperatorType *ot) ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f); } -static int gp_vertexpaint_set_exec(bContext *C, wmOperator *op) +static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; Paint *paint = &ts->gp_vertexpaint->paint; - Brush *brush = brush = paint->brush; + Brush *brush = paint->brush; bool changed = false; int i; @@ -485,8 +485,8 @@ void GPENCIL_OT_vertex_color_set(wmOperatorType *ot) ot->description = "Set active color to all selected vertex"; /* api callbacks */ - ot->exec = gp_vertexpaint_set_exec; - ot->poll = gp_vertexpaint_mode_poll; + ot->exec = gpencil_vertexpaint_set_exec; + ot->poll = gpencil_vertexpaint_mode_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -497,7 +497,9 @@ void GPENCIL_OT_vertex_color_set(wmOperatorType *ot) } /* Helper to extract color from vertex color to create a palette. */ -static bool gp_extract_palette_from_vertex(bContext *C, const bool selected, const int threshold) +static bool gpencil_extract_palette_from_vertex(bContext *C, + const bool selected, + const int threshold) { Main *bmain = CTX_data_main(C); Object *ob = CTX_data_active_object(C); @@ -657,7 +659,7 @@ static uint get_material_type(MaterialGPencilStyle *gp_style, return r_i; } -static bool gp_material_to_vertex_poll(bContext *C) +static bool gpencil_material_to_vertex_poll(bContext *C) { /* only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); @@ -668,7 +670,7 @@ static bool gp_material_to_vertex_poll(bContext *C) return true; } -static int gp_material_to_vertex_exec(bContext *C, wmOperator *op) +static int gpencil_material_to_vertex_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Object *ob = CTX_data_active_object(C); @@ -814,7 +816,7 @@ static int gp_material_to_vertex_exec(bContext *C, wmOperator *op) /* Generate a Palette. */ if (palette) { - gp_extract_palette_from_vertex(C, selected, 1); + gpencil_extract_palette_from_vertex(C, selected, 1); } /* Clean unused materials. */ @@ -834,8 +836,8 @@ void GPENCIL_OT_material_to_vertex_color(wmOperatorType *ot) ot->description = "Replace materials in strokes with Vertex Color"; /* api callbacks */ - ot->exec = gp_material_to_vertex_exec; - ot->poll = gp_material_to_vertex_poll; + ot->exec = gpencil_material_to_vertex_exec; + ot->poll = gpencil_material_to_vertex_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -852,7 +854,7 @@ void GPENCIL_OT_material_to_vertex_color(wmOperatorType *ot) } /* Extract Palette from Vertex Color. */ -static bool gp_extract_palette_vertex_poll(bContext *C) +static bool gpencil_extract_palette_vertex_poll(bContext *C) { /* only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); @@ -863,12 +865,12 @@ static bool gp_extract_palette_vertex_poll(bContext *C) return true; } -static int gp_extract_palette_vertex_exec(bContext *C, wmOperator *op) +static int gpencil_extract_palette_vertex_exec(bContext *C, wmOperator *op) { const bool selected = RNA_boolean_get(op->ptr, "selected"); const int threshold = RNA_int_get(op->ptr, "threshold"); - if (gp_extract_palette_from_vertex(C, selected, threshold)) { + if (gpencil_extract_palette_from_vertex(C, selected, threshold)) { BKE_reportf(op->reports, RPT_INFO, "Palette created"); } else { @@ -886,8 +888,8 @@ void GPENCIL_OT_extract_palette_vertex(wmOperatorType *ot) ot->description = "Extract all colors used in Grease Pencil Vertex and create a Palette"; /* api callbacks */ - ot->exec = gp_extract_palette_vertex_exec; - ot->poll = gp_extract_palette_vertex_poll; + ot->exec = gpencil_extract_palette_vertex_exec; + ot->poll = gpencil_extract_palette_vertex_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index fe3f0871fdc..99d55350527 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -263,7 +263,7 @@ static void brush_calc_dvec_2d(tGP_BrushVertexpaintData *gso) * number of pixels (see: GP_GRID_PIXEL_SIZE) */ -static void gp_grid_cells_init(tGP_BrushVertexpaintData *gso) +static void gpencil_grid_cells_init(tGP_BrushVertexpaintData *gso) { tGP_Grid *grid; float bottom[2]; @@ -298,7 +298,7 @@ static void gp_grid_cells_init(tGP_BrushVertexpaintData *gso) } /* Get the index used in the grid base on dvec. */ -static void gp_grid_cell_average_color_idx_get(tGP_BrushVertexpaintData *gso, int r_idx[2]) +static void gpencil_grid_cell_average_color_idx_get(tGP_BrushVertexpaintData *gso, int r_idx[2]) { /* Lower direction. */ if (gso->dvec[1] < 0.0f) { @@ -348,7 +348,7 @@ static void gp_grid_cell_average_color_idx_get(tGP_BrushVertexpaintData *gso, in } } -static int gp_grid_cell_index_get(tGP_BrushVertexpaintData *gso, int pc[2]) +static int gpencil_grid_cell_index_get(tGP_BrushVertexpaintData *gso, int pc[2]) { float bottom[2], top[2]; @@ -366,7 +366,7 @@ static int gp_grid_cell_index_get(tGP_BrushVertexpaintData *gso, int pc[2]) } /* Fill the grid with the color in each cell and assign point cell index. */ -static void gp_grid_colors_calc(tGP_BrushVertexpaintData *gso) +static void gpencil_grid_colors_calc(tGP_BrushVertexpaintData *gso) { tGP_Selected *selected = NULL; bGPDstroke *gps_selected = NULL; @@ -383,7 +383,7 @@ static void gp_grid_colors_calc(tGP_BrushVertexpaintData *gso) selected = &gso->pbuffer[i]; gps_selected = selected->gps; pt = &gps_selected->points[selected->pt_index]; - int grid_index = gp_grid_cell_index_get(gso, selected->pc); + int grid_index = gpencil_grid_cell_index_get(gso, selected->pc); if (grid_index > -1) { grid = &gso->grid[grid_index]; @@ -639,7 +639,7 @@ static bool brush_smear_apply(tGP_BrushVertexpaintData *gso, /* Need get average colors in the grid. */ if ((!gso->grid_ready) && (gso->pbuffer_used > 0)) { - gp_grid_colors_calc(gso); + gpencil_grid_colors_calc(gso); } /* The influence is equal to strength and no decay around brush radius. */ @@ -657,10 +657,10 @@ static bool brush_smear_apply(tGP_BrushVertexpaintData *gso, inf *= fac; /* Retry row and col for average color. */ - gp_grid_cell_average_color_idx_get(gso, average_idx); + gpencil_grid_cell_average_color_idx_get(gso, average_idx); /* Retry average color cell. */ - int grid_index = gp_grid_cell_index_get(gso, selected->pc); + int grid_index = gpencil_grid_cell_index_get(gso, selected->pc); if (grid_index > -1) { int row = grid_index / gso->grid_size; int col = grid_index - (gso->grid_size * row); @@ -700,7 +700,7 @@ static bool brush_smear_apply(tGP_BrushVertexpaintData *gso, /* ************************************************ */ /* Header Info */ -static void gp_vertexpaint_brush_header_set(bContext *C) +static void gpencil_vertexpaint_brush_header_set(bContext *C) { ED_workspace_status_text(C, TIP_("GPencil Vertex Paint: LMB to paint | RMB/Escape to Exit" @@ -712,7 +712,7 @@ static void gp_vertexpaint_brush_header_set(bContext *C) /* Init/Exit ----------------------------------------------- */ -static bool gp_vertexpaint_brush_init(bContext *C, wmOperator *op) +static bool gpencil_vertexpaint_brush_init(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); @@ -765,15 +765,15 @@ static bool gp_vertexpaint_brush_init(bContext *C, wmOperator *op) } /* Setup space conversions. */ - gp_point_conversion_init(C, &gso->gsc); + gpencil_point_conversion_init(C, &gso->gsc); /* Update header. */ - gp_vertexpaint_brush_header_set(C); + gpencil_vertexpaint_brush_header_set(C); return true; } -static void gp_vertexpaint_brush_exit(bContext *C, wmOperator *op) +static void gpencil_vertexpaint_brush_exit(bContext *C, wmOperator *op) { tGP_BrushVertexpaintData *gso = op->customdata; @@ -791,17 +791,17 @@ static void gp_vertexpaint_brush_exit(bContext *C, wmOperator *op) } /* Poll callback for stroke vertex paint operator. */ -static bool gp_vertexpaint_brush_poll(bContext *C) +static bool gpencil_vertexpaint_brush_poll(bContext *C) { /* NOTE: this is a bit slower, but is the most accurate... */ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0; } /* Helper to save the points selected by the brush. */ -static void gp_save_selected_point(tGP_BrushVertexpaintData *gso, - bGPDstroke *gps, - int index, - int pc[2]) +static void gpencil_save_selected_point(tGP_BrushVertexpaintData *gso, + bGPDstroke *gps, + int index, + int pc[2]) { tGP_Selected *selected; bGPDspoint *pt = &gps->points[index]; @@ -822,10 +822,10 @@ static void gp_save_selected_point(tGP_BrushVertexpaintData *gso, } /* Select points in this stroke and add to an array to be used later. */ -static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, - bGPDstroke *gps, - const char tool, - const float diff_mat[4][4]) +static void gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, + bGPDstroke *gps, + const char tool, + const float diff_mat[4][4]) { GP_SpaceConversion *gsc = &gso->gsc; rcti *rect = &gso->brush_rect; @@ -851,8 +851,8 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, if (gps->totpoints == 1) { bGPDspoint pt_temp; pt = &gps->points[0]; - gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); - gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); + gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp); + gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; /* do boundbox check first */ @@ -863,7 +863,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, if (len_v2v2_int(mval_i, pc1) <= radius) { /* apply operation to this point */ if (pt_active != NULL) { - gp_save_selected_point(gso, gps_active, 0, pc1); + gpencil_save_selected_point(gso, gps_active, 0, pc1); } } } @@ -888,11 +888,11 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, } bGPDspoint npt; - gp_point_to_parent_space(pt1, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); + gpencil_point_to_parent_space(pt1, diff_mat, &npt); + gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); - gp_point_to_parent_space(pt2, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); + gpencil_point_to_parent_space(pt2, diff_mat, &npt); + gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); /* Check that point segment of the boundbox of the selection stroke */ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || @@ -901,7 +901,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, * brush region (either within stroke painted, or on its lines) * - this assumes that linewidth is irrelevant */ - if (gp_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { + if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { /* To each point individually... */ pt = &gps->points[i]; @@ -914,7 +914,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, continue; } hit = true; - gp_save_selected_point(gso, gps_active, index, pc1); + gpencil_save_selected_point(gso, gps_active, index, pc1); } /* Only do the second point if this is the last segment, @@ -931,7 +931,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1; if (pt_active != NULL) { hit = true; - gp_save_selected_point(gso, gps_active, index, pc2); + gpencil_save_selected_point(gso, gps_active, index, pc2); include_last = false; } } @@ -950,7 +950,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { hit = true; - gp_save_selected_point(gso, gps_active, index, pc1); + gpencil_save_selected_point(gso, gps_active, index, pc1); include_last = false; } @@ -970,7 +970,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, /* Need repeat the effect because if we don't do that the tint process * is very slow. */ for (int repeat = 0; repeat < 50; repeat++) { - gp_save_selected_point(gso, gps_active, -1, NULL); + gpencil_save_selected_point(gso, gps_active, -1, NULL); } } } @@ -979,11 +979,11 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, } /* Apply vertex paint brushes to strokes in the given frame. */ -static bool gp_vertexpaint_brush_do_frame(bContext *C, - tGP_BrushVertexpaintData *gso, - bGPDlayer *gpl, - bGPDframe *gpf, - const float diff_mat[4][4]) +static bool gpencil_vertexpaint_brush_do_frame(bContext *C, + tGP_BrushVertexpaintData *gso, + bGPDlayer *gpl, + bGPDframe *gpf, + const float diff_mat[4][4]) { Object *ob = CTX_data_active_object(C); const char tool = ob->mode == OB_MODE_VERTEX_GPENCIL ? gso->brush->gpencil_vertex_tool : @@ -1010,7 +1010,7 @@ static bool gp_vertexpaint_brush_do_frame(bContext *C, } /* Check points below the brush. */ - gp_vertexpaint_select_stroke(gso, gps, tool, diff_mat); + gpencil_vertexpaint_select_stroke(gso, gps, tool, diff_mat); } /* For Average tool, need calculate the average resulting color from all colors @@ -1092,7 +1092,7 @@ static bool gp_vertexpaint_brush_do_frame(bContext *C, } /* Apply brush effect to all layers. */ -static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpaintData *gso) +static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpaintData *gso) { ToolSettings *ts = CTX_data_tool_settings(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); @@ -1138,7 +1138,7 @@ static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpai } /* affect strokes in this frame */ - changed |= gp_vertexpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat); + changed |= gpencil_vertexpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat); } } } @@ -1146,7 +1146,7 @@ static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpai /* Apply to active frame's strokes */ if (gpl->actframe != NULL) { gso->mf_falloff = 1.0f; - changed |= gp_vertexpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); + changed |= gpencil_vertexpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); } } } @@ -1155,7 +1155,7 @@ static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpai } /* Calculate settings for applying brush */ -static void gp_vertexpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) +static void gpencil_vertexpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) { tGP_BrushVertexpaintData *gso = op->customdata; Brush *brush = gso->brush; @@ -1196,9 +1196,9 @@ static void gp_vertexpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA * brush_calc_dvec_2d(gso); /* Calc grid for smear tool. */ - gp_grid_cells_init(gso); + gpencil_grid_cells_init(gso); - changed = gp_vertexpaint_brush_apply_to_layers(C, gso); + changed = gpencil_vertexpaint_brush_apply_to_layers(C, gso); /* Updates */ if (changed) { @@ -1216,7 +1216,9 @@ static void gp_vertexpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA * /* Running --------------------------------------------- */ /* helper - a record stroke, and apply paint event */ -static void gp_vertexpaint_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event) +static void gpencil_vertexpaint_brush_apply_event(bContext *C, + wmOperator *op, + const wmEvent *event) { tGP_BrushVertexpaintData *gso = op->customdata; PointerRNA itemptr; @@ -1238,28 +1240,28 @@ static void gp_vertexpaint_brush_apply_event(bContext *C, wmOperator *op, const RNA_float_set(&itemptr, "pressure", pressure); /* apply */ - gp_vertexpaint_brush_apply(C, op, &itemptr); + gpencil_vertexpaint_brush_apply(C, op, &itemptr); } /* reapply */ -static int gp_vertexpaint_brush_exec(bContext *C, wmOperator *op) +static int gpencil_vertexpaint_brush_exec(bContext *C, wmOperator *op) { - if (!gp_vertexpaint_brush_init(C, op)) { + if (!gpencil_vertexpaint_brush_init(C, op)) { return OPERATOR_CANCELLED; } RNA_BEGIN (op->ptr, itemptr, "stroke") { - gp_vertexpaint_brush_apply(C, op, &itemptr); + gpencil_vertexpaint_brush_apply(C, op, &itemptr); } RNA_END; - gp_vertexpaint_brush_exit(C, op); + gpencil_vertexpaint_brush_exit(C, op); return OPERATOR_FINISHED; } /* start modal painting */ -static int gp_vertexpaint_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int gpencil_vertexpaint_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event) { tGP_BrushVertexpaintData *gso = NULL; const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input"); @@ -1273,7 +1275,7 @@ static int gp_vertexpaint_brush_invoke(bContext *C, wmOperator *op, const wmEven } /* init painting data */ - if (!gp_vertexpaint_brush_init(C, op)) { + if (!gpencil_vertexpaint_brush_init(C, op)) { return OPERATOR_CANCELLED; } @@ -1288,7 +1290,7 @@ static int gp_vertexpaint_brush_invoke(bContext *C, wmOperator *op, const wmEven /* apply first dab... */ gso->is_painting = true; - gp_vertexpaint_brush_apply_event(C, op, event); + gpencil_vertexpaint_brush_apply_event(C, op, event); /* redraw view with feedback */ ED_region_tag_redraw(region); @@ -1298,7 +1300,7 @@ static int gp_vertexpaint_brush_invoke(bContext *C, wmOperator *op, const wmEven } /* painting - handle events */ -static int gp_vertexpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent *event) +static int gpencil_vertexpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent *event) { tGP_BrushVertexpaintData *gso = op->customdata; const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input"); @@ -1313,7 +1315,7 @@ static int gp_vertexpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent case MOUSEMOVE: case INBETWEEN_MOUSEMOVE: /* apply brush effect at new position */ - gp_vertexpaint_brush_apply_event(C, op, event); + gpencil_vertexpaint_brush_apply_event(C, op, event); /* force redraw, so that the cursor will at least be valid */ redraw_region = true; @@ -1329,7 +1331,7 @@ static int gp_vertexpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent /* end painting, since we're not modal */ gso->is_painting = false; - gp_vertexpaint_brush_exit(C, op); + gpencil_vertexpaint_brush_exit(C, op); return OPERATOR_FINISHED; } break; @@ -1338,7 +1340,7 @@ static int gp_vertexpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent case MIDDLEMOUSE: case RIGHTMOUSE: case EVT_ESCKEY: - gp_vertexpaint_brush_exit(C, op); + gpencil_vertexpaint_brush_exit(C, op); return OPERATOR_FINISHED; } } @@ -1353,13 +1355,13 @@ static int gp_vertexpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent gso->is_painting = true; gso->first = true; - gp_vertexpaint_brush_apply_event(C, op, event); + gpencil_vertexpaint_brush_apply_event(C, op, event); break; /* Exit modal operator, based on the "standard" ops */ case RIGHTMOUSE: case EVT_ESCKEY: - gp_vertexpaint_brush_exit(C, op); + gpencil_vertexpaint_brush_exit(C, op); return OPERATOR_FINISHED; /* MMB is often used for view manipulations */ @@ -1421,11 +1423,11 @@ void GPENCIL_OT_vertex_paint(wmOperatorType *ot) ot->description = "Paint stroke points with a color"; /* api callbacks */ - ot->exec = gp_vertexpaint_brush_exec; - ot->invoke = gp_vertexpaint_brush_invoke; - ot->modal = gp_vertexpaint_brush_modal; - ot->cancel = gp_vertexpaint_brush_exit; - ot->poll = gp_vertexpaint_brush_poll; + ot->exec = gpencil_vertexpaint_brush_exec; + ot->invoke = gpencil_vertexpaint_brush_invoke; + ot->modal = gpencil_vertexpaint_brush_modal; + ot->cancel = gpencil_vertexpaint_brush_exit; + ot->poll = gpencil_vertexpaint_brush_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c index 2ebf1aba353..e41146575e4 100644 --- a/source/blender/editors/gpencil/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil/gpencil_weight_paint.c @@ -268,7 +268,7 @@ static bool brush_draw_apply(tGP_BrushWeightpaintData *gso, /* ************************************************ */ /* Header Info */ -static void gp_weightpaint_brush_header_set(bContext *C) +static void gpencil_weightpaint_brush_header_set(bContext *C) { ED_workspace_status_text(C, TIP_("GPencil Weight Paint: LMB to paint | RMB/Escape to Exit")); } @@ -278,7 +278,7 @@ static void gp_weightpaint_brush_header_set(bContext *C) /* Init/Exit ----------------------------------------------- */ -static bool gp_weightpaint_brush_init(bContext *C, wmOperator *op) +static bool gpencil_weightpaint_brush_init(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); @@ -330,15 +330,15 @@ static bool gp_weightpaint_brush_init(bContext *C, wmOperator *op) } /* Setup space conversions. */ - gp_point_conversion_init(C, &gso->gsc); + gpencil_point_conversion_init(C, &gso->gsc); /* Update header. */ - gp_weightpaint_brush_header_set(C); + gpencil_weightpaint_brush_header_set(C); return true; } -static void gp_weightpaint_brush_exit(bContext *C, wmOperator *op) +static void gpencil_weightpaint_brush_exit(bContext *C, wmOperator *op) { tGP_BrushWeightpaintData *gso = op->customdata; @@ -352,17 +352,17 @@ static void gp_weightpaint_brush_exit(bContext *C, wmOperator *op) } /* Poll callback for stroke weight paint operator. */ -static bool gp_weightpaint_brush_poll(bContext *C) +static bool gpencil_weightpaint_brush_poll(bContext *C) { /* NOTE: this is a bit slower, but is the most accurate... */ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0; } /* Helper to save the points selected by the brush. */ -static void gp_save_selected_point(tGP_BrushWeightpaintData *gso, - bGPDstroke *gps, - int index, - int pc[2]) +static void gpencil_save_selected_point(tGP_BrushWeightpaintData *gso, + bGPDstroke *gps, + int index, + int pc[2]) { tGP_Selected *selected; bGPDspoint *pt = &gps->points[index]; @@ -381,9 +381,9 @@ static void gp_save_selected_point(tGP_BrushWeightpaintData *gso, } /* Select points in this stroke and add to an array to be used later. */ -static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, - bGPDstroke *gps, - const float diff_mat[4][4]) +static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, + bGPDstroke *gps, + const float diff_mat[4][4]) { GP_SpaceConversion *gsc = &gso->gsc; rcti *rect = &gso->brush_rect; @@ -409,8 +409,8 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, if (gps->totpoints == 1) { bGPDspoint pt_temp; pt = &gps->points[0]; - gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); - gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); + gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp); + gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; /* do boundbox check first */ @@ -421,7 +421,7 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, if (len_v2v2_int(mval_i, pc1) <= radius) { /* apply operation to this point */ if (pt_active != NULL) { - gp_save_selected_point(gso, gps_active, 0, pc1); + gpencil_save_selected_point(gso, gps_active, 0, pc1); } } } @@ -436,11 +436,11 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, pt2 = gps->points + i + 1; bGPDspoint npt; - gp_point_to_parent_space(pt1, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); + gpencil_point_to_parent_space(pt1, diff_mat, &npt); + gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); - gp_point_to_parent_space(pt2, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); + gpencil_point_to_parent_space(pt2, diff_mat, &npt); + gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); /* Check that point segment of the boundbox of the selection stroke */ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || @@ -449,14 +449,14 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, * brush region (either within stroke painted, or on its lines) * - this assumes that linewidth is irrelevant */ - if (gp_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { + if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { /* To each point individually... */ pt = &gps->points[i]; pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { - gp_save_selected_point(gso, gps_active, index, pc1); + gpencil_save_selected_point(gso, gps_active, index, pc1); } /* Only do the second point if this is the last segment, @@ -472,7 +472,7 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1; if (pt_active != NULL) { - gp_save_selected_point(gso, gps_active, index, pc2); + gpencil_save_selected_point(gso, gps_active, index, pc2); include_last = false; } } @@ -490,7 +490,7 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { - gp_save_selected_point(gso, gps_active, index, pc1); + gpencil_save_selected_point(gso, gps_active, index, pc1); include_last = false; } @@ -501,11 +501,11 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, } /* Apply weight paint brushes to strokes in the given frame. */ -static bool gp_weightpaint_brush_do_frame(bContext *C, - tGP_BrushWeightpaintData *gso, - bGPDlayer *gpl, - bGPDframe *gpf, - const float diff_mat[4][4]) +static bool gpencil_weightpaint_brush_do_frame(bContext *C, + tGP_BrushWeightpaintData *gso, + bGPDlayer *gpl, + bGPDframe *gpf, + const float diff_mat[4][4]) { Object *ob = CTX_data_active_object(C); char tool = gso->brush->gpencil_weight_tool; @@ -531,7 +531,7 @@ static bool gp_weightpaint_brush_do_frame(bContext *C, } /* Check points below the brush. */ - gp_weightpaint_select_stroke(gso, gps, diff_mat); + gpencil_weightpaint_select_stroke(gso, gps, diff_mat); } /*--------------------------------------------------------------------- @@ -561,7 +561,7 @@ static bool gp_weightpaint_brush_do_frame(bContext *C, } /* Apply brush effect to all layers. */ -static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpaintData *gso) +static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpaintData *gso) { ToolSettings *ts = CTX_data_tool_settings(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); @@ -608,7 +608,7 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai } /* affect strokes in this frame */ - changed |= gp_weightpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat); + changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat); } } } @@ -616,7 +616,7 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai if (gpl->actframe != NULL) { /* Apply to active frame's strokes */ gso->mf_falloff = 1.0f; - changed |= gp_weightpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); + changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); } } } @@ -625,7 +625,7 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai } /* Calculate settings for applying brush */ -static void gp_weightpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) +static void gpencil_weightpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) { tGP_BrushWeightpaintData *gso = op->customdata; Brush *brush = gso->brush; @@ -658,7 +658,7 @@ static void gp_weightpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA * /* Calculate 2D direction vector and relative angle. */ brush_calc_dvec_2d(gso); - changed = gp_weightpaint_brush_apply_to_layers(C, gso); + changed = gpencil_weightpaint_brush_apply_to_layers(C, gso); /* Updates */ if (changed) { @@ -676,7 +676,9 @@ static void gp_weightpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA * /* Running --------------------------------------------- */ /* helper - a record stroke, and apply paint event */ -static void gp_weightpaint_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event) +static void gpencil_weightpaint_brush_apply_event(bContext *C, + wmOperator *op, + const wmEvent *event) { tGP_BrushWeightpaintData *gso = op->customdata; PointerRNA itemptr; @@ -698,28 +700,28 @@ static void gp_weightpaint_brush_apply_event(bContext *C, wmOperator *op, const RNA_float_set(&itemptr, "pressure", pressure); /* apply */ - gp_weightpaint_brush_apply(C, op, &itemptr); + gpencil_weightpaint_brush_apply(C, op, &itemptr); } /* reapply */ -static int gp_weightpaint_brush_exec(bContext *C, wmOperator *op) +static int gpencil_weightpaint_brush_exec(bContext *C, wmOperator *op) { - if (!gp_weightpaint_brush_init(C, op)) { + if (!gpencil_weightpaint_brush_init(C, op)) { return OPERATOR_CANCELLED; } RNA_BEGIN (op->ptr, itemptr, "stroke") { - gp_weightpaint_brush_apply(C, op, &itemptr); + gpencil_weightpaint_brush_apply(C, op, &itemptr); } RNA_END; - gp_weightpaint_brush_exit(C, op); + gpencil_weightpaint_brush_exit(C, op); return OPERATOR_FINISHED; } /* start modal painting */ -static int gp_weightpaint_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int gpencil_weightpaint_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event) { tGP_BrushWeightpaintData *gso = NULL; const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input"); @@ -733,7 +735,7 @@ static int gp_weightpaint_brush_invoke(bContext *C, wmOperator *op, const wmEven } /* init painting data */ - if (!gp_weightpaint_brush_init(C, op)) { + if (!gpencil_weightpaint_brush_init(C, op)) { return OPERATOR_CANCELLED; } @@ -748,7 +750,7 @@ static int gp_weightpaint_brush_invoke(bContext *C, wmOperator *op, const wmEven /* apply first dab... */ gso->is_painting = true; - gp_weightpaint_brush_apply_event(C, op, event); + gpencil_weightpaint_brush_apply_event(C, op, event); /* redraw view with feedback */ ED_region_tag_redraw(region); @@ -758,7 +760,7 @@ static int gp_weightpaint_brush_invoke(bContext *C, wmOperator *op, const wmEven } /* painting - handle events */ -static int gp_weightpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent *event) +static int gpencil_weightpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent *event) { tGP_BrushWeightpaintData *gso = op->customdata; const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input"); @@ -773,7 +775,7 @@ static int gp_weightpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent case MOUSEMOVE: case INBETWEEN_MOUSEMOVE: /* apply brush effect at new position */ - gp_weightpaint_brush_apply_event(C, op, event); + gpencil_weightpaint_brush_apply_event(C, op, event); /* force redraw, so that the cursor will at least be valid */ redraw_region = true; @@ -789,7 +791,7 @@ static int gp_weightpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent /* end painting, since we're not modal */ gso->is_painting = false; - gp_weightpaint_brush_exit(C, op); + gpencil_weightpaint_brush_exit(C, op); return OPERATOR_FINISHED; } break; @@ -798,7 +800,7 @@ static int gp_weightpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent case MIDDLEMOUSE: case RIGHTMOUSE: case EVT_ESCKEY: - gp_weightpaint_brush_exit(C, op); + gpencil_weightpaint_brush_exit(C, op); return OPERATOR_FINISHED; } } @@ -813,13 +815,13 @@ static int gp_weightpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent gso->is_painting = true; gso->first = true; - gp_weightpaint_brush_apply_event(C, op, event); + gpencil_weightpaint_brush_apply_event(C, op, event); break; /* Exit modal operator, based on the "standard" ops */ case RIGHTMOUSE: case EVT_ESCKEY: - gp_weightpaint_brush_exit(C, op); + gpencil_weightpaint_brush_exit(C, op); return OPERATOR_FINISHED; /* MMB is often used for view manipulations */ @@ -881,11 +883,11 @@ void GPENCIL_OT_weight_paint(wmOperatorType *ot) ot->description = "Paint stroke points with a color"; /* api callbacks */ - ot->exec = gp_weightpaint_brush_exec; - ot->invoke = gp_weightpaint_brush_invoke; - ot->modal = gp_weightpaint_brush_modal; - ot->cancel = gp_weightpaint_brush_exit; - ot->poll = gp_weightpaint_brush_poll; + ot->exec = gpencil_weightpaint_brush_exec; + ot->invoke = gpencil_weightpaint_brush_invoke; + ot->modal = gpencil_weightpaint_brush_modal; + ot->cancel = gpencil_weightpaint_brush_exit; + ot->poll = gpencil_weightpaint_brush_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 426a470b128..3aecec0d6b6 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -281,10 +281,13 @@ typedef enum eAnim_Update_Flags { /* filtering flags - under what circumstances should a channel be returned */ typedef enum eAnimFilter_Flags { - /** data which channel represents is fits the dopesheet filters - * (i.e. scene visibility criteria) */ - /* XXX: it's hard to think of any examples where this *ISN'T* the case... - * perhaps becomes implicit?. */ + /** + * Data which channel represents is fits the dope-sheet filters + * (i.e. scene visibility criteria). + * + * XXX: it's hard to think of any examples where this *ISN'T* the case... + * perhaps becomes implicit?. + */ ANIMFILTER_DATA_VISIBLE = (1 << 0), /** channel is visible within the channel-list hierarchy * (i.e. F-Curves within Groups in ActEdit) */ @@ -297,7 +300,7 @@ typedef enum eAnimFilter_Flags { /** for its type, channel should be "active" one */ ANIMFILTER_ACTIVE = (1 << 4), - /** channel is a child of the active group (* Actions speciality) */ + /** channel is a child of the active group (* Actions specialty) */ ANIMFILTER_ACTGROUPED = (1 << 5), /** channel must be selected/not-selected, but both must not be set together */ @@ -310,8 +313,10 @@ typedef enum eAnimFilter_Flags { * for Graph Editor's option for keys on select curves only */ ANIMFILTER_SELEDIT = (1 << 9), - /** flags used to enforce certain data types - * \node the ones for curves and NLA tracks were redundant and have been removed for now... + /** + * Flags used to enforce certain data types. + * + * \note The ones for curves and NLA tracks were redundant and have been removed for now. */ ANIMFILTER_ANIMDATA = (1 << 10), @@ -321,7 +326,7 @@ typedef enum eAnimFilter_Flags { /** for checking if we should keep some collapsed channel around (internal use only!) */ ANIMFILTER_TMP_PEEK = (1 << 30), - /** ignore ONLYSEL flag from filterflag, (internal use only!) */ + /** Ignore ONLYSEL flag from #bDopeSheet.filterflag (internal use only!) */ ANIMFILTER_TMP_IGNORE_ONLYSEL = (1u << 31), } eAnimFilter_Flags; @@ -640,14 +645,14 @@ bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt); /* ---------- Current Frame Drawing ---------------- */ /* flags for Current Frame Drawing */ -enum eAnimEditDraw_CurrentFrame { +typedef enum eAnimEditDraw_CurrentFrame { /* plain time indicator with no special indicators */ /* DRAWCFRA_PLAIN = 0, */ /* UNUSED */ /* time indication in seconds or frames */ DRAWCFRA_UNIT_SECONDS = (1 << 0), /* draw indicator extra wide (for timeline) */ DRAWCFRA_WIDE = (1 << 1), -}; +} eAnimEditDraw_CurrentFrame; /* main call to draw current-frame indicator in an Animation Editor */ void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 541e2633512..eef431c40fa 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -174,7 +174,7 @@ void ED_operatormacros_armature(void); void ED_keymap_armature(struct wmKeyConfig *keyconf); /* armature_relations.c */ -int join_armature_exec(struct bContext *C, struct wmOperator *op); +int ED_armature_join_objects_exec(struct bContext *C, struct wmOperator *op); /* armature_select.c */ struct Base *ED_armature_base_and_ebone_from_select_buffer(struct Base **bases, diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 95c454043da..79f5f62f293 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -66,7 +66,7 @@ int ED_curve_nurb_select_count(struct View3D *v3d, struct Nurb *nu); bool ED_curve_nurb_select_all(const struct Nurb *nu); bool ED_curve_nurb_deselect_all(const struct Nurb *nu); -int join_curve_exec(struct bContext *C, struct wmOperator *op); +int ED_curve_join_objects_exec(struct bContext *C, struct wmOperator *op); /* editcurve_select.c */ bool ED_curve_select_check(struct View3D *v3d, struct EditNurb *editnurb); diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 2a1d9c2dd6c..f961f835f12 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -87,15 +87,24 @@ typedef enum eGP_ReprojectModes { * Used as part of the 'stroke cache' used during drawing of new strokes */ typedef struct tGPspoint { - float x, y; /* x and y coordinates of cursor (in relative to area) */ - float pressure; /* pressure of tablet at this point */ - float strength; /* pressure of tablet at this point for alpha factor */ - float time; /* Time relative to stroke start (used when converting to path) */ - float uv_fac; /* factor of uv along the stroke */ - float uv_rot; /* uv rotation for dor mode */ - float rnd[3]; /* rnd value */ - bool rnd_dirty; /* rnd flag */ - float vert_color[4]; /* Point vertex color. */ + /** Coordinates x and y of cursor (in relative to area). */ + float x, y; + /** Pressure of tablet at this point. */ + float pressure; + /** Pressure of tablet at this point for alpha factor. */ + float strength; + /** Time relative to stroke start (used when converting to path). */ + float time; + /** Factor of uv along the stroke. */ + float uv_fac; + /** UV rotation for dot mode. */ + float uv_rot; + /** Random value. */ + float rnd[3]; + /** Random flag. */ + bool rnd_dirty; + /** Point vertex color. */ + float vert_color[4]; } tGPspoint; /* ----------- Grease Pencil Tools/Context ------------- */ @@ -166,28 +175,31 @@ void ED_annotation_draw_ex(struct Scene *scene, const char spacetype); /* ----------- Grease-Pencil AnimEdit API ------------------ */ -bool ED_gplayer_frames_looper(struct bGPDlayer *gpl, - struct Scene *scene, - short (*gpf_cb)(struct bGPDframe *, struct Scene *)); -void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool onlysel); - -bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl); -void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode); -void ED_gplayer_frames_select_box(struct bGPDlayer *gpl, float min, float max, short select_mode); -void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, - struct bGPDlayer *gpl, - short tool, - short select_mode); +bool ED_gpencil_layer_frames_looper(struct bGPDlayer *gpl, + struct Scene *scene, + short (*gpf_cb)(struct bGPDframe *, struct Scene *)); +void ED_gpencil_layer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool onlysel); + +bool ED_gpencil_layer_frame_select_check(struct bGPDlayer *gpl); +void ED_gpencil_layer_frame_select_set(struct bGPDlayer *gpl, short mode); +void ED_gpencil_layer_frames_select_box(struct bGPDlayer *gpl, + float min, + float max, + short select_mode); +void ED_gpencil_layer_frames_select_region(struct KeyframeEditData *ked, + struct bGPDlayer *gpl, + short tool, + short select_mode); void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode); void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode); -bool ED_gplayer_frames_delete(struct bGPDlayer *gpl); -void ED_gplayer_frames_duplicate(struct bGPDlayer *gpl); +bool ED_gpencil_layer_frames_delete(struct bGPDlayer *gpl); +void ED_gpencil_layer_frames_duplicate(struct bGPDlayer *gpl); -void ED_gplayer_frames_keytype_set(struct bGPDlayer *gpl, short type); +void ED_gpencil_layer_frames_keytype_set(struct bGPDlayer *gpl, short type); -void ED_gplayer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode); -void ED_gplayer_mirror_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode); +void ED_gpencil_layer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode); +void ED_gpencil_layer_mirror_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode); void ED_gpencil_anim_copybuf_free(void); bool ED_gpencil_anim_copybuf_copy(struct bAnimContext *ac); @@ -242,18 +254,18 @@ void ED_gpencil_add_defaults(struct bContext *C, struct Object *ob); void ED_gpencil_setup_modes(struct bContext *C, struct bGPdata *gpd, int newmode); bool ED_object_gpencil_exit(struct Main *bmain, struct Object *ob); -void ED_gp_project_stroke_to_plane(const struct Scene *scene, - const struct Object *ob, - const struct RegionView3D *rv3d, - struct bGPDstroke *gps, - const float origin[3], - const int axis); -void ED_gp_project_point_to_plane(const struct Scene *scene, - const struct Object *ob, - const struct RegionView3D *rv3d, - const float origin[3], - const int axis, - struct bGPDspoint *pt); +void ED_gpencil_project_stroke_to_plane(const struct Scene *scene, + const struct Object *ob, + const struct RegionView3D *rv3d, + struct bGPDstroke *gps, + const float origin[3], + const int axis); +void ED_gpencil_project_point_to_plane(const struct Scene *scene, + const struct Object *ob, + const struct RegionView3D *rv3d, + const float origin[3], + const int axis, + struct bGPDspoint *pt); void ED_gpencil_drawing_reference_get(const struct Scene *scene, const struct Object *ob, char align_flag, diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h index 938d1059f90..5c2106b934c 100644 --- a/source/blender/editors/include/ED_mball.h +++ b/source/blender/editors/include/ED_mball.h @@ -38,8 +38,12 @@ void ED_operatortypes_metaball(void); void ED_operatormacros_metaball(void); void ED_keymap_metaball(struct wmKeyConfig *keyconf); -struct MetaElem *ED_mball_add_primitive( - struct bContext *C, struct Object *obedit, float mat[4][4], float dia, int type); +struct MetaElem *ED_mball_add_primitive(struct bContext *C, + struct Object *obedit, + bool obedit_is_new, + float mat[4][4], + float dia, + int type); bool ED_mball_select_pick( struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 20e54df1ccb..9c49d991182 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -426,6 +426,15 @@ bool ED_mesh_color_remove_index(struct Mesh *me, const int n); bool ED_mesh_color_remove_active(struct Mesh *me); bool ED_mesh_color_remove_named(struct Mesh *me, const char *name); +bool ED_mesh_sculpt_color_ensure(struct Mesh *me, const char *name); +int ED_mesh_sculpt_color_add(struct Mesh *me, + const char *name, + const bool active_set, + const bool do_init); +bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, const int n); +bool ED_mesh_sculpt_color_remove_active(struct Mesh *me); +bool ED_mesh_sculpt_color_remove_named(struct Mesh *me, const char *name); + void ED_mesh_report_mirror(struct wmOperator *op, int totmirr, int totfail); void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, char selectmode); @@ -445,8 +454,8 @@ void EDBM_redo_state_restore(struct BMBackup, struct BMEditMesh *em, int recalct void EDBM_redo_state_free(struct BMBackup *, struct BMEditMesh *em, int recalctess); /* *** meshtools.c *** */ -int join_mesh_exec(struct bContext *C, struct wmOperator *op); -int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op); +int ED_mesh_join_objects_exec(struct bContext *C, struct wmOperator *op); +int ED_mesh_shapes_join_objects_exec(struct bContext *C, struct wmOperator *op); /* mirror lookup api */ /* Spatial Mirror */ diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 5c33513f0a4..73c58753531 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -185,7 +185,7 @@ struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, - int dupflag); + const uint dupflag); void ED_object_parent(struct Object *ob, struct Object *parent, @@ -421,6 +421,10 @@ int ED_object_gpencil_modifier_move_down(struct ReportList *reports, int ED_object_gpencil_modifier_move_up(struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md); +bool ED_object_gpencil_modifier_move_to_index(struct ReportList *reports, + struct Object *ob, + struct GpencilModifierData *md, + const int index); int ED_object_gpencil_modifier_apply(struct Main *bmain, struct ReportList *reports, struct Depsgraph *depsgraph, @@ -449,6 +453,10 @@ int ED_object_shaderfx_move_down(struct ReportList *reports, int ED_object_shaderfx_move_up(struct ReportList *reports, struct Object *ob, struct ShaderFxData *fx); +bool ED_object_shaderfx_move_to_index(struct ReportList *reports, + struct Object *ob, + struct ShaderFxData *fx, + const int index); /* object_select.c */ void ED_object_select_linked_by_id(struct bContext *C, struct ID *id); diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index f03739c74c4..ba70abcc055 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -47,7 +47,7 @@ void ED_operatortypes_render(void); /* render_update.c */ -void ED_render_engine_changed(struct Main *bmain); +void ED_render_engine_changed(struct Main *bmain, const bool update_scene_data); void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *area); void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *screen); diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h index 51f3eea74fa..9826ec8c3b8 100644 --- a/source/blender/editors/include/ED_screen_types.h +++ b/source/blender/editors/include/ED_screen_types.h @@ -131,7 +131,7 @@ enum { */ AZONE_FULLSCREEN, /** - * Hotspot azone around scroll-bars to show/hide them. + * Hot-spot #AZone around scroll-bars to show/hide them. * Only show the scroll-bars when the cursor is close. */ AZONE_REGION_SCROLL, diff --git a/source/blender/editors/include/ED_time_scrub_ui.h b/source/blender/editors/include/ED_time_scrub_ui.h index d5b9fa2a553..483dce56577 100644 --- a/source/blender/editors/include/ED_time_scrub_ui.h +++ b/source/blender/editors/include/ED_time_scrub_ui.h @@ -32,6 +32,11 @@ struct bContext; struct bDopeSheet; struct wmEvent; +void ED_time_scrub_draw_current_frame(const struct ARegion *region, + const struct Scene *scene, + bool display_seconds, + bool draw_vert_line); + void ED_time_scrub_draw(const struct ARegion *region, const struct Scene *scene, bool display_seconds, diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 59dcc9a8ace..1cedd4e122f 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1706,12 +1706,17 @@ void UI_panel_category_draw_all(struct ARegion *region, const char *category_id_ struct PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname); +struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContext *C, + const struct wmEvent *event); +void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data); + /* Polyinstantiated panels for representing a list of data. */ struct Panel *UI_panel_add_instanced(struct ScrArea *area, struct ARegion *region, struct ListBase *panels, char *panel_idname, - int list_index); + int list_index, + struct PointerRNA *custom_data); void UI_panels_free_instanced(struct bContext *C, struct ARegion *region); #define LIST_PANEL_UNIQUE_STR_LEN 4 @@ -2004,6 +2009,10 @@ void uiTemplatePathBuilder(uiLayout *layout, struct PointerRNA *root_ptr, const char *text); void uiTemplateModifiers(uiLayout *layout, struct bContext *C); +void uiTemplateGpencilModifiers(uiLayout *layout, struct bContext *C); +void uiTemplateShaderFx(uiLayout *layout, struct bContext *C); +void uiTemplateConstraints(uiLayout *layout, struct bContext *C, bool use_bone_constraints); + uiLayout *uiTemplateGpencilModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr); void uiTemplateGpencilColorPreview(uiLayout *layout, struct bContext *C, @@ -2014,11 +2023,9 @@ void uiTemplateGpencilColorPreview(uiLayout *layout, float scale, int filter); -uiLayout *uiTemplateShaderFx(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr); - void uiTemplateOperatorRedoProperties(uiLayout *layout, const struct bContext *C); -uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr); +void uiTemplateConstraintHeader(uiLayout *layout, struct PointerRNA *ptr); void uiTemplatePreview(uiLayout *layout, struct bContext *C, struct ID *id, diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index a304c76bc9d..0529ee08da6 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -106,6 +106,7 @@ struct PreviewImage *UI_icon_to_preview(int icon_id); int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, const bool big); int UI_idcode_icon_get(const int idcode); +int UI_library_icon_get(const struct ID *id); #ifdef __cplusplus } diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index ffc06e94a90..0ddc45f4878 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -180,9 +180,10 @@ void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *region, int colorid); /* scrollbar drawing */ -View2DScrollers *UI_view2d_scrollers_calc(struct View2D *v2d, const struct rcti *mask_custom); -void UI_view2d_scrollers_draw(struct View2D *v2d, View2DScrollers *scrollers); -void UI_view2d_scrollers_free(View2DScrollers *scrollers); +void UI_view2d_scrollers_calc(struct View2D *v2d, + const struct rcti *mask_custom, + struct View2DScrollers *r_scrollers); +void UI_view2d_scrollers_draw(struct View2D *v2d, const struct rcti *mask_custom); /* list view tools */ void UI_view2d_listview_view_to_cell(float columnwidth, diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 04c259ab092..55f41913499 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1504,7 +1504,7 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) void ui_but_override_flag(uiBut *but) { - const int override_status = RNA_property_override_library_status( + const uint override_status = RNA_property_override_library_status( &but->rnapoin, but->rnaprop, but->rnaindex); if (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN) { @@ -6422,7 +6422,7 @@ void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn co } /** - * \param separator_string: when not NULL, this string is used as a separator, + * \param search_sep_string: when not NULL, this string is used as a separator, * showing the icon and highlighted text after the last instance of this string. */ void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string) diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index cc370113422..15d00d8537b 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -561,7 +561,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) const bool is_array_component = (is_array && but->rnaindex != -1); const bool is_whole_array = (is_array && but->rnaindex == -1); - const int override_status = RNA_property_override_library_status(ptr, prop, -1); + const uint override_status = RNA_property_override_library_status(ptr, prop, -1); const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0; /* Set the (button_pointer, button_prop) diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 499d2f7f1fa..720a5bcff37 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -25,6 +25,7 @@ #include <string.h> #include "DNA_color_types.h" +#include "DNA_curve_types.h" #include "DNA_curveprofile_types.h" #include "DNA_movieclip_types.h" #include "DNA_screen_types.h" @@ -118,51 +119,53 @@ void UI_draw_roundbox_aa( bool filled, float minx, float miny, float maxx, float maxy, float rad, const float color[4]) { uiWidgetBaseParameters widget_params = { - .recti.xmin = minx, - .recti.ymin = miny, - .recti.xmax = maxx, - .recti.ymax = maxy, + .recti.xmin = minx + U.pixelsize, + .recti.ymin = miny + U.pixelsize, + .recti.xmax = maxx - U.pixelsize, + .recti.ymax = maxy - U.pixelsize, + .rect.xmin = minx, + .rect.ymin = miny, + .rect.xmax = maxx, + .rect.ymax = maxy, .radi = rad, + .rad = rad, .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f, .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f, .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f, .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f, - .color_inner1[0] = color[0], - .color_inner2[0] = color[0], - .color_inner1[1] = color[1], - .color_inner2[1] = color[1], - .color_inner1[2] = color[2], - .color_inner2[2] = color[2], - .color_inner1[3] = color[3], - .color_inner2[3] = color[3], + .color_inner1[0] = filled ? color[0] : 0.0f, + .color_inner1[1] = filled ? color[1] : 0.0f, + .color_inner1[2] = filled ? color[2] : 0.0f, + .color_inner1[3] = filled ? color[3] : 0.0f, + .color_inner2[0] = filled ? color[0] : 0.0f, + .color_inner2[1] = filled ? color[1] : 0.0f, + .color_inner2[2] = filled ? color[2] : 0.0f, + .color_inner2[3] = filled ? color[3] : 0.0f, + .color_outline[0] = color[0], + .color_outline[1] = color[1], + .color_outline[2] = color[2], + .color_outline[3] = color[3], .alpha_discard = 1.0f, }; - GPU_blend(true); - + /* XXX this is to emulate previous behavior of semitransparent fills but that's was a side effect + * of the previous AA method. Better fix the callers. */ if (filled) { - /* plain antialiased filled box */ - widget_params.color_inner1[3] *= 0.125f; - widget_params.color_inner2[3] *= 0.125f; - - /* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space. - * If it has been scaled, then it's no longer valid. */ - GPUBatch *batch = ui_batch_roundbox_get(filled, true); - GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); - GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params); - GPU_batch_draw(batch); + widget_params.color_inner1[3] *= 0.65f; + widget_params.color_inner2[3] *= 0.65f; + widget_params.color_outline[3] *= 0.65f; } - else { - /* plain antialiased unfilled box */ - GPU_line_smooth(true); - GPUBatch *batch = ui_batch_roundbox_get(filled, false); - GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); - GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params); - GPU_batch_draw(batch); + /* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space. + * If it has been scaled, then it's no longer valid. */ - GPU_line_smooth(false); - } + GPUBatch *batch = ui_batch_roundbox_widget_get(); + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); + GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params); + + GPU_blend(true); + + GPU_batch_draw(batch); GPU_blend(false); } @@ -251,32 +254,49 @@ void UI_draw_roundbox_4fv( immEnd(); immUnbindProgram(); #endif - uiWidgetBaseParameters widget_params = { - .recti.xmin = minx, - .recti.ymin = miny, - .recti.xmax = maxx, - .recti.ymax = maxy, + .recti.xmin = minx + U.pixelsize, + .recti.ymin = miny + U.pixelsize, + .recti.xmax = maxx - U.pixelsize, + .recti.ymax = maxy - U.pixelsize, + .rect.xmin = minx, + .rect.ymin = miny, + .rect.xmax = maxx, + .rect.ymax = maxy, .radi = rad, + .rad = rad, .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f, .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f, .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f, .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f, - .color_inner1[0] = col[0], - .color_inner2[0] = col[0], - .color_inner1[1] = col[1], - .color_inner2[1] = col[1], - .color_inner1[2] = col[2], - .color_inner2[2] = col[2], - .color_inner1[3] = col[3], - .color_inner2[3] = col[3], + .color_inner1[0] = filled ? col[0] : 0.0f, + .color_inner1[1] = filled ? col[1] : 0.0f, + .color_inner1[2] = filled ? col[2] : 0.0f, + .color_inner1[3] = filled ? col[3] : 0.0f, + .color_inner2[0] = filled ? col[0] : 0.0f, + .color_inner2[1] = filled ? col[1] : 0.0f, + .color_inner2[2] = filled ? col[2] : 0.0f, + .color_inner2[3] = filled ? col[3] : 0.0f, + .color_outline[0] = col[0], + .color_outline[1] = col[1], + .color_outline[2] = col[2], + .color_outline[3] = col[3], .alpha_discard = 1.0f, }; + /* Exactly the same as UI_draw_roundbox_aa but does not do the legacy transparency. */ - GPUBatch *batch = ui_batch_roundbox_get(filled, false); + /* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space. + * If it has been scaled, then it's no longer valid. */ + + GPUBatch *batch = ui_batch_roundbox_widget_get(); GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params); + + GPU_blend(true); + GPU_batch_draw(batch); + + GPU_blend(false); } #if 0 @@ -427,32 +447,46 @@ void UI_draw_roundbox_shade_x(bool filled, immEnd(); immUnbindProgram(); #endif - uiWidgetBaseParameters widget_params = { - .recti.xmin = minx, - .recti.ymin = miny, - .recti.xmax = maxx, - .recti.ymax = maxy, + .recti.xmin = minx + U.pixelsize, + .recti.ymin = miny + U.pixelsize, + .recti.xmax = maxx - U.pixelsize, + .recti.ymax = maxy - U.pixelsize, + .rect.xmin = minx, + .rect.ymin = miny, + .rect.xmax = maxx, + .rect.ymax = maxy, .radi = rad, + .rad = rad, .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f, .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f, .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f, .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f, - .color_inner1[0] = min_ff(1.0f, col[0] + shadetop), - .color_inner2[0] = max_ff(0.0f, col[0] + shadedown), - .color_inner1[1] = min_ff(1.0f, col[1] + shadetop), - .color_inner2[1] = max_ff(0.0f, col[1] + shadedown), - .color_inner1[2] = min_ff(1.0f, col[2] + shadetop), - .color_inner2[2] = max_ff(0.0f, col[2] + shadedown), - .color_inner1[3] = 1.0f, - .color_inner2[3] = 1.0f, + .color_inner1[0] = !filled ? 0.0f : min_ff(1.0f, col[0] + shadetop), + .color_inner1[1] = !filled ? 0.0f : min_ff(1.0f, col[1] + shadetop), + .color_inner1[2] = !filled ? 0.0f : min_ff(1.0f, col[2] + shadetop), + .color_inner1[3] = !filled ? 0.0f : 1.0f, + .color_inner2[0] = !filled ? 0.0f : max_ff(0.0f, col[0] + shadedown), + .color_inner2[1] = !filled ? 0.0f : max_ff(0.0f, col[1] + shadedown), + .color_inner2[2] = !filled ? 0.0f : max_ff(0.0f, col[2] + shadedown), + .color_inner2[3] = !filled ? 0.0f : 1.0f, + /* TODO: non-filled box don't have gradients. Just use middle color. */ + .color_outline[0] = clamp_f(col[0] + shadetop + shadedown, 0.0f, 1.0f), + .color_outline[1] = clamp_f(col[1] + shadetop + shadedown, 0.0f, 1.0f), + .color_outline[2] = clamp_f(col[2] + shadetop + shadedown, 0.0f, 1.0f), + .color_outline[3] = clamp_f(col[3] + shadetop + shadedown, 0.0f, 1.0f), + .shade_dir = 1.0f, .alpha_discard = 1.0f, }; - GPUBatch *batch = ui_batch_roundbox_get(filled, false); + GPU_blend(true); + + GPUBatch *batch = ui_batch_roundbox_widget_get(); GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params); GPU_batch_draw(batch); + + GPU_blend(false); } #if 0 /* unused */ @@ -765,10 +799,8 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region), * * \note This function is to be used with the 2D dashed shader enabled. * - * \param pos: is a PRIM_FLOAT, 2, GPU_FETCH_FLOAT vertex attribute. - * \param line_origin: is a PRIM_FLOAT, 2, GPU_FETCH_FLOAT vertex attribute. - * - * The next 4 parameters are the offsets for the view, not the zones. + * \param pos: is a #PRIM_FLOAT, 2, #GPU_FETCH_FLOAT vertex attribute. + * \param x1, x2, y1, y2: The offsets for the view, not the zones. */ void UI_draw_safe_areas(uint pos, float x1, @@ -801,7 +833,7 @@ void UI_draw_safe_areas(uint pos, static void draw_scope_end(const rctf *rect, GLint *scissor) { - /* restore scissortest */ + /* Restore scissor test. */ GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]); GPU_blend_set_func_separate( @@ -2131,7 +2163,19 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol, immUnbindProgram(); } -/** Used to draw a curve profile widget. Somewhat similar to ui_draw_but_CURVE */ +/** + * Helper for #ui_draw_but_CURVEPROFILE. Used to tell whether to draw a control point's handles. + */ +static bool point_draw_handles(CurveProfilePoint *point) +{ + return (point->flag & PROF_SELECT && + (ELEM(point->h1, HD_FREE, HD_ALIGN) || ELEM(point->h2, HD_FREE, HD_ALIGN))) || + ELEM(point->flag, PROF_H1_SELECT, PROF_H2_SELECT); +} + +/** + * Draws the curve profile widget. Somewhat similar to ui_draw_but_CURVE. + */ void ui_draw_but_CURVEPROFILE(ARegion *region, uiBut *but, const uiWidgetColors *wcol, @@ -2147,18 +2191,18 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, profile = (CurveProfile *)but->poin; } - /* Calculate offset and zoom */ + /* Calculate offset and zoom. */ float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&profile->view_rect); float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&profile->view_rect); float offsx = profile->view_rect.xmin - (1.0f / zoomx); float offsy = profile->view_rect.ymin - (1.0f / zoomy); - /* Exit early if too narrow */ + /* Exit early if too narrow. */ if (zoomx == 0.0f) { return; } - /* Test needed because path can draw outside of boundary */ + /* Test needed because path can draw outside of boundary. */ int scissor[4]; GPU_scissor_get_i(scissor); rcti scissor_new = { @@ -2180,7 +2224,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - /* Backdrop */ + /* Draw the backdrop. */ float color_backdrop[4] = {0, 0, 0, 1}; if (profile->flag & PROF_USE_CLIP) { gl_shaded_color_get_fl((uchar *)wcol->inner, -20, color_backdrop); @@ -2199,33 +2243,33 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); } - /* 0.25 step grid */ + /* 0.25 step grid. */ gl_shaded_color((uchar *)wcol->inner, -16); ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.25f); - /* 1.0 step grid */ + /* 1.0 step grid. */ gl_shaded_color((uchar *)wcol->inner, -24); ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 1.0f); - /* Draw the path's fill */ + /* Draw the path's fill. */ if (profile->table == NULL) { - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); } CurveProfilePoint *pts = profile->table; - /* Also add the last points on the right and bottom edges to close off the fill polygon */ + /* Also add the last points on the right and bottom edges to close off the fill polygon. */ bool add_left_tri = profile->view_rect.xmin < 0.0f; bool add_bottom_tri = profile->view_rect.ymin < 0.0f; uint tot_points = (uint)PROF_N_TABLE(profile->path_len) + 1 + add_left_tri + add_bottom_tri; uint tot_triangles = tot_points - 2; - /* Create array of the positions of the table's points */ + /* Create array of the positions of the table's points. */ float(*table_coords)[2] = MEM_mallocN(sizeof(*table_coords) * tot_points, "table x coords"); for (i = 0; i < (uint)PROF_N_TABLE(profile->path_len); - i++) { /* Only add the points from the table here */ + i++) { /* Only add the points from the table here. */ table_coords[i][0] = pts[i].x; table_coords[i][1] = pts[i].y; } if (add_left_tri && add_bottom_tri) { - /* Add left side, bottom left corner, and bottom side points */ + /* Add left side, bottom left corner, and bottom side points. */ table_coords[tot_points - 3][0] = profile->view_rect.xmin; table_coords[tot_points - 3][1] = 1.0f; table_coords[tot_points - 2][0] = profile->view_rect.xmin; @@ -2234,30 +2278,30 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, table_coords[tot_points - 1][1] = profile->view_rect.ymin; } else if (add_left_tri) { - /* Add the left side and bottom left corner points */ + /* Add the left side and bottom left corner points. */ table_coords[tot_points - 2][0] = profile->view_rect.xmin; table_coords[tot_points - 2][1] = 1.0f; table_coords[tot_points - 1][0] = profile->view_rect.xmin; table_coords[tot_points - 1][1] = 0.0f; } else if (add_bottom_tri) { - /* Add the bottom side and bottom left corner points */ + /* Add the bottom side and bottom left corner points. */ table_coords[tot_points - 2][0] = 0.0f; table_coords[tot_points - 2][1] = profile->view_rect.ymin; table_coords[tot_points - 1][0] = 1.0f; table_coords[tot_points - 1][1] = profile->view_rect.ymin; } else { - /* Just add the bottom corner point. Side points would be redundant anyway */ + /* Just add the bottom corner point. Side points would be redundant anyway. */ table_coords[tot_points - 1][0] = 0.0f; table_coords[tot_points - 1][1] = 0.0f; } - /* Calculate the table point indices of the triangles for the profile's fill */ + /* Calculate the table point indices of the triangles for the profile's fill. */ uint(*tri_indices)[3] = MEM_mallocN(sizeof(*tri_indices) * tot_triangles, "return tri indices"); BLI_polyfill_calc(table_coords, tot_points, -1, tri_indices); - /* Draw the triangles for the profile fill */ + /* Draw the triangles for the profile fill. */ immUniformColor3ubvAlpha((const uchar *)wcol->item, 128); GPU_blend(true); GPU_polygon_smooth(false); @@ -2273,7 +2317,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, immEnd(); MEM_freeN(tri_indices); - /* Draw the profile's path so the edge stands out a bit */ + /* Draw the profile's path so the edge stands out a bit. */ tot_points -= (add_left_tri + add_left_tri); GPU_line_width(1.0f); immUniformColor3ubvAlpha((const uchar *)wcol->item, 255); @@ -2285,9 +2329,44 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, immVertex2f(pos, fx, fy); } immEnd(); - immUnbindProgram(); MEM_freeN(table_coords); + /* Draw the handles for the selected control points. */ + pts = profile->path; + tot_points = (uint)profile->path_len; + int selected_free_points = 0; + for (i = 0; i < tot_points; i++) { + if (point_draw_handles(&pts[i])) { + selected_free_points++; + } + } + /* Draw the lines to the handles from the points. */ + if (selected_free_points > 0) { + GPU_line_width(1.0f); + gl_shaded_color((uchar *)wcol->inner, -24); + GPU_line_smooth(true); + immBegin(GPU_PRIM_LINES, selected_free_points * 4); + float ptx, pty; + for (i = 0; i < tot_points; i++) { + if (point_draw_handles(&pts[i])) { + ptx = rect->xmin + zoomx * (pts[i].x - offsx); + pty = rect->ymin + zoomy * (pts[i].y - offsy); + + fx = rect->xmin + zoomx * (pts[i].h1_loc[0] - offsx); + fy = rect->ymin + zoomy * (pts[i].h1_loc[1] - offsy); + immVertex2f(pos, ptx, pty); + immVertex2f(pos, fx, fy); + + fx = rect->xmin + zoomx * (pts[i].h2_loc[0] - offsx); + fy = rect->ymin + zoomy * (pts[i].h2_loc[1] - offsy); + immVertex2f(pos, ptx, pty); + immVertex2f(pos, fx, fy); + } + } + immEnd(); + } + immUnbindProgram(); + /* New GPU instructions for control points and sampled points. */ format = immVertexFormat(); pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); @@ -2311,8 +2390,6 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, } /* Draw the control points. */ - pts = profile->path; - tot_points = (uint)profile->path_len; GPU_line_smooth(false); GPU_blend(false); GPU_point_size(max_ff(3.0f, min_ff(UI_DPI_FAC / but->block->aspect * 5.0f, 5.0f))); @@ -2325,6 +2402,28 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, } immEnd(); + /* Draw the handle points. */ + if (selected_free_points > 0) { + GPU_line_smooth(false); + GPU_blend(false); + GPU_point_size(max_ff(2.0f, min_ff(UI_DPI_FAC / but->block->aspect * 4.0f, 4.0f))); + immBegin(GPU_PRIM_POINTS, selected_free_points * 2); + for (i = 0; i < tot_points; i++) { + if (point_draw_handles(&pts[i])) { + fx = rect->xmin + zoomx * (pts[i].h1_loc[0] - offsx); + fy = rect->ymin + zoomy * (pts[i].h1_loc[1] - offsy); + immAttr4fv(col, (pts[i].flag & PROF_H1_SELECT) ? color_vert_select : color_vert); + immVertex2f(pos, fx, fy); + + fx = rect->xmin + zoomx * (pts[i].h2_loc[0] - offsx); + fy = rect->ymin + zoomy * (pts[i].h2_loc[1] - offsy); + immAttr4fv(col, (pts[i].flag & PROF_H2_SELECT) ? color_vert_select : color_vert); + immVertex2f(pos, fx, fy); + } + } + immEnd(); + } + /* Draw the sampled points in addition to the control points if they have been created */ pts = profile->segments; tot_points = (uint)profile->segments_len; @@ -2339,7 +2438,6 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, } immEnd(); } - immUnbindProgram(); /* restore scissortest */ @@ -2678,7 +2776,6 @@ void ui_draw_dropshadow( GPU_batch_draw(batch); /* outline emphasis */ - GPU_line_smooth(true); float color[4] = {0.0f, 0.0f, 0.0f, 0.4f}; UI_draw_roundbox_4fv(false, rct->xmin - 0.5f, @@ -2687,7 +2784,6 @@ void ui_draw_dropshadow( rct->ymax + 0.5f, radius + 0.5f, color); - GPU_line_smooth(false); GPU_blend(false); } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 42feda0e1bc..f6bfb492c92 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -4872,7 +4872,7 @@ static void ui_numedit_set_active(uiBut *but) /* Don't change the cursor once pressed. */ if ((but->flag & UI_SELECT) == 0) { - if ((but->drawflag & (UI_BUT_ACTIVE_LEFT)) || (but->drawflag & (UI_BUT_ACTIVE_RIGHT))) { + if ((but->drawflag & UI_BUT_ACTIVE_LEFT) || (but->drawflag & UI_BUT_ACTIVE_RIGHT)) { if (data->changed_cursor) { WM_cursor_modal_restore(data->window); data->changed_cursor = false; @@ -6944,7 +6944,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block, d[0] = mx - data->dragstartx; d[1] = my - data->dragstarty; - if (len_squared_v2(d) < (3.0f * 3.0f)) { + if (len_squared_v2(d) < (9.0f * U.dpi_fac)) { snap = false; } } @@ -6953,32 +6953,38 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block, fy = (my - dragy) / zoomy; if (data->dragsel != -1) { - CurveProfilePoint *point_last = NULL; + float last_x, last_y; const float mval_factor = ui_mouse_scale_warp_factor(shift); bool moved_point = false; /* for ctrl grid, can't use orig coords because of sorting */ fx *= mval_factor; fy *= mval_factor; - /* Move all the points that aren't the last or the first */ - for (a = 1; a < profile->path_len - 1; a++) { - if (pts[a].flag & PROF_SELECT) { - float origx = pts[a].x, origy = pts[a].y; - pts[a].x += fx; - pts[a].y += fy; - if (snap) { - pts[a].x = 0.125f * roundf(8.0f * pts[a].x); - pts[a].y = 0.125f * roundf(8.0f * pts[a].y); + /* Move all selected points. */ + float delta[2] = {fx, fy}; + for (a = 0; a < profile->path_len; a++) { + /* Don't move the last and first control points. */ + if ((pts[a].flag & PROF_SELECT) && (a != 0) && (a != profile->path_len)) { + moved_point |= BKE_curveprofile_move_point(profile, &pts[a], snap, delta); + last_x = pts[a].x; + last_y = pts[a].y; + } + else { + /* Move handles when they're selected but the control point isn't. */ + if (ELEM(pts[a].h2, HD_FREE, HD_ALIGN) && pts[a].flag == PROF_H1_SELECT) { + moved_point |= BKE_curveprofile_move_handle(&pts[a], true, snap, delta); + last_x = pts[a].h1_loc[0]; + last_y = pts[a].h1_loc[1]; } - if (!moved_point && (pts[a].x != origx || pts[a].y != origy)) { - moved_point = true; + if (ELEM(pts[a].h2, HD_FREE, HD_ALIGN) && pts[a].flag == PROF_H2_SELECT) { + moved_point |= BKE_curveprofile_move_handle(&pts[a], false, snap, delta); + last_x = pts[a].h2_loc[0]; + last_y = pts[a].h2_loc[1]; } - - point_last = &pts[a]; } } - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); if (moved_point) { data->draglastx = evtx; @@ -6989,10 +6995,8 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block, * but in practice this isnt really an issue */ if (ui_but_is_cursor_warp(but)) { /* OK but can go outside bounds */ - data->ungrab_mval[0] = but->rect.xmin + - ((point_last->x - profile->view_rect.xmin) * zoomx); - data->ungrab_mval[1] = but->rect.ymin + - ((point_last->y - profile->view_rect.ymin) * zoomy); + data->ungrab_mval[0] = but->rect.xmin + ((last_x - profile->view_rect.xmin) * zoomx); + data->ungrab_mval[1] = but->rect.ymin + ((last_y - profile->view_rect.ymin) * zoomy); BLI_rctf_clamp_pt_v(&but->rect, data->ungrab_mval); } #endif @@ -7000,7 +7004,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block, data->dragchange = true; /* mark for selection */ } else { - /* clamp for clip */ + /* Clamp the view rect when clipping is on. */ if (profile->flag & PROF_USE_CLIP) { if (profile->view_rect.xmin - fx < profile->clip_rect.xmin) { fx = profile->view_rect.xmin - profile->clip_rect.xmin; @@ -7031,16 +7035,26 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block, } /** + * Helper for #ui_do_but_CURVEPROFILE. Used to tell whether to select a control point's handles. + */ +static bool point_draw_handles(CurveProfilePoint *point) +{ + return (point->flag & PROF_SELECT && + (ELEM(point->h1, HD_FREE, HD_ALIGN) || ELEM(point->h2, HD_FREE, HD_ALIGN))) || + ELEM(point->flag, PROF_H1_SELECT, PROF_H2_SELECT); +} + +/** * Interaction for curve profile widget. * \note Uses hardcoded keys rather than the keymap. */ static int ui_do_but_CURVEPROFILE( bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { - int mx, my, i; + CurveProfile *profile = (CurveProfile *)but->poin; + int mx = event->x; + int my = event->y; - mx = event->x; - my = event->y; ui_window_to_block(data->region, block, &mx, &my); /* Move selected control points. */ @@ -7053,12 +7067,10 @@ static int ui_do_but_CURVEPROFILE( return WM_UI_HANDLER_BREAK; } - CurveProfile *profile = (CurveProfile *)but->poin; - /* Delete selected control points. */ if (event->type == EVT_XKEY && event->val == KM_RELEASE) { BKE_curveprofile_remove_by_flag(profile, PROF_SELECT); - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); button_activate_state(C, but, BUTTON_STATE_EXIT); return WM_UI_HANDLER_BREAK; } @@ -7066,76 +7078,94 @@ static int ui_do_but_CURVEPROFILE( /* Selecting, adding, and starting point movements. */ if (data->state == BUTTON_STATE_HIGHLIGHT) { if (event->type == LEFTMOUSE && event->val == KM_PRESS) { - CurveProfilePoint *pts; /* Path or table. */ const float m_xy[2] = {mx, my}; - float dist_min_sq; - int i_selected = -1; if (event->ctrl) { float f_xy[2]; BLI_rctf_transform_pt_v(&profile->view_rect, &but->rect, f_xy, m_xy); BKE_curveprofile_insert(profile, f_xy[0], f_xy[1]); - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_CLIP); } /* Check for selecting of a point by finding closest point in radius. */ - dist_min_sq = square_f(U.dpi_fac * 14.0f); /* 14 pixels radius for selecting points. */ - pts = profile->path; - for (i = 0; i < profile->path_len; i++) { + CurveProfilePoint *pts = profile->path; + float dist_min_sq = square_f(U.dpi_fac * 14.0f); /* 14 pixels radius for selecting points. */ + int i_selected = -1; + short selection_type = 0; /* For handle selection. */ + for (int i = 0; i < profile->path_len; i++) { float f_xy[2]; BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &pts[i].x); - const float dist_sq = len_squared_v2v2(m_xy, f_xy); + float dist_sq = len_squared_v2v2(m_xy, f_xy); if (dist_sq < dist_min_sq) { i_selected = i; + selection_type = PROF_SELECT; dist_min_sq = dist_sq; } + + /* Also select handles if the point is selected and it has the right handle type. */ + if (point_draw_handles(&pts[i])) { + if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) { + BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, pts[i].h1_loc); + dist_sq = len_squared_v2v2(m_xy, f_xy); + if (dist_sq < dist_min_sq) { + i_selected = i; + selection_type = PROF_H1_SELECT; + dist_min_sq = dist_sq; + } + } + if (ELEM(profile->path[i].h2, HD_FREE, HD_ALIGN)) { + BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, pts[i].h2_loc); + dist_sq = len_squared_v2v2(m_xy, f_xy); + if (dist_sq < dist_min_sq) { + i_selected = i; + selection_type = PROF_H2_SELECT; + dist_min_sq = dist_sq; + } + } + } } - /* Add a point if the click was close to the path but not a control point. */ - if (i_selected == -1) { /* No control point selected. */ + /* Add a point if the click was close to the path but not a control point or handle. */ + if (i_selected == -1) { float f_xy[2], f_xy_prev[2]; - pts = profile->table; - BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &pts[0].x); + CurveProfilePoint *table = profile->table; + BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &table[0].x); dist_min_sq = square_f(U.dpi_fac * 8.0f); /* 8 pixel radius from each table point. */ /* Loop through the path's high resolution table and find what's near the click. */ - for (i = 1; i <= PROF_N_TABLE(profile->path_len); i++) { + for (int i = 1; i <= PROF_N_TABLE(profile->path_len); i++) { copy_v2_v2(f_xy_prev, f_xy); - BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &pts[i].x); + BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &table[i].x); if (dist_squared_to_line_segment_v2(m_xy, f_xy_prev, f_xy) < dist_min_sq) { BLI_rctf_transform_pt_v(&profile->view_rect, &but->rect, f_xy, m_xy); CurveProfilePoint *new_pt = BKE_curveprofile_insert(profile, f_xy[0], f_xy[1]); - BKE_curveprofile_update(profile, false); - - /* reset pts back to the control points. */ - pts = profile->path; + BKE_curveprofile_update(profile, PROF_UPDATE_CLIP); /* Get the index of the newly added point. */ - for (i = 0; i < profile->path_len; i++) { - if (&pts[i] == new_pt) { - i_selected = i; - } - } + i_selected = (int)(new_pt - profile->path); + BLI_assert(i_selected >= 0 && i_selected <= profile->path_len); + selection_type = PROF_SELECT; break; } } } - /* Change the flag for the point(s) if one was selected. */ + /* Change the flag for the point(s) if one was selected or added. */ if (i_selected != -1) { /* Deselect all if this one is deselected, except if we hold shift. */ - if (!event->shift) { - for (i = 0; i < profile->path_len; i++) { - pts[i].flag &= ~PROF_SELECT; - } - pts[i_selected].flag |= PROF_SELECT; + if (event->shift) { + pts[i_selected].flag ^= selection_type; } else { - pts[i_selected].flag ^= PROF_SELECT; + for (int i = 0; i < profile->path_len; i++) { + // pts[i].flag &= ~(PROF_SELECT | PROF_H1_SELECT | PROF_H2_SELECT); + profile->path[i].flag &= ~(PROF_SELECT | PROF_H1_SELECT | PROF_H2_SELECT); + } + profile->path[i_selected].flag |= selection_type; } } else { @@ -7166,19 +7196,13 @@ static int ui_do_but_CURVEPROFILE( else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* Finish move. */ if (data->dragsel != -1) { - CurveProfilePoint *pts = profile->path; if (data->dragchange == false) { /* Deselect all, select one. */ - if (!event->shift) { - for (i = 0; i < profile->path_len; i++) { - pts[i].flag &= ~PROF_SELECT; - } - pts[data->dragsel].flag |= PROF_SELECT; - } } else { - BKE_curveprofile_update(profile, true); /* Remove doubles after move. */ + /* Remove doubles, clip after move. */ + BKE_curveprofile_update(profile, PROF_UPDATE_REMOVE_DOUBLES | PROF_UPDATE_CLIP); } } button_activate_state(C, but, BUTTON_STATE_EXIT); @@ -9947,7 +9971,7 @@ static int ui_handle_menu_event(bContext *C, if (ELEM(event->val, KM_PRESS, KM_DBL_CLICK)) { if ((is_parent_menu == false) && (U.uiflag & USER_MENUOPENAUTO) == 0) { /* for root menus, allow clicking to close */ - if (block->flag & (UI_BLOCK_OUT_1)) { + if (block->flag & UI_BLOCK_OUT_1) { menu->menuretval = UI_RETURN_OK; } else { @@ -9955,7 +9979,7 @@ static int ui_handle_menu_event(bContext *C, } } else if (saferct && !BLI_rctf_isect_pt(&saferct->parent, event->x, event->y)) { - if (block->flag & (UI_BLOCK_OUT_1)) { + if (block->flag & UI_BLOCK_OUT_1) { menu->menuretval = UI_RETURN_OK; } else { @@ -10049,7 +10073,7 @@ static int ui_handle_menu_event(bContext *C, /* strict check, and include the parent rect */ if (!menu->dotowards && !saferct) { - if (block->flag & (UI_BLOCK_OUT_1)) { + if (block->flag & UI_BLOCK_OUT_1) { menu->menuretval = UI_RETURN_OK; } else { diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index deea3028354..7411639a99f 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -2192,6 +2192,26 @@ int ui_id_icon_get(const bContext *C, ID *id, const bool big) return iconid; } +int UI_library_icon_get(const ID *id) +{ + if (ID_IS_LINKED(id)) { + if (id->tag & LIB_TAG_MISSING) { + return ICON_LIBRARY_DATA_BROKEN; + } + else if (id->tag & LIB_TAG_INDIRECT) { + return ICON_LIBRARY_DATA_INDIRECT; + } + else { + return ICON_LIBRARY_DATA_DIRECT; + } + } + else if (ID_IS_OVERRIDE_LIBRARY(id)) { + return ICON_LIBRARY_DATA_OVERRIDE; + } + + return ICON_NONE; +} + int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, const bool big) { ID *id = NULL; diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 6cd990ec2b0..fac78808a9a 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -848,6 +848,8 @@ typedef struct uiWidgetBaseParameters { * The absolute value itself is the discard factor. * Initialize value to 1.0.f if you don't want discard */ float alpha_discard; + float tria_type; + float _pad[3]; } uiWidgetBaseParameters; enum { @@ -861,8 +863,7 @@ enum { ROUNDBOX_TRIA_MAX, /* don't use */ }; -struct GPUBatch *ui_batch_roundbox_get(bool filled, bool antialiased); -struct GPUBatch *ui_batch_roundbox_widget_get(int tria); +struct GPUBatch *ui_batch_roundbox_widget_get(void); struct GPUBatch *ui_batch_roundbox_shadow_get(void); void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 6aefef197df..188ff62d923 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -5576,6 +5576,7 @@ static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout, panel->layout = layout; pt->draw(C, panel); panel->layout = NULL; + BLI_assert(panel->runtime.custom_data_ptr == NULL); MEM_freeN(panel); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 41c89d2d832..924fc6738e1 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -513,7 +513,7 @@ static bool override_type_set_button_poll(bContext *C) UI_context_active_but_prop_get(C, &ptr, &prop, &index); - const int override_status = RNA_property_override_library_status(&ptr, prop, index); + const uint override_status = RNA_property_override_library_status(&ptr, prop, index); return (ptr.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE)); } @@ -613,7 +613,7 @@ static bool override_remove_button_poll(bContext *C) UI_context_active_but_prop_get(C, &ptr, &prop, &index); - const int override_status = RNA_property_override_library_status(&ptr, prop, index); + const uint override_status = RNA_property_override_library_status(&ptr, prop, index); return (ptr.data && ptr.owner_id && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN)); } @@ -630,11 +630,11 @@ static int override_remove_button_exec(bContext *C, wmOperator *op) UI_context_active_but_prop_get(C, &ptr, &prop, &index); ID *id = ptr.owner_id; - IDOverrideLibraryProperty *oprop = RNA_property_override_property_find(&ptr, prop); + IDOverrideLibraryProperty *oprop = RNA_property_override_property_find(&ptr, prop, &id); BLI_assert(oprop != NULL); BLI_assert(id != NULL && id->override_library != NULL); - const bool is_template = (id->override_library->reference == NULL); + const bool is_template = ID_IS_OVERRIDE_LIBRARY_TEMPLATE(id); /* We need source (i.e. linked data) to restore values of deleted overrides... * If this is an override template, we obviously do not need to restore anything. */ @@ -1309,7 +1309,7 @@ static int editsource_text_edit(bContext *C, printf("%s:%d\n", filepath, line); for (text = bmain->texts.first; text; text = text->id.next) { - if (text->name && BLI_path_cmp(text->name, filepath) == 0) { + if (text->filepath && BLI_path_cmp(text->filepath, filepath) == 0) { break; } } diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 55657d7297a..2eeab4efbc7 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -245,20 +245,25 @@ static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_ /********* Functions for instanced panels. ***********/ -static Panel *UI_panel_add_instanced_ex( - ScrArea *area, ARegion *region, ListBase *panels, PanelType *panel_type, int list_index) +static Panel *UI_panel_add_instanced_ex(ScrArea *area, + ARegion *region, + ListBase *panels, + PanelType *panel_type, + int list_index, + PointerRNA *custom_data) { Panel *panel = MEM_callocN(sizeof(Panel), "instanced panel"); panel->type = panel_type; BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname)); panel->runtime.list_index = list_index; + panel->runtime.custom_data_ptr = custom_data; /* Add the panel's children too. Although they aren't instanced panels, we can still use this * function to create them, as UI_panel_begin does other things we don't need to do. */ LISTBASE_FOREACH (LinkData *, child, &panel_type->children) { PanelType *child_type = child->data; - UI_panel_add_instanced_ex(area, region, &panel->children, child_type, list_index); + UI_panel_add_instanced_ex(area, region, &panel->children, child_type, list_index, custom_data); } /* Make sure the panel is added to the end of the display-order as well. This is needed for @@ -283,8 +288,12 @@ static Panel *UI_panel_add_instanced_ex( * Called in situations where panels need to be added dynamically rather than having only one panel * corresponding to each PanelType. */ -Panel *UI_panel_add_instanced( - ScrArea *area, ARegion *region, ListBase *panels, char *panel_idname, int list_index) +Panel *UI_panel_add_instanced(ScrArea *area, + ARegion *region, + ListBase *panels, + char *panel_idname, + int list_index, + PointerRNA *custom_data) { ARegionType *region_type = region->type; @@ -296,7 +305,7 @@ Panel *UI_panel_add_instanced( return NULL; } - return UI_panel_add_instanced_ex(area, region, panels, panel_type, list_index); + return UI_panel_add_instanced_ex(area, region, panels, panel_type, list_index, custom_data); } /** @@ -332,7 +341,8 @@ static void panel_free_block(ARegion *region, Panel *panel) } /** - * Free a panel and it's children. + * Free a panel and it's children. Custom data is shared by the panel and its children + * and is freed by #UI_panels_free_instanced. * * \note The only panels that should need to be deleted at runtime are panels with the * #PNL_INSTANCED flag set. @@ -369,6 +379,13 @@ void UI_panels_free_instanced(bContext *C, ARegion *region) if (C != NULL && panel->activedata != NULL) { panel_activate_state(C, panel, PANEL_STATE_EXIT); } + + /* Free panel's custom data. */ + if (panel->runtime.custom_data_ptr != NULL) { + MEM_freeN(panel->runtime.custom_data_ptr); + } + + /* Free the panel and its sub-panels. */ panel_delete(region, ®ion->panels, panel); } } @@ -387,9 +404,19 @@ bool UI_panel_list_matches_data(ARegion *region, ListBase *data, uiListPanelIDFromDataFunc panel_idname_func) { - int data_len = BLI_listbase_count(data); + /* Check for NULL data. */ + int data_len = 0; + Link *data_link = NULL; + if (data == NULL) { + data_len = 0; + data_link = NULL; + } + else { + data_len = BLI_listbase_count(data); + data_link = data->first; + } + int i = 0; - Link *data_link = data->first; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->type != NULL && panel->type->flag & PNL_INSTANCED) { /* The panels were reordered by drag and drop. */ @@ -493,7 +520,7 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr /** * Recursive implementation for #UI_panel_set_expand_from_list_data. * - * \return Whether the closed flag for the panel or any subpanels changed. + * \return Whether the closed flag for the panel or any sub-panels changed. */ static bool panel_set_expand_from_list_data_recursive(Panel *panel, short flag, short *flag_index) { @@ -513,7 +540,7 @@ static bool panel_set_expand_from_list_data_recursive(Panel *panel, short flag, } /** - * Set the expansion of the panel and its subpanels from the flag stored by the list data + * Set the expansion of the panel and its sub-panels from the flag stored by the list data * corresponding to this panel. The flag has expansion stored in each bit in depth first * order. */ @@ -583,6 +610,26 @@ static void set_panels_list_data_expand_flag(const bContext *C, ARegion *region) /****************************** panels ******************************/ +/** + * Set flag state for a panel and its sub-panels. + * + * \return True if this function changed any of the flags, false if it didn't. + */ +static bool panel_set_flag_recursive(Panel *panel, int flag, bool value) +{ + short flag_original = panel->flag; + + SET_FLAG_FROM_TEST(panel->flag, value, flag); + + bool changed = (flag_original != panel->flag); + + LISTBASE_FOREACH (Panel *, child, &panel->children) { + changed |= panel_set_flag_recursive(child, flag, value); + } + + return changed; +} + static void panels_collapse_all(const bContext *C, ScrArea *area, ARegion *region, @@ -980,7 +1027,7 @@ void ui_draw_aligned_panel(uiStyle *style, * can't be dragged. This may be changed in future. */ show_background); const int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK; - const bool draw_box_style = (panel->type && panel->type->flag & (PNL_DRAW_BOX)); + const bool draw_box_style = (panel->type && panel->type->flag & PNL_DRAW_BOX); /* Use the theme for box widgets for box-style panels. */ uiWidgetColors *box_wcol = NULL; @@ -1160,7 +1207,7 @@ void ui_draw_aligned_panel(uiStyle *style, /* Draw panel backdrop if it wasn't already been drawn by the single opaque round box earlier. * Note: Sub-panels blend with panels, so they can't be opaque. */ if (show_background && !(draw_box_style && !is_subpanel)) { - /* Draw the bottom subpanels . */ + /* Draw the bottom sub-panels. */ if (draw_box_style) { if (panel->next) { immUniformThemeColor(panel_col); @@ -1461,11 +1508,6 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co ps->panel->ofsx = 0; ps->panel->ofsy = -get_panel_size_y(ps->panel); ps->panel->ofsx += ps->panel->runtime.region_ofsx; - /* Extra margin if the panel is a box style panel. */ - if (ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX) { - ps->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN; - ps->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN; - } for (a = 0; a < tot - 1; a++, ps++) { psnext = ps + 1; @@ -1475,16 +1517,12 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co bool use_box_next = psnext->panel->type && psnext->panel->type->flag & PNL_DRAW_BOX; psnext->panel->ofsx = ps->panel->ofsx; psnext->panel->ofsy = get_panel_real_ofsy(ps->panel) - get_panel_size_y(psnext->panel); + /* Extra margin for box style panels. */ + ps->panel->ofsx += (use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0.0f; if (use_box || use_box_next) { psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN; } - if (use_box && !use_box_next) { - psnext->panel->ofsx -= UI_PANEL_BOX_STYLE_MARGIN; - } - else if (!use_box && use_box_next) { - psnext->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN; - } } else { psnext->panel->ofsx = get_panel_real_ofsx(ps->panel); @@ -1492,6 +1530,10 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co get_panel_size_y(psnext->panel); } } + /* Extra margin for the last panel if it's a box-style panel. */ + if (panelsort[tot - 1].panel->type && panelsort[tot - 1].panel->type->flag & PNL_DRAW_BOX) { + panelsort[tot - 1].panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN; + } /* we interpolate */ done = false; @@ -2017,14 +2059,28 @@ static void ui_handle_panel_header( if (button == 2) { /* close */ ED_region_tag_redraw(region); } - else { /* collapse */ + else { + /* Collapse and expand panels. */ + if (ctrl) { - /* Only collapse all for parent panels. */ + /* For parent panels, collapse all other panels or toggle children. */ if (block->panel->type != NULL && block->panel->type->parent == NULL) { - panels_collapse_all(C, area, region, block->panel); + if (block->panel->flag & PNL_CLOSED || BLI_listbase_is_empty(&block->panel->children)) { + panels_collapse_all(C, area, region, block->panel); - /* reset the view - we don't want to display a view without content */ - UI_view2d_offset(®ion->v2d, 0.0f, 1.0f); + /* Reset the view - we don't want to display a view without content. */ + UI_view2d_offset(®ion->v2d, 0.0f, 1.0f); + } + else { + const int closed_flag = (align == BUT_HORIZONTAL) ? PNL_CLOSEDX : PNL_CLOSEDY; + /* If a panel has sub-panels and it's open, toggle the expansion + * of the sub-panels (based on the expansion of the first subpanel). */ + Panel *first_child = block->panel->children.first; + BLI_assert(first_child != NULL); + panel_set_flag_recursive( + block->panel, closed_flag, (first_child->flag & PNL_CLOSED) == 0); + block->panel->flag |= closed_flag; + } } } @@ -2847,6 +2903,56 @@ int ui_handler_panel_region(bContext *C, return retval; } +static void ui_panel_custom_data_set_recursive(Panel *panel, PointerRNA *custom_data) +{ + panel->runtime.custom_data_ptr = custom_data; + + LISTBASE_FOREACH (Panel *, child_panel, &panel->children) { + ui_panel_custom_data_set_recursive(child_panel, custom_data); + } +} + +void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data) +{ + BLI_assert(panel->type != NULL); + + /* Free the old custom data, which should be shared among all of the panel's sub-panels. */ + if (panel->runtime.custom_data_ptr != NULL) { + MEM_freeN(panel->runtime.custom_data_ptr); + } + + ui_panel_custom_data_set_recursive(panel, custom_data); +} + +PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wmEvent *event) +{ + ARegion *region = CTX_wm_region(C); + + Panel *panel = NULL; + LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { + panel = block->panel; + if (panel == NULL) { + continue; + } + + int mx = event->x; + int my = event->y; + ui_window_to_block(region, block, &mx, &my); + int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my); + if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { + break; + } + } + + if (panel == NULL) { + return NULL; + } + + PointerRNA *customdata = panel->runtime.custom_data_ptr; + + return customdata; +} + /**************** window level modal panel interaction **************/ /* note, this is modal handler and should not swallow events for animation */ @@ -2899,24 +3005,6 @@ static void ui_handler_remove_panel(bContext *C, void *userdata) panel_activate_state(C, panel, PANEL_STATE_EXIT); } -/** - * Set selection state for a panel and its subpanels. The subpanels need to know they are selected - * too so they can be drawn above their parent when it is dragged. - */ -static void set_panel_selection(Panel *panel, bool value) -{ - if (value) { - panel->flag |= PNL_SELECT; - } - else { - panel->flag &= ~PNL_SELECT; - } - - LISTBASE_FOREACH (Panel *, child, &panel->children) { - set_panel_selection(child, value); - } -} - static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state) { uiHandlePanelData *data = panel->activedata; @@ -2929,6 +3017,8 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS bool was_drag_drop = (data && data->state == PANEL_STATE_DRAG); + /* Set selection state for the panel and its sub-panels, which need to know they are selected + * too so they can be drawn above their parent when it's dragged. */ if (state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) { if (data && data->state != PANEL_STATE_ANIMATION) { /* XXX: @@ -2941,10 +3031,10 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS check_panel_overlap(region, NULL); /* clears */ } - set_panel_selection(panel, false); + panel_set_flag_recursive(panel, PNL_SELECT, false); } else { - set_panel_selection(panel, true); + panel_set_flag_recursive(panel, PNL_SELECT, true); } if (data && data->animtimer) { diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index 3e34b7f3f8a..65f5798bdce 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -184,7 +184,12 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi pup->block->handle = NULL; } - if (pup->but) { + /* Find block minimum width. */ + if (uiLayoutGetUnitsX(pup->layout) != 0.0f) { + /* Use the minimum width from the layout if it's set. */ + minwidth = uiLayoutGetUnitsX(pup->layout) * UI_UNIT_X; + } + else if (pup->but) { /* minimum width to enforece */ if (pup->but->drawstr[0]) { minwidth = BLI_rctf_size_x(&pup->but->rect); @@ -193,7 +198,13 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi /* For buttons with no text, use the minimum (typically icon only). */ minwidth = UI_MENU_WIDTH_MIN; } + } + else { + minwidth = UI_MENU_WIDTH_MIN; + } + /* Find block direction. */ + if (pup->but) { if (pup->block->direction != 0) { /* allow overriding the direction from menu_func */ direction = pup->block->direction; @@ -203,7 +214,6 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi } } else { - minwidth = UI_MENU_WIDTH_MIN; direction = UI_DIR_DOWN; } diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c index 68be08ef4f8..c88dd1954c9 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.c @@ -77,6 +77,9 @@ struct uiSearchItems { int *icons; int *states; + /** Is there any item with an icon? */ + bool has_icon; + AutoComplete *autocpl; void *active; }; @@ -122,6 +125,10 @@ bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int return true; } + if (iconid) { + items->has_icon = true; + } + /* hijack for finding active item */ if (items->active) { if (poin == items->active) { @@ -562,6 +569,10 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) /* widget itself */ if ((search_sep_len == 0) || !(name_sep_test = strstr(data->items.names[a], data->sep_string))) { + if (!icon && data->items.has_icon) { + /* If there is any icon item, make sure all items line up. */ + icon = ICON_BLANK1; + } /* Simple menu item. */ ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, use_sep_char, NULL); diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index b64f080d9cc..9fed98ffda2 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -923,7 +923,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) .style = UI_TIP_STYLE_NORMAL, .color_id = UI_TIP_LC_NORMAL, }); - field->text = BLI_sprintfN(TIP_("Library: %s"), id->lib->name); + field->text = BLI_sprintfN(TIP_("Library: %s"), id->lib->filepath); } } } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 1ce1e2950d5..baea948e122 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -361,11 +361,16 @@ static bool id_search_add(const bContext *C, * followed by ID_NAME-2 characters from id->name */ char name_ui[MAX_ID_FULL_NAME_UI]; - BKE_id_full_name_ui_prefix_get(name_ui, id, UI_SEP_CHAR); - int iconid = ui_id_icon_get(C, id, template_ui->preview); bool has_sep_char = (id->lib != NULL); + /* When using previews, the library hint (linked, overridden, missing) is added with a + * character prefix, otherwise we can use a icon. */ + BKE_id_full_name_ui_prefix_get(name_ui, id, template_ui->preview, UI_SEP_CHAR); + if (!template_ui->preview) { + iconid = UI_library_icon_get(id); + } + if (!UI_search_item_add( items, name_ui, id, iconid, has_sep_char ? UI_BUT_HAS_SEP_CHAR : 0)) { return false; @@ -511,6 +516,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); ID *id = idptr.data; int event = POINTER_AS_INT(arg_event); + const char *undo_push_label = NULL; switch (event) { case UI_ID_BROWSE: @@ -531,6 +537,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) id_us_clear_real(id); id_fake_user_clear(id); id->us = 0; + undo_push_label = "Delete Data-Block"; } break; @@ -542,6 +549,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) else { id_us_min(id); } + undo_push_label = "Fake User"; } else { return; @@ -572,15 +580,17 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) } RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); + undo_push_label = "Make Local"; } break; case UI_ID_OVERRIDE: - if (id && id->override_library) { + if (id && ID_IS_OVERRIDE_LIBRARY(id)) { BKE_lib_override_library_free(&id->override_library, true); /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); + undo_push_label = "Override Data-Block"; } break; case UI_ID_ALONE: @@ -601,6 +611,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) id_single_user(C, id, &template_ui->ptr, template_ui->prop); DEG_relations_tag_update(bmain); } + undo_push_label = "Make Single User"; } break; #if 0 @@ -608,6 +619,10 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; #endif } + + if (undo_push_label != NULL) { + ED_undo_push(C, undo_push_label); + } } static const char *template_id_browse_tip(const StructRNA *type) @@ -1823,6 +1838,20 @@ void uiTemplatePathBuilder(uiLayout *layout, * Template for building the panel layout for the active object's modifiers. * \{ */ +/** + * Get the active object or the property region's pinned object. + */ +static Object *get_context_object(const bContext *C) +{ + SpaceProperties *sbuts = CTX_wm_space_properties(C); + if (sbuts != NULL && (sbuts->pinid != NULL) && GS(sbuts->pinid->name) == ID_OB) { + return (Object *)sbuts->pinid; + } + else { + return CTX_data_active_object(C); + } +} + static void modifier_panel_id(void *md_link, char *r_name) { ModifierData *md = (ModifierData *)md_link; @@ -1834,14 +1863,7 @@ void uiTemplateModifiers(uiLayout *UNUSED(layout), bContext *C) ScrArea *sa = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); - Object *ob; - SpaceProperties *sbuts = CTX_wm_space_properties(C); - if (sbuts != NULL && (sbuts->pinid != NULL) && GS(sbuts->pinid->name) == ID_OB) { - ob = (Object *)sbuts->pinid; - } - else { - ob = CTX_data_active_object(C); - } + Object *ob = get_context_object(C); ListBase *modifiers = &ob->modifiers; bool panels_match = UI_panel_list_matches_data(region, modifiers, modifier_panel_id); @@ -1851,14 +1873,22 @@ void uiTemplateModifiers(uiLayout *UNUSED(layout), bContext *C) ModifierData *md = modifiers->first; for (int i = 0; md; i++, md = md->next) { const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); - if (mti->panelRegister) { - char panel_idname[MAX_NAME]; - modifier_panel_id(md, panel_idname); + if (mti->panelRegister == NULL) { + continue; + } - Panel *new_panel = UI_panel_add_instanced(sa, region, ®ion->panels, panel_idname, i); - if (new_panel != NULL) { - UI_panel_set_expand_from_list_data(C, new_panel); - } + char panel_idname[MAX_NAME]; + modifier_panel_id(md, panel_idname); + + /* Create custom data RNA pointer. */ + PointerRNA *md_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata"); + RNA_pointer_create(&ob->id, &RNA_Modifier, md, md_ptr); + + Panel *new_panel = UI_panel_add_instanced( + sa, region, ®ion->panels, panel_idname, i, md_ptr); + + if (new_panel != NULL) { + UI_panel_set_expand_from_list_data(C, new_panel); } } } @@ -1868,274 +1898,321 @@ void uiTemplateModifiers(uiLayout *UNUSED(layout), bContext *C) if ((panel->type != NULL) && (panel->type->flag & PNL_INSTANCED)) UI_panel_set_expand_from_list_data(C, panel); } + + /* Assuming there's only one group of instanced panels, update the custom data pointers. */ + Panel *panel = region->panels.first; + LISTBASE_FOREACH (ModifierData *, md, modifiers) { + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + if (mti->panelRegister == NULL) { + continue; + } + + /* Move to the next instanced panel corresponding to the next modifier. */ + while ((panel->type == NULL) || !(panel->type->flag & PNL_INSTANCED)) { + panel = panel->next; + BLI_assert(panel != NULL); /* There shouldn't be fewer panels than modifiers with UIs. */ + } + + PointerRNA *md_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata"); + RNA_pointer_create(&ob->id, &RNA_Modifier, md, md_ptr); + UI_panel_custom_data_set(panel, md_ptr); + + panel = panel->next; + } } } /** \} */ /* -------------------------------------------------------------------- */ -/** \name Grease Pencil Modifier Template +/** \name Constraints Template + * + * Template for building the panel layout for the active object or bone's constraints. * \{ */ -#define ERROR_LIBDATA_MESSAGE TIP_("Can't edit external library data") +/** For building the panel UI for constraints. */ +#define CONSTRAINT_TYPE_PANEL_PREFIX "OBJECT_PT_" +#define CONSTRAINT_BONE_TYPE_PANEL_PREFIX "BONE_PT_" -static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob, GpencilModifierData *md) +/** + * Check if the panel's ID starts with 'BONE', meaning it is a bone constraint. + */ +static bool constraint_panel_is_bone(Panel *panel) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); - PointerRNA ptr; - uiBlock *block; - uiLayout *box, *column, *row, *sub; - uiLayout *result = NULL; - - /* create RNA pointer */ - RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, &ptr); - - column = uiLayoutColumn(layout, true); - uiLayoutSetContextPointer(column, "modifier", &ptr); - - /* rounded header ------------------------------------------------------------------- */ - box = uiLayoutBox(column); - - row = uiLayoutRow(box, false); - block = uiLayoutGetBlock(row); - - UI_block_emboss_set(block, UI_EMBOSS_NONE); - /* Open/Close ................................. */ - uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE); - - /* modifier-type icon */ - uiItemL(row, "", RNA_struct_ui_icon(ptr.type)); - UI_block_emboss_set(block, UI_EMBOSS); + return (panel->panelname[0] == 'B') && (panel->panelname[1] == 'O') && + (panel->panelname[2] == 'N') && (panel->panelname[3] == 'E'); +} - /* modifier name */ - if (mti->isDisabled && mti->isDisabled(md, 0)) { - uiLayoutSetRedAlert(row, true); +/** + * Get the constraints for the active pose bone or the active / pinned object. + */ +static ListBase *get_constraints(const bContext *C, bool use_bone_constraints) +{ + ListBase *constraints = {NULL}; + if (use_bone_constraints) { + bPoseChannel *pose_bone = CTX_data_pointer_get(C, "pose_bone").data; + if (pose_bone != NULL) { + constraints = &pose_bone->constraints; + } } - uiItemR(row, &ptr, "name", 0, "", ICON_NONE); - uiLayoutSetRedAlert(row, false); - - /* mode enabling buttons */ - UI_block_align_begin(block); - uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE); - uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE); - - if (mti->flags & eGpencilModifierTypeFlag_SupportsEditmode) { - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, false); - uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE); + else { + Object *ob = get_context_object(C); + if (ob != NULL) { + constraints = &ob->constraints; + } } + return constraints; +} - UI_block_align_end(block); - - /* Up/Down + Delete ........................... */ - UI_block_align_begin(block); - uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_gpencil_modifier_move_up"); - uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_gpencil_modifier_move_down"); - UI_block_align_end(block); - - UI_block_emboss_set(block, UI_EMBOSS_NONE); - uiItemO(row, "", ICON_X, "OBJECT_OT_gpencil_modifier_remove"); - UI_block_emboss_set(block, UI_EMBOSS); +/** + * Move a constraint to the index it's moved to after a drag and drop. + */ +static void constraint_reorder(bContext *C, Panel *panel, int new_index) +{ + bool constraint_from_bone = constraint_panel_is_bone(panel); + ListBase *lb = get_constraints(C, constraint_from_bone); - /* modifier settings (under the header) --------------------------------------------------- */ - if (md->mode & eGpencilModifierMode_Expanded) { - /* apply/convert/copy */ - box = uiLayoutBox(column); - row = uiLayoutRow(box, false); + bConstraint *con = BLI_findlink(lb, panel->runtime.list_index); + PointerRNA props_ptr; + wmOperatorType *ot = WM_operatortype_find("CONSTRAINT_OT_move_to_index", false); + WM_operator_properties_create_ptr(&props_ptr, ot); + RNA_string_set(&props_ptr, "constraint", con->name); + RNA_int_set(&props_ptr, "index", new_index); + /* Set owner to #EDIT_CONSTRAINT_OWNER_OBJECT or #EDIT_CONSTRAINT_OWNER_BONE. */ + RNA_enum_set(&props_ptr, "owner", constraint_from_bone ? 1 : 0); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr); + WM_operator_properties_free(&props_ptr); +} - /* only here obdata, the rest of modifiers is ob level */ - UI_block_lock_set(block, BKE_object_obdata_is_libdata(ob), ERROR_LIBDATA_MESSAGE); +/** + * Get the expand flag from the active constraint to use for the panel. + */ +static short get_constraint_expand_flag(const bContext *C, Panel *panel) +{ + bool constraint_from_bone = constraint_panel_is_bone(panel); + ListBase *lb = get_constraints(C, constraint_from_bone); - uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT); + bConstraint *con = BLI_findlink(lb, panel->runtime.list_index); + return con->ui_expand_flag; +} - sub = uiLayoutRow(row, false); - if (mti->flags & eGpencilModifierTypeFlag_NoApply) { - uiLayoutSetEnabled(sub, false); - } - uiItemEnumO(sub, - "OBJECT_OT_gpencil_modifier_apply", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"), - 0, - "apply_as", - MODIFIER_APPLY_DATA); +/** + * Save the expand flag for the panel and sub-panels to the constraint. + */ +static void set_constraint_expand_flag(const bContext *C, Panel *panel, short expand_flag) +{ + bool constraint_from_bone = constraint_panel_is_bone(panel); + ListBase *lb = get_constraints(C, constraint_from_bone); - UI_block_lock_clear(block); - UI_block_lock_set(block, ob && ID_IS_LINKED(ob), ERROR_LIBDATA_MESSAGE); + bConstraint *con = BLI_findlink(lb, panel->runtime.list_index); + con->ui_expand_flag = expand_flag; +} - uiItemO(row, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), - ICON_NONE, - "OBJECT_OT_gpencil_modifier_copy"); +/** + * Function with void * argument for #uiListPanelIDFromDataFunc. + * + * \note: Constraint panel types are assumed to be named with the struct name field + * concatenated to the defined prefix. + */ +static void object_constraint_panel_id(void *md_link, char *r_name) +{ + bConstraint *con = (bConstraint *)md_link; + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(con->type); - /* result is the layout block inside the box, - * that we return so that modifier settings can be drawn */ - result = uiLayoutColumn(box, false); - block = uiLayoutAbsoluteBlock(box); - } + strcpy(r_name, CONSTRAINT_TYPE_PANEL_PREFIX); + strcat(r_name, cti->structName); +} - /* error messages */ - if (md->error) { - box = uiLayoutBox(column); - row = uiLayoutRow(box, false); - uiItemL(row, md->error, ICON_ERROR); - } +static void bone_constraint_panel_id(void *md_link, char *r_name) +{ + bConstraint *con = (bConstraint *)md_link; + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(con->type); - return result; + strcpy(r_name, CONSTRAINT_BONE_TYPE_PANEL_PREFIX); + strcat(r_name, cti->structName); } -uiLayout *uiTemplateGpencilModifier(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +/** + * Check if the constraint panels don't match the data and rebuild the panels if so. + */ +void uiTemplateConstraints(uiLayout *UNUSED(layout), bContext *C, bool use_bone_constraints) { - Object *ob; - GpencilModifierData *md, *vmd; - int i; - - /* verify we have valid data */ - if (!RNA_struct_is_a(ptr->type, &RNA_GpencilModifier)) { - RNA_warning("Expected modifier on object"); - return NULL; - } + ScrArea *sa = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); - ob = (Object *)ptr->owner_id; - md = ptr->data; + ListBase *constraints = get_constraints(C, use_bone_constraints); - if (!ob || !(GS(ob->id.name) == ID_OB)) { - RNA_warning("Expected modifier on object"); - return NULL; - } + /* Switch between the bone panel ID function and the object panel ID function. */ + uiListPanelIDFromDataFunc panel_id_func = use_bone_constraints ? bone_constraint_panel_id : + object_constraint_panel_id; - UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE); + bool panels_match = UI_panel_list_matches_data(region, constraints, panel_id_func); - /* find modifier and draw it */ - vmd = ob->greasepencil_modifiers.first; - for (i = 0; vmd; i++, vmd = vmd->next) { - if (md == vmd) { - return gpencil_draw_modifier(layout, ob, md); + if (!panels_match) { + UI_panels_free_instanced(C, region); + bConstraint *con = (constraints == NULL) ? NULL : constraints->first; + for (int i = 0; con; i++, con = con->next) { + char panel_idname[MAX_NAME]; + panel_id_func(con, panel_idname); + + Panel *new_panel = UI_panel_add_instanced( + sa, region, ®ion->panels, panel_idname, i, NULL); + if (new_panel) { + /* Set the list panel functionality function pointers since we don't do it with + * python. */ + new_panel->type->set_list_data_expand_flag = set_constraint_expand_flag; + new_panel->type->get_list_data_expand_flag = get_constraint_expand_flag; + new_panel->type->reorder = constraint_reorder; + + UI_panel_set_expand_from_list_data(C, new_panel); + } + } + } + else { + /* The expansion might have been changed elsewhere, so we still need to set it. */ + LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { + if ((panel->type != NULL) && (panel->type->flag & PNL_INSTANCED)) + UI_panel_set_expand_from_list_data(C, panel); } } - - return NULL; } +#undef CONSTRAINT_TYPE_PANEL_PREFIX +#undef CONSTRAINT_BONE_TYPE_PANEL_PREFIX + /** \} */ /* -------------------------------------------------------------------- */ -/** \name Grease Pencil Shader FX Template +/** \name Grease Pencil Modifiers Template * \{ */ -static uiLayout *gpencil_draw_shaderfx(uiLayout *layout, Object *ob, ShaderFxData *md) +/** + * Function with void * argument for #uiListPanelIDFromDataFunc. + */ +static void gpencil_modifier_panel_id(void *md_link, char *r_name) { - const ShaderFxTypeInfo *mti = BKE_shaderfx_get_info(md->type); - PointerRNA ptr; - uiBlock *block; - uiLayout *box, *column, *row, *sub; - uiLayout *result = NULL; + ModifierData *md = (ModifierData *)md_link; + BKE_gpencil_modifierType_panel_id(md->type, r_name); +} - /* create RNA pointer */ - RNA_pointer_create(&ob->id, &RNA_ShaderFx, md, &ptr); +void uiTemplateGpencilModifiers(uiLayout *UNUSED(layout), bContext *C) +{ + ScrArea *sa = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + Object *ob = get_context_object(C); + ListBase *modifiers = &ob->greasepencil_modifiers; - column = uiLayoutColumn(layout, true); - uiLayoutSetContextPointer(column, "shaderfx", &ptr); + bool panels_match = UI_panel_list_matches_data(region, modifiers, gpencil_modifier_panel_id); - /* rounded header ------------------------------------------------------------------- */ - box = uiLayoutBox(column); + if (!panels_match) { + UI_panels_free_instanced(C, region); + GpencilModifierData *md = modifiers->first; + for (int i = 0; md; i++, md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); + if (mti->panelRegister == NULL) { + continue; + } - row = uiLayoutRow(box, false); - block = uiLayoutGetBlock(row); + char panel_idname[MAX_NAME]; + gpencil_modifier_panel_id(md, panel_idname); - UI_block_emboss_set(block, UI_EMBOSS_NONE); - /* Open/Close ................................. */ - uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE); + /* Create custom data RNA pointer. */ + PointerRNA *md_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata"); + RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, md_ptr); - /* shader-type icon */ - uiItemL(row, "", RNA_struct_ui_icon(ptr.type)); - UI_block_emboss_set(block, UI_EMBOSS); + Panel *new_panel = UI_panel_add_instanced( + sa, region, ®ion->panels, panel_idname, i, md_ptr); - /* effect name */ - if (mti->isDisabled && mti->isDisabled(md, 0)) { - uiLayoutSetRedAlert(row, true); + if (new_panel != NULL) { + UI_panel_set_expand_from_list_data(C, new_panel); + } + } } - uiItemR(row, &ptr, "name", 0, "", ICON_NONE); - uiLayoutSetRedAlert(row, false); - - /* mode enabling buttons */ - UI_block_align_begin(block); - uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE); - uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE); + else { + /* The expansion might have been changed elsewhere, so we still need to set it. */ + LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { + if ((panel->type != NULL) && (panel->type->flag & PNL_INSTANCED)) + UI_panel_set_expand_from_list_data(C, panel); + } - if (mti->flags & eShaderFxTypeFlag_SupportsEditmode) { - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, false); - uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE); - } + /* Assuming there's only one group of instanced panels, update the custom data pointers. */ + Panel *panel = region->panels.first; + LISTBASE_FOREACH (ModifierData *, md, modifiers) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); + if (mti->panelRegister == NULL) { + continue; + } - UI_block_align_end(block); + /* Move to the next instanced panel corresponding to the next modifier. */ + while ((panel->type == NULL) || !(panel->type->flag & PNL_INSTANCED)) { + panel = panel->next; + BLI_assert(panel != NULL); /* There shouldn't be fewer panels than modifiers with UIs. */ + } - /* Up/Down + Delete ........................... */ - UI_block_align_begin(block); - uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_shaderfx_move_up"); - uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_shaderfx_move_down"); - UI_block_align_end(block); + PointerRNA *md_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata"); + RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, md_ptr); + UI_panel_custom_data_set(panel, md_ptr); - UI_block_emboss_set(block, UI_EMBOSS_NONE); - uiItemO(row, "", ICON_X, "OBJECT_OT_shaderfx_remove"); - UI_block_emboss_set(block, UI_EMBOSS); + panel = panel->next; + } + } +} - /* effect settings (under the header) --------------------------------------------------- */ - if (md->mode & eShaderFxMode_Expanded) { - /* apply/convert/copy */ - box = uiLayoutBox(column); - row = uiLayoutRow(box, false); +/** \} */ - /* only here obdata, the rest of effect is ob level */ - UI_block_lock_set(block, BKE_object_obdata_is_libdata(ob), ERROR_LIBDATA_MESSAGE); +/** \} */ - /* result is the layout block inside the box, - * that we return so that effect settings can be drawn */ - result = uiLayoutColumn(box, false); - block = uiLayoutAbsoluteBlock(box); - } +#define ERROR_LIBDATA_MESSAGE TIP_("Can't edit external library data") - /* error messages */ - if (md->error) { - box = uiLayoutBox(column); - row = uiLayoutRow(box, false); - uiItemL(row, md->error, ICON_ERROR); - } +/* -------------------------------------------------------------------- */ +/** \name ShaderFx Template + * + * Template for building the panel layout for the active object's grease pencil shader + * effects. + * \{ */ - return result; +/** + * Function with void * argument for #uiListPanelIDFromDataFunc. + */ +static void shaderfx_panel_id(void *fx_v, char *r_idname) +{ + ShaderFxData *fx = (ShaderFxData *)fx_v; + BKE_shaderfxType_panel_id(fx->type, r_idname); } -uiLayout *uiTemplateShaderFx(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +/** + * Check if the shader effect panels don't match the data and rebuild the panels if so. + */ +void uiTemplateShaderFx(uiLayout *UNUSED(layout), bContext *C) { - Object *ob; - ShaderFxData *fx, *vfx; - int i; - - /* verify we have valid data */ - if (!RNA_struct_is_a(ptr->type, &RNA_ShaderFx)) { - RNA_warning("Expected shader fx on object"); - return NULL; - } + ScrArea *sa = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + Object *ob = get_context_object(C); + ListBase *shaderfx = &ob->shader_fx; - ob = (Object *)ptr->owner_id; - fx = ptr->data; + bool panels_match = UI_panel_list_matches_data(region, shaderfx, shaderfx_panel_id); - if (!ob || !(GS(ob->id.name) == ID_OB)) { - RNA_warning("Expected shader fx on object"); - return NULL; + if (!panels_match) { + UI_panels_free_instanced(C, region); + ShaderFxData *fx = shaderfx->first; + for (int i = 0; fx; i++, fx = fx->next) { + char panel_idname[MAX_NAME]; + shaderfx_panel_id(fx, panel_idname); + + Panel *new_panel = UI_panel_add_instanced( + sa, region, ®ion->panels, panel_idname, i, NULL); + if (new_panel != NULL) { + UI_panel_set_expand_from_list_data(C, new_panel); + } + } } - - UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE); - - /* find modifier and draw it */ - vfx = ob->shader_fx.first; - for (i = 0; vfx; i++, vfx = vfx->next) { - if (fx == vfx) { - return gpencil_draw_shaderfx(layout, ob, fx); + else { + /* The expansion might have been changed elsewhere, so we still need to set it. */ + LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { + if ((panel->type != NULL) && (panel->type->flag & PNL_INSTANCED)) + UI_panel_set_expand_from_list_data(C, panel); } } - - return NULL; } /** \} */ @@ -2441,38 +2518,25 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Constraint Template +/** \name Constraint Header Template * \{ */ +#define ERROR_LIBDATA_MESSAGE TIP_("Can't edit external library data") + static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v) { ED_object_constraint_active_set(ob_v, con_v); } -/* draw panel showing settings for a constraint */ -static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) +static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con) { bPoseChannel *pchan = BKE_pose_channel_active(ob); - const bConstraintTypeInfo *cti; uiBlock *block; - uiLayout *result = NULL, *col, *box, *row; + uiLayout *sub; PointerRNA ptr; - char typestr[32]; short proxy_protected, xco = 0, yco = 0; // int rb_col; // UNUSED - /* get constraint typeinfo */ - cti = BKE_constraint_typeinfo_get(con); - if (cti == NULL) { - /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */ - BLI_strncpy(typestr, - (con->type == CONSTRAINT_TYPE_NULL) ? IFACE_("Null") : IFACE_("Unknown"), - sizeof(typestr)); - } - else { - BLI_strncpy(typestr, IFACE_(cti->name), sizeof(typestr)); - } - /* determine whether constraint is proxy protected or not */ if (BKE_constraints_proxylocked_owner(ob, pchan)) { proxy_protected = (con->flag & CONSTRAINT_PROXY_LOCAL) == 0; @@ -2487,36 +2551,23 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr); - col = uiLayoutColumn(layout, true); - uiLayoutSetContextPointer(col, "constraint", &ptr); - - box = uiLayoutBox(col); - row = uiLayoutRow(box, false); - block = uiLayoutGetBlock(box); + uiLayoutSetContextPointer(layout, "constraint", &ptr); - /* Draw constraint header */ + /* Constraint type icon. */ + sub = uiLayoutRow(layout, false); + uiLayoutSetEmboss(sub, false); + uiLayoutSetRedAlert(sub, (con->flag & CONSTRAINT_DISABLE)); + uiItemL(sub, "", RNA_struct_ui_icon(ptr.type)); - /* open/close */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); - uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE); - - /* constraint-type icon */ - uiItemL(row, "", RNA_struct_ui_icon(ptr.type)); UI_block_emboss_set(block, UI_EMBOSS); - if (con->flag & CONSTRAINT_DISABLE) { - uiLayoutSetRedAlert(row, true); - } - if (proxy_protected == 0) { - uiItemR(row, &ptr, "name", 0, "", ICON_NONE); + uiItemR(layout, &ptr, "name", 0, "", ICON_NONE); } else { - uiItemL(row, con->name, ICON_NONE); + uiItemL(layout, con->name, ICON_NONE); } - uiLayoutSetRedAlert(row, false); - /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */ if (proxy_protected) { UI_block_emboss_set(block, UI_EMBOSS_NONE); @@ -2555,54 +2606,20 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) UI_block_emboss_set(block, UI_EMBOSS); } else { - short prev_proxylock, show_upbut, show_downbut; - - /* Up/Down buttons: - * Proxy-constraints are not allowed to occur after local (non-proxy) constraints - * as that poses problems when restoring them, so disable the "up" button where - * it may cause this situation. - * - * Up/Down buttons should only be shown (or not grayed - todo) if they serve some purpose. - */ - if (BKE_constraints_proxylocked_owner(ob, pchan)) { - if (con->prev) { - prev_proxylock = (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1; - } - else { - prev_proxylock = 0; - } - } - else { - prev_proxylock = 0; - } - - show_upbut = ((prev_proxylock == 0) && (con->prev)); - show_downbut = (con->next) ? 1 : 0; - /* enabled */ UI_block_emboss_set(block, UI_EMBOSS_NONE); - uiItemR(row, &ptr, "mute", 0, "", 0); + uiItemR(layout, &ptr, "mute", 0, "", 0); UI_block_emboss_set(block, UI_EMBOSS); - uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT); - - /* up/down */ - if (show_upbut || show_downbut) { - UI_block_align_begin(block); - if (show_upbut) { - uiItemO(row, "", ICON_TRIA_UP, "CONSTRAINT_OT_move_up"); - } - - if (show_downbut) { - uiItemO(row, "", ICON_TRIA_DOWN, "CONSTRAINT_OT_move_down"); - } - UI_block_align_end(block); - } + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); /* Close 'button' - emboss calls here disable drawing of 'button' behind X */ UI_block_emboss_set(block, UI_EMBOSS_NONE); - uiItemO(row, "", ICON_X, "CONSTRAINT_OT_delete"); + uiItemO(layout, "", ICON_X, "CONSTRAINT_OT_delete"); UI_block_emboss_set(block, UI_EMBOSS); + + /* Some extra padding at the end, so the 'x' icon isn't too close to drag button. */ + uiItemS(layout); } /* Set but-locks for protected settings (magic numbers are used here!) */ @@ -2610,23 +2627,11 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) UI_block_lock_set(block, true, TIP_("Cannot edit Proxy-Protected Constraint")); } - /* Draw constraint data */ - if ((con->flag & CONSTRAINT_EXPAND) == 0) { - (yco) -= 10.5f * UI_UNIT_Y; - } - else { - box = uiLayoutBox(col); - block = uiLayoutAbsoluteBlock(box); - result = box; - } - /* clear any locks set up for proxies/lib-linking */ UI_block_lock_clear(block); - - return result; } -uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr) +void uiTemplateConstraintHeader(uiLayout *layout, PointerRNA *ptr) { Object *ob; bConstraint *con; @@ -2634,7 +2639,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr) /* verify we have valid data */ if (!RNA_struct_is_a(ptr->type, &RNA_Constraint)) { RNA_warning("Expected constraint on object"); - return NULL; + return; } ob = (Object *)ptr->owner_id; @@ -2642,7 +2647,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr) if (!ob || !(GS(ob->id.name) == ID_OB)) { RNA_warning("Expected constraint on object"); - return NULL; + return; } UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE); @@ -2651,11 +2656,11 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr) if (con->type == CONSTRAINT_TYPE_KINEMATIC) { bKinematicConstraint *data = con->data; if (data->flag & CONSTRAINT_IK_TEMP) { - return NULL; + return; } } - return draw_constraint(layout, ob, con); + draw_constraint_header(layout, ob, con); } /** \} */ @@ -4525,7 +4530,7 @@ static void CurveProfile_presets_dofunc(bContext *C, void *profile_v, int event) profile->preset = event; BKE_curveprofile_reset(profile); - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); ED_undo_push(C, "CurveProfile tools"); ED_region_tag_redraw(CTX_wm_region(C)); @@ -4641,7 +4646,7 @@ static void CurveProfile_tools_dofunc(bContext *C, void *profile_v, int event) switch (event) { case UIPROFILE_FUNC_RESET: /* reset */ BKE_curveprofile_reset(profile); - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); break; case UIPROFILE_FUNC_RESET_VIEW: /* reset view to clipping rect */ profile->view_rect = profile->clip_rect; @@ -4707,7 +4712,7 @@ static void CurveProfile_buttons_zoom_in(bContext *C, void *profile_v, void *UNU CurveProfile *profile = profile_v; float d; - /* we allow 20 times zoom */ + /* Allow a 20x zoom. */ if (BLI_rctf_size_x(&profile->view_rect) > 0.04f * BLI_rctf_size_x(&profile->clip_rect)) { d = 0.1154f * BLI_rctf_size_x(&profile->view_rect); profile->view_rect.xmin += d; @@ -4771,7 +4776,7 @@ static void CurveProfile_clipping_toggle(bContext *C, void *cb_v, void *profile_ profile->flag ^= PROF_USE_CLIP; - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); rna_update_cb(C, cb_v, NULL); } @@ -4780,7 +4785,7 @@ static void CurveProfile_buttons_reverse(bContext *C, void *cb_v, void *profile_ CurveProfile *profile = profile_v; BKE_curveprofile_reverse(profile); - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); rna_update_cb(C, cb_v, NULL); } @@ -4789,35 +4794,23 @@ static void CurveProfile_buttons_delete(bContext *C, void *cb_v, void *profile_v CurveProfile *profile = profile_v; BKE_curveprofile_remove_by_flag(profile, SELECT); - BKE_curveprofile_update(profile, false); - - rna_update_cb(C, cb_v, NULL); -} - -static void CurveProfile_buttons_setsharp(bContext *C, void *cb_v, void *profile_v) -{ - CurveProfile *profile = profile_v; - - BKE_curveprofile_selected_handle_set(profile, HD_VECT, HD_VECT); - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); rna_update_cb(C, cb_v, NULL); } -static void CurveProfile_buttons_setcurved(bContext *C, void *cb_v, void *profile_v) +static void CurveProfile_buttons_update(bContext *C, void *arg1_v, void *profile_v) { CurveProfile *profile = profile_v; - - BKE_curveprofile_selected_handle_set(profile, HD_AUTO, HD_AUTO); - BKE_curveprofile_update(profile, false); - - rna_update_cb(C, cb_v, NULL); + BKE_curveprofile_update(profile, PROF_UPDATE_REMOVE_DOUBLES | PROF_UPDATE_CLIP); + rna_update_cb(C, arg1_v, NULL); } -static void CurveProfile_buttons_update(bContext *C, void *arg1_v, void *profile_v) +static void CurveProfile_buttons_reset(bContext *C, void *arg1_v, void *profile_v) { CurveProfile *profile = profile_v; - BKE_curveprofile_update(profile, true); + BKE_curveprofile_reset(profile); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); rna_update_cb(C, arg1_v, NULL); } @@ -4836,7 +4829,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp UI_block_emboss_set(block, UI_EMBOSS); - uiLayoutRow(layout, false); + uiLayoutSetPropSep(layout, false); /* Preset selector */ /* There is probably potential to use simpler "uiItemR" functions here, but automatic updating @@ -4845,6 +4838,29 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp block, CurveProfile_buttons_presets, profile, "Preset", 0, 0, UI_UNIT_X, UI_UNIT_X, ""); UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + /* Show a "re-apply" preset button when it has been changed from the preset. */ + if (profile->flag & PROF_DIRTY_PRESET) { + /* Only for dynamic presets. */ + if (ELEM(profile->preset, PROF_PRESET_STEPS, PROF_PRESET_SUPPORTS)) { + bt = uiDefIconTextBut(block, + UI_BTYPE_BUT, + 0, + ICON_NONE, + "Apply Preset", + 0, + 0, + UI_UNIT_X, + UI_UNIT_X, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + "Reapply and update the preset, removing changes"); + UI_but_funcN_set(bt, CurveProfile_buttons_reset, MEM_dupallocN(cb), profile); + } + } + row = uiLayoutRow(layout, false); /* (Left aligned) */ @@ -4952,11 +4968,24 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp ""); /* Position sliders for (first) selected point */ + float *selection_x, *selection_y; for (i = 0; i < profile->path_len; i++) { if (profile->path[i].flag & PROF_SELECT) { point = &profile->path[i]; + selection_x = &point->x; + selection_y = &point->y; break; } + else if (profile->path[i].flag & PROF_H1_SELECT) { + point = &profile->path[i]; + selection_x = &point->h1_loc[0]; + selection_y = &point->h1_loc[1]; + } + else if (profile->path[i].flag & PROF_H2_SELECT) { + point = &profile->path[i]; + selection_x = &point->h2_loc[0]; + selection_y = &point->h2_loc[1]; + } } if (i == 0 || i == profile->path_len - 1) { point_last_or_first = true; @@ -4972,46 +5001,19 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp bounds.xmax = bounds.ymax = 1000.0; } - uiLayoutRow(layout, true); - UI_block_funcN_set(block, CurveProfile_buttons_update, MEM_dupallocN(cb), profile); + row = uiLayoutRow(layout, true); - /* Sharp / Smooth */ - bt = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_LINCURVE, - 0, - 0, - UI_UNIT_X, - UI_UNIT_X, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - TIP_("Set the point's handle type to sharp")); - if (point_last_or_first) { - UI_but_flag_enable(bt, UI_BUT_DISABLED); - } - UI_but_funcN_set(bt, CurveProfile_buttons_setsharp, MEM_dupallocN(cb), profile); - bt = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_SMOOTHCURVE, - 0, - 0, - UI_UNIT_X, - UI_UNIT_X, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - TIP_("Set the point's handle type to smooth")); - UI_but_funcN_set(bt, CurveProfile_buttons_setcurved, MEM_dupallocN(cb), profile); - if (point_last_or_first) { - UI_but_flag_enable(bt, UI_BUT_DISABLED); - } + PointerRNA point_ptr; + RNA_pointer_create(ptr->owner_id, &RNA_CurveProfilePoint, point, &point_ptr); + PropertyRNA *prop_handle_type = RNA_struct_find_property(&point_ptr, "handle_type_1"); + uiItemFullR(row, + &point_ptr, + prop_handle_type, + RNA_NO_INDEX, + 0, + UI_ITEM_R_EXPAND | UI_ITEM_R_ICON_ONLY, + "", + ICON_NONE); /* Position */ bt = uiDefButF(block, @@ -5022,16 +5024,16 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp 2 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y, - &point->x, + selection_x, bounds.xmin, bounds.xmax, 1, 5, ""); + UI_but_funcN_set(bt, CurveProfile_buttons_update, MEM_dupallocN(cb), profile); if (point_last_or_first) { UI_but_flag_enable(bt, UI_BUT_DISABLED); } - bt = uiDefButF(block, UI_BTYPE_NUM, 0, @@ -5040,12 +5042,13 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp 1 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y, - &point->y, + selection_y, bounds.ymin, bounds.ymax, 1, 5, ""); + UI_but_funcN_set(bt, CurveProfile_buttons_update, MEM_dupallocN(cb), profile); if (point_last_or_first) { UI_but_flag_enable(bt, UI_BUT_DISABLED); } @@ -7271,37 +7274,35 @@ void uiTemplateCacheFile(uiLayout *layout, SpaceProperties *sbuts = CTX_wm_space_properties(C); - uiLayout *row = uiLayoutRow(layout, false); - uiBlock *block = uiLayoutGetBlock(row); - uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, ""); - - row = uiLayoutRow(layout, false); - uiLayout *split = uiLayoutSplit(row, 0.0f, false); - row = uiLayoutRow(split, true); + uiLayout *row, *sub, *subsub; - uiItemR(row, &fileptr, "filepath", 0, "", ICON_NONE); - uiItemO(row, "", ICON_FILE_REFRESH, "cachefile.reload"); + uiLayoutSetPropSep(layout, true); - row = uiLayoutRow(layout, false); - uiItemR(row, &fileptr, "is_sequence", 0, "Is Sequence", ICON_NONE); + row = uiLayoutRow(layout, true); + uiItemR(row, &fileptr, "filepath", 0, NULL, ICON_NONE); + sub = uiLayoutRow(row, true); + uiItemO(sub, "", ICON_FILE_REFRESH, "cachefile.reload"); row = uiLayoutRow(layout, false); - uiItemR(row, &fileptr, "override_frame", 0, "Override Frame", ICON_NONE); + uiItemR(row, &fileptr, "is_sequence", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, false); - uiLayoutSetActive(row, RNA_boolean_get(&fileptr, "override_frame")); - uiItemR(row, &fileptr, "frame", 0, "Frame", ICON_NONE); + row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame")); + sub = uiLayoutRow(row, true); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, &fileptr, "override_frame", 0, "", ICON_NONE); + subsub = uiLayoutRow(sub, true); + uiLayoutSetActive(subsub, RNA_boolean_get(&fileptr, "override_frame")); + uiItemR(subsub, &fileptr, "frame", 0, "", ICON_NONE); + uiItemDecoratorR(row, &fileptr, "frame", 0); row = uiLayoutRow(layout, false); - uiItemR(row, &fileptr, "frame_offset", 0, "Frame Offset", ICON_NONE); + uiItemR(row, &fileptr, "frame_offset", 0, NULL, ICON_NONE); uiLayoutSetActive(row, !RNA_boolean_get(&fileptr, "is_sequence")); - row = uiLayoutRow(layout, false); - uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE); - - row = uiLayoutRow(layout, false); - uiLayoutSetActive(row, (sbuts->mainb == BCONTEXT_CONSTRAINT)); - uiItemR(row, &fileptr, "scale", 0, "Scale", ICON_NONE); + if (sbuts->mainb == BCONTEXT_CONSTRAINT) { + row = uiLayoutRow(layout, false); + uiItemR(row, &fileptr, "scale", 0, IFACE_("Manual Scale"), ICON_NONE); + } /* TODO: unused for now, so no need to expose. */ #if 0 diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 3737b607305..432da3d5dd5 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -45,6 +45,7 @@ #include "RNA_access.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "UI_resources.h" #include "WM_api.h" @@ -384,6 +385,7 @@ typedef struct CollItemSearch { char *name; int index; int iconid; + bool is_id; uint has_sep_char : 1; } CollItemSearch; @@ -418,6 +420,7 @@ void ui_rna_collection_search_update_fn(const struct bContext *C, const bool skip_filter = data->search_but && !data->search_but->changed; char name_buf[UI_MAX_DRAW_STR]; char *name; + bool has_id_icon = false; /* build a temporary list of relevant items first */ RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) { @@ -437,16 +440,20 @@ void ui_rna_collection_search_update_fn(const struct bContext *C, int iconid = ICON_NONE; bool has_sep_char = false; + bool is_id = itemptr.type && RNA_struct_is_ID(itemptr.type); - if (itemptr.type && RNA_struct_is_ID(itemptr.type)) { + if (is_id) { iconid = ui_id_icon_get(C, itemptr.data, false); + if (!ELEM(iconid, 0, ICON_BLANK1)) { + has_id_icon = true; + } if (requires_exact_data_name) { name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), NULL); } else { const ID *id = itemptr.data; - BKE_id_full_name_ui_prefix_get(name_buf, id, UI_SEP_CHAR); + BKE_id_full_name_ui_prefix_get(name_buf, itemptr.data, true, UI_SEP_CHAR); BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI, "Name string buffer should be big enough to hold full UI ID name"); name = name_buf; @@ -464,6 +471,7 @@ void ui_rna_collection_search_update_fn(const struct bContext *C, cis->name = BLI_strdup(name); cis->index = i; cis->iconid = iconid; + cis->is_id = is_id; cis->has_sep_char = has_sep_char; BLI_addtail(items_list, cis); } @@ -480,6 +488,17 @@ void ui_rna_collection_search_update_fn(const struct bContext *C, /* add search items from temporary list */ for (cis = items_list->first; cis; cis = cis->next) { + /* If no item has an own icon to display, libraries can use the library icons rather than the + * name prefix for showing the library status. */ + if (!has_id_icon && cis->is_id) { + cis->iconid = UI_library_icon_get(cis->data); + /* No need to re-allocate, string should be shorter than before (lib status prefix is + * removed). */ + BKE_id_full_name_ui_prefix_get(name_buf, cis->data, false, UI_SEP_CHAR); + BLI_assert(strlen(name_buf) <= MEM_allocN_len(cis->name)); + strcpy(cis->name, name_buf); + } + if (!UI_search_item_add(items, cis->name, cis->data, diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 0498b312618..16a5a13885b 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -393,35 +393,14 @@ static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}} * * \{ */ -/* offset in triavec[] in shader per type */ -static const int tria_ofs[ROUNDBOX_TRIA_MAX] = { - [ROUNDBOX_TRIA_NONE] = 0, - [ROUNDBOX_TRIA_ARROWS] = 0, - [ROUNDBOX_TRIA_SCROLL] = 12, - [ROUNDBOX_TRIA_MENU] = 28, - [ROUNDBOX_TRIA_CHECK] = 34, - [ROUNDBOX_TRIA_HOLD_ACTION_ARROW] = 40, -}; -static const int tria_vcount[ROUNDBOX_TRIA_MAX] = { - [ROUNDBOX_TRIA_NONE] = 0, - [ROUNDBOX_TRIA_ARROWS] = 6, - [ROUNDBOX_TRIA_SCROLL] = 16, - [ROUNDBOX_TRIA_MENU] = 6, - [ROUNDBOX_TRIA_CHECK] = 6, - [ROUNDBOX_TRIA_HOLD_ACTION_ARROW] = 3, -}; - static struct { - GPUBatch *roundbox_widget[ROUNDBOX_TRIA_MAX]; - - GPUBatch *roundbox_simple; - GPUBatch *roundbox_simple_aa; - GPUBatch *roundbox_simple_outline; + GPUBatch *roundbox_widget; GPUBatch *roundbox_shadow; + /* TODO remove */ GPUVertFormat format; uint vflag_id; -} g_ui_batch_cache = {{0}}; +} g_ui_batch_cache = {0}; static GPUVertFormat *vflag_format(void) { @@ -436,7 +415,7 @@ static GPUVertFormat *vflag_format(void) #define INNER 0 #define OUTLINE 1 #define EMBOSS 2 -#define NO_AA WIDGET_AA_JITTER +#define NO_AA 0 static void set_roundbox_vertex_data(GPUVertBufRaw *vflag_step, uint32_t d) { @@ -462,176 +441,30 @@ static uint32_t set_roundbox_vertex(GPUVertBufRaw *vflag_step, return *data; } -static uint32_t set_tria_vertex( - GPUVertBufRaw *vflag_step, int tria_type, int tria_v, int tria_id, int jit_v) -{ - uint32_t *data = GPU_vertbuf_raw_step(vflag_step); - if (ELEM(tria_type, ROUNDBOX_TRIA_ARROWS)) { - tria_v += tria_id * tria_vcount[ROUNDBOX_TRIA_ARROWS]; - } - *data = tria_ofs[tria_type] + tria_v; - *data |= jit_v << 6; - *data |= (tria_id == 0) ? (1 << 10) : 0; /* is first tria */ - *data |= 1 << 14; /* is tria vert */ - return *data; -} - -static void roundbox_batch_add_tria(GPUVertBufRaw *vflag_step, int tria, uint32_t last_data) +GPUBatch *ui_batch_roundbox_widget_get(void) { - const int tria_num = - ELEM(tria, ROUNDBOX_TRIA_CHECK, ROUNDBOX_TRIA_HOLD_ACTION_ARROW, ROUNDBOX_TRIA_MENU) ? 1 : 2; - /* for each tria */ - for (int t = 0; t < tria_num; t++) { - for (int j = 0; j < WIDGET_AA_JITTER; j++) { - /* restart */ - set_roundbox_vertex_data(vflag_step, last_data); - set_tria_vertex(vflag_step, tria, 0, t, j); - for (int v = 0; v < tria_vcount[tria]; v++) { - last_data = set_tria_vertex(vflag_step, tria, v, t, j); - } - } - } -} - -GPUBatch *ui_batch_roundbox_widget_get(int tria) -{ - if (g_ui_batch_cache.roundbox_widget[tria] == NULL) { - uint32_t last_data; - GPUVertBufRaw vflag_step; + if (g_ui_batch_cache.roundbox_widget == NULL) { GPUVertBuf *vbo = GPU_vertbuf_create_with_format(vflag_format()); - int vcount = WIDGET_SIZE_MAX; /* inner */ - vcount += 2; /* restart */ - vcount += ((WIDGET_SIZE_MAX + 1) * 2) * WIDGET_AA_JITTER; /* outline (edges) */ - vcount += 2; /* restart */ - vcount += ((WIDGET_CURVE_RESOLU * 2) * 2) * WIDGET_AA_JITTER; /* emboss */ - if (tria) { - vcount += (tria_vcount[tria] + 2) * WIDGET_AA_JITTER; /* tria1 */ - if (!ELEM(tria, ROUNDBOX_TRIA_CHECK, ROUNDBOX_TRIA_HOLD_ACTION_ARROW, ROUNDBOX_TRIA_MENU)) { - vcount += (tria_vcount[tria] + 2) * WIDGET_AA_JITTER; /* tria2 */ - } - } - GPU_vertbuf_data_alloc(vbo, vcount); - GPU_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step); - /* Inner */ - for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) { - for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU - 1; a2 >= 0; a1++, a2--) { - last_data = set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER); - last_data = set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER); - } - } - /* restart */ - set_roundbox_vertex_data(&vflag_step, last_data); - set_roundbox_vertex(&vflag_step, 0, 0, 0, true, false, OUTLINE); - /* Outlines */ - for (int j = 0; j < WIDGET_AA_JITTER; j++) { - for (int c = 0; c < 4; c++) { - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) { - set_roundbox_vertex(&vflag_step, c, a, j, true, false, OUTLINE); - set_roundbox_vertex(&vflag_step, c, a, j, false, false, OUTLINE); - } - } - /* Close the loop. */ - set_roundbox_vertex(&vflag_step, 0, 0, j, true, false, OUTLINE); - last_data = set_roundbox_vertex(&vflag_step, 0, 0, j, false, false, OUTLINE); - } - /* restart */ - set_roundbox_vertex_data(&vflag_step, last_data); - set_roundbox_vertex(&vflag_step, 0, 0, 0, false, false, EMBOSS); - /* Emboss */ - /* go back and forth : avoid degenerate triangle (but beware of backface cull) */ - bool rev = false; - for (int j = 0; j < WIDGET_AA_JITTER; j++, rev = !rev) { - for (int c = (rev) ? 1 : 0; (rev) ? c >= 0 : c < 2; (rev) ? c-- : c++) { - int sta = (rev) ? WIDGET_CURVE_RESOLU - 1 : 0; - int end = WIDGET_CURVE_RESOLU; - for (int a = sta; (rev) ? a >= 0 : a < end; (rev) ? a-- : a++) { - set_roundbox_vertex(&vflag_step, c, a, j, false, false, EMBOSS); - last_data = set_roundbox_vertex(&vflag_step, c, a, j, false, true, EMBOSS); - } - } - } - if (tria) { - roundbox_batch_add_tria(&vflag_step, tria, last_data); - } - g_ui_batch_cache.roundbox_widget[tria] = GPU_batch_create_ex( - GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO); - gpu_batch_presets_register(g_ui_batch_cache.roundbox_widget[tria]); - } - return g_ui_batch_cache.roundbox_widget[tria]; -} -GPUBatch *ui_batch_roundbox_get(bool filled, bool antialiased) -{ - GPUBatch **batch = NULL; + GPU_vertbuf_data_alloc(vbo, 12); - if (filled) { - if (antialiased) { - batch = &g_ui_batch_cache.roundbox_simple_aa; - } - else { - batch = &g_ui_batch_cache.roundbox_simple; - } - } - else { - if (antialiased) { - BLI_assert(0); /* Use GL_LINE_SMOOTH instead!!: */ - } - else { - batch = &g_ui_batch_cache.roundbox_simple_outline; - } - } + GPUIndexBufBuilder ibuf; + GPU_indexbuf_init(&ibuf, GPU_PRIM_TRIS, 6, 12); + /* Widget */ + GPU_indexbuf_add_tri_verts(&ibuf, 0, 1, 2); + GPU_indexbuf_add_tri_verts(&ibuf, 2, 1, 3); + /* Trias */ + GPU_indexbuf_add_tri_verts(&ibuf, 4, 5, 6); + GPU_indexbuf_add_tri_verts(&ibuf, 6, 5, 7); - if (*batch == NULL) { - uint32_t last_data; - GPUVertBufRaw vflag_step; - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(vflag_format()); - int vcount = WIDGET_SIZE_MAX; - vcount += (filled) ? 2 : 0; - vcount *= (antialiased) ? WIDGET_AA_JITTER : 1; - GPU_vertbuf_data_alloc(vbo, vcount); - GPU_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step); + GPU_indexbuf_add_tri_verts(&ibuf, 8, 9, 10); + GPU_indexbuf_add_tri_verts(&ibuf, 10, 9, 11); - if (filled) { - for (int j = 0; j < WIDGET_AA_JITTER; j++) { - if (!antialiased) { - j = NO_AA; - } - /* restart */ - set_roundbox_vertex(&vflag_step, 0, 0, j, true, false, INNER); - for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) { - for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU - 1; a2 >= 0; a1++, a2--) { - last_data = set_roundbox_vertex(&vflag_step, c1, a1, j, true, false, INNER); - last_data = set_roundbox_vertex(&vflag_step, c2, a2, j, true, false, INNER); - } - } - /* restart */ - set_roundbox_vertex_data(&vflag_step, last_data); - if (!antialiased) { - break; - } - } - *batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO); - } - else { - for (int j = 0; j < WIDGET_AA_JITTER; j++) { - if (!antialiased) { - j = NO_AA; - } - for (int c = 0; c < 4; c++) { - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) { - set_roundbox_vertex(&vflag_step, c, a, j, true, false, INNER); - } - } - if (!antialiased) { - break; - } - } - *batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO); - } - - gpu_batch_presets_register(*batch); + g_ui_batch_cache.roundbox_widget = GPU_batch_create_ex( + GPU_PRIM_TRIS, vbo, GPU_indexbuf_build(&ibuf), GPU_BATCH_OWNS_INDEX | GPU_BATCH_OWNS_VBO); + gpu_batch_presets_register(g_ui_batch_cache.roundbox_widget); } - return *batch; + return g_ui_batch_cache.roundbox_widget; } GPUBatch *ui_batch_roundbox_shadow_get(void) @@ -1314,14 +1147,13 @@ static void widgetbase_set_uniform_colors_ubv(uiWidgetBase *wtb, /* keep in sync with shader */ #define MAX_WIDGET_BASE_BATCH 6 -#define MAX_WIDGET_PARAMETERS 11 +#define MAX_WIDGET_PARAMETERS 12 static struct { - GPUBatch *batch; /* Batch type */ uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]; int count; bool enabled; -} g_widget_base_batch = {0}; +} g_widget_base_batch = {{{{0}}}}; void UI_widgetbase_draw_cache_flush(void) { @@ -1332,7 +1164,7 @@ void UI_widgetbase_draw_cache_flush(void) return; } - GPUBatch *batch = g_widget_base_batch.batch; + GPUBatch *batch = ui_batch_roundbox_widget_get(); if (g_widget_base_batch.count == 1) { /* draw single */ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); @@ -1376,31 +1208,15 @@ void UI_widgetbase_draw_cache_end(void) GPU_blend(false); } -static void draw_widgetbase_batch(GPUBatch *batch, uiWidgetBase *wtb) +static void draw_widgetbase_batch(uiWidgetBase *wtb) { + wtb->uniform_params.tria_type = wtb->tria1.type; wtb->uniform_params.tria1_size = wtb->tria1.size; wtb->uniform_params.tria2_size = wtb->tria2.size; copy_v2_v2(wtb->uniform_params.tria1_center, wtb->tria1.center); copy_v2_v2(wtb->uniform_params.tria2_center, wtb->tria2.center); if (g_widget_base_batch.enabled) { - if (g_widget_base_batch.batch == NULL) { - g_widget_base_batch.batch = ui_batch_roundbox_widget_get(ROUNDBOX_TRIA_ARROWS); - } - - /* draw multi */ - if (batch != g_ui_batch_cache.roundbox_widget[ROUNDBOX_TRIA_NONE] && - batch != g_widget_base_batch.batch) { - /* issue previous calls before changing batch type. */ - UI_widgetbase_draw_cache_flush(); - g_widget_base_batch.batch = batch; - } - - /* No need to change batch if tria is not visible. Just scale it to 0. */ - if (batch == g_ui_batch_cache.roundbox_widget[ROUNDBOX_TRIA_NONE]) { - wtb->uniform_params.tria1_size = wtb->uniform_params.tria2_size = 0; - } - g_widget_base_batch.params[g_widget_base_batch.count] = wtb->uniform_params; g_widget_base_batch.count++; @@ -1412,6 +1228,7 @@ static void draw_widgetbase_batch(GPUBatch *batch, uiWidgetBase *wtb) const float checker_params[3] = { UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f}; /* draw single */ + GPUBatch *batch = ui_batch_roundbox_widget_get(); GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); GPU_batch_uniform_4fv_array( batch, "parameters", MAX_WIDGET_PARAMETERS, (float *)&wtb->uniform_params); @@ -1434,8 +1251,6 @@ static void widgetbase_draw_ex(uiWidgetBase *wtb, show_alpha_checkers = false; } - GPU_blend(true); - /* backdrop non AA */ if (wtb->draw_inner) { if (wcol->shaded == 0) { @@ -1455,7 +1270,7 @@ static void widgetbase_draw_ex(uiWidgetBase *wtb, outline_col[0] = wcol->outline[0]; outline_col[1] = wcol->outline[1]; outline_col[2] = wcol->outline[2]; - outline_col[3] = wcol->outline[3] / WIDGET_AA_JITTER; + outline_col[3] = wcol->outline[3]; /* emboss bottom shadow */ if (wtb->draw_emboss) { @@ -1467,7 +1282,7 @@ static void widgetbase_draw_ex(uiWidgetBase *wtb, tria_col[0] = wcol->item[0]; tria_col[1] = wcol->item[1]; tria_col[2] = wcol->item[2]; - tria_col[3] = (uchar)((float)wcol->item[3] / WIDGET_AA_JITTER); + tria_col[3] = wcol->item[3]; } /* Draw everything in one drawcall */ @@ -1476,11 +1291,10 @@ static void widgetbase_draw_ex(uiWidgetBase *wtb, widgetbase_set_uniform_colors_ubv( wtb, inner_col1, inner_col2, outline_col, emboss_col, tria_col, show_alpha_checkers); - GPUBatch *roundbox_batch = ui_batch_roundbox_widget_get(wtb->tria1.type); - draw_widgetbase_batch(roundbox_batch, wtb); + GPU_blend(true); + draw_widgetbase_batch(wtb); + GPU_blend(false); } - - GPU_blend(false); } static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol) diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index f8419ba3eba..d696c99851b 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -113,10 +113,10 @@ BLI_INLINE void clamp_rctf_to_rcti(rcti *dst, const rctf *src) static int view2d_scroll_mapped(int scroll) { if (scroll & V2D_SCROLL_HORIZONTAL_FULLR) { - scroll &= ~(V2D_SCROLL_HORIZONTAL); + scroll &= ~V2D_SCROLL_HORIZONTAL; } if (scroll & V2D_SCROLL_VERTICAL_FULLR) { - scroll &= ~(V2D_SCROLL_VERTICAL); + scroll &= ~V2D_SCROLL_VERTICAL; } return scroll; } @@ -198,7 +198,7 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll) } /* horizontal scroller */ - if (scroll & (V2D_SCROLL_BOTTOM)) { + if (scroll & V2D_SCROLL_BOTTOM) { /* on bottom edge of region */ v2d->hor = *mask_scroll; v2d->hor.ymax = scroll_height; @@ -211,7 +211,7 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll) /* adjust vertical scroller if there's a horizontal scroller, to leave corner free */ if (scroll & V2D_SCROLL_VERTICAL) { - if (scroll & (V2D_SCROLL_BOTTOM)) { + if (scroll & V2D_SCROLL_BOTTOM) { /* on bottom edge of region */ v2d->vert.ymin = v2d->hor.ymax; } @@ -1408,22 +1408,22 @@ struct View2DScrollers { int vert_min, vert_max; /* vertical scrollbar */ int hor_min, hor_max; /* horizontal scrollbar */ - rcti hor, vert; /* exact size of slider backdrop */ - int horfull, vertfull; /* set if sliders are full, we don't draw them */ + /** Exact size of slider backdrop. */ + rcti hor, vert; + /* set if sliders are full, we don't draw them */ + /* int horfull, vertfull; */ /* UNUSED */ }; /* Calculate relevant scroller properties */ -View2DScrollers *UI_view2d_scrollers_calc(View2D *v2d, const rcti *mask_custom) +void UI_view2d_scrollers_calc(View2D *v2d, + const rcti *mask_custom, + struct View2DScrollers *r_scrollers) { - View2DScrollers *scrollers; rcti vert, hor; float fac1, fac2, totsize, scrollsize; int scroll = view2d_scroll_mapped(v2d->scroll); int smaller; - /* scrollers is allocated here... */ - scrollers = MEM_callocN(sizeof(View2DScrollers), "View2DScrollers"); - /* Always update before drawing (for dynamically sized scrollers). */ view2d_masks(v2d, mask_custom); @@ -1452,12 +1452,12 @@ View2DScrollers *UI_view2d_scrollers_calc(View2D *v2d, const rcti *mask_custom) vert.xmax -= smaller; } - CLAMP(vert.ymin, vert.ymin, vert.ymax - V2D_SCROLL_HANDLE_SIZE_HOTSPOT); - CLAMP(hor.xmin, hor.xmin, hor.xmax - V2D_SCROLL_HANDLE_SIZE_HOTSPOT); + CLAMP_MAX(vert.ymin, vert.ymax - V2D_SCROLL_HANDLE_SIZE_HOTSPOT); + CLAMP_MAX(hor.xmin, hor.xmax - V2D_SCROLL_HANDLE_SIZE_HOTSPOT); /* store in scrollers, used for drawing */ - scrollers->vert = vert; - scrollers->hor = hor; + r_scrollers->vert = vert; + r_scrollers->hor = hor; /* scroller 'buttons': * - These should always remain within the visible region of the scrollbar @@ -1475,30 +1475,30 @@ View2DScrollers *UI_view2d_scrollers_calc(View2D *v2d, const rcti *mask_custom) fac1 = (v2d->cur.xmin - v2d->tot.xmin) / totsize; if (fac1 <= 0.0f) { - scrollers->hor_min = hor.xmin; + r_scrollers->hor_min = hor.xmin; } else { - scrollers->hor_min = (int)(hor.xmin + (fac1 * scrollsize)); + r_scrollers->hor_min = (int)(hor.xmin + (fac1 * scrollsize)); } fac2 = (v2d->cur.xmax - v2d->tot.xmin) / totsize; if (fac2 >= 1.0f) { - scrollers->hor_max = hor.xmax; + r_scrollers->hor_max = hor.xmax; } else { - scrollers->hor_max = (int)(hor.xmin + (fac2 * scrollsize)); + r_scrollers->hor_max = (int)(hor.xmin + (fac2 * scrollsize)); } /* prevent inverted sliders */ - if (scrollers->hor_min > scrollers->hor_max) { - scrollers->hor_min = scrollers->hor_max; + if (r_scrollers->hor_min > r_scrollers->hor_max) { + r_scrollers->hor_min = r_scrollers->hor_max; } /* prevent sliders from being too small to grab */ - if ((scrollers->hor_max - scrollers->hor_min) < V2D_SCROLL_THUMB_SIZE_MIN) { - scrollers->hor_max = scrollers->hor_min + V2D_SCROLL_THUMB_SIZE_MIN; + if ((r_scrollers->hor_max - r_scrollers->hor_min) < V2D_SCROLL_THUMB_SIZE_MIN) { + r_scrollers->hor_max = r_scrollers->hor_min + V2D_SCROLL_THUMB_SIZE_MIN; - CLAMP(scrollers->hor_max, hor.xmin + V2D_SCROLL_THUMB_SIZE_MIN, hor.xmax); - CLAMP(scrollers->hor_min, hor.xmin, hor.xmax - V2D_SCROLL_THUMB_SIZE_MIN); + CLAMP(r_scrollers->hor_max, hor.xmin + V2D_SCROLL_THUMB_SIZE_MIN, hor.xmax); + CLAMP(r_scrollers->hor_min, hor.xmin, hor.xmax - V2D_SCROLL_THUMB_SIZE_MIN); } } @@ -1513,39 +1513,39 @@ View2DScrollers *UI_view2d_scrollers_calc(View2D *v2d, const rcti *mask_custom) fac1 = (v2d->cur.ymin - v2d->tot.ymin) / totsize; if (fac1 <= 0.0f) { - scrollers->vert_min = vert.ymin; + r_scrollers->vert_min = vert.ymin; } else { - scrollers->vert_min = (int)(vert.ymin + (fac1 * scrollsize)); + r_scrollers->vert_min = (int)(vert.ymin + (fac1 * scrollsize)); } fac2 = (v2d->cur.ymax - v2d->tot.ymin) / totsize; if (fac2 >= 1.0f) { - scrollers->vert_max = vert.ymax; + r_scrollers->vert_max = vert.ymax; } else { - scrollers->vert_max = (int)(vert.ymin + (fac2 * scrollsize)); + r_scrollers->vert_max = (int)(vert.ymin + (fac2 * scrollsize)); } /* prevent inverted sliders */ - if (scrollers->vert_min > scrollers->vert_max) { - scrollers->vert_min = scrollers->vert_max; + if (r_scrollers->vert_min > r_scrollers->vert_max) { + r_scrollers->vert_min = r_scrollers->vert_max; } /* prevent sliders from being too small to grab */ - if ((scrollers->vert_max - scrollers->vert_min) < V2D_SCROLL_THUMB_SIZE_MIN) { - scrollers->vert_max = scrollers->vert_min + V2D_SCROLL_THUMB_SIZE_MIN; + if ((r_scrollers->vert_max - r_scrollers->vert_min) < V2D_SCROLL_THUMB_SIZE_MIN) { + r_scrollers->vert_max = r_scrollers->vert_min + V2D_SCROLL_THUMB_SIZE_MIN; - CLAMP(scrollers->vert_max, vert.ymin + V2D_SCROLL_THUMB_SIZE_MIN, vert.ymax); - CLAMP(scrollers->vert_min, vert.ymin, vert.ymax - V2D_SCROLL_THUMB_SIZE_MIN); + CLAMP(r_scrollers->vert_max, vert.ymin + V2D_SCROLL_THUMB_SIZE_MIN, vert.ymax); + CLAMP(r_scrollers->vert_min, vert.ymin, vert.ymax - V2D_SCROLL_THUMB_SIZE_MIN); } } - - return scrollers; } /* Draw scrollbars in the given 2d-region */ -void UI_view2d_scrollers_draw(View2D *v2d, View2DScrollers *vs) +void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom) { + View2DScrollers scrollers; + UI_view2d_scrollers_calc(v2d, mask_custom, &scrollers); bTheme *btheme = UI_GetTheme(); rcti vert, hor; const int scroll = view2d_scroll_mapped(v2d->scroll); @@ -1556,8 +1556,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, View2DScrollers *vs) UI_GetThemeColor4ubv(TH_BACK, scrollers_back_color); /* make copies of rects for less typing */ - vert = vs->vert; - hor = vs->hor; + vert = scrollers.vert; + hor = scrollers.hor; /* horizontal scrollbar */ if (scroll & V2D_SCROLL_HORIZONTAL) { @@ -1566,8 +1566,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, View2DScrollers *vs) rcti slider; int state; - slider.xmin = vs->hor_min; - slider.xmax = vs->hor_max; + slider.xmin = scrollers.hor_min; + slider.xmax = scrollers.hor_max; slider.ymin = hor.ymin; slider.ymax = hor.ymax; @@ -1602,8 +1602,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, View2DScrollers *vs) slider.xmin = vert.xmin; slider.xmax = vert.xmax; - slider.ymin = vs->vert_min; - slider.ymax = vs->vert_max; + slider.ymin = scrollers.vert_min; + slider.ymax = scrollers.vert_max; state = (v2d->scroll_ui & V2D_SCROLL_V_ACTIVE) ? UI_SCROLL_PRESSED : 0; @@ -1631,12 +1631,6 @@ void UI_view2d_scrollers_draw(View2D *v2d, View2DScrollers *vs) btheme->tui.widget_emboss[3] = emboss_alpha; } -/* free temporary memory used for drawing scrollers */ -void UI_view2d_scrollers_free(View2DScrollers *scrollers) -{ - MEM_freeN(scrollers); -} - /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 98bbd7af943..0efb49f42bf 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -1922,6 +1922,9 @@ struct View2DScrollers { /* focus bubbles */ int vert_min, vert_max; /* vertical scrollbar */ int hor_min, hor_max; /* horizontal scrollbar */ + + /* These values are written into, even if we don't use them. */ + rcti _hor, _vert; }; /* quick enum for vsm->zone (scroller handles) */ @@ -2011,7 +2014,7 @@ static void scroller_activate_init(bContext *C, const char in_scroller) { v2dScrollerMove *vsm; - View2DScrollers *scrollers; + View2DScrollers scrollers; ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; rctf tot_cur_union; @@ -2032,7 +2035,7 @@ static void scroller_activate_init(bContext *C, /* 'zone' depends on where mouse is relative to bubble * - zooming must be allowed on this axis, otherwise, default to pan */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); + UI_view2d_scrollers_calc(v2d, NULL, &scrollers); /* Use a union of 'cur' & 'tot' in case the current view is far outside 'tot'. In this cases * moving the scroll bars has far too little effect and the view can get stuck T31476. */ @@ -2049,15 +2052,15 @@ static void scroller_activate_init(bContext *C, /* get 'zone' (i.e. which part of scroller is activated) */ vsm->zone = mouse_in_scroller_handle( - event->mval[0], v2d->hor.xmin, v2d->hor.xmax, scrollers->hor_min, scrollers->hor_max); + event->mval[0], v2d->hor.xmin, v2d->hor.xmax, scrollers.hor_min, scrollers.hor_max); if ((v2d->keepzoom & V2D_LOCKZOOM_X) && ELEM(vsm->zone, SCROLLHANDLE_MIN, SCROLLHANDLE_MAX)) { /* default to scroll, as handles not usable */ vsm->zone = SCROLLHANDLE_BAR; } - vsm->scrollbarwidth = scrollers->hor_max - scrollers->hor_min; - vsm->scrollbar_orig = ((scrollers->hor_max + scrollers->hor_min) / 2) + region->winrct.xmin; + vsm->scrollbarwidth = scrollers.hor_max - scrollers.hor_min; + vsm->scrollbar_orig = ((scrollers.hor_max + scrollers.hor_min) / 2) + region->winrct.xmin; } else { /* vertical scroller - calculate adjustment factor first */ @@ -2069,18 +2072,17 @@ static void scroller_activate_init(bContext *C, /* get 'zone' (i.e. which part of scroller is activated) */ vsm->zone = mouse_in_scroller_handle( - event->mval[1], v2d->vert.ymin, v2d->vert.ymax, scrollers->vert_min, scrollers->vert_max); + event->mval[1], v2d->vert.ymin, v2d->vert.ymax, scrollers.vert_min, scrollers.vert_max); if ((v2d->keepzoom & V2D_LOCKZOOM_Y) && ELEM(vsm->zone, SCROLLHANDLE_MIN, SCROLLHANDLE_MAX)) { /* default to scroll, as handles not usable */ vsm->zone = SCROLLHANDLE_BAR; } - vsm->scrollbarwidth = scrollers->vert_max - scrollers->vert_min; - vsm->scrollbar_orig = ((scrollers->vert_max + scrollers->vert_min) / 2) + region->winrct.ymin; + vsm->scrollbarwidth = scrollers.vert_max - scrollers.vert_min; + vsm->scrollbar_orig = ((scrollers.vert_max + scrollers.vert_min) / 2) + region->winrct.ymin; } - UI_view2d_scrollers_free(scrollers); ED_region_tag_redraw_no_rebuild(region); } @@ -2299,8 +2301,8 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent * } /* zone is also inappropriate if scroller is not visible... */ - if (((vsm->scroller == 'h') && (v2d->scroll & (V2D_SCROLL_HORIZONTAL_FULLR))) || - ((vsm->scroller == 'v') && (v2d->scroll & (V2D_SCROLL_VERTICAL_FULLR)))) { + if (((vsm->scroller == 'h') && (v2d->scroll & V2D_SCROLL_HORIZONTAL_FULLR)) || + ((vsm->scroller == 'v') && (v2d->scroll & V2D_SCROLL_VERTICAL_FULLR))) { /* free customdata initialized */ scroller_activate_exit(C, op); diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index fc2c55ffeda..9db1fe31494 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -410,8 +410,11 @@ void WM_OT_alembic_export(wmOperatorType *ot) "Use Subdivision Schema", "Export meshes using Alembic's subdivision schema"); - RNA_def_boolean( - ot->srna, "apply_subdiv", 0, "Apply Subdivision Surface", "Export subdivision surfaces as meshes"); + RNA_def_boolean(ot->srna, + "apply_subdiv", + 0, + "Apply Subdivision Surface", + "Export subdivision surfaces as meshes"); RNA_def_boolean(ot->srna, "curves_as_mesh", @@ -667,6 +670,7 @@ void WM_OT_alembic_import(wmOperatorType *ot) ot->name = "Import Alembic"; ot->description = "Load an Alembic archive"; ot->idname = "WM_OT_alembic_import"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ot->invoke = wm_alembic_import_invoke; ot->exec = wm_alembic_import_exec; diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 9091e7d8afc..c1a4492994a 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -857,6 +857,7 @@ void WM_OT_collada_import(wmOperatorType *ot) ot->name = "Import COLLADA"; ot->description = "Load a Collada file"; ot->idname = "WM_OT_collada_import"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ot->invoke = WM_operator_filesel; ot->exec = wm_collada_import_exec; diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index e94412233ff..d18f5de357f 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -121,7 +121,7 @@ enum { BEV_MODAL_MARK_SHARP_TOGGLE, BEV_MODAL_OUTER_MITER_CHANGE, BEV_MODAL_INNER_MITER_CHANGE, - BEV_MODAL_CUSTOM_PROFILE_TOGGLE, + BEV_MODAL_PROFILE_TYPE_CHANGE, BEV_MODAL_VERTEX_MESH_CHANGE, }; @@ -146,7 +146,7 @@ static void edbm_bevel_update_status_text(bContext *C, wmOperator *op) int available_len = sizeof(buf); Scene *sce = CTX_data_scene(C); char offset_str[NUM_STR_REP_LEN]; - const char *mode_str, *omiter_str, *imiter_str, *vmesh_str; + const char *mode_str, *omiter_str, *imiter_str, *vmesh_str, *profile_type_str; PropertyRNA *prop; #define WM_MODALKEY(_id) \ @@ -170,6 +170,9 @@ static void edbm_bevel_update_status_text(bContext *C, wmOperator *op) prop = RNA_struct_find_property(op->ptr, "offset_type"); RNA_property_enum_name_gettexted( C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &mode_str); + prop = RNA_struct_find_property(op->ptr, "profile_type"); + RNA_property_enum_name_gettexted( + C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &profile_type_str); prop = RNA_struct_find_property(op->ptr, "miter_outer"); RNA_property_enum_name_gettexted( C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &omiter_str); @@ -195,7 +198,7 @@ static void edbm_bevel_update_status_text(bContext *C, wmOperator *op) "%s: Harden Normals (%s), " "%s: Mark Seam (%s), " "%s: Mark Sharp (%s), " - "%s: Custom Profile (%s), " + "%s: Profile Type (%s), " "%s: Intersection (%s)"), WM_MODALKEY(BEV_MODAL_CONFIRM), WM_MODALKEY(BEV_MODAL_CANCEL), @@ -221,8 +224,8 @@ static void edbm_bevel_update_status_text(bContext *C, wmOperator *op) WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_seam")), WM_MODALKEY(BEV_MODAL_MARK_SHARP_TOGGLE), WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_sharp")), - WM_MODALKEY(BEV_MODAL_CUSTOM_PROFILE_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "use_custom_profile")), + WM_MODALKEY(BEV_MODAL_PROFILE_TYPE_CHANGE), + profile_type_str, WM_MODALKEY(BEV_MODAL_VERTEX_MESH_CHANGE), vmesh_str); @@ -327,6 +330,7 @@ static bool edbm_bevel_calc(wmOperator *op) const float offset = get_bevel_offset(op); const int offset_type = RNA_enum_get(op->ptr, "offset_type"); + const int profile_type = RNA_enum_get(op->ptr, "profile_type"); const int segments = RNA_int_get(op->ptr, "segments"); const float profile = RNA_float_get(op->ptr, "profile"); const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); @@ -340,7 +344,6 @@ static bool edbm_bevel_calc(wmOperator *op) const int miter_outer = RNA_enum_get(op->ptr, "miter_outer"); const int miter_inner = RNA_enum_get(op->ptr, "miter_inner"); const float spread = RNA_float_get(op->ptr, "spread"); - const bool use_custom_profile = RNA_boolean_get(op->ptr, "use_custom_profile"); const int vmesh_method = RNA_enum_get(op->ptr, "vmesh_method"); for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { @@ -364,16 +367,17 @@ static bool edbm_bevel_calc(wmOperator *op) EDBM_op_init(em, &bmop, op, - "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f " - "clamp_overlap=%b material=%i loop_slide=%b mark_seam=%b mark_sharp=%b " - "harden_normals=%b face_strength_mode=%i " - "miter_outer=%i miter_inner=%i spread=%f smoothresh=%f use_custom_profile=%b " - "custom_profile=%p vmesh_method=%i", + "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i " + "profile_type=%i profile=%f clamp_overlap=%b material=%i loop_slide=%b " + "mark_seam=%b mark_sharp=%b harden_normals=%b face_strength_mode=%i " + "miter_outer=%i miter_inner=%i spread=%f smoothresh=%f custom_profile=%p " + "vmesh_method=%i", BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, + profile_type, profile, clamp_overlap, material, @@ -386,7 +390,6 @@ static bool edbm_bevel_calc(wmOperator *op) miter_inner, spread, me->smoothresh, - use_custom_profile, opdata->custom_profile, vmesh_method); @@ -681,7 +684,7 @@ wmKeyMap *bevel_modal_keymap(wmKeyConfig *keyconf) 0, "Change inner miter", "Cycle through inner miter kinds"}, - {BEV_MODAL_CUSTOM_PROFILE_TOGGLE, "CUSTOM_PROFILE_TOGGLE", 0, "Toggle custom profile", ""}, + {BEV_MODAL_PROFILE_TYPE_CHANGE, "PROFILE_TYPE_CHANGE", 0, "Cycle through profile types", ""}, {BEV_MODAL_VERTEX_MESH_CHANGE, "VERTEX_MESH_CHANGE", 0, @@ -892,9 +895,13 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } - case BEV_MODAL_CUSTOM_PROFILE_TOGGLE: { - bool use_custom_profile = RNA_boolean_get(op->ptr, "use_custom_profile"); - RNA_boolean_set(op->ptr, "use_custom_profile", !use_custom_profile); + case BEV_MODAL_PROFILE_TYPE_CHANGE: { + int profile_type = RNA_enum_get(op->ptr, "profile_type"); + profile_type++; + if (profile_type > BEVEL_PROFILE_CUSTOM) { + profile_type = BEVEL_PROFILE_SUPERELLIPSE; + } + RNA_enum_set(op->ptr, "profile_type", profile_type); edbm_bevel_calc(op); edbm_bevel_update_status_text(C, op); handled = true; @@ -938,21 +945,12 @@ static void edbm_bevel_ui(bContext *C, wmOperator *op) RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + int profile_type = RNA_enum_get(&ptr, "profile_type"); + if (RNA_enum_get(&ptr, "offset_type") == BEVEL_AMT_PERCENT) { uiItemR(layout, &ptr, "offset_pct", 0, NULL, ICON_NONE); } else { - switch (RNA_enum_get(&ptr, "offset_type")) { - case BEVEL_AMT_DEPTH: - offset_name = "Depth"; - break; - case BEVEL_AMT_WIDTH: - offset_name = "Width"; - break; - case BEVEL_AMT_OFFSET: - offset_name = "Offset"; - break; - } prop = RNA_struct_find_property(op->ptr, "offset_type"); RNA_property_enum_name_gettexted( C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &offset_name); @@ -972,7 +970,14 @@ static void edbm_bevel_ui(bContext *C, wmOperator *op) uiItemR(col, &ptr, "harden_normals", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "segments", 0, NULL, ICON_NONE); - uiItemR(layout, &ptr, "profile", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + if (ELEM(profile_type, BEVEL_PROFILE_SUPERELLIPSE, BEVEL_PROFILE_CUSTOM)) { + uiItemR(layout, + &ptr, + "profile", + UI_ITEM_R_SLIDER, + (profile_type == BEVEL_PROFILE_SUPERELLIPSE) ? IFACE_("Shape") : IFACE_("Miter Shape"), + ICON_NONE); + } uiItemR(layout, &ptr, "material", 0, NULL, ICON_NONE); uiItemL(layout, "Miter Type:", ICON_NONE); @@ -990,9 +995,11 @@ static void edbm_bevel_ui(bContext *C, wmOperator *op) row = uiLayoutRow(layout, true); uiItemR(row, &ptr, "vmesh_method", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(layout, &ptr, "use_custom_profile", 0, NULL, ICON_NONE); - if (RNA_boolean_get(&ptr, "use_custom_profile")) { - /* Get an RNA pointer to ToolSettings to give to the curve profile template code */ + uiItemL(layout, "Profile Type:", ICON_NONE); + row = uiLayoutRow(layout, true); + uiItemR(row, &ptr, "profile_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + if (profile_type == BEVEL_PROFILE_CUSTOM) { + /* Get an RNA pointer to ToolSettings to give to the curve profile template code. */ Scene *scene = CTX_data_scene(C); RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr); uiTemplateCurveProfile(layout, &toolsettings_ptr, "custom_bevel_profile_preset"); @@ -1012,6 +1019,25 @@ void MESH_OT_bevel(wmOperatorType *ot) "Depth", "Amount is perpendicular distance from original edge to bevel face"}, {BEVEL_AMT_PERCENT, "PERCENT", 0, "Percent", "Amount is percent of adjacent edge length"}, + {BEVEL_AMT_ABSOLUTE, + "ABSOLUTE", + 0, + "Absolute", + "Amount is absolute distance along adjacent edge"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem prop_profile_type_items[] = { + {BEVEL_PROFILE_SUPERELLIPSE, + "SUPERELLIPSE", + 0, + "Superellipse", + "The profile can be a concave or convex curve"}, + {BEVEL_PROFILE_CUSTOM, + "CUSTOM", + 0, + "Custom", + "The profile can be any arbitrary path between its endpoints"}, {0, NULL, 0, NULL, NULL}, }; @@ -1068,13 +1094,24 @@ void MESH_OT_bevel(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR_XY | OPTYPE_BLOCKING; /* properties */ - RNA_def_enum( - ot->srna, "offset_type", offset_type_items, 0, "Width Type", "What distance Width measures"); + RNA_def_enum(ot->srna, + "offset_type", + offset_type_items, + 0, + "Width Type", + "The method for determining the size of the bevel"); prop = RNA_def_property(ot->srna, "offset", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_range(prop, 0.0, 1e6); RNA_def_property_ui_range(prop, 0.0, 100.0, 1, 3); RNA_def_property_ui_text(prop, "Width", "Bevel amount"); + RNA_def_enum(ot->srna, + "profile_type", + prop_profile_type_items, + 0, + "Profile Type", + "The type of shape used to rebuild a beveled section"); + prop = RNA_def_property(ot->srna, "offset_pct", PROP_FLOAT, PROP_PERCENTAGE); RNA_def_property_range(prop, 0.0, 100); RNA_def_property_ui_text(prop, "Width Percent", "Bevel amount for percentage method"); @@ -1161,12 +1198,6 @@ void MESH_OT_bevel(wmOperatorType *ot) 0.0f, 100.0f); - RNA_def_boolean(ot->srna, - "use_custom_profile", - false, - "Custom Profile", - "Use a custom profile for the bevel"); - RNA_def_enum(ot->srna, "vmesh_method", vmesh_method_items, diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 5f5599b53df..369c7735d20 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1895,12 +1895,12 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, if (!f) { if (kcd->is_interactive) { - /* try to use backbuffer selection method if ray casting failed */ + /* Try to use back-buffer selection method if ray casting failed. */ f = EDBM_face_find_nearest(&kcd->vc, &dist); /* cheat for now; just put in the origin instead * of a true coordinate on the face. - * This just puts a point 1.0f infront of the view. */ + * This just puts a point 1.0f in front of the view. */ add_v3_v3v3(co, origin, ray); } } @@ -1908,8 +1908,10 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, return f; } -/* find the 2d screen space density of vertices within a radius. used to scale snapping - * distance for picking edges/verts.*/ +/** + * Find the 2d screen space density of vertices within a radius. + * Used to scale snapping distance for picking edges/verts. + */ static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius) { BMFace *f; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index a0a3d24e49a..2cffb3ecdec 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -4161,7 +4161,7 @@ static Base *mesh_separate_tagged( CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE); /* Take into account user preferences for duplicating actions. */ - short dupflag = USER_DUP_MESH | (U.dupflag & USER_DUP_ACT); + const eDupli_ID_Flags dupflag = USER_DUP_MESH | (U.dupflag & USER_DUP_ACT); base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, dupflag); /* normally would call directly after but in this case delay recalc */ @@ -4233,7 +4233,7 @@ static Base *mesh_separate_arrays(Main *bmain, CustomData_bmesh_init_pool(&bm_new->pdata, faces_len, BM_FACE); /* Take into account user preferences for duplicating actions. */ - short dupflag = USER_DUP_MESH | (U.dupflag & USER_DUP_ACT); + const eDupli_ID_Flags dupflag = USER_DUP_MESH | (U.dupflag & USER_DUP_ACT); base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, dupflag); /* normally would call directly after but in this case delay recalc */ @@ -7240,8 +7240,11 @@ void MESH_OT_wireframe(wmOperatorType *ot) /* use 1 rather then 10 for max else dragging the button moves too far */ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4); RNA_def_float_distance(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f); - RNA_def_boolean( - ot->srna, "use_crease", false, "Crease", "Crease hub edges for an improved subdivision surface"); + RNA_def_boolean(ot->srna, + "use_crease", + false, + "Crease", + "Crease hub edges for an improved subdivision surface"); prop = RNA_def_float( ot->srna, "crease_weight", 0.01f, 0.0f, 1e3f, "Crease weight", "", 0.0f, 1.0f); RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2); diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 51b699acd63..8fce726eff5 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -121,8 +121,15 @@ static void delete_customdata_layer(Mesh *me, CustomDataLayer *layer) CustomData *data; int layer_index, tot, n; - data = mesh_customdata_get_type( - me, (ELEM(type, CD_MLOOPUV, CD_MLOOPCOL)) ? BM_LOOP : BM_FACE, &tot); + char htype = BM_FACE; + if (ELEM(type, CD_MLOOPCOL, CD_MLOOPUV)) { + htype = BM_LOOP; + } + else if (ELEM(type, CD_PROP_COLOR)) { + htype = BM_VERT; + } + + data = mesh_customdata_get_type(me, htype, &tot); layer_index = CustomData_get_layer_index(data, type); n = (layer - &data->layers[layer_index]); BLI_assert(n >= 0 && (n + layer_index) < data->totlayer); @@ -488,6 +495,117 @@ bool ED_mesh_color_remove_named(Mesh *me, const char *name) } } +/*********************** Sculpt Vertex colors operators ************************/ + +/* note: keep in sync with ED_mesh_uv_texture_add */ +int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool active_set, const bool do_init) +{ + BMEditMesh *em; + int layernum; + + if (me->edit_mesh) { + em = me->edit_mesh; + + layernum = CustomData_number_of_layers(&em->bm->vdata, CD_PROP_COLOR); + if (layernum >= MAX_MCOL) { + return -1; + } + + /* CD_PROP_COLOR */ + BM_data_layer_add_named(em->bm, &em->bm->vdata, CD_PROP_COLOR, name); + /* copy data from active vertex color layer */ + if (layernum && do_init) { + const int layernum_dst = CustomData_get_active_layer(&em->bm->vdata, CD_PROP_COLOR); + BM_data_layer_copy(em->bm, &em->bm->vdata, CD_PROP_COLOR, layernum_dst, layernum); + } + if (active_set || layernum == 0) { + CustomData_set_layer_active(&em->bm->vdata, CD_PROP_COLOR, layernum); + } + } + else { + layernum = CustomData_number_of_layers(&me->vdata, CD_PROP_COLOR); + if (layernum >= MAX_MCOL) { + return -1; + } + + if (CustomData_has_layer(&me->vdata, CD_PROP_COLOR) && do_init) { + MPropCol *color_data = CustomData_get_layer(&me->vdata, CD_PROP_COLOR); + CustomData_add_layer_named( + &me->vdata, CD_PROP_COLOR, CD_DUPLICATE, color_data, me->totvert, name); + } + else { + CustomData_add_layer_named(&me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, me->totvert, name); + } + + if (active_set || layernum == 0) { + CustomData_set_layer_active(&me->vdata, CD_PROP_COLOR, layernum); + } + + BKE_mesh_update_customdata_pointers(me, true); + } + + DEG_id_tag_update(&me->id, 0); + WM_main_add_notifier(NC_GEOM | ND_DATA, me); + + return layernum; +} + +bool ED_mesh_sculpt_color_ensure(struct Mesh *me, const char *name) +{ + BLI_assert(me->edit_mesh == NULL); + + if (me->totvert && !CustomData_has_layer(&me->vdata, CD_PROP_COLOR)) { + CustomData_add_layer_named(&me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, me->totvert, name); + BKE_mesh_update_customdata_pointers(me, true); + } + + DEG_id_tag_update(&me->id, 0); + + return (me->mloopcol != NULL); +} + +bool ED_mesh_sculpt_color_remove_index(Mesh *me, const int n) +{ + CustomData *vdata = GET_CD_DATA(me, vdata); + CustomDataLayer *cdl; + int index; + + index = CustomData_get_layer_index_n(vdata, CD_PROP_COLOR, n); + cdl = (index == -1) ? NULL : &vdata->layers[index]; + + if (!cdl) { + return false; + } + + delete_customdata_layer(me, cdl); + DEG_id_tag_update(&me->id, 0); + WM_main_add_notifier(NC_GEOM | ND_DATA, me); + + return true; +} +bool ED_mesh_sculpt_color_remove_active(Mesh *me) +{ + CustomData *vdata = GET_CD_DATA(me, vdata); + const int n = CustomData_get_active_layer(vdata, CD_PROP_COLOR); + if (n != -1) { + return ED_mesh_sculpt_color_remove_index(me, n); + } + else { + return false; + } +} +bool ED_mesh_sculpt_color_remove_named(Mesh *me, const char *name) +{ + CustomData *vdata = GET_CD_DATA(me, vdata); + const int n = CustomData_get_named_layer(vdata, CD_PROP_COLOR, name); + if (n != -1) { + return ED_mesh_sculpt_color_remove_index(me, n); + } + else { + return false; + } +} + /*********************** UV texture operators ************************/ static bool layers_poll(bContext *C) @@ -619,6 +737,62 @@ void MESH_OT_vertex_color_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/*********************** Sculpt Vertex Color Operators ************************/ + +static int mesh_sculpt_vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = ED_object_context(C); + Mesh *me = ob->data; + + if (ED_mesh_sculpt_color_add(me, NULL, true, true) == -1) { + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + +void MESH_OT_sculpt_vertex_color_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Sculpt Vertex Color"; + ot->description = "Add vertex color layer"; + ot->idname = "MESH_OT_sculpt_vertex_color_add"; + + /* api callbacks */ + ot->poll = layers_poll; + ot->exec = mesh_sculpt_vertex_color_add_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int mesh_sculpt_vertex_color_remove_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = ED_object_context(C); + Mesh *me = ob->data; + + if (!ED_mesh_sculpt_color_remove_active(me)) { + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + +void MESH_OT_sculpt_vertex_color_remove(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Sculpt Vertex Color"; + ot->description = "Remove vertex color layer"; + ot->idname = "MESH_OT_sculpt_vertex_color_remove"; + + /* api callbacks */ + ot->exec = mesh_sculpt_vertex_color_remove_exec; + ot->poll = layers_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* *** CustomData clear functions, we need an operator for each *** */ static int mesh_customdata_clear_exec__internal(bContext *C, char htype, int type) diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 5e70069456b..bebad312454 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -267,6 +267,8 @@ void MESH_OT_uv_texture_add(struct wmOperatorType *ot); void MESH_OT_uv_texture_remove(struct wmOperatorType *ot); void MESH_OT_vertex_color_add(struct wmOperatorType *ot); void MESH_OT_vertex_color_remove(struct wmOperatorType *ot); +void MESH_OT_sculpt_vertex_color_add(struct wmOperatorType *ot); +void MESH_OT_sculpt_vertex_color_remove(struct wmOperatorType *ot); /* no create_mask yet */ void MESH_OT_customdata_mask_clear(struct wmOperatorType *ot); void MESH_OT_customdata_skin_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index c52a5956ac4..ad1e91a57c0 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -155,6 +155,8 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_uv_texture_remove); WM_operatortype_append(MESH_OT_vertex_color_add); WM_operatortype_append(MESH_OT_vertex_color_remove); + WM_operatortype_append(MESH_OT_sculpt_vertex_color_add); + WM_operatortype_append(MESH_OT_sculpt_vertex_color_remove); WM_operatortype_append(MESH_OT_customdata_mask_clear); WM_operatortype_append(MESH_OT_customdata_skin_add); WM_operatortype_append(MESH_OT_customdata_skin_clear); @@ -278,8 +280,8 @@ void ED_operatormacros_mesh(void) RNA_boolean_set(otmacro->ptr, "mirror", false); ot = WM_operatortype_append_macro( - "MESH_OT_extrude_region_dissolve_move_intersect", - "Extrude, Dissolve, Move and Intersect", + "MESH_OT_extrude_manifold", + "Extrude Manifold", "Extrude, dissolves edges whose faces form a flat surface and intersect new edges", OPTYPE_UNDO | OPTYPE_REGISTER); otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 917bbe61e3d..1bdf2ede22a 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -297,7 +297,7 @@ static void join_mesh_single(Depsgraph *depsgraph, *mpoly_pp += me->totpoly; } -int join_mesh_exec(bContext *C, wmOperator *op) +int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -706,12 +706,14 @@ int join_mesh_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/*********************** JOIN AS SHAPES ***************************/ +/* -------------------------------------------------------------------- */ +/** \name Join as Shapes + * \{ */ /* Append selected meshes vertex locations as shapes of the active mesh, * return 0 if no join is made (error) and 1 of the join is done */ -int join_mesh_shapes_exec(bContext *C, wmOperator *op) +int ED_mesh_shapes_join_objects_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -796,6 +798,8 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Mesh Topology Mirror API * \{ */ diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index a25175510cd..094011ebef1 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -58,6 +58,10 @@ #include "mball_intern.h" +/* -------------------------------------------------------------------- */ +/** \name Edit Mode Functions + * \{ */ + /* This function is used to free all MetaElems from MetaBall */ void ED_mball_editmball_free(Object *obedit) { @@ -93,9 +97,36 @@ void ED_mball_editmball_load(Object *UNUSED(obedit)) { } -/* Add metaelem primitive to metaball object (which is in edit mode) */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Selection + * \{ */ + +bool ED_mball_deselect_all_multi(bContext *C) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ViewContext vc; + ED_view3d_viewcontext_init(C, &vc, depsgraph); + uint bases_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( + vc.view_layer, vc.v3d, &bases_len); + bool changed_multi = BKE_mball_deselect_all_multi_ex(bases, bases_len); + MEM_freeN(bases); + return changed_multi; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Meta Primitive Utility + * \{ */ + +/** + * Add meta-element primitive to meta-ball object (which is in edit mode). + */ MetaElem *ED_mball_add_primitive( - bContext *UNUSED(C), Object *obedit, float mat[4][4], float dia, int type) + bContext *UNUSED(C), Object *obedit, bool obedit_is_new, float mat[4][4], float dia, int type) { MetaBall *mball = (MetaBall *)obedit->data; MetaElem *ml; @@ -109,16 +140,28 @@ MetaElem *ED_mball_add_primitive( ml = BKE_mball_element_add(mball, type); ml->rad *= dia; - mball->wiresize *= dia; - mball->rendersize *= dia; + + if (obedit_is_new) { + mball->wiresize *= dia; + mball->rendersize *= dia; + } copy_v3_v3(&ml->x, mat[3]); + /* MB_ELIPSOID works differently (intentional?). Whatever the case, + * on testing this needs to be skipped otherwise it doesn't behave like other types. */ + if (type != MB_ELIPSOID) { + mul_v3_fl(&ml->expx, dia); + } ml->flag |= SELECT; mball->lastelem = ml; return ml; } -/***************************** Select/Deselect operator *****************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select/Deselect Operator + * \{ */ /* Select or deselect all MetaElements */ static int mball_select_all_exec(bContext *C, wmOperator *op) @@ -175,8 +218,11 @@ void MBALL_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } +/** \} */ + /* -------------------------------------------------------------------- */ -/* Select Similar */ +/** \name Select Similar Operator + * \{ */ enum { SIMMBALL_TYPE = 1, @@ -428,9 +474,12 @@ void MBALL_OT_select_similar(wmOperatorType *ot) RNA_def_float(ot->srna, "threshold", 0.1, 0.0, FLT_MAX, "Threshold", "", 0.01, 1.0); } -/***************************** Select random operator *****************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Random Operator + * \{ */ -/* Random metaball selection */ static int select_random_metaelems_exec(bContext *C, wmOperator *op) { const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); @@ -494,7 +543,11 @@ void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot) WM_operator_properties_select_random(ot); } -/***************************** Duplicate operator *****************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Duplicate Meta-Ball Operator + * \{ */ /* Duplicate selected MetaElements */ static int duplicate_metaelems_exec(bContext *C, wmOperator *UNUSED(op)) @@ -546,9 +599,14 @@ void MBALL_OT_duplicate_metaelems(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/***************************** Delete operator *****************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Meta-Ball Operator + * + * Delete all selected MetaElems (not MetaBall). + * \{ */ -/* Delete all selected MetaElems (not MetaBall) */ static int delete_metaelems_exec(bContext *C, wmOperator *UNUSED(op)) { ViewLayer *view_layer = CTX_data_view_layer(C); @@ -601,9 +659,12 @@ void MBALL_OT_delete_metaelems(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/***************************** Hide operator *****************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hide Meta-Elements Operator + * \{ */ -/* Hide selected MetaElems */ static int hide_metaelems_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -646,9 +707,12 @@ void MBALL_OT_hide_metaelems(wmOperatorType *ot) ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected"); } -/***************************** Unhide operator *****************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Un-Hide Meta-Elements Operator + * \{ */ -/* Unhide all edited MetaElems */ static int reveal_metaelems_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -689,6 +753,12 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot) RNA_def_boolean(ot->srna, "select", true, "Select", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Pick Utility + * \{ */ + /* Select MetaElement with mouse click (user can select radius circle or * stiffness circle) */ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) @@ -740,7 +810,7 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese continue; } - if (metaelem_id != (hitresult & 0xFFFF0000 & ~(MBALLSEL_ANY))) { + if (metaelem_id != (hitresult & 0xFFFF0000 & ~MBALLSEL_ANY)) { continue; } @@ -831,15 +901,4 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese return false; } -bool ED_mball_deselect_all_multi(bContext *C) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ViewContext vc; - ED_view3d_viewcontext_init(C, &vc, depsgraph); - uint bases_len = 0; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( - vc.view_layer, vc.v3d, &bases_len); - bool changed_multi = BKE_mball_deselect_all_multi_ex(bases, bases_len); - MEM_freeN(bases); - return changed_multi; -} +/** \} */ diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index fb273cf49a8..953ef8114f9 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -91,8 +91,4 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() -if(WITH_NEW_OBJECT_TYPES) - add_definitions(-DWITH_NEW_OBJECT_TYPES) -endif() - blender_add_lib(bf_editor_object "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 8289f52b0c8..8073d87080f 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -65,6 +65,7 @@ #include "BKE_effect.h" #include "BKE_font.h" #include "BKE_gpencil_curve.h" +#include "BKE_gpencil_geom.h" #include "BKE_hair.h" #include "BKE_key.h" #include "BKE_lattice.h" @@ -96,6 +97,8 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "UI_interface.h" + #include "WM_api.h" #include "WM_types.h" @@ -857,7 +860,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) * we want to pass in 1 so other values such as resolution are scaled by 1.0. */ dia = RNA_float_get(op->ptr, "radius") / 2; - ED_mball_add_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type")); + ED_mball_add_primitive(C, obedit, newob, mat, dia, RNA_enum_get(op->ptr, "type")); /* userdef */ if (newob && !enter_editmode) { @@ -1508,6 +1511,14 @@ void OBJECT_OT_speaker_add(wmOperatorType *ot) /** \name Add Hair Operator * \{ */ +static bool object_hair_add_poll(bContext *C) +{ + if (!U.experimental.use_new_hair_type) { + return false; + } + return ED_operator_objectmode(C); +} + static int object_hair_add_exec(bContext *C, wmOperator *op) { ushort local_view_bits; @@ -1531,7 +1542,7 @@ void OBJECT_OT_hair_add(wmOperatorType *ot) /* api callbacks */ ot->exec = object_hair_add_exec; - ot->poll = ED_operator_objectmode; + ot->poll = object_hair_add_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1545,6 +1556,14 @@ void OBJECT_OT_hair_add(wmOperatorType *ot) /** \name Add Point Cloud Operator * \{ */ +static bool object_pointcloud_add_poll(bContext *C) +{ + if (!U.experimental.use_new_particle_system) { + return false; + } + return ED_operator_objectmode(C); +} + static int object_pointcloud_add_exec(bContext *C, wmOperator *op) { ushort local_view_bits; @@ -1568,7 +1587,7 @@ void OBJECT_OT_pointcloud_add(wmOperatorType *ot) /* api callbacks */ ot->exec = object_pointcloud_add_exec; - ot->poll = ED_operator_objectmode; + ot->poll = object_pointcloud_add_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2129,11 +2148,11 @@ void OBJECT_OT_duplicates_make_real(wmOperatorType *ot) static const EnumPropertyItem convert_target_items[] = { {OB_CURVE, "CURVE", ICON_OUTLINER_OB_CURVE, "Curve from Mesh/Text", ""}, {OB_MESH, "MESH", ICON_OUTLINER_OB_MESH, "Mesh from Curve/Meta/Surf/Text", ""}, - {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil from Curve", ""}, + {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil from Curve/Mesh", ""}, {0, NULL, 0, NULL, NULL}, }; -static void convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob) +static void object_data_convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob) { if (ob->runtime.curve_cache == NULL) { /* Force creation. This is normally not needed but on operator @@ -2152,7 +2171,7 @@ static void convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Objec } } -static void curvetomesh(Main *bmain, Depsgraph *depsgraph, Object *ob) +static void object_data_convert_curve_to_mesh(Main *bmain, Depsgraph *depsgraph, Object *ob) { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); Curve *curve = ob->data; @@ -2185,17 +2204,22 @@ static void curvetomesh(Main *bmain, Depsgraph *depsgraph, Object *ob) } } -static bool convert_poll(bContext *C) +static bool object_convert_poll(bContext *C) { Scene *scene = CTX_data_scene(C); Base *base_act = CTX_data_active_base(C); Object *obact = base_act ? base_act->object : NULL; - return (!ID_IS_LINKED(scene) && obact && (BKE_object_is_in_editmode(obact) == false) && - (base_act->flag & BASE_SELECTED) && !ID_IS_LINKED(obact)); + if (obact == NULL || obact->data == NULL || ID_IS_LINKED(obact) || + ID_IS_OVERRIDE_LIBRARY(obact) || ID_IS_OVERRIDE_LIBRARY(obact->data)) { + return false; + } + + return (!ID_IS_LINKED(scene) && (BKE_object_is_in_editmode(obact) == false) && + (base_act->flag & BASE_SELECTED)); } -/* Helper for convert_exec */ +/* Helper for object_convert_exec */ static Base *duplibase_for_convert( Main *bmain, Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, Base *base, Object *ob) { @@ -2230,7 +2254,7 @@ static Base *duplibase_for_convert( * time we need to duplicate an object to convert it. Even worse, this is not 100% correct, since * we do not yet have duplicated obdata. * However, that is a safe solution for now. Proper, longer-term solution is to refactor - * convert_exec to: + * object_convert_exec to: * - duplicate all data it needs to in a first loop. * - do a single update. * - convert data in a second loop. */ @@ -2248,7 +2272,7 @@ static Base *duplibase_for_convert( return basen; } -static int convert_exec(bContext *C, wmOperator *op) +static int object_convert_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); @@ -2261,9 +2285,16 @@ static int convert_exec(bContext *C, wmOperator *op) Nurb *nu; MetaBall *mb; Mesh *me; - Object *gpencil_ob = NULL; + Object *ob_gpencil = NULL; const short target = RNA_enum_get(op->ptr, "target"); bool keep_original = RNA_boolean_get(op->ptr, "keep_original"); + + const float angle = RNA_float_get(op->ptr, "angle"); + const int thickness = RNA_int_get(op->ptr, "thickness"); + const bool use_seams = RNA_boolean_get(op->ptr, "seams"); + const bool use_faces = RNA_boolean_get(op->ptr, "faces"); + const float offset = RNA_float_get(op->ptr, "offset"); + int a, mballConverted = 0; bool gpencilConverted = false; @@ -2375,6 +2406,54 @@ static int convert_exec(bContext *C, wmOperator *op) ED_rigidbody_object_remove(bmain, scene, newob); } } + else if (ob->type == OB_MESH && target == OB_GPENCIL) { + ob->flag |= OB_DONE; + + /* Create a new grease pencil object and copy transformations. */ + ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; + float loc[3], size[3], rot[3][3], eul[3]; + float matrix[4][4]; + mat4_to_loc_rot_size(loc, rot, size, ob->obmat); + mat3_to_eul(eul, rot); + + ob_gpencil = ED_gpencil_add_object(C, loc, local_view_bits); + copy_v3_v3(ob_gpencil->loc, loc); + copy_v3_v3(ob_gpencil->rot, eul); + copy_v3_v3(ob_gpencil->scale, size); + unit_m4(matrix); + /* Set object in 3D mode. */ + bGPdata *gpd = (bGPdata *)ob_gpencil->data; + gpd->draw_mode = GP_DRAWMODE_3D; + + BKE_gpencil_convert_mesh(bmain, + depsgraph, + scene, + ob_gpencil, + ob, + angle, + thickness, + offset, + matrix, + 0, + use_seams, + use_faces); + gpencilConverted = true; + + /* Remove unused materials. */ + int actcol = ob_gpencil->actcol; + for (int slot = 1; slot <= ob_gpencil->totcol; slot++) { + while (slot <= ob_gpencil->totcol && + !BKE_object_material_slot_used(ob_gpencil->data, slot)) { + ob_gpencil->actcol = slot; + BKE_object_material_slot_remove(CTX_data_main(C), ob_gpencil); + + if (actcol >= slot) { + actcol--; + } + } + } + ob_gpencil->actcol = actcol; + } else if (ob->type == OB_MESH) { ob->flag |= OB_DONE; @@ -2470,7 +2549,7 @@ static int convert_exec(bContext *C, wmOperator *op) if (target == OB_MESH) { /* No assumption should be made that the resulting objects is a mesh, as conversion can * fail. */ - curvetomesh(bmain, depsgraph, newob); + object_data_convert_curve_to_mesh(bmain, depsgraph, newob); /* meshes doesn't use displist */ BKE_object_free_curve_cache(newob); } @@ -2495,7 +2574,7 @@ static int convert_exec(bContext *C, wmOperator *op) /* No assumption should be made that the resulting objects is a mesh, as conversion can * fail. */ - curvetomesh(bmain, depsgraph, newob); + object_data_convert_curve_to_mesh(bmain, depsgraph, newob); /* meshes doesn't use displist */ BKE_object_free_curve_cache(newob); } @@ -2509,10 +2588,10 @@ static int convert_exec(bContext *C, wmOperator *op) * Nurbs Surface are not supported. */ ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; - gpencil_ob = ED_gpencil_add_object(C, ob->loc, local_view_bits); - copy_v3_v3(gpencil_ob->rot, ob->rot); - copy_v3_v3(gpencil_ob->scale, ob->scale); - BKE_gpencil_convert_curve(bmain, scene, gpencil_ob, ob, false, false, true); + ob_gpencil = ED_gpencil_add_object(C, ob->loc, local_view_bits); + copy_v3_v3(ob_gpencil->rot, ob->rot); + copy_v3_v3(ob_gpencil->scale, ob->scale); + BKE_gpencil_convert_curve(bmain, scene, ob_gpencil, ob, false, false, true); gpencilConverted = true; } } @@ -2549,7 +2628,7 @@ static int convert_exec(bContext *C, wmOperator *op) } } - convert_ensure_curve_cache(depsgraph, scene, baseob); + object_data_convert_ensure_curve_cache(depsgraph, scene, baseob); BKE_mesh_from_metaball(&baseob->runtime.curve_cache->disp, newob->data); if (obact->type == OB_MBALL) { @@ -2618,12 +2697,12 @@ static int convert_exec(bContext *C, wmOperator *op) } FOREACH_SCENE_OBJECT_END; } - /* Remove curves converted to Grease Pencil object. */ + /* Remove curves and meshes converted to Grease Pencil object. */ if (gpencilConverted) { - FOREACH_SCENE_OBJECT_BEGIN (scene, ob_curve) { - if (ob_curve->type == OB_CURVE) { - if (ob_curve->flag & OB_DONE) { - ED_object_base_free_and_unlink(bmain, scene, ob_curve); + FOREACH_SCENE_OBJECT_BEGIN (scene, ob_delete) { + if ((ob_delete->type == OB_CURVE) || (ob_delete->type == OB_MESH)) { + if (ob_delete->flag & OB_DONE) { + ED_object_base_free_and_unlink(bmain, scene, ob_delete); } } } @@ -2652,8 +2731,28 @@ static int convert_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static void object_convert_ui(bContext *UNUSED(C), wmOperator *op) +{ + uiLayout *layout = op->layout; + PointerRNA ptr; + + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + uiItemR(layout, &ptr, "target", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "keep_original", 0, NULL, ICON_NONE); + + if (RNA_enum_get(&ptr, "target") == OB_GPENCIL) { + uiItemR(layout, &ptr, "thickness", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "angle", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "offset", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "seams", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "faces", 0, NULL, ICON_NONE); + } +} + void OBJECT_OT_convert(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Convert to"; ot->description = "Convert selected objects to another type"; @@ -2661,8 +2760,9 @@ void OBJECT_OT_convert(wmOperatorType *ot) /* api callbacks */ ot->invoke = WM_menu_invoke; - ot->exec = convert_exec; - ot->poll = convert_poll; + ot->exec = object_convert_exec; + ot->poll = object_convert_poll; + ot->ui = object_convert_ui; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2675,6 +2775,31 @@ void OBJECT_OT_convert(wmOperatorType *ot) 0, "Keep Original", "Keep original objects instead of replacing them"); + + prop = RNA_def_float_rotation(ot->srna, + "angle", + 0, + NULL, + DEG2RADF(0.0f), + DEG2RADF(180.0f), + "Threshold Angle", + "Threshold to determine ends of the strokes", + DEG2RADF(0.0f), + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(70.0f)); + + RNA_def_int(ot->srna, "thickness", 5, 1, 100, "Thickness", "", 1, 100); + RNA_def_boolean(ot->srna, "seams", 0, "Only Seam Edges", "Convert only seam edges"); + RNA_def_boolean(ot->srna, "faces", 1, "Export Faces", "Export faces as filled strokes"); + RNA_def_float_distance(ot->srna, + "offset", + 0.01f, + 0.0, + OBJECT_ADD_SIZE_MAXF, + "Stroke Offset", + "Offset strokes from fill", + 0.0, + 100.00); } /** \} */ @@ -2693,8 +2818,12 @@ void OBJECT_OT_convert(wmOperatorType *ot) /* used below, assumes id.new is correct */ /* leaves selection of base/object unaltered */ /* Does set ID->newid pointers. */ -static Base *object_add_duplicate_internal( - Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob, int dupflag) +static Base *object_add_duplicate_internal(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + Object *ob, + const eDupli_ID_Flags dupflag, + const eLibIDDuplicateFlags duplicate_options) { Base *base, *basen = NULL; Object *obn; @@ -2703,7 +2832,7 @@ static Base *object_add_duplicate_internal( /* nothing? */ } else { - obn = ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag)); + obn = ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options)); DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); base = BKE_view_layer_base_find(view_layer, ob); @@ -2742,12 +2871,13 @@ static Base *object_add_duplicate_internal( * note: caller must do DAG_relations_tag_update(bmain); * this is not done automatic since we may duplicate many objects in a batch */ Base *ED_object_add_duplicate( - Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, int dupflag) + Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, const eDupli_ID_Flags dupflag) { Base *basen; Object *ob; - basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag); + basen = object_add_duplicate_internal( + bmain, scene, view_layer, base->object, dupflag, LIB_ID_DUPLICATE_IS_SUBPROCESS); if (basen == NULL) { return NULL; } @@ -2775,10 +2905,11 @@ static int duplicate_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); const bool linked = RNA_boolean_get(op->ptr, "linked"); - int dupflag = (linked) ? 0 : U.dupflag; + const eDupli_ID_Flags dupflag = (linked) ? 0 : (eDupli_ID_Flags)U.dupflag; CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - Base *basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag); + Base *basen = object_add_duplicate_internal( + bmain, scene, view_layer, base->object, dupflag, 0); /* note that this is safe to do with this context iterator, * the list is made in advance */ @@ -2849,7 +2980,7 @@ void OBJECT_OT_duplicate(wmOperatorType *ot) * Use for drag & drop. * \{ */ -static int add_named_exec(bContext *C, wmOperator *op) +static int object_add_named_exec(bContext *C, wmOperator *op) { wmWindow *win = CTX_wm_window(C); const wmEvent *event = win ? win->eventstate : NULL; @@ -2859,7 +2990,7 @@ static int add_named_exec(bContext *C, wmOperator *op) Base *basen; Object *ob; const bool linked = RNA_boolean_get(op->ptr, "linked"); - int dupflag = (linked) ? 0 : U.dupflag; + const eDupli_ID_Flags dupflag = (linked) ? 0 : (eDupli_ID_Flags)U.dupflag; char name[MAX_ID_NAME - 2]; /* find object, create fake base */ @@ -2872,7 +3003,7 @@ static int add_named_exec(bContext *C, wmOperator *op) } /* prepare dupli */ - basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag); + basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag, 0); if (basen == NULL) { BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated"); @@ -2912,7 +3043,7 @@ void OBJECT_OT_add_named(wmOperatorType *ot) ot->idname = "OBJECT_OT_add_named"; /* api callbacks */ - ot->exec = add_named_exec; + ot->exec = object_add_named_exec; ot->poll = ED_operator_objectmode; /* flags */ @@ -2933,23 +3064,24 @@ void OBJECT_OT_add_named(wmOperatorType *ot) * * \{ */ -static bool join_poll(bContext *C) +static bool object_join_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if (!ob || ID_IS_LINKED(ob)) { - return 0; + if (ob == NULL || ob->data == NULL || ID_IS_LINKED(ob) || ID_IS_OVERRIDE_LIBRARY(ob) || + ID_IS_OVERRIDE_LIBRARY(ob->data)) { + return false; } if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE, OB_GPENCIL)) { return ED_operator_screenactive(C); } else { - return 0; + return false; } } -static int join_exec(bContext *C, wmOperator *op) +static int object_join_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); @@ -2970,13 +3102,13 @@ static int join_exec(bContext *C, wmOperator *op) } if (ob->type == OB_MESH) { - return join_mesh_exec(C, op); + return ED_mesh_join_objects_exec(C, op); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { - return join_curve_exec(C, op); + return ED_curve_join_objects_exec(C, op); } else if (ob->type == OB_ARMATURE) { - return join_armature_exec(C, op); + return ED_armature_join_objects_exec(C, op); } else if (ob->type == OB_GPENCIL) { return ED_gpencil_join_objects_exec(C, op); @@ -2993,8 +3125,8 @@ void OBJECT_OT_join(wmOperatorType *ot) ot->idname = "OBJECT_OT_join"; /* api callbacks */ - ot->exec = join_exec; - ot->poll = join_poll; + ot->exec = object_join_exec; + ot->poll = object_join_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3010,8 +3142,9 @@ static bool join_shapes_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if (!ob || ID_IS_LINKED(ob)) { - return 0; + if (ob == NULL || ob->data == NULL || ID_IS_LINKED(ob) || ID_IS_OVERRIDE_LIBRARY(ob) || + ID_IS_OVERRIDE_LIBRARY(ob->data)) { + return false; } /* only meshes supported at the moment */ @@ -3019,7 +3152,7 @@ static bool join_shapes_poll(bContext *C) return ED_operator_screenactive(C); } else { - return 0; + return false; } } @@ -3037,7 +3170,7 @@ static int join_shapes_exec(bContext *C, wmOperator *op) } if (ob->type == OB_MESH) { - return join_mesh_shapes_exec(C, op); + return ED_mesh_shapes_join_objects_exec(C, op); } return OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index a2d33ffe413..5746480e3f8 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1557,6 +1557,77 @@ void CONSTRAINT_OT_move_up(wmOperatorType *ot) /** \} */ /* ------------------------------------------------------------------- */ +/** \name Move Constraint To Index Operator + * \{ */ + +static int constraint_move_to_index_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, 0); + + int new_index = RNA_int_get(op->ptr, "index"); + if (new_index < 0) { + new_index = 0; + } + + if (con) { + ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL); + int current_index = BLI_findindex(conlist, con); + BLI_assert(current_index >= 0); + + BLI_listbase_link_move(conlist, con, new_index - current_index); + + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +static int constraint_move_to_index_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) +{ + if (edit_constraint_invoke_properties(C, op)) { + return constraint_move_to_index_exec(C, op); + } + else { + return OPERATOR_CANCELLED; + } +} + +void CONSTRAINT_OT_move_to_index(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Move Constraint To Index"; + ot->idname = "CONSTRAINT_OT_move_to_index"; + ot->description = + "Change the constraint's position in the list so it evaluates after the set number of " + "others"; + + /* callbacks */ + ot->exec = constraint_move_to_index_exec; + ot->invoke = constraint_move_to_index_invoke; + ot->poll = edit_constraint_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + edit_constraint_properties(ot); + RNA_def_int(ot->srna, + "index", + 0, + 0, + INT_MAX, + "Index", + "The index to move the constraint to", + 0, + INT_MAX); +} + +/** \} */ + +/* ------------------------------------------------------------------- */ /** \name Clear Pose Constraints Operator * \{ */ diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 274cd31406c..0df33255c34 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -381,7 +381,7 @@ static bool data_transfer_exec_is_object_valid(wmOperator *op, me->id.tag &= ~LIB_TAG_DOIT; return true; } - else if (!ID_IS_LINKED(me)) { + else if (!ID_IS_LINKED(me) && !ID_IS_OVERRIDE_LIBRARY(me)) { /* Do not apply transfer operation more than once. */ /* XXX This is not nice regarding vgroups, which are half-Object data... :/ */ BKE_reportf( @@ -446,8 +446,8 @@ static int data_transfer_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } - if (reverse_transfer && ID_IS_LINKED(ob_src->data)) { - /* Do not transfer to linked data, not supported. */ + if (reverse_transfer && (ID_IS_LINKED(ob_src->data) || ID_IS_OVERRIDE_LIBRARY(ob_src->data))) { + /* Do not transfer to linked or override data, not supported. */ return OPERATOR_CANCELLED; } @@ -530,7 +530,7 @@ static bool data_transfer_poll(bContext *C) { Object *ob = ED_object_active_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && ob->type == OB_MESH && data); + return (ob != NULL && ob->type == OB_MESH && data != NULL); } /* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ @@ -786,7 +786,7 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op) const bool use_delete = false; /* Never when used from modifier, for now. */ - if (!ob_src) { + if (!ob_src || ID_IS_LINKED(ob_dst) || ID_IS_OVERRIDE_LIBRARY(ob_dst)) { return OPERATOR_CANCELLED; } @@ -854,7 +854,7 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op) static int datalayout_transfer_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return datalayout_transfer_exec(C, op); } else { diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index d522dcabae3..283aaec85ef 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -600,7 +600,8 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag { bool ok = false; - if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob)) { + if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob) || ID_IS_OVERRIDE_LIBRARY(ob) || + ID_IS_OVERRIDE_LIBRARY(ob->data)) { return false; } @@ -695,14 +696,10 @@ bool ED_object_editmode_enter(bContext *C, int flag) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Object *ob; /* Active layer checked here for view3d, * callers that don't want view context can call the extended version. */ - ob = CTX_data_active_object(C); - if ((ob == NULL) || ID_IS_LINKED(ob)) { - return false; - } + Object *ob = CTX_data_active_object(C); return ED_object_editmode_enter_ex(bmain, scene, ob, flag); } @@ -760,7 +757,8 @@ static bool editmode_toggle_poll(bContext *C) Object *ob = CTX_data_active_object(C); /* covers proxies too */ - if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob->data)) { + if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob->data) || ID_IS_OVERRIDE_LIBRARY(ob) || + ID_IS_OVERRIDE_LIBRARY(ob->data)) { return 0; } @@ -1368,7 +1366,8 @@ static bool shade_poll(bContext *C) Object *obact = OBACT(view_layer); if (obact != NULL) { /* Doesn't handle edit-data, sculpt dynamic-topology, or their undo systems. */ - if (obact->mode & (OB_MODE_EDIT | OB_MODE_SCULPT)) { + if (obact->mode & (OB_MODE_EDIT | OB_MODE_SCULPT) || obact->data == NULL || + ID_IS_OVERRIDE_LIBRARY(obact) || ID_IS_OVERRIDE_LIBRARY(obact->data)) { return false; } } @@ -1771,15 +1770,6 @@ static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout const char *name = BKE_collection_ui_name_get(menu->collection); UI_block_flag_enable(uiLayoutGetBlock(layout), UI_BLOCK_IS_FLIP); - uiItemIntO(layout, name, ICON_NONE, menu->ot->idname, "collection_index", menu->index); - uiItemS(layout); - - for (MoveToCollectionData *submenu = menu->submenus.first; submenu != NULL; - submenu = submenu->next) { - move_to_collection_menus_items(layout, submenu); - } - - uiItemS(layout); WM_operator_properties_create_ptr(&menu->ptr, menu->ot); RNA_int_set(&menu->ptr, "collection_index", menu->index); @@ -1787,6 +1777,15 @@ static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout uiItemFullO_ptr( layout, menu->ot, "New Collection", ICON_ADD, menu->ptr.data, WM_OP_INVOKE_DEFAULT, 0, NULL); + + uiItemS(layout); + + uiItemIntO(layout, name, ICON_SCENE_DATA, menu->ot->idname, "collection_index", menu->index); + + for (MoveToCollectionData *submenu = menu->submenus.first; submenu != NULL; + submenu = submenu->next) { + move_to_collection_menus_items(layout, submenu); + } } static void move_to_collection_menus_items(uiLayout *layout, MoveToCollectionData *menu) diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c index 147bd3d7871..6e0376358bb 100644 --- a/source/blender/editors/object/object_facemap_ops.c +++ b/source/blender/editors/object/object_facemap_ops.c @@ -171,14 +171,15 @@ static bool face_map_supported_poll(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib); + return (ob && !ID_IS_LINKED(ob) && !ID_IS_OVERRIDE_LIBRARY(ob) && ob->type == OB_MESH && data && + !ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data)); } static bool face_map_supported_edit_mode_poll(bContext *C) { Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - if (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib) { + + if (face_map_supported_poll(C)) { if (ob->mode == OB_MODE_EDIT) { return true; } diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index 6d0f53cfa1e..cfdb6fea52d 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -24,6 +24,7 @@ #include <math.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "MEM_guardedalloc.h" @@ -54,6 +55,8 @@ #include "ED_object.h" #include "ED_screen.h" +#include "UI_interface.h" + #include "WM_api.h" #include "WM_types.h" @@ -105,23 +108,6 @@ GpencilModifierData *ED_object_gpencil_modifier_add( return new_md; } -/* Return true if the object has a modifier of type 'type' other than - * the modifier pointed to be 'exclude', otherwise returns false. */ -static bool UNUSED_FUNCTION(gpencil_object_has_modifier)(const Object *ob, - const GpencilModifierData *exclude, - GpencilModifierType type) -{ - GpencilModifierData *md; - - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { - if ((md != exclude) && (md->type == type)) { - return true; - } - } - - return false; -} - static bool gpencil_object_modifier_remove(Main *bmain, Object *ob, GpencilModifierData *md, @@ -211,6 +197,40 @@ int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports), return 1; } +bool ED_object_gpencil_modifier_move_to_index(ReportList *reports, + Object *ob, + GpencilModifierData *md, + const int index) +{ + BLI_assert(md != NULL); + BLI_assert(index >= 0); + if (index >= BLI_listbase_count(&ob->greasepencil_modifiers)) { + BKE_report(reports, RPT_WARNING, "Cannot move modifier beyond the end of the stack"); + return false; + } + + int md_index = BLI_findindex(&ob->greasepencil_modifiers, md); + BLI_assert(md_index != -1); + if (md_index < index) { + /* Move modifier down in list. */ + for (; md_index < index; md_index++) { + if (!ED_object_gpencil_modifier_move_down(reports, ob, md)) { + break; + } + } + } + else { + /* Move modifier up in list. */ + for (; md_index > index; md_index--) { + if (!ED_object_gpencil_modifier_move_up(reports, ob, md)) { + break; + } + } + } + + return true; +} + static int gpencil_modifier_apply_obdata( ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md) { @@ -428,22 +448,58 @@ static void gpencil_edit_modifier_properties(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -static int gpencil_edit_modifier_invoke_properties(bContext *C, wmOperator *op) +static void gpencil_edit_modifier_report_property(wmOperatorType *ot) { - GpencilModifierData *md; + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "report", false, "Report", "Create a notification after the operation"); + RNA_def_property_flag(prop, PROP_HIDDEN); +} +/** + * \param event: If this isn't NULL, the operator will also look for panels underneath + * the cursor with customdata set to a modifier. + * \param r_retval: This should be used if #event is used in order to to return + * #OPERATOR_PASS_THROUGH to check other operators with the same key set. + */ +static bool gpencil_edit_modifier_invoke_properties(bContext *C, + wmOperator *op, + const wmEvent *event, + int *r_retval) +{ if (RNA_struct_property_is_set(op->ptr, "modifier")) { return true; } - else { - PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_GpencilModifier); - if (ptr.data) { - md = ptr.data; - RNA_string_set(op->ptr, "modifier", md->name); - return true; + + PointerRNA ctx_ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_GpencilModifier); + if (ctx_ptr.data != NULL) { + GpencilModifierData *md = ctx_ptr.data; + RNA_string_set(op->ptr, "modifier", md->name); + return true; + } + + /* Check the custom data of panels under the mouse for a modifier. */ + if (event != NULL) { + PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event); + + if (!(panel_ptr == NULL || RNA_pointer_is_null(panel_ptr))) { + if (RNA_struct_is_a(panel_ptr->type, &RNA_GpencilModifier)) { + GpencilModifierData *md = panel_ptr->data; + RNA_string_set(op->ptr, "modifier", md->name); + return true; + } + else { + BLI_assert(r_retval != NULL); /* We need the return value in this case. */ + if (r_retval != NULL) { + *r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + } + return false; + } } } + if (r_retval != NULL) { + *r_retval = OPERATOR_CANCELLED; + } return false; } @@ -472,24 +528,35 @@ static int gpencil_modifier_remove_exec(bContext *C, wmOperator *op) Object *ob = ED_object_active_context(C); GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md)) { + if (md == NULL) { + return OPERATOR_CANCELLED; + } + + /* Store name temporarily for report. */ + char name[MAX_NAME]; + strcpy(name, md->name); + + if (!ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md)) { return OPERATOR_CANCELLED; } WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + if (RNA_boolean_get(op->ptr, "report")) { + BKE_reportf(op->reports, RPT_INFO, "Removed modifier: %s", name); + } + return OPERATOR_FINISHED; } -static int gpencil_modifier_remove_invoke(bContext *C, - wmOperator *op, - const wmEvent *UNUSED(event)) +static int gpencil_modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (gpencil_edit_modifier_invoke_properties(C, op)) { + int retval; + if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) { return gpencil_modifier_remove_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } @@ -506,6 +573,7 @@ void OBJECT_OT_gpencil_modifier_remove(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; gpencil_edit_modifier_properties(ot); + gpencil_edit_modifier_report_property(ot); } /************************ move up modifier operator *********************/ @@ -525,15 +593,14 @@ static int gpencil_modifier_move_up_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int gpencil_modifier_move_up_invoke(bContext *C, - wmOperator *op, - const wmEvent *UNUSED(event)) +static int gpencil_modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (gpencil_edit_modifier_invoke_properties(C, op)) { + int retval; + if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) { return gpencil_modifier_move_up_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } @@ -569,15 +636,14 @@ static int gpencil_modifier_move_down_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int gpencil_modifier_move_down_invoke(bContext *C, - wmOperator *op, - const wmEvent *UNUSED(event)) +static int gpencil_modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (gpencil_edit_modifier_invoke_properties(C, op)) { + int retval; + if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) { return gpencil_modifier_move_down_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } @@ -596,6 +662,59 @@ void OBJECT_OT_gpencil_modifier_move_down(wmOperatorType *ot) gpencil_edit_modifier_properties(ot); } +/* ************************* Move to Index Gpencil Modifier Operator ************************* */ + +static bool gpencil_modifier_move_to_index_poll(bContext *C) +{ + return gpencil_edit_modifier_poll(C); +} + +static int gpencil_modifier_move_to_index_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + int index = RNA_int_get(op->ptr, "index"); + + if (!ED_object_gpencil_modifier_move_to_index(op->reports, ob, md, index)) { + return OPERATOR_CANCELLED; + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int gpencil_modifier_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int retval; + if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) { + return gpencil_modifier_move_to_index_exec(C, op); + } + else { + return retval; + } +} + +void OBJECT_OT_gpencil_modifier_move_to_index(wmOperatorType *ot) +{ + ot->name = "Move Active Modifier to Index"; + ot->idname = "OBJECT_OT_gpencil_modifier_move_to_index"; + ot->description = + "Change the modifier's position in the list so it evaluates after the set number of " + "others"; + + ot->invoke = gpencil_modifier_move_to_index_invoke; + ot->exec = gpencil_modifier_move_to_index_exec; + ot->poll = gpencil_modifier_move_to_index_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); + RNA_def_int( + ot->srna, "index", 0, 0, INT_MAX, "Index", "The index to move the modifier to", 0, INT_MAX); +} + /************************ apply modifier operator *********************/ static int gpencil_modifier_apply_exec(bContext *C, wmOperator *op) @@ -606,23 +725,36 @@ static int gpencil_modifier_apply_exec(bContext *C, wmOperator *op) GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); int apply_as = RNA_enum_get(op->ptr, "apply_as"); - if (!md || !ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) { + if (md == NULL) { + return OPERATOR_CANCELLED; + } + + /* Store name temporarily for report. */ + char name[MAX_NAME]; + strcpy(name, md->name); + + if (!ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) { return OPERATOR_CANCELLED; } DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + if (RNA_boolean_get(op->ptr, "report")) { + BKE_reportf(op->reports, RPT_INFO, "Applied modifier: %s", name); + } + return OPERATOR_FINISHED; } -static int gpencil_modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int gpencil_modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (gpencil_edit_modifier_invoke_properties(C, op)) { + int retval; + if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) { return gpencil_modifier_apply_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } @@ -656,6 +788,7 @@ void OBJECT_OT_gpencil_modifier_apply(wmOperatorType *ot) "Apply as", "How to apply the modifier to the geometry"); gpencil_edit_modifier_properties(ot); + gpencil_edit_modifier_report_property(ot); } /************************ copy modifier operator *********************/ @@ -675,13 +808,14 @@ static int gpencil_modifier_copy_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int gpencil_modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int gpencil_modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (gpencil_edit_modifier_invoke_properties(C, op)) { + int retval; + if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) { return gpencil_modifier_copy_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index c5a6e38fbcb..afc87c0caba 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -153,7 +153,10 @@ bool edit_modifier_poll_generic(struct bContext *C, const bool is_editmode_allowed); bool edit_modifier_poll(struct bContext *C); void edit_modifier_properties(struct wmOperatorType *ot); -int edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op); +bool edit_modifier_invoke_properties(struct bContext *C, + struct wmOperator *op, + const struct wmEvent *event, + int *r_retval); struct ModifierData *edit_modifier_property_get(struct wmOperator *op, struct Object *ob, int type); @@ -190,6 +193,7 @@ void OBJECT_OT_gpencil_modifier_add(struct wmOperatorType *ot); void OBJECT_OT_gpencil_modifier_remove(struct wmOperatorType *ot); void OBJECT_OT_gpencil_modifier_move_up(struct wmOperatorType *ot); void OBJECT_OT_gpencil_modifier_move_down(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_move_to_index(struct wmOperatorType *ot); void OBJECT_OT_gpencil_modifier_apply(struct wmOperatorType *ot); void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot); @@ -198,6 +202,7 @@ void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot); void OBJECT_OT_shaderfx_remove(struct wmOperatorType *ot); void OBJECT_OT_shaderfx_move_up(struct wmOperatorType *ot); void OBJECT_OT_shaderfx_move_down(struct wmOperatorType *ot); +void OBJECT_OT_shaderfx_move_to_index(struct wmOperatorType *ot); /* object_constraint.c */ void OBJECT_OT_constraint_add(struct wmOperatorType *ot); @@ -217,6 +222,7 @@ void POSE_OT_ik_clear(struct wmOperatorType *ot); void CONSTRAINT_OT_delete(struct wmOperatorType *ot); void CONSTRAINT_OT_move_up(struct wmOperatorType *ot); +void CONSTRAINT_OT_move_to_index(struct wmOperatorType *ot); void CONSTRAINT_OT_move_down(struct wmOperatorType *ot); void CONSTRAINT_OT_stretchto_reset(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index c518fd32c7f..5d4476ecb8c 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -116,7 +116,7 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) case OB_SURF: case OB_FONT: case OB_MBALL: - if (mode & (OB_MODE_EDIT)) { + if (mode & OB_MODE_EDIT) { return true; } break; diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index a6c5814e88a..6b0eff5b6e5 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -88,6 +88,8 @@ #include "ED_screen.h" #include "ED_sculpt.h" +#include "UI_interface.h" + #include "WM_api.h" #include "WM_types.h" @@ -1037,22 +1039,58 @@ void edit_modifier_properties(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -int edit_modifier_invoke_properties(bContext *C, wmOperator *op) +static void edit_modifier_report_property(wmOperatorType *ot) { - ModifierData *md; + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "report", false, "Report", "Create a notification after the operation"); + RNA_def_property_flag(prop, PROP_HIDDEN); +} +/** + * \param event: If this isn't NULL, the operator will also look for panels underneath + * the cursor with customdata set to a modifier. + * \param r_retval: This should be used if #event is used in order to to return + * #OPERATOR_PASS_THROUGH to check other operators with the same key set. + */ +bool edit_modifier_invoke_properties(bContext *C, + wmOperator *op, + const wmEvent *event, + int *r_retval) +{ if (RNA_struct_property_is_set(op->ptr, "modifier")) { return true; } - else { - PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_Modifier); - if (ptr.data) { - md = ptr.data; - RNA_string_set(op->ptr, "modifier", md->name); - return true; + + PointerRNA ctx_ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_Modifier); + if (ctx_ptr.data != NULL) { + ModifierData *md = ctx_ptr.data; + RNA_string_set(op->ptr, "modifier", md->name); + return true; + } + + /* Check the custom data of panels under the mouse for a modifier. */ + if (event != NULL) { + PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event); + + if (!(panel_ptr == NULL || RNA_pointer_is_null(panel_ptr))) { + if (RNA_struct_is_a(panel_ptr->type, &RNA_Modifier)) { + ModifierData *md = panel_ptr->data; + RNA_string_set(op->ptr, "modifier", md->name); + return true; + } + else { + BLI_assert(r_retval != NULL); /* We need the return value in this case. */ + if (r_retval != NULL) { + *r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + } + return false; + } } } + if (r_retval != NULL) { + *r_retval = OPERATOR_CANCELLED; + } return false; } @@ -1085,7 +1123,15 @@ static int modifier_remove_exec(bContext *C, wmOperator *op) ModifierData *md = edit_modifier_property_get(op, ob, 0); int mode_orig = ob->mode; - if (!md || !ED_object_modifier_remove(op->reports, bmain, ob, md)) { + if (md == NULL) { + return OPERATOR_CANCELLED; + } + + /* Store name temporarily for report. */ + char name[MAX_NAME]; + strcpy(name, md->name); + + if (!ED_object_modifier_remove(op->reports, bmain, ob, md)) { return OPERATOR_CANCELLED; } @@ -1099,16 +1145,22 @@ static int modifier_remove_exec(bContext *C, wmOperator *op) } } } + + if (RNA_boolean_get(op->ptr, "report")) { + BKE_reportf(op->reports, RPT_INFO, "Removed modifier: %s", name); + } + return OPERATOR_FINISHED; } -static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties(C, op, event, &retval)) { return modifier_remove_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } @@ -1125,6 +1177,7 @@ void OBJECT_OT_modifier_remove(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; edit_modifier_properties(ot); + edit_modifier_report_property(ot); } /** \} */ @@ -1148,13 +1201,14 @@ static int modifier_move_up_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties(C, op, event, &retval)) { return modifier_move_up_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } @@ -1194,13 +1248,14 @@ static int modifier_move_down_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties(C, op, event, &retval)) { return modifier_move_down_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } @@ -1246,13 +1301,14 @@ static int modifier_move_to_index_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties(C, op, event, &retval)) { return modifier_move_to_index_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } @@ -1291,6 +1347,10 @@ static bool modifier_apply_poll(bContext *C) Object *ob = (ptr.owner_id != NULL) ? (Object *)ptr.owner_id : ED_object_active_context(C); ModifierData *md = ptr.data; /* May be NULL. */ + if (ID_IS_OVERRIDE_LIBRARY(ob) || ID_IS_OVERRIDE_LIBRARY(ob->data)) { + CTX_wm_operator_poll_msg_set(C, "Modifiers cannot be applied on override data"); + return false; + } if ((ob->data != NULL) && ID_REAL_USERS(ob->data) > 1) { CTX_wm_operator_poll_msg_set(C, "Modifiers cannot be applied to multi-user data"); return false; @@ -1315,7 +1375,15 @@ static int modifier_apply_exec(bContext *C, wmOperator *op) ModifierData *md = edit_modifier_property_get(op, ob, 0); int apply_as = RNA_enum_get(op->ptr, "apply_as"); - if (!md || !ED_object_modifier_apply(bmain, op->reports, depsgraph, scene, ob, md, apply_as)) { + if (md == NULL) { + return OPERATOR_CANCELLED; + } + + /* Store name temporarily for report. */ + char name[MAX_NAME]; + strcpy(name, md->name); + + if (!ED_object_modifier_apply(bmain, op->reports, depsgraph, scene, ob, md, apply_as)) { return OPERATOR_CANCELLED; } @@ -1323,16 +1391,21 @@ static int modifier_apply_exec(bContext *C, wmOperator *op) DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + if (RNA_boolean_get(op->ptr, "report")) { + BKE_reportf(op->reports, RPT_INFO, "Applied modifier: %s", name); + } + return OPERATOR_FINISHED; } -static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties(C, op, event, &retval)) { return modifier_apply_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } @@ -1366,6 +1439,7 @@ void OBJECT_OT_modifier_apply(wmOperatorType *ot) "Apply as", "How to apply the modifier to the geometry"); edit_modifier_properties(ot); + edit_modifier_report_property(ot); } /** \} */ @@ -1396,7 +1470,7 @@ static int modifier_convert_exec(bContext *C, wmOperator *op) static int modifier_convert_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return modifier_convert_exec(C, op); } else { @@ -1440,13 +1514,14 @@ static int modifier_copy_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties(C, op, event, &retval)) { return modifier_copy_exec(C, op); } else { - return OPERATOR_CANCELLED; + return retval; } } @@ -1501,7 +1576,7 @@ static int multires_higher_levels_delete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return multires_higher_levels_delete_exec(C, op); } else { @@ -1579,7 +1654,7 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op) static int multires_subdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return multires_subdivide_exec(C, op); } else { @@ -1656,7 +1731,7 @@ static int multires_reshape_exec(bContext *C, wmOperator *op) static int multires_reshape_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return multires_reshape_exec(C, op); } else { @@ -1720,7 +1795,7 @@ static int multires_external_save_invoke(bContext *C, wmOperator *op, const wmEv Mesh *me = ob->data; char path[FILE_MAX]; - if (!edit_modifier_invoke_properties(C, op)) { + if (!edit_modifier_invoke_properties(C, op, NULL, NULL)) { return OPERATOR_CANCELLED; } @@ -1837,7 +1912,7 @@ static int multires_base_apply_exec(bContext *C, wmOperator *op) static int multires_base_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return multires_base_apply_exec(C, op); } else { @@ -1891,7 +1966,7 @@ static int multires_unsubdivide_exec(bContext *C, wmOperator *op) static int multires_unsubdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return multires_unsubdivide_exec(C, op); } else { @@ -1949,7 +2024,7 @@ static int multires_rebuild_subdiv_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return multires_rebuild_subdiv_exec(C, op); } else { @@ -1999,8 +2074,9 @@ static bool skin_poll(bContext *C) static bool skin_edit_poll(bContext *C) { - return (CTX_data_edit_object(C) && - edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH), true)); + Object *ob = CTX_data_edit_object(C); + return (ob != NULL && edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH), true) && + !ID_IS_OVERRIDE_LIBRARY(ob) && !ID_IS_OVERRIDE_LIBRARY(ob->data)); } static void skin_root_clear(BMVert *bm_vert, GSet *visited, const int cd_vert_skin_offset) @@ -2327,7 +2403,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op) static int skin_armature_create_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return skin_armature_create_exec(C, op); } else { @@ -2406,7 +2482,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op) static int correctivesmooth_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return correctivesmooth_bind_exec(C, op); } else { @@ -2483,7 +2559,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op) static int meshdeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return meshdeform_bind_exec(C, op); } else { @@ -2539,7 +2615,7 @@ static int explode_refresh_exec(bContext *C, wmOperator *op) static int explode_refresh_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return explode_refresh_exec(C, op); } else { @@ -2743,7 +2819,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) static int ocean_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return ocean_bake_exec(C, op); } else { @@ -2822,7 +2898,7 @@ static int laplaciandeform_bind_exec(bContext *C, wmOperator *op) static int laplaciandeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return laplaciandeform_bind_exec(C, op); } else { @@ -2891,7 +2967,7 @@ static int surfacedeform_bind_exec(bContext *C, wmOperator *op) static int surfacedeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) { + if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { return surfacedeform_bind_exec(C, op); } else { diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 05f1ced8615..e28bbb3fb1c 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -109,10 +109,8 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_light_add); WM_operatortype_append(OBJECT_OT_camera_add); WM_operatortype_append(OBJECT_OT_speaker_add); -#ifdef WITH_NEW_OBJECT_TYPES WM_operatortype_append(OBJECT_OT_hair_add); WM_operatortype_append(OBJECT_OT_pointcloud_add); -#endif WM_operatortype_append(OBJECT_OT_volume_add); WM_operatortype_append(OBJECT_OT_volume_import); WM_operatortype_append(OBJECT_OT_add); @@ -152,6 +150,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_gpencil_modifier_remove); WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_up); WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_down); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_to_index); WM_operatortype_append(OBJECT_OT_gpencil_modifier_apply); WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy); @@ -160,6 +159,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_shaderfx_remove); WM_operatortype_append(OBJECT_OT_shaderfx_move_up); WM_operatortype_append(OBJECT_OT_shaderfx_move_down); + WM_operatortype_append(OBJECT_OT_shaderfx_move_to_index); WM_operatortype_append(OBJECT_OT_correctivesmooth_bind); WM_operatortype_append(OBJECT_OT_meshdeform_bind); @@ -179,6 +179,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(CONSTRAINT_OT_delete); WM_operatortype_append(CONSTRAINT_OT_move_up); WM_operatortype_append(CONSTRAINT_OT_move_down); + WM_operatortype_append(CONSTRAINT_OT_move_to_index); WM_operatortype_append(CONSTRAINT_OT_stretchto_reset); WM_operatortype_append(CONSTRAINT_OT_limitdistance_reset); WM_operatortype_append(CONSTRAINT_OT_childof_set_inverse); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index fd2fcb11635..509b70f849e 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -33,6 +33,7 @@ #include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" +#include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" @@ -68,6 +69,7 @@ #include "BKE_gpencil.h" #include "BKE_hair.h" #include "BKE_idprop.h" +#include "BKE_idtype.h" #include "BKE_lattice.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -1771,7 +1773,10 @@ static Collection *single_object_users_collection(Main *bmain, /* Generate new copies for objects in given collection and all its children, * and optionally also copy collections themselves. */ if (copy_collections && !is_master_collection) { - collection = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection)); + Collection *collection_new; + BKE_id_copy(bmain, &collection->id, (ID **)&collection_new); + id_us_min(&collection_new->id); + collection = ID_NEW_SET(collection, collection_new); } /* We do not remap to new objects here, this is done in separate step. */ @@ -2246,47 +2251,66 @@ void OBJECT_OT_make_local(wmOperatorType *ot) /** \name Make Library Override Operator * \{ */ -static void make_override_library_tag_object(Object *obact, Object *ob) +static bool make_override_hierarchy_recursive_tag(Main *bmain, ID *id) { - if (ob == obact) { - return; + MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id); + + /* This way we won't process again that ID should we encounter it again through another + * relationship hierarchy. + * Note that this does not free any memory from relations, so we can still use the entries. + */ + BKE_main_relations_ID_remove(bmain, id); + + for (; entry != NULL; entry = entry->next) { + /* We only consider IDs from the same library. */ + if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) { + if (make_override_hierarchy_recursive_tag(bmain, *entry->id_pointer)) { + id->tag |= LIB_TAG_DOIT; + } + } } - if (!ID_IS_LINKED(ob)) { - return; + return (id->tag & LIB_TAG_DOIT) != 0; +} + +static int make_override_tag_ids_cb(LibraryIDLinkCallbackData *cb_data) +{ + if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK)) { + return IDWALK_RET_STOP_RECURSION; } - /* Note: all this is very case-by-case bad handling, ultimately we'll want a real full - * 'automatic', generic handling of all this, - * will probably require adding some override-aware stuff to library_query code... */ + ID *id_root = cb_data->user_data; + Library *library_root = id_root->lib; + ID *id = *cb_data->id_pointer; + ID *id_owner = cb_data->id_owner; - if (obact->type == OB_ARMATURE && ob->modifiers.first != NULL) { - for (ModifierData *md = ob->modifiers.first; md != NULL; md = md->next) { - if (md->type == eModifierType_Armature) { - ArmatureModifierData *amd = (ArmatureModifierData *)md; - if (amd->object == obact) { - ob->id.tag |= LIB_TAG_DOIT; - break; - } - } - } + BLI_assert(id_owner == cb_data->id_self); + + if (ELEM(id, NULL, id_owner)) { + return IDWALK_RET_NOP; } - else if (ob->parent == obact) { - ob->id.tag |= LIB_TAG_DOIT; + + BLI_assert(id->lib != NULL); + BLI_assert(id_owner->lib == library_root); + + if (id->tag & LIB_TAG_DOIT) { + /* Already processed, but maybe not with the same chain of dependency, so we need to check that + * one nonetheless. */ + return IDWALK_RET_STOP_RECURSION; } - if (ob->id.tag & LIB_TAG_DOIT) { - printf("Indirectly overriding %s for %s\n", ob->id.name, obact->id.name); + if (id->lib != library_root) { + /* We do not override data-blocks from other libraries, nor do we process them. */ + return IDWALK_RET_STOP_RECURSION; } -} -static void make_override_library_tag_collections(Collection *collection) -{ - collection->id.tag |= LIB_TAG_DOIT; - for (CollectionChild *coll_child = collection->children.first; coll_child != NULL; - coll_child = coll_child->next) { - make_override_library_tag_collections(coll_child->collection); + /* We tag all collections and objects for override. And we also tag all other data-blocks which + * would user one of those. */ + if (ELEM(GS(id->name), ID_OB, ID_GR)) { + id->tag |= LIB_TAG_DOIT; } + + return IDWALK_RET_NOP; } /* Set the object to override. */ @@ -2335,6 +2359,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Object *obact = CTX_data_active_object(C); + ID *id_root = NULL; bool success = false; @@ -2348,111 +2373,156 @@ static int make_override_library_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + id_root = &obact->instance_collection->id; + } + else if (!ID_IS_OVERRIDABLE_LIBRARY(obact)) { + BKE_reportf(op->reports, + RPT_ERROR_INVALID_INPUT, + "Active object '%s' is not overridable", + obact->id.name + 2); + return OPERATOR_CANCELLED; + } + /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */ + else { + id_root = &obact->id; + } - Object *obcollection = obact; - Collection *collection = obcollection->instance_collection; + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection); - Base *base = BLI_findlink(&dup_collection_objects, RNA_enum_get(op->ptr, "object")); - obact = base->object; + /* Tag all collections and objects, as well as other IDs using them. */ + id_root->tag |= LIB_TAG_DOIT; - /* First, we make a library override of the linked collection itself, and all its children. */ - make_override_library_tag_collections(collection); + BKE_main_relations_create(bmain, 0); - /* Then, we make library override of the whole set of objects in the Collection. */ - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) { - ob->id.tag |= LIB_TAG_DOIT; - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - /* Then, we remove (untag) bone shape objects, you shall never want to override those - * (hopefully)... */ - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) { - if (ob->type == OB_ARMATURE && ob->pose != NULL) { - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { - if (pchan->custom != NULL) { - pchan->custom->id.tag &= ~LIB_TAG_DOIT; - } + BKE_library_foreach_ID_link( + bmain, id_root, make_override_tag_ids_cb, id_root, IDWALK_READONLY | IDWALK_RECURSE); + + /* Then, we remove (untag) bone shape objects, you shall never want to override those + * (hopefully)... */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & LIB_TAG_DOIT)) { + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { + if (pchan->custom != NULL) { + pchan->custom->id.tag &= ~LIB_TAG_DOIT; } } } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } - success = BKE_lib_override_library_create_from_tag(bmain); + /* The we tag all intermediary data-blocks in-between to overridden ones (e.g. if a shapekey has + * a driver using an armature object's bone, we need to override the shapekey/obdata, the objects + * using them, etc.) */ + make_override_hierarchy_recursive_tag(bmain, id_root); + + BKE_main_relations_free(bmain); + + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (id->tag & LIB_TAG_DOIT && id->lib != NULL) { + printf("ID %s tagged for override\n", id->name); + } + } + FOREACH_MAIN_ID_END; - /* Instantiate our newly overridden objects in scene, if not yet done. */ + success = BKE_lib_override_library_create_from_tag(bmain); + + if (success) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Collection *new_collection = (Collection *)collection->id.newid; - BKE_collection_add_from_object(bmain, scene, obcollection, new_collection); + BKE_main_collection_sync(bmain); + + switch (GS(id_root->name)) { + case ID_GR: { + Collection *collection_new = ((Collection *)id_root->newid); + BKE_collection_add_from_object(bmain, scene, obact, collection_new); + + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) { + if (ob_new != NULL && ob_new->id.override_library != NULL) { + Base *base; + if ((base = BKE_view_layer_base_find(view_layer, ob_new)) == NULL) { + BKE_collection_object_add_from(bmain, scene, obact, ob_new); + base = BKE_view_layer_base_find(view_layer, ob_new); + DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); + } - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (new_collection, new_ob) { - if (new_ob != NULL && new_ob->id.override_library != NULL) { - if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) { - BKE_collection_object_add_from(bmain, scene, obcollection, new_ob); - base = BKE_view_layer_base_find(view_layer, new_ob); - DEG_id_tag_update_ex(bmain, &new_ob->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); + if (ob_new == (Object *)obact->id.newid) { + /* TODO: is setting active needed? */ + BKE_view_layer_base_select_and_set_active(view_layer, base); + } + } } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + break; + } + case ID_OB: { + BKE_collection_object_add_from(bmain, scene, obact, ((Object *)id_root->newid)); + break; + } + default: + BLI_assert(0); + } - if (new_ob == (Object *)obact->id.newid) { - /* TODO: is setting active needed? */ - BKE_view_layer_base_select_and_set_active(view_layer, base); + /* We need to ensure all new overrides of objects are properly instantiated. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + Object *ob_new = (Object *)ob->id.newid; + if (ob_new != NULL) { + BLI_assert(ob_new->id.override_library != NULL && + ob_new->id.override_library->reference == &ob->id); + + Collection *default_instantiating_collection = NULL; + Base *base; + if ((base = BKE_view_layer_base_find(view_layer, ob_new)) == NULL) { + if (default_instantiating_collection == NULL) { + switch (GS(id_root->name)) { + case ID_GR: { + default_instantiating_collection = BKE_collection_add( + bmain, (Collection *)id_root, "OVERRIDE_HIDDEN"); + break; + } + case ID_OB: { + /* Add the new container collection to one of the collections instantiating the + * root object, or scene's master collection if none found. */ + Object *ob_root = (Object *)id_root; + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (BKE_collection_has_object(collection, ob_root) && + BKE_view_layer_has_collection(view_layer, collection)) { + default_instantiating_collection = BKE_collection_add( + bmain, collection, "OVERRIDE_HIDDEN"); + } + } + if (default_instantiating_collection == NULL) { + default_instantiating_collection = BKE_collection_add( + bmain, scene->master_collection, "OVERRIDE_HIDDEN"); + } + break; + } + default: + BLI_assert(0); + } + /* Hide the collection from viewport and render. */ + default_instantiating_collection->flag |= COLLECTION_RESTRICT_VIEWPORT | + COLLECTION_RESTRICT_RENDER; + } + + BKE_collection_object_add(bmain, default_instantiating_collection, ob_new); + DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); } - /* We still want to store all objects' current override status (i.e. change of parent). */ - BKE_lib_override_library_operations_create(bmain, &new_ob->id, true); } } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; /* Remove the instance empty from this scene, the items now have an overridden collection * instead. */ - ED_object_base_free_and_unlink(bmain, scene, obcollection); - - /* Also, we'd likely want to lock by default things like - * transformations of implicitly overridden objects? */ - - DEG_id_tag_update(&scene->id, 0); - - /* Cleanup. */ - BKE_main_id_clear_newpoins(bmain); - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - } - else if (!ID_IS_OVERRIDABLE_LIBRARY(obact)) { - BKE_reportf(op->reports, - RPT_ERROR_INVALID_INPUT, - "Active object '%s' is not overridable", - obact->id.name + 2); - return OPERATOR_CANCELLED; - } - /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */ - else if (obact->type == OB_ARMATURE) { - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - - obact->id.tag |= LIB_TAG_DOIT; - - for (Object *ob = bmain->objects.first; ob != NULL; ob = ob->id.next) { - make_override_library_tag_object(obact, ob); + if (id_root != &obact->id) { + ED_object_base_free_and_unlink(bmain, scene, obact); } - - success = BKE_lib_override_library_create_from_tag(bmain); - - /* Also, we'd likely want to lock by default things like - * transformations of implicitly overridden objects? */ - - /* Cleanup. */ - BKE_main_id_clear_newpoins(bmain); - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - } - /* TODO: probably more cases where we want to do automated smart things in the future! */ - else { - /* For now, remapp all local usages of linked ID to local override one here. */ - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, true); - success = (BKE_lib_override_library_create_from_id(bmain, &obact->id, true) != NULL); - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); } + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_WINDOW, NULL); return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c index 1d7920b9991..664d4219686 100644 --- a/source/blender/editors/object/object_remesh.c +++ b/source/blender/editors/object/object_remesh.c @@ -100,7 +100,12 @@ static bool object_remesh_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if (ob == NULL) { + if (ob == NULL || ob->data == NULL) { + return false; + } + + if (ID_IS_LINKED(ob) || ID_IS_LINKED(ob->data) || ID_IS_OVERRIDE_LIBRARY(ob->data)) { + CTX_wm_operator_poll_msg_set(C, "The remesher cannot worked on linked or override data"); return false; } @@ -174,6 +179,11 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) BKE_remesh_reproject_sculpt_face_sets(new_mesh, mesh); } + if (mesh->flag & ME_REMESH_REPROJECT_VERTEX_COLORS) { + BKE_mesh_runtime_clear_geometry(mesh); + BKE_remesh_reproject_vertex_paint(new_mesh, mesh); + } + BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true); if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) { @@ -521,7 +531,9 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev /* Project the selected face in the previous step of the Bounding Box. */ for (int i = 0; i < 4; i++) { - ED_view3d_project(ar, cd->preview_plane[i], preview_plane_proj[i]); + float preview_plane_world_space[3]; + mul_v3_m4v3(preview_plane_world_space, active_object->obmat, cd->preview_plane[i]); + ED_view3d_project(ar, preview_plane_world_space, preview_plane_proj[i]); } /* Get the initial X and Y axis of the basis from the edges of the Bounding Box face. */ @@ -569,7 +581,9 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev copy_v3_v3(cd->text_mat[3], text_pos); /* Scale the text. */ - const float pixelsize = ED_view3d_pixel_size(rv3d, text_pos); + float text_pos_word_space[3]; + mul_v3_m4v3(text_pos_word_space, active_object->obmat, text_pos); + const float pixelsize = ED_view3d_pixel_size(rv3d, text_pos_word_space); scale_m4_fl(scale_mat, pixelsize * 0.5f); mul_m4_m4_post(cd->text_mat, scale_mat); diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c index 5db4a5a4f57..d9f37b8e38b 100644 --- a/source/blender/editors/object/object_shader_fx.c +++ b/source/blender/editors/object/object_shader_fx.c @@ -200,6 +200,40 @@ int ED_object_shaderfx_move_down(ReportList *UNUSED(reports), Object *ob, Shader return 1; } +bool ED_object_shaderfx_move_to_index(ReportList *reports, + Object *ob, + ShaderFxData *fx, + const int index) +{ + BLI_assert(fx != NULL); + BLI_assert(index >= 0); + if (index >= BLI_listbase_count(&ob->shader_fx)) { + BKE_report(reports, RPT_WARNING, "Cannot move effect beyond the end of the stack"); + return false; + } + + int fx_index = BLI_findindex(&ob->shader_fx, fx); + BLI_assert(fx_index != -1); + if (fx_index < index) { + /* Move shaderfx down in list. */ + for (; fx_index < index; fx_index++) { + if (!ED_object_shaderfx_move_down(reports, ob, fx)) { + break; + } + } + } + else { + /* Move shaderfx up in list. */ + for (; fx_index > index; fx_index--) { + if (!ED_object_shaderfx_move_up(reports, ob, fx)) { + break; + } + } + } + + return true; +} + /************************ add effect operator *********************/ static int shaderfx_add_exec(bContext *C, wmOperator *op) @@ -391,8 +425,8 @@ static int shaderfx_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UN void OBJECT_OT_shaderfx_remove(wmOperatorType *ot) { - ot->name = "Remove Grease Pencil Modifier"; - ot->description = "Remove a shaderfx from the active grease pencil object"; + ot->name = "Remove Grease Pencil Effect"; + ot->description = "Remove a effect from the active grease pencil object"; ot->idname = "OBJECT_OT_shaderfx_remove"; ot->invoke = shaderfx_remove_invoke; @@ -433,8 +467,8 @@ static int shaderfx_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *U void OBJECT_OT_shaderfx_move_up(wmOperatorType *ot) { - ot->name = "Move Up Modifier"; - ot->description = "Move shaderfx up in the stack"; + ot->name = "Move Up Effect"; + ot->description = "Move effect up in the stack"; ot->idname = "OBJECT_OT_shaderfx_move_up"; ot->invoke = shaderfx_move_up_invoke; @@ -475,8 +509,8 @@ static int shaderfx_move_down_invoke(bContext *C, wmOperator *op, const wmEvent void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot) { - ot->name = "Move Down Modifier"; - ot->description = "Move shaderfx down in the stack"; + ot->name = "Move Down Effect"; + ot->description = "Move effect down in the stack"; ot->idname = "OBJECT_OT_shaderfx_move_down"; ot->invoke = shaderfx_move_down_invoke; @@ -487,3 +521,55 @@ void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; edit_shaderfx_properties(ot); } + +/************************ move shaderfx to index operator *********************/ + +static bool shaderfx_move_to_index_poll(bContext *C) +{ + return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0); +} + +static int shaderfx_move_to_index_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); + int index = RNA_int_get(op->ptr, "index"); + + if (!fx || !ED_object_shaderfx_move_to_index(op->reports, ob, fx, index)) { + return OPERATOR_CANCELLED; + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int shaderfx_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (edit_shaderfx_invoke_properties(C, op)) { + return shaderfx_move_to_index_exec(C, op); + } + else { + return OPERATOR_CANCELLED; + } +} + +void OBJECT_OT_shaderfx_move_to_index(wmOperatorType *ot) +{ + ot->name = "Move Effect to Index"; + ot->idname = "OBJECT_OT_shaderfx_move_to_index"; + ot->description = + "Change the effect's position in the list so it evaluates after the set number of " + "others"; + + ot->invoke = shaderfx_move_to_index_invoke; + ot->exec = shaderfx_move_to_index_exec; + ot->poll = shaderfx_move_to_index_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_shaderfx_properties(ot); + RNA_def_int( + ot->srna, "index", 0, 0, INT_MAX, "Index", "The index to move the effect to", 0, INT_MAX); +} diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c index 26d33bbc375..71778f92349 100644 --- a/source/blender/editors/object/object_shapekey.c +++ b/source/blender/editors/object/object_shapekey.c @@ -216,40 +216,38 @@ static bool object_shape_key_mirror( /********************** shape key operators *********************/ -static bool shape_key_mode_poll(bContext *C) +static bool shape_key_poll(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && ob->mode != OB_MODE_EDIT); + + return (ob != NULL && !ID_IS_LINKED(ob) && !ID_IS_OVERRIDE_LIBRARY(ob) && data != NULL && + !ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data)); } -static bool shape_key_mode_exists_poll(bContext *C) +static bool shape_key_mode_poll(bContext *C) { Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - /* same as shape_key_mode_poll */ - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && ob->mode != OB_MODE_EDIT) && - /* check a keyblock exists */ - (BKE_keyblock_from_object(ob) != NULL); + return (shape_key_poll(C) && ob->mode != OB_MODE_EDIT); } -static bool shape_key_move_poll(bContext *C) +static bool shape_key_mode_exists_poll(bContext *C) { - /* Same as shape_key_mode_exists_poll above, but ensure we have at least two shapes! */ Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - Key *key = BKE_key_from_object(ob); - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && ob->mode != OB_MODE_EDIT && - key && key->totkey > 1); + return (shape_key_mode_poll(C) && + /* check a keyblock exists */ + (BKE_keyblock_from_object(ob) != NULL)); } -static bool shape_key_poll(bContext *C) +static bool shape_key_move_poll(bContext *C) { + /* Same as shape_key_mode_exists_poll above, but ensure we have at least two shapes! */ Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)); + Key *key = BKE_key_from_object(ob); + + return (shape_key_mode_poll(C) && key != NULL && key->totkey > 1); } static int shape_key_add_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 132b530455e..161611d59c9 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -1098,15 +1098,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) mul_m4_v3(obedit->imat, cent); } else { - if (around == V3D_AROUND_CENTER_MEDIAN) { - if (em->bm->totvert) { - const float total_div = 1.0f / (float)em->bm->totvert; - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - madd_v3_v3fl(cent, eve->co, total_div); - } - } - } - else { + if (around == V3D_AROUND_CENTER_BOUNDS) { float min[3], max[3]; INIT_MINMAX(min, max); BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { @@ -1114,6 +1106,14 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) } mid_v3_v3v3(cent, min, max); } + else { /* #V3D_AROUND_CENTER_MEDIAN. */ + if (em->bm->totvert) { + const float total_div = 1.0f / (float)em->bm->totvert; + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + madd_v3_v3fl(cent, eve->co, total_div); + } + } + } } BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { @@ -1211,12 +1211,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) else if (centermode == ORIGIN_TO_CENTER_OF_MASS_VOLUME) { BKE_mesh_center_of_volume(me, cent); } - else if (around == V3D_AROUND_CENTER_MEDIAN) { - BKE_mesh_center_median(me, cent); - } - else { + else if (around == V3D_AROUND_CENTER_BOUNDS) { BKE_mesh_center_bounds(me, cent); } + else { /* #V3D_AROUND_CENTER_MEDIAN. */ + BKE_mesh_center_median(me, cent); + } negate_v3_v3(cent_neg, cent); BKE_mesh_translate(me, cent_neg, 1); @@ -1231,12 +1231,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (around == V3D_AROUND_CENTER_MEDIAN) { - BKE_curve_center_median(cu, cent); - } - else { + else if (around == V3D_AROUND_CENTER_BOUNDS) { BKE_curve_center_bounds(cu, cent); } + else { /* #V3D_AROUND_CENTER_MEDIAN. */ + BKE_curve_center_median(cu, cent); + } /* don't allow Z change if curve is 2D */ if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) { @@ -1324,12 +1324,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (around == V3D_AROUND_CENTER_MEDIAN) { - BKE_mball_center_median(mb, cent); - } - else { + else if (around == V3D_AROUND_CENTER_BOUNDS) { BKE_mball_center_bounds(mb, cent); } + else { /* #V3D_AROUND_CENTER_MEDIAN. */ + BKE_mball_center_median(mb, cent); + } negate_v3_v3(cent_neg, cent); BKE_mball_translate(mb, cent_neg); @@ -1351,12 +1351,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (around == V3D_AROUND_CENTER_MEDIAN) { - BKE_lattice_center_median(lt, cent); - } - else { + else if (around == V3D_AROUND_CENTER_BOUNDS) { BKE_lattice_center_bounds(lt, cent); } + else { /* #V3D_AROUND_CENTER_MEDIAN. */ + BKE_lattice_center_median(lt, cent); + } negate_v3_v3(cent_neg, cent); BKE_lattice_translate(lt, cent_neg, 1); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index fb79cfb910e..7ca2a89f61d 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -77,7 +77,10 @@ #include "object_intern.h" -/************************ Exported Functions **********************/ +/* -------------------------------------------------------------------- */ +/** \name Public Utility Functions + * \{ */ + static bool vertex_group_use_vert_sel(Object *ob) { if (ob->mode == OB_MODE_EDIT) { @@ -682,7 +685,11 @@ static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type) MEM_freeN((void *)vgroup_validmap); } -/***********************Start weight transfer (WT)*********************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Shared Weight Transfer Operator Properties + * \{ */ static const EnumPropertyItem WT_vertex_group_select_item[] = { {WT_VGROUP_ACTIVE, "ACTIVE", 0, "Active Group", "The active Vertex Group"}, @@ -779,7 +786,15 @@ static void vgroup_operator_subset_select_props(wmOperatorType *ot, bool use_act ot->prop = prop; } -/***********************End weight transfer (WT)***********************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name High Level Vertex Group Add/Remove + * + * Wrap lower level `BKE` functions. + * + * \note that operations on many vertices should use #ED_vgroup_parray_alloc. + * \{ */ /* for Mesh in Object mode */ /* allows editmode for Lattice */ @@ -976,7 +991,11 @@ void ED_vgroup_select_by_name(Object *ob, const char *name) ob->actdef = BKE_object_defgroup_name_index(ob, name) + 1; } -/********************** Operator Implementations *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Function Implementations + * \{ */ /* only in editmode */ static void vgroup_select_verts(Object *ob, int select) @@ -2634,48 +2653,49 @@ static void vgroup_assign_verts(Object *ob, const float weight) } } -/********************** vertex group operators *********************/ +/** \} */ -static bool vertex_group_poll(bContext *C) +/* -------------------------------------------------------------------- */ +/** \name Shared Operator Poll Functions + * \{ */ + +static bool vertex_group_supported_poll(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && - OB_TYPE_SUPPORT_VGROUP(ob->type) && ob->defbase.first); + return (ob && !ID_IS_LINKED(ob) && OB_TYPE_SUPPORT_VGROUP(ob->type) && + !ID_IS_OVERRIDE_LIBRARY(ob) && data && !ID_IS_LINKED(data) && + !ID_IS_OVERRIDE_LIBRARY(data)); } -static bool vertex_group_supported_poll(bContext *C) +static bool vertex_group_poll(bContext *C) { Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && - !ID_IS_LINKED(data)); + + return (vertex_group_supported_poll(C) && ob->defbase.first); } static bool vertex_group_mesh_poll(bContext *C) { Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && ob->type == OB_MESH && - ob->defbase.first); + return (vertex_group_poll(C) && ob->type == OB_MESH); } static bool UNUSED_FUNCTION(vertex_group_mesh_supported_poll)(bContext *C) { Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED(data)); + + return (vertex_group_supported_poll(C) && ob->type == OB_MESH); } static bool UNUSED_FUNCTION(vertex_group_poll_edit)(bContext *C) { Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) { - return 0; + if (!vertex_group_supported_poll(C)) { + return false; } return BKE_object_is_in_editmode_vgroup(ob); @@ -2687,9 +2707,8 @@ static bool vertex_group_vert_poll_ex(bContext *C, const short ob_type_flag) { Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) { + if (!vertex_group_supported_poll(C)) { return false; } @@ -2747,14 +2766,13 @@ static bool vertex_group_mesh_vert_select_poll(bContext *C) static bool vertex_group_vert_select_unlocked_poll(bContext *C) { Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) { - return 0; + if (!vertex_group_supported_poll(C)) { + return false; } if (!(BKE_object_is_in_editmode_vgroup(ob) || BKE_object_is_in_wpaint_select_vert(ob))) { - return 0; + return false; } if (ob->actdef != 0) { @@ -2763,26 +2781,31 @@ static bool vertex_group_vert_select_unlocked_poll(bContext *C) return !(dg->flag & DG_LOCK_WEIGHT); } } - return 1; + return true; } static bool vertex_group_vert_select_mesh_poll(bContext *C) { Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) { - return 0; + if (!vertex_group_supported_poll(C)) { + return false; } /* only difference to #vertex_group_vert_select_poll */ if (ob->type != OB_MESH) { - return 0; + return false; } return (BKE_object_is_in_editmode_vgroup(ob) || BKE_object_is_in_wpaint_select_vert(ob)); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Add Operator + * \{ */ + static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); @@ -2811,6 +2834,12 @@ void OBJECT_OT_vertex_group_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Remove Operator + * \{ */ + static int vertex_group_remove_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -2858,6 +2887,12 @@ void OBJECT_OT_vertex_group_remove(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Assign Operator + * \{ */ + static int vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op)) { ToolSettings *ts = CTX_data_tool_settings(C); @@ -2888,6 +2923,12 @@ void OBJECT_OT_vertex_group_assign(wmOperatorType *ot) ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Assign New Operator + * \{ */ + /* NOTE: just a wrapper around vertex_group_assign_exec(), except we add these to a new group */ static int vertex_group_assign_new_exec(bContext *C, wmOperator *op) { @@ -2917,6 +2958,12 @@ void OBJECT_OT_vertex_group_assign_new(wmOperatorType *ot) ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Remove From Operator + * \{ */ + static int vertex_group_remove_from_exec(bContext *C, wmOperator *op) { const bool use_all_groups = RNA_boolean_get(op->ptr, "use_all_groups"); @@ -2968,6 +3015,12 @@ void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Select Operator + * \{ */ + static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); @@ -2998,6 +3051,12 @@ void OBJECT_OT_vertex_group_select(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Deselect Operator + * \{ */ + static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); @@ -3037,6 +3096,12 @@ static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Copy Operator + * \{ */ + void OBJECT_OT_vertex_group_copy(wmOperatorType *ot) { /* identifiers */ @@ -3074,6 +3139,12 @@ static int vertex_group_levels_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Levels Operator + * \{ */ + void OBJECT_OT_vertex_group_levels(wmOperatorType *ot) { /* identifiers */ @@ -3115,6 +3186,12 @@ static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op)) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Normalize Operator + * \{ */ + void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot) { /* identifiers */ @@ -3158,6 +3235,12 @@ static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Normalize All Operator + * \{ */ + void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot) { /* identifiers */ @@ -3182,6 +3265,12 @@ void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot) "Keep the values of the active group while normalizing others"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Fix Position Operator + * \{ */ + static int vertex_group_fix_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); @@ -3259,6 +3348,12 @@ void OBJECT_OT_vertex_group_fix(wmOperatorType *ot) 1.f); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Lock Operator + * \{ */ + static int vertex_group_lock_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); @@ -3361,6 +3456,12 @@ void OBJECT_OT_vertex_group_lock(wmOperatorType *ot) "Apply the action based on vertex group selection"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Invert Operator + * \{ */ + static int vertex_group_invert_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -3410,6 +3511,12 @@ void OBJECT_OT_vertex_group_invert(wmOperatorType *ot) "Remove verts from groups that have zero weight after inverting"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Invert Operator + * \{ */ + static int vertex_group_smooth_exec(bContext *C, wmOperator *op) { const float fac = RNA_float_get(op->ptr, "factor"); @@ -3482,6 +3589,12 @@ void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot) 1.0f); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Clean Operator + * \{ */ + static int vertex_group_clean_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -3535,6 +3648,12 @@ void OBJECT_OT_vertex_group_clean(wmOperatorType *ot) "Keep verts assigned to at least one group when cleaning"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Quantize Operator + * \{ */ + static int vertex_group_quantize_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -3574,6 +3693,12 @@ void OBJECT_OT_vertex_group_quantize(wmOperatorType *ot) RNA_def_int(ot->srna, "steps", 4, 1, 1000, "Steps", "Number of steps between 0 and 1", 1, 100); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Limit Total Operator + * \{ */ + static int vertex_group_limit_total_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -3625,6 +3750,12 @@ void OBJECT_OT_vertex_group_limit_total(wmOperatorType *ot) RNA_def_int(ot->srna, "limit", 4, 1, 32, "Limit", "Maximum number of deform weights", 1, 32); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Mirror Operator + * \{ */ + static int vertex_group_mirror_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -3677,6 +3808,12 @@ void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot) "Use topology based mirroring (for when both sides of mesh have matching, unique topology)"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Copy to Linked Operator + * \{ */ + static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -3720,6 +3857,12 @@ void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Copy to Selected Operator + * \{ */ + static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op) { Object *obact = ED_object_context(C); @@ -3768,6 +3911,12 @@ void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Set Active Operator + * \{ */ + static int set_active_group_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -3836,6 +3985,12 @@ void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot) ot->prop = prop; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Sort Operator + * \{ */ + /* creates the name_array parameter for vgroup_do_remap, call this before fiddling * with the order of vgroups then call vgroup_do_remap after */ static char *vgroup_init_remap(Object *ob) @@ -4030,6 +4185,12 @@ void OBJECT_OT_vertex_group_sort(wmOperatorType *ot) RNA_def_enum(ot->srna, "sort_type", vgroup_sort_type, SORT_TYPE_NAME, "Sort type", "Sort type"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Move Operator + * \{ */ + static int vgroup_move_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -4089,6 +4250,12 @@ void OBJECT_OT_vertex_group_move(wmOperatorType *ot) "Direction to move the active vertex group towards"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Weight Paste Operator + * \{ */ + static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) { MDeformVert *dvert_act; @@ -4218,6 +4385,12 @@ void OBJECT_OT_vertex_weight_paste(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Weight Delete Operator + * \{ */ + static int vertex_weight_delete_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -4262,6 +4435,12 @@ void OBJECT_OT_vertex_weight_delete(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Set Active by Weight Operator + * \{ */ + static int vertex_weight_set_active_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -4303,6 +4482,12 @@ void OBJECT_OT_vertex_weight_set_active(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Normalize Active Vertex Operator + * \{ */ + static int vertex_weight_normalize_active_vertex_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); @@ -4338,6 +4523,12 @@ void OBJECT_OT_vertex_weight_normalize_active_vertex(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Group Copy Weights from Active Operator + * \{ */ + static int vertex_weight_copy_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); @@ -4366,3 +4557,5 @@ void OBJECT_OT_vertex_weight_copy(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** \} */ diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index ef5ed806c1e..457c8ba30e6 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -4103,7 +4103,7 @@ static void brush_add_count_iter(void *__restrict iter_data_v, BrushAddCountIterTLSData *tls = tls_v->userdata_chunk; const int number = iter_data->number; const short size = iter_data->size; - const short size2 = size * size; + const int size2 = size * size; float dmx, dmy; if (number > 1) { dmx = size; diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 8524870c15e..8f6b5aa8bc3 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -270,31 +270,31 @@ static void fluid_bake_sequence(FluidJob *job) *(job->do_update) = true; } - /* Get current pause frame (pointer) - depending on bake type */ + /* Get current pause frame (pointer) - depending on bake type. */ pause_frame = job->pause_frame; - /* Set frame to start point (depending on current pause frame value) */ + /* Set frame to start point (depending on current pause frame value). */ is_first_frame = ((*pause_frame) == 0); frame = is_first_frame ? mds->cache_frame_start : (*pause_frame); - /* Save orig frame and update scene frame */ + /* Save orig frame and update scene frame. */ orig_frame = CFRA; CFRA = frame; - /* Loop through selected frames */ + /* Loop through selected frames. */ for (; frame <= mds->cache_frame_end; frame++) { const float progress = (frame - mds->cache_frame_start) / (float)frames; - /* Keep track of pause frame - needed to init future loop */ + /* Keep track of pause frame - needed to init future loop. */ (*pause_frame) = frame; - /* If user requested stop, quit baking */ + /* If user requested stop, quit baking. */ if (G.is_break) { job->success = 0; return; } - /* Update progress bar */ + /* Update progress bar. */ if (job->do_update) { *(job->do_update) = true; } @@ -304,17 +304,17 @@ static void fluid_bake_sequence(FluidJob *job) CFRA = frame; - /* Update animation system */ + /* Update animation system. */ ED_update_for_newframe(job->bmain, job->depsgraph); - /* If user requested stop, quit baking */ + /* If user requested stop, quit baking. */ if (G.is_break) { job->success = 0; return; } } - /* Restore frame position that we were on before bake */ + /* Restore frame position that we were on before bake. */ CFRA = orig_frame; } @@ -355,9 +355,9 @@ static void fluid_bake_endjob(void *customdata) WM_set_locked_interface(G_MAIN->wm.first, false); /* Bake was successful: - * Report for ended bake and how long it took */ + * Report for ended bake and how long it took. */ if (job->success) { - /* Show bake info */ + /* Show bake info. */ WM_reportf( RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start); } @@ -365,7 +365,7 @@ static void fluid_bake_endjob(void *customdata) if (mds->error[0] != '\0') { WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error); } - else { /* User canceled the bake */ + else { /* User canceled the bake. */ WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name); } } diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c index 700a94e4f93..5bd56baf41e 100644 --- a/source/blender/editors/physics/physics_pointcache.c +++ b/source/blender/editors/physics/physics_pointcache.c @@ -132,7 +132,7 @@ static void ptcache_job_endjob(void *customdata) WM_set_locked_interface(job->wm, false); WM_main_add_notifier(NC_SCENE | ND_FRAME, scene); - WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->baker->pid.ob); + WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->baker->pid.owner_id); } static void ptcache_free_bake(PointCache *cache) diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 10f69f3fe9d..7d0ad42c703 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -178,7 +178,7 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area) } } -void ED_render_engine_changed(Main *bmain) +void ED_render_engine_changed(Main *bmain, const bool update_scene_data) { /* on changing the render engine type, clear all running render engines */ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { @@ -198,7 +198,7 @@ void ED_render_engine_changed(Main *bmain) update_ctx.view_layer = view_layer; ED_render_id_flush_update(&update_ctx, &scene->id); } - if (scene->nodetree) { + if (scene->nodetree && update_scene_data) { ntreeCompositUpdateRLayers(scene->nodetree); } } diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c index c32bb69db4e..a1fa5e2d655 100644 --- a/source/blender/editors/scene/scene_edit.c +++ b/source/blender/editors/scene/scene_edit.c @@ -122,7 +122,7 @@ void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer) DEG_graph_relations_update(depsgraph, bmain, scene, layer); DEG_on_visible_update(bmain, false); - ED_render_engine_changed(bmain); + ED_render_engine_changed(bmain, false); ED_update_for_newframe(bmain, depsgraph); } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index c04122edd36..a182dd662af 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -646,7 +646,7 @@ void ED_region_tag_redraw(ARegion *region) void ED_region_tag_redraw_cursor(ARegion *region) { if (region) { - region->do_draw_overlay = RGN_DRAW; + region->do_draw_paintcursor = RGN_DRAW; } } @@ -1145,7 +1145,7 @@ static void region_overlap_fix(ScrArea *area, ARegion *region) /* find overlapping previous region on same place */ for (ar1 = region->prev; ar1; ar1 = ar1->prev) { - if (ar1->flag & (RGN_FLAG_HIDDEN)) { + if (ar1->flag & RGN_FLAG_HIDDEN) { continue; } @@ -1194,7 +1194,7 @@ static void region_overlap_fix(ScrArea *area, ARegion *region) /* At this point, 'region' is in its final position and still open. * Make a final check it does not overlap any previous 'other side' region. */ for (ar1 = region->prev; ar1; ar1 = ar1->prev) { - if (ar1->flag & (RGN_FLAG_HIDDEN)) { + if (ar1->flag & RGN_FLAG_HIDDEN) { continue; } if (ELEM(ar1->alignment, RGN_ALIGN_FLOAT)) { @@ -1556,7 +1556,14 @@ static void region_rect_recursive( /* Tag for redraw if size changes. */ if (region->winx != prev_winx || region->winy != prev_winy) { - ED_region_tag_redraw(region); + /* 3D View needs a full rebuild in case a progressive render runs. Rest can live with + * no-rebuild (e.g. Outliner) */ + if (area->spacetype == SPACE_VIEW3D) { + ED_region_tag_redraw(region); + } + else { + ED_region_tag_redraw_no_rebuild(region); + } } /* Clear, initialize on demand. */ @@ -2348,9 +2355,9 @@ BLI_INLINE bool streq_array_any(const char *s, const char *arr[]) /** * Builds the panel layout for the input \a panel or type \a pt. * - * \param panel The panel to draw. Can be null, in which case a panel with the type of \a pt will - * be created. - * \param unique_panel_str A unique identifier for the name of the \a uiBlock associated with the + * \param panel: The panel to draw. Can be null, + * in which case a panel with the type of \a pt will be created. + * \param unique_panel_str: A unique identifier for the name of the \a uiBlock associated with the * panel. Used when the panel is an instanced panel so a unique identifier is needed to find the * correct old \a uiBlock, and NULL otherwise. */ @@ -2566,16 +2573,16 @@ void ED_region_panels_layout_ex(const bContext *C, /* only allow scrolling in vertical direction */ v2d->keepofs |= V2D_LOCKOFS_X | V2D_KEEPOFS_Y; v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X); - v2d->scroll &= ~(V2D_SCROLL_BOTTOM); - v2d->scroll |= (V2D_SCROLL_RIGHT); + v2d->scroll &= ~V2D_SCROLL_BOTTOM; + v2d->scroll |= V2D_SCROLL_RIGHT; } else { /* for now, allow scrolling in both directions (since layouts are optimized for vertical, * they often don't fit in horizontal layout) */ v2d->keepofs &= ~(V2D_LOCKOFS_X | V2D_LOCKOFS_Y | V2D_KEEPOFS_X | V2D_KEEPOFS_Y); - v2d->scroll |= (V2D_SCROLL_BOTTOM); - v2d->scroll &= ~(V2D_SCROLL_RIGHT); + v2d->scroll |= V2D_SCROLL_BOTTOM; + v2d->scroll &= ~V2D_SCROLL_RIGHT; } /* collect categories */ @@ -2788,9 +2795,7 @@ void ED_region_panels_draw(const bContext *C, ARegion *region) mask_buf.xmax -= UI_PANEL_CATEGORY_MARGIN_WIDTH; mask = &mask_buf; } - View2DScrollers *scrollers = UI_view2d_scrollers_calc(v2d, mask); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, mask); } void ED_region_panels_ex( diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 6f004238522..b6f210d7f13 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1331,6 +1331,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const oldscreen->animtimer = NULL; ED_screen_change(C, screen); + ED_area_tag_refresh(fullsa); BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index b2243f2ccb9..5de8ccd404d 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -366,19 +366,20 @@ bool ED_operator_object_active_editable_mesh(bContext *C) { Object *ob = ED_object_active_context(C); return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob) && (ob->type == OB_MESH) && - !ID_IS_LINKED(ob->data)); + !ID_IS_LINKED(ob->data) && !ID_IS_OVERRIDE_LIBRARY(ob->data)); } bool ED_operator_object_active_editable_font(bContext *C) { Object *ob = ED_object_active_context(C); - return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob) && (ob->type == OB_FONT)); + return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob) && (ob->type == OB_FONT) && + !ID_IS_LINKED(ob->data) && !ID_IS_OVERRIDE_LIBRARY(ob->data)); } bool ED_operator_editable_mesh(bContext *C) { Mesh *mesh = ED_mesh_context(C); - return (mesh != NULL) && !ID_IS_LINKED(mesh); + return (mesh != NULL) && !ID_IS_LINKED(mesh) && !ID_IS_OVERRIDE_LIBRARY(mesh); } bool ED_operator_editmesh(bContext *C) @@ -1761,7 +1762,7 @@ static void area_move_apply_do(const bContext *C, screen->do_refresh = true; redraw_all = true; } - ED_area_tag_redraw(area); + ED_area_tag_redraw_no_rebuild(area); } } if (redraw_all) { @@ -4273,68 +4274,67 @@ static void SCREEN_OT_region_context_menu(wmOperatorType *ot) * * Animation Step. * \{ */ +static bool screen_animation_region_supports_time_follow(eSpace_Type spacetype, + eRegionType regiontype) +{ + return (regiontype == RGN_TYPE_WINDOW && + ELEM(spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) || + (spacetype == SPACE_CLIP && regiontype == RGN_TYPE_PREVIEW); +} -static int match_region_with_redraws(int spacetype, - int regiontype, - int redraws, - bool from_anim_edit) +static bool match_region_with_redraws(const ScrArea *area, + eRegionType regiontype, + eScreen_Redraws_Flag redraws, + bool from_anim_edit) { + const eSpace_Type spacetype = area->spacetype; if (regiontype == RGN_TYPE_WINDOW) { switch (spacetype) { case SPACE_VIEW3D: if ((redraws & TIME_ALL_3D_WIN) || from_anim_edit) { - return 1; + return true; } break; case SPACE_GRAPH: case SPACE_NLA: if ((redraws & TIME_ALL_ANIM_WIN) || from_anim_edit) { - return 1; + return true; } break; case SPACE_ACTION: /* if only 1 window or 3d windows, we do timeline too * NOTE: Now we do action editor in all these cases, since timeline is here. */ if ((redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN)) || from_anim_edit) { - return 1; + return true; } break; case SPACE_PROPERTIES: if (redraws & TIME_ALL_BUTS_WIN) { - return 1; + return true; } break; case SPACE_SEQ: if ((redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) || from_anim_edit) { - return 1; + return true; } break; case SPACE_NODE: - if (redraws & (TIME_NODES)) { - return 1; + if (redraws & TIME_NODES) { + return true; } break; case SPACE_IMAGE: if ((redraws & TIME_ALL_IMAGE_WIN) || from_anim_edit) { - return 1; + return true; } break; case SPACE_CLIP: if ((redraws & TIME_CLIPS) || from_anim_edit) { - return 1; + return true; } break; - } - } - else if (regiontype == RGN_TYPE_CHANNELS) { - switch (spacetype) { - case SPACE_GRAPH: - case SPACE_ACTION: - case SPACE_NLA: - if (redraws & TIME_ALL_ANIM_WIN) { - return 1; - } + default: break; } } @@ -4345,30 +4345,68 @@ static int match_region_with_redraws(int spacetype, * during playback, so asking people to enable special option * for this is a bit tricky, so add exception here for refreshing * Properties Editor for SpaceClip always */ - return 1; + return true; } if (redraws & TIME_ALL_BUTS_WIN) { - return 1; + return true; } } - else if (ELEM(regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) { + else if (regiontype == RGN_TYPE_HEADER) { if (spacetype == SPACE_ACTION) { - return 1; + /* The timeline shows the current frame in the header. Other headers + * don't need to be updated. */ + SpaceAction *saction = (SpaceAction *)area->spacedata.first; + return saction->mode == SACTCONT_TIMELINE; } } else if (regiontype == RGN_TYPE_PREVIEW) { switch (spacetype) { case SPACE_SEQ: if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) { - return 1; + return true; } break; case SPACE_CLIP: - return 1; + return true; + default: + break; } } - return 0; + return false; +} + +static void screen_animation_region_tag_redraw(ScrArea *area, + ARegion *region, + const Scene *scene, + eScreen_Redraws_Flag redraws) +{ + /* Do follow time here if editor type supports it */ + if ((redraws & TIME_FOLLOW) && + (screen_animation_region_supports_time_follow(area->spacetype, region->regiontype))) { + float w = BLI_rctf_size_x(®ion->v2d.cur); + if (scene->r.cfra < region->v2d.cur.xmin) { + region->v2d.cur.xmax = scene->r.cfra; + region->v2d.cur.xmin = region->v2d.cur.xmax - w; + ED_region_tag_redraw(region); + return; + } + else if (scene->r.cfra > region->v2d.cur.xmax) { + region->v2d.cur.xmin = scene->r.cfra; + region->v2d.cur.xmax = region->v2d.cur.xmin + w; + ED_region_tag_redraw(region); + return; + } + } + + /* No need to do a full redraw as the current frame indicator is only updated. + * We do need to redraw when this area is in full screen as no other areas + * will be tagged for redrawing. */ + if ((region->regiontype == RGN_TYPE_WINDOW) && + (ELEM(area->spacetype, SPACE_GRAPH, SPACE_NLA, SPACE_ACTION, SPACE_SEQ)) && !area->full) { + return; + } + ED_region_tag_redraw(region); } //#define PROFILE_AUDIO_SYNCH @@ -4409,7 +4447,8 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv } if (scene_eval == NULL) { - /* Happens when undo/redo system is used during playback, nothing meaningful we can do here. + /* Happens when undo/redo system is used during playback, nothing meaningful we can do + * here. */ } else if (scene_eval->id.recalc & ID_RECALC_AUDIO_SEEK) { @@ -4549,28 +4588,12 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv redraw = true; } else if (match_region_with_redraws( - area->spacetype, region->regiontype, sad->redraws, sad->from_anim_edit)) { + area, region->regiontype, sad->redraws, sad->from_anim_edit)) { redraw = true; } if (redraw) { - ED_region_tag_redraw(region); - /* do follow here if editor type supports it */ - if ((sad->redraws & TIME_FOLLOW)) { - if ((region->regiontype == RGN_TYPE_WINDOW && - ELEM(area->spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) || - (area->spacetype == SPACE_CLIP && region->regiontype == RGN_TYPE_PREVIEW)) { - float w = BLI_rctf_size_x(®ion->v2d.cur); - if (scene->r.cfra < region->v2d.cur.xmin) { - region->v2d.cur.xmax = scene->r.cfra; - region->v2d.cur.xmin = region->v2d.cur.xmax - w; - } - else if (scene->r.cfra > region->v2d.cur.xmax) { - region->v2d.cur.xmin = scene->r.cfra; - region->v2d.cur.xmax = region->v2d.cur.xmin + w; - } - } - } + screen_animation_region_tag_redraw(area, region, scene, sad->redraws); } } } diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c index 7ce92bc3e4d..0af81e0db21 100644 --- a/source/blender/editors/screen/workspace_layout_edit.c +++ b/source/blender/editors/screen/workspace_layout_edit.c @@ -38,7 +38,7 @@ #include "screen_intern.h" /** - * Empty screen, with 1 dummy area without spacedata. Uses window size. + * Empty screen, with 1 dummy area without space-data. Uses window size. */ WorkSpaceLayout *ED_workspace_layout_add(Main *bmain, WorkSpace *workspace, diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index b8754953741..ed87d524627 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -64,10 +64,12 @@ set(SRC sculpt_detail.c sculpt_dyntopo.c sculpt_face_set.c + sculpt_filter_color.c sculpt_filter_mask.c sculpt_filter_mesh.c sculpt_mask_expand.c sculpt_multiplane_scrape.c + sculpt_paint_color.c sculpt_pose.c sculpt_smooth.c sculpt_transform.c diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 4222a466a7b..1291de04634 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1441,7 +1441,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) * cursor won't be tagged to update, so always initialize the preview chain if it is * null before drawing it. */ if (update_previews || !ss->pose_ik_chain_preview) { - BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false); + BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false, false); /* Free the previous pose brush preview. */ if (ss->pose_ik_chain_preview) { diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 08af3bdd16c..7f64fdf3501 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -1301,7 +1301,7 @@ static bool brush_colors_flip_poll(bContext *C) else { Object *ob = CTX_data_active_object(C); if (ob != NULL) { - if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) { + if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT | OB_MODE_SCULPT)) { return true; } } diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 5e3204b6d5a..dfb8f03fa6e 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -811,7 +811,7 @@ static bool project_paint_PickColor( } /** - * Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusion test) + * Check if 'pt' is in front of the 3 verts on the Z axis (used for screen-space occlusion test) * \return * - `0`: no occlusion * - `-1`: no occlusion but 2D intersection is true @@ -836,7 +836,7 @@ static int project_paint_occlude_ptv(const float pt[3], } /* From here on we know there IS an intersection */ - /* if ALL of the verts are infront of us then we know it intersects ? */ + /* if ALL of the verts are in front of us then we know it intersects ? */ if (v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) { return 1; } diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index c32e496f4f5..6e0402fc6e0 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -146,12 +146,11 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) PBVHNode **nodes; int totnode; bool multires; - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; mode = RNA_enum_get(op->ptr, "mode"); value = RNA_float_get(op->ptr, "value"); - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false); pbvh = ob->sculpt->pbvh; multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); @@ -169,7 +168,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings); if (multires) { @@ -313,7 +312,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * /* Transform the clip planes in object space. */ ED_view3d_clipping_calc(&bb, clip_planes, vc->region, vc->obact, rect); - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false); pbvh = ob->sculpt->pbvh; multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); @@ -344,7 +343,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); if (nodes) { @@ -500,7 +499,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) ED_view3d_clipping_calc(&bb, clip_planes, vc.region, vc.obact, &data.rect); - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false); pbvh = ob->sculpt->pbvh; multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); @@ -533,7 +532,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.task_data.value = value; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); if (nodes) { diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 0f54d5e0821..191ae1da343 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -304,7 +304,10 @@ static bool palette_extract_img_poll(bContext *C) { SpaceLink *sl = CTX_wm_space_data(C); if ((sl != NULL) && (sl->spacetype == SPACE_IMAGE)) { - return true; + SpaceImage *sima = CTX_wm_space_image(C); + Image *image = sima->image; + ImageUser iuser = sima->iuser; + return BKE_image_has_ibuf(image, &iuser); } return false; @@ -326,16 +329,16 @@ static int palette_extract_img_exec(bContext *C, wmOperator *op) ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); - if (ibuf->rect) { + if (ibuf && ibuf->rect) { /* Extract all colors. */ + const int range = (int)pow(10.0f, threshold); for (int row = 0; row < ibuf->y; row++) { for (int col = 0; col < ibuf->x; col++) { float color[4]; IMB_sampleImageAtLocation(ibuf, (float)col, (float)row, false, color); - const float range = pow(10.0f, threshold); - color[0] = truncf(color[0] * range) / range; - color[1] = truncf(color[1] * range) / range; - color[2] = truncf(color[2] * range) / range; + for (int i = 0; i < 3; i++) { + color[i] = truncf(color[i] * range) / range; + } uint key = rgb_to_cpack(color[0], color[1], color[2]); if (!BLI_ghash_haskey(color_table, POINTER_FROM_INT(key))) { @@ -360,6 +363,8 @@ static int palette_extract_img_exec(bContext *C, wmOperator *op) static void PALETTE_OT_extract_from_image(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Extract Palette from Image"; ot->idname = "PALETTE_OT_extract_from_image"; @@ -373,7 +378,8 @@ static void PALETTE_OT_extract_from_image(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_int(ot->srna, "threshold", 1, 1, 4, "Threshold", "", 1, 4); + prop = RNA_def_int(ot->srna, "threshold", 1, 1, 1, "Threshold", "", 1, 1); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /* Sort Palette color by Hue and Saturation. */ diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 2c6f708d82a..447d5373a48 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -909,7 +909,7 @@ PaintStroke *paint_stroke_new(bContext *C, stroke->zoom_2d = max_ff(zoomx, zoomy); if (stroke->stroke_mode == BRUSH_STROKE_INVERT) { - if (br->flag & (BRUSH_CURVE)) { + if (br->flag & BRUSH_CURVE) { RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL); } } @@ -1467,8 +1467,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) } else if (first_modal || /* regular dabs */ - (!(br->flag & (BRUSH_AIRBRUSH)) && - (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) || + (!(br->flag & BRUSH_AIRBRUSH) && (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) || /* airbrush */ ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer)) { diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 6de54b3ae6a..7ac778630ac 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1101,12 +1101,12 @@ static void vertex_paint_init_session(Depsgraph *depsgraph, BLI_assert(ob->sculpt == NULL); ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); ob->sculpt->mode_type = object_mode; - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); } static void vertex_paint_init_stroke(Depsgraph *depsgraph, Object *ob) { - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); } static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob) @@ -1425,10 +1425,10 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) } } - /* Weightpaint works by overriding colors in mesh, - * so need to make sure we recalc on enter and + /* Weight-paint works by overriding colors in mesh, + * so need to make sure we recalculate on enter and * exit (exit needs doing regardless because we - * should redeform). + * should re-deform). */ DEG_id_tag_update(&me->id, 0); @@ -2171,7 +2171,7 @@ static void calculate_average_weight(SculptThreadedTaskData *data, data->custom_data = accum; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings); uint accum_len = 0; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 75c88047914..fb7ae4d017d 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -30,6 +30,7 @@ #include "BLI_gsqueue.h" #include "BLI_hash.h" #include "BLI_math.h" +#include "BLI_math_color_blend.h" #include "BLI_task.h" #include "BLI_utildefines.h" @@ -73,6 +74,8 @@ #include "DEG_depsgraph.h" +#include "IMB_colormanagement.h" + #include "WM_api.h" #include "WM_message.h" #include "WM_toolsystem.h" @@ -153,6 +156,21 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index) return NULL; } +const float *SCULPT_vertex_color_get(SculptSession *ss, int index) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + if (ss->vcol) { + return ss->vcol[index].color; + } + break; + case PBVH_BMESH: + case PBVH_GRIDS: + break; + } + return NULL; +} + void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]) { switch (BKE_pbvh_type(ss->pbvh)) { @@ -180,6 +198,23 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]) } } +static const float *sculpt_vertex_persistent_co_get(SculptSession *ss, int index) +{ + if (ss->persistent_base) { + return ss->persistent_base[index].co; + } + return SCULPT_vertex_co_get(ss, index); +} + +static void sculpt_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]) +{ + if (ss->persistent_base) { + copy_v3_v3(no, ss->persistent_base[index].no); + return; + } + SCULPT_vertex_normal_get(ss, index, no); +} + float SCULPT_vertex_mask_get(SculptSession *ss, int index) { BMVert *v; @@ -633,6 +668,13 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, } } } + + if (ss->fake_neighbors.use_fake_neighbors) { + BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); + if (ss->fake_neighbors.fake_neighbor_index[index] != FAKE_NEIGHBOR_NONE) { + sculpt_vertex_neighbor_add(iter, ss->fake_neighbors.fake_neighbor_index[index]); + } + } } static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, @@ -665,6 +707,13 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x); } + if (ss->fake_neighbors.use_fake_neighbors) { + BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); + if (ss->fake_neighbors.fake_neighbor_index[index] != FAKE_NEIGHBOR_NONE) { + sculpt_vertex_neighbor_add(iter, ss->fake_neighbors.fake_neighbor_index[index]); + } + } + if (neighbors.coords != neighbors.coords_fixed) { MEM_freeN(neighbors.coords); } @@ -821,7 +870,7 @@ int SCULPT_nearest_vertex_get( nvtd.nearest_vertex_distance_squared = FLT_MAX; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); settings.func_reduce = nearest_vertex_get_reduce; settings.userdata_chunk = &nvtd; settings.userdata_chunk_size = sizeof(NearestVertexTLSData); @@ -998,6 +1047,8 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool) SCULPT_TOOL_LAYER, SCULPT_TOOL_POSE, SCULPT_TOOL_CLOTH, + SCULPT_TOOL_PAINT, + SCULPT_TOOL_SMEAR, SCULPT_TOOL_DRAW_FACE_SETS); } @@ -1045,9 +1096,7 @@ typedef enum StrokeFlags { /* Initialize a SculptOrigVertData for accessing original vertex data; * handles BMesh, mesh, and multires. */ -static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data, - Object *ob, - SculptUndoNode *unode) +void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, SculptUndoNode *unode) { SculptSession *ss = ob->sculpt; BMesh *bm = ss->bm; @@ -1062,6 +1111,7 @@ static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data, data->coords = data->unode->co; data->normals = data->unode->no; data->vmasks = data->unode->mask; + data->colors = data->unode->col; } } @@ -1071,7 +1121,7 @@ void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode * { SculptUndoNode *unode; unode = SCULPT_undo_push_node(ob, node, SCULPT_UNDO_COORDS); - sculpt_orig_vert_data_unode_init(data, ob, unode); + SCULPT_orig_vert_data_unode_init(data, ob, unode); } /* Update a SculptOrigVertData for a particular vertex from the PBVH @@ -1087,6 +1137,9 @@ void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter orig_data->no = orig_data->normals[iter->i]; } } + else if (orig_data->unode->type == SCULPT_UNDO_COLOR) { + orig_data->col = orig_data->colors[iter->i]; + } else if (orig_data->unode->type == SCULPT_UNDO_MASK) { if (orig_data->bm_log) { orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert); @@ -1247,7 +1300,7 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata, PBVHVertexIter vd; SculptOrigVertData orig_data; - sculpt_orig_vert_data_unode_init(&orig_data, data->ob, unode); + SCULPT_orig_vert_data_unode_init(&orig_data, data->ob, unode); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -1265,6 +1318,9 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata, else if (orig_data.unode->type == SCULPT_UNDO_MASK) { *vd.mask = orig_data.mask; } + else if (orig_data.unode->type == SCULPT_UNDO_COLOR) { + copy_v4_v4(vd.col, orig_data.col); + } if (vd.mvert) { vd.mvert->flag |= ME_VERT_PBVH_UPDATE; @@ -1288,7 +1344,7 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) /** * Disable OpenMP when dynamic-topology is enabled. Otherwise, new entries might be inserted by - * #sculpt_undo_push_node() into the GHash used internally by #BM_log_original_vert_co() + * #SCULPT_undo_push_node() into the #GHash used internally by #BM_log_original_vert_co() * by a different thread. See T33787. */ SculptThreadedTaskData data = { .sd = sd, @@ -1298,9 +1354,11 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode); + BKE_pbvh_parallel_range_settings(&settings, true && !ss->bm, totnode); BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); + BKE_pbvh_node_color_buffer_free(ss->pbvh); + MEM_SAFE_FREE(nodes); } @@ -1478,6 +1536,9 @@ bool SCULPT_brush_test_cube(SculptBrushTest *test, { float side = M_SQRT1_2; float local_co[3]; + float i_local[4][4]; + + invert_m4_m4(i_local, local); if (sculpt_brush_test_clipping(test, co)) { return false; @@ -1924,7 +1985,7 @@ static void calc_area_center( AreaNormalCenterTLSData anctd = {{{0}}}; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); @@ -1953,8 +2014,7 @@ void SCULPT_calc_area_normal( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]) { const Brush *brush = BKE_paint_brush(&sd->paint); - bool use_threading = (sd->flags & SCULPT_USE_OPENMP); - SCULPT_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no); + SCULPT_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, r_area_no); } /* Expose 'calc_area_normal' externally. */ @@ -2024,7 +2084,7 @@ static void calc_area_normal_and_center( AreaNormalCenterTLSData anctd = {{{0}}}; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); @@ -2116,6 +2176,11 @@ static float brush_strength(const Sculpt *sd, return alpha * pressure * overlap * feather; case SCULPT_TOOL_SLIDE_RELAX: return alpha * pressure * overlap * feather * 2.0f; + case SCULPT_TOOL_PAINT: + final_pressure = pressure * pressure; + return final_pressure * overlap * feather; + case SCULPT_TOOL_SMEAR: + return pressure * overlap * feather; case SCULPT_TOOL_CLAY_STRIPS: /* Clay Strips needs less strength to compensate the curve. */ final_pressure = powf(pressure, 1.5f); @@ -2577,11 +2642,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob) } } -/* Note: uses after-struct allocated mem to store actual cache... */ -typedef struct SculptDoBrushSmoothGridDataChunk { - size_t tmpgrid_size; -} SculptDoBrushSmoothGridDataChunk; - typedef struct { SculptSession *ss; const float *ray_start; @@ -2689,7 +2749,7 @@ static void bmesh_topology_rake( .strength = factor, }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); } @@ -2746,7 +2806,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); } @@ -2834,7 +2894,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); } @@ -2911,7 +2971,7 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); } @@ -3098,7 +3158,7 @@ static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); if (ss->cache->alt_smooth) { for (int i = 0; i < 4; i++) { BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); @@ -3308,7 +3368,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); } @@ -3422,7 +3482,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); } @@ -3495,7 +3555,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); } @@ -3604,7 +3664,7 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); } @@ -3811,7 +3871,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); } @@ -3933,7 +3993,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); } @@ -4006,7 +4066,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); } @@ -4080,7 +4140,7 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); } @@ -4093,7 +4153,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, Sculpt *sd = data->sd; const Brush *brush = data->brush; - const bool use_persistent_base = ss->layer_base && brush->flag & BRUSH_PERSISTENT; + const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT; PBVHVertexIter vd; SculptOrigVertData orig_data; @@ -4123,7 +4183,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, const int vi = vd.index; float *disp_factor; if (use_persistent_base) { - disp_factor = &ss->layer_base[vi].disp; + disp_factor = &ss->persistent_base[vi].disp; } else { disp_factor = &ss->cache->layer_displacement_factor[vi]; @@ -4153,9 +4213,9 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, float normal[3]; if (use_persistent_base) { - copy_v3_v3(normal, ss->layer_base[vi].no); + sculpt_vertex_persistent_normal_get(ss, vi, normal); mul_v3_fl(normal, brush->height); - madd_v3_v3v3fl(final_co, ss->layer_base[vi].co, normal, *disp_factor); + madd_v3_v3v3fl(final_co, sculpt_vertex_persistent_co_get(ss, vi), normal, *disp_factor); } else { normal_short_to_float_v3(normal, orig_data.no); @@ -4196,7 +4256,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); } @@ -4263,7 +4323,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); } @@ -4388,7 +4448,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); } @@ -4539,7 +4599,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) ClaySampleData csd = {{0}}; TaskParallelSettings sample_settings; - BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode); sample_settings.func_reduce = calc_clay_surface_reduce; sample_settings.userdata_chunk = &csd; sample_settings.userdata_chunk_size = sizeof(ClaySampleData); @@ -4570,7 +4630,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); } @@ -4677,6 +4737,17 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t mul_v3_fl(temp, displace); add_v3_v3(area_co, temp); + /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the + * vertices. When in Add mode, vertices that are below the plane and inside the cube are move + * towards the plane. In this situation, there may be cases where a vertex is outside the cube + * but below the plane, so won't be deformed, causing artifacts. In order to prevent these + * artifacts, this displaces the test cube space in relation to the plane in order to + * deform more vertices that may be below it. */ + /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set + * by doing multiple tests using the default "Clay Strips" brush preset. */ + float area_co_displaced[3]; + madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f); + /* Init brush local space matrix. */ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); mat[0][3] = 0.0f; @@ -4684,13 +4755,19 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t mat[1][3] = 0.0f; copy_v3_v3(mat[2], area_no); mat[2][3] = 0.0f; - copy_v3_v3(mat[3], ss->cache->location); + copy_v3_v3(mat[3], area_co_displaced); mat[3][3] = 1.0f; normalize_m4(mat); /* Scale brush local space matrix. */ scale_m4_fl(scale, ss->cache->radius); mul_m4_m4m4(tmat, mat, scale); + + /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in + * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices + * during big deformation while keeping the surface as uniform as possible. */ + mul_v3_fl(tmat[2], 1.25f); + invert_m4_m4(mat, tmat); SculptThreadedTaskData data = { @@ -4704,7 +4781,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); } @@ -4798,7 +4875,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); } @@ -4891,7 +4968,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); } @@ -5064,7 +5141,7 @@ static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings); } @@ -5136,7 +5213,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings); } @@ -5255,23 +5332,23 @@ static void do_brush_action_task_cb(void *__restrict userdata, /* Face Sets modifications do a single undo push */ if (data->brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) { + BKE_pbvh_node_mark_redraw(data->nodes[n]); /* Draw face sets in smooth mode moves the vertices. */ if (ss->cache->alt_smooth) { SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS); BKE_pbvh_node_mark_update(data->nodes[n]); } } - else { - SCULPT_undo_push_node(data->ob, - data->nodes[n], - data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : - SCULPT_UNDO_COORDS); - } - - if (data->brush->sculpt_tool == SCULPT_TOOL_MASK) { + else if (data->brush->sculpt_tool == SCULPT_TOOL_MASK) { + SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK); BKE_pbvh_node_mark_update_mask(data->nodes[n]); } + else if (ELEM(data->brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) { + SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COLOR); + BKE_pbvh_node_mark_update_color(data->nodes[n]); + } else { + SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS); BKE_pbvh_node_mark_update(data->nodes[n]); } } @@ -5282,7 +5359,17 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe int totnode; PBVHNode **nodes; - /* Build a list of all nodes that are potentially within the brush's area of influence. */ + /* Check for unsupported features. */ + PBVHType type = BKE_pbvh_type(ss->pbvh); + if (brush->sculpt_tool == SCULPT_TOOL_PAINT && type != PBVH_FACES) { + return; + } + + if (brush->sculpt_tool == SCULPT_TOOL_SMEAR && type != PBVH_FACES) { + return; + } + + /* Build a list of all nodes that are potentially within the brush's area of influence */ /* These brushes need to update all nodes as they are not constrained by the brush radius */ /* Elastic deform needs all nodes to avoid artifacts as the effect of the brush is not @@ -5322,7 +5409,14 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe * and the number of nodes under the brush influence. */ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS && ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0 && !ss->cache->alt_smooth) { - SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_FACE_SETS); + + /* Dyntopo does not support Face Sets data, so it can't store/restore it from undo. */ + /* TODO (pablodp606): This check should be done in the undo code and not here, but the rest of + * the sculpt code is not checking for unsupported undo types that may return a null node. */ + if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) { + SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_FACE_SETS); + } + if (ss->cache->invert) { /* When inverting the brush, pick the paint face mask ID from the mesh. */ ss->cache->paint_face_set = SCULPT_active_face_set_get(ss); @@ -5345,7 +5439,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); if (sculpt_brush_needs_normal(ss, brush)) { @@ -5464,6 +5558,12 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe case SCULPT_TOOL_DRAW_FACE_SETS: SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode); break; + case SCULPT_TOOL_PAINT: + SCULPT_do_paint_brush(sd, ob, nodes, totnode); + break; + case SCULPT_TOOL_SMEAR: + SCULPT_do_smear_brush(sd, ob, nodes, totnode); + break; } if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_MASK) && @@ -5602,7 +5702,7 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); } @@ -5690,7 +5790,7 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, SCULPT_flush_stroke_deform_task_cb, &settings); if (vertCos) { @@ -5991,6 +6091,10 @@ static const char *sculpt_tool_name(Sculpt *sd) return "Cloth Brush"; case SCULPT_TOOL_DRAW_FACE_SETS: return "Draw Face Sets"; + case SCULPT_TOOL_PAINT: + return "Paint Brush"; + case SCULPT_TOOL_SMEAR: + return "Smear Brush"; } return "Sculpting"; @@ -6005,6 +6109,7 @@ void SCULPT_cache_free(StrokeCache *cache) MEM_SAFE_FREE(cache->dial); MEM_SAFE_FREE(cache->surface_smooth_laplacian_disp); MEM_SAFE_FREE(cache->layer_displacement_factor); + MEM_SAFE_FREE(cache->prev_colors); if (cache->pose_ik_chain) { SCULPT_pose_ik_chain_free(cache->pose_ik_chain); @@ -6119,7 +6224,11 @@ static void sculpt_update_cache_invariants( cache->saved_mask_brush_tool = brush->mask_tool; brush->mask_tool = BRUSH_MASK_SMOOTH; } - else if (ELEM(brush->sculpt_tool, SCULPT_TOOL_SLIDE_RELAX, SCULPT_TOOL_DRAW_FACE_SETS)) { + else if (ELEM(brush->sculpt_tool, + SCULPT_TOOL_SLIDE_RELAX, + SCULPT_TOOL_DRAW_FACE_SETS, + SCULPT_TOOL_PAINT, + SCULPT_TOOL_SMEAR)) { /* Do nothing, this tool has its own smooth mode. */ } else { @@ -6266,6 +6375,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru int tool = brush->sculpt_tool; if (ELEM(tool, + SCULPT_TOOL_PAINT, SCULPT_TOOL_GRAB, SCULPT_TOOL_ELASTIC_DEFORM, SCULPT_TOOL_CLOTH, @@ -6519,7 +6629,7 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd, ((brush->sculpt_tool == SCULPT_TOOL_MASK) && (brush->mask_tool == BRUSH_MASK_SMOOTH)) || (brush->sculpt_tool == SCULPT_TOOL_POSE) || (brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) || - (brush->sculpt_tool == SCULPT_TOOL_CLOTH) || + (brush->sculpt_tool == SCULPT_TOOL_CLOTH) || (brush->sculpt_tool == SCULPT_TOOL_SMEAR) || (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS)); } @@ -6533,7 +6643,7 @@ void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *b if (ss->shapekey_active || ss->deform_modifiers_active || (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, false, false); } } @@ -6877,7 +6987,7 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op) SculptSession *ss = CTX_data_active_object(C)->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); int mode = RNA_enum_get(op->ptr, "mode"); - bool is_smooth; + bool is_smooth, needs_colors; bool need_mask = false; if (brush->sculpt_tool == SCULPT_TOOL_MASK) { @@ -6892,7 +7002,8 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op) sculpt_brush_init_tex(scene, sd, ss); is_smooth = sculpt_needs_connectivity_info(sd, brush, ss, mode); - BKE_sculpt_update_object_for_edit(depsgraph, ob, is_smooth, need_mask); + needs_colors = ELEM(brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR); + BKE_sculpt_update_object_for_edit(depsgraph, ob, is_smooth, need_mask, needs_colors); } static void sculpt_restore_mesh(Sculpt *sd, Object *ob) @@ -7035,12 +7146,19 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up if (update_flags & SCULPT_UPDATE_COORDS) { BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB); + + /* Coordinates were modified, so fake neighbors are not longer valid. */ + SCULPT_fake_neighbors_free(ob); } if (update_flags & SCULPT_UPDATE_MASK) { BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); } + if (update_flags & SCULPT_UPDATE_COLOR) { + BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateColor); + } + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { BKE_pbvh_bmesh_after_stroke(ss->pbvh); } @@ -7155,6 +7273,9 @@ static void sculpt_stroke_update_step(bContext *C, if (brush->sculpt_tool == SCULPT_TOOL_MASK) { SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK); } + else if (ELEM(brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) { + SCULPT_flush_update_step(C, SCULPT_UPDATE_COLOR); + } else { SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS); } @@ -7192,7 +7313,11 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str if (brush->sculpt_tool == SCULPT_TOOL_MASK) { brush->mask_tool = ss->cache->saved_mask_brush_tool; } - else if (ELEM(brush->sculpt_tool, SCULPT_TOOL_SLIDE_RELAX, SCULPT_TOOL_DRAW_FACE_SETS)) { + else if (ELEM(brush->sculpt_tool, + SCULPT_TOOL_SLIDE_RELAX, + SCULPT_TOOL_DRAW_FACE_SETS, + SCULPT_TOOL_PAINT, + SCULPT_TOOL_SMEAR)) { /* Do nothing. */ } else { @@ -7208,6 +7333,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str SCULPT_automasking_end(ob); } + BKE_pbvh_node_color_buffer_free(ss->pbvh); SCULPT_cache_free(ss->cache); ss->cache = NULL; @@ -7346,18 +7472,18 @@ static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op)) if (ss) { SCULPT_vertex_random_access_init(ss); - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); - MEM_SAFE_FREE(ss->layer_base); + MEM_SAFE_FREE(ss->persistent_base); const int totvert = SCULPT_vertex_count_get(ss); - ss->layer_base = MEM_mallocN(sizeof(SculptLayerPersistentBase) * totvert, - "layer persistent base"); + ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert, + "layer persistent base"); for (int i = 0; i < totvert; i++) { - copy_v3_v3(ss->layer_base[i].co, SCULPT_vertex_co_get(ss, i)); - SCULPT_vertex_normal_get(ss, i, ss->layer_base[i].no); - ss->layer_base[i].disp = 0.0f; + copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i)); + SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no); + ss->persistent_base[i].disp = 0.0f; } } @@ -7548,7 +7674,7 @@ static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob) ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); ob->sculpt->mode_type = OB_MODE_SCULPT; - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); /* Here we can detect geometry that was just added to Sculpt Mode as it has the * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */ @@ -7834,7 +7960,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float return; } - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); if (!ss->pmap) { return; @@ -7886,6 +8012,417 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float ss->preview_vert_index_count = totpoints; } +static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + + ID *data; + data = ob->data; + if (data && ID_IS_LINKED(data)) { + return OPERATOR_CANCELLED; + } + + if (ob->type != OB_MESH) { + return OPERATOR_CANCELLED; + } + + Mesh *mesh = ob->data; + + const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL); + if (mloopcol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n); + + const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); + if (MPropCol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); + + MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); + MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); + + for (int i = 0; i < mesh->totpoly; i++) { + MPoly *c_poly = &polys[i]; + for (int j = 0; j < c_poly->totloop; j++) { + int loop_index = c_poly->loopstart + j; + MLoop *c_loop = &loops[c_poly->loopstart + j]; + loopcols[loop_index].r = (char)(vertcols[c_loop->v].color[0] * 255); + loopcols[loop_index].g = (char)(vertcols[c_loop->v].color[1] * 255); + loopcols[loop_index].b = (char)(vertcols[c_loop->v].color[2] * 255); + loopcols[loop_index].a = (char)(vertcols[c_loop->v].color[3] * 255); + } + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Sculpt Vertex Color to Vertex Color"; + ot->description = "Copy the Sculpt Vertex Color to a regular color layer"; + ot->idname = "SCULPT_OT_vertex_to_loop_colors"; + + /* api callbacks */ + ot->poll = SCULPT_mode_poll; + ot->exec = vertex_to_loop_colors_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + + ID *data; + data = ob->data; + if (data && ID_IS_LINKED(data)) { + return OPERATOR_CANCELLED; + } + + if (ob->type != OB_MESH) { + return OPERATOR_CANCELLED; + } + + Mesh *mesh = ob->data; + + const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL); + if (mloopcol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n); + + const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); + if (MPropCol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); + + MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); + MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); + + for (int i = 0; i < mesh->totpoly; i++) { + MPoly *c_poly = &polys[i]; + for (int j = 0; j < c_poly->totloop; j++) { + int loop_index = c_poly->loopstart + j; + MLoop *c_loop = &loops[c_poly->loopstart + j]; + vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f); + vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f); + vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f); + vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f); + } + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Color to Sculpt Vertex Color"; + ot->description = "Copy the active loop color layer to the vertex color"; + ot->idname = "SCULPT_OT_loop_to_vertex_colors"; + + /* api callbacks */ + ot->poll = SCULPT_mode_poll; + ot->exec = loop_to_vertex_colors_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int sculpt_sample_color_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *UNUSED(e)) +{ + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Brush *brush = BKE_paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; + int active_vertex = SCULPT_active_vertex_get(ss); + const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex); + if (!active_vertex_color) { + return OPERATOR_CANCELLED; + } + + float color_srgb[3]; + copy_v3_v3(color_srgb, active_vertex_color); + IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb); + BKE_brush_color_set(scene, brush, color_srgb); + BKE_brush_alpha_set(scene, brush, active_vertex_color[3]); + + WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_sample_color(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Sample color"; + ot->idname = "SCULPT_OT_sample_color"; + ot->description = "Sample the vertex color of the active vertex"; + + /* api callbacks */ + ot->invoke = sculpt_sample_color_invoke; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER; +} + +/* Fake Neighbors. */ +/* This allows the sculpt tools to work on meshes with multiple connected components as they had + * only one connected component. When initialized and enabled, the sculpt API will return extra + * connectivity neighbors that are not in the real mesh. These neighbors are calculated for each + * vertex using the minimun distance to a vertex that is in a different connected component. */ + +/* The fake neighbors first need to be ensured to be initialized. + * After that tools which needs fake neighbors functionality need to + * temporarily enable it: + * + * void my_awesome_sculpt_tool() { + * SCULPT_fake_neighbors_ensure(sd, object, brush->disconnected_distance_max); + * SCULPT_fake_neighbors_enable(ob); + * + * ... Logic of the tool ... + * SCULPT_fake_neighbors_disable(ob); + * } + * + * Such approach allows to keep all the connectivity information ready for reuse + * (withouy having lag prior to every stroke), but also makes it so the affect + * is localized to a specific brushes and tools only. */ + +enum { + SCULPT_TOPOLOGY_ID_NONE, + SCULPT_TOPOLOGY_ID_DEFAULT, +}; + +static int SCULPT_vertex_get_connected_component(SculptSession *ss, int index) +{ + if (ss->vertex_info.connected_component) { + return ss->vertex_info.connected_component[index]; + } + return SCULPT_TOPOLOGY_ID_DEFAULT; +} + +static void SCULPT_fake_neighbor_init(SculptSession *ss, const float max_dist) +{ + const int totvert = SCULPT_vertex_count_get(ss); + ss->fake_neighbors.fake_neighbor_index = MEM_malloc_arrayN( + totvert, sizeof(int), "fake neighbor"); + for (int i = 0; i < totvert; i++) { + ss->fake_neighbors.fake_neighbor_index[i] = FAKE_NEIGHBOR_NONE; + } + + ss->fake_neighbors.current_max_distance = max_dist; +} + +static void SCULPT_fake_neighbor_add(SculptSession *ss, int v_index_a, int v_index_b) +{ + if (ss->fake_neighbors.fake_neighbor_index[v_index_a] == FAKE_NEIGHBOR_NONE) { + ss->fake_neighbors.fake_neighbor_index[v_index_a] = v_index_b; + ss->fake_neighbors.fake_neighbor_index[v_index_b] = v_index_a; + } +} + +static void sculpt_pose_fake_neighbors_free(SculptSession *ss) +{ + MEM_SAFE_FREE(ss->fake_neighbors.fake_neighbor_index); +} + +typedef struct NearestVertexFakeNeighborTLSData { + int nearest_vertex_index; + float nearest_vertex_distance_squared; + int current_topology_id; +} NearestVertexFakeNeighborTLSData; + +static void do_fake_neighbor_search_task_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + NearestVertexFakeNeighborTLSData *nvtd = tls->userdata_chunk; + PBVHVertexIter vd; + + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.index); + if (vd_topology_id != nvtd->current_topology_id && + ss->fake_neighbors.fake_neighbor_index[vd.index] == FAKE_NEIGHBOR_NONE) { + float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co); + if (distance_squared < nvtd->nearest_vertex_distance_squared && + distance_squared < data->max_distance_squared) { + nvtd->nearest_vertex_index = vd.index; + nvtd->nearest_vertex_distance_squared = distance_squared; + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void fake_neighbor_search_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + NearestVertexFakeNeighborTLSData *join = chunk_join; + NearestVertexFakeNeighborTLSData *nvtd = chunk; + if (join->nearest_vertex_index == -1) { + join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; + } + else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) { + join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; + } +} + +static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, float max_distance) +{ + SculptSession *ss = ob->sculpt; + PBVHNode **nodes = NULL; + int totnode; + SculptSearchSphereData data = { + .ss = ss, + .sd = sd, + .radius_squared = max_distance * max_distance, + .original = false, + .center = SCULPT_vertex_co_get(ss, index), + }; + BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); + + if (totnode == 0) { + return -1; + } + + SculptThreadedTaskData task_data = { + .sd = sd, + .ob = ob, + .nodes = nodes, + .max_distance_squared = max_distance * max_distance, + }; + + copy_v3_v3(task_data.nearest_vertex_search_co, SCULPT_vertex_co_get(ss, index)); + + NearestVertexFakeNeighborTLSData nvtd; + nvtd.nearest_vertex_index = -1; + nvtd.nearest_vertex_distance_squared = FLT_MAX; + nvtd.current_topology_id = SCULPT_vertex_get_connected_component(ss, index); + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + settings.func_reduce = fake_neighbor_search_reduce; + settings.userdata_chunk = &nvtd; + settings.userdata_chunk_size = sizeof(NearestVertexFakeNeighborTLSData); + BLI_task_parallel_range(0, totnode, &task_data, do_fake_neighbor_search_task_cb, &settings); + + MEM_SAFE_FREE(nodes); + + return nvtd.nearest_vertex_index; +} + +typedef struct SculptTopologyIDFloodFillData { + int next_id; +} SculptTopologyIDFloodFillData; + +static bool SCULPT_connected_components_floodfill_cb( + SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata) +{ + SculptTopologyIDFloodFillData *data = userdata; + ss->vertex_info.connected_component[from_v] = data->next_id; + ss->vertex_info.connected_component[to_v] = data->next_id; + return true; +} + +static void sculpt_connected_components_ensure(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + /* Topology IDs already initialized. They only need to be recalculated when the PBVH is rebuild. + */ + if (ss->vertex_info.connected_component) { + return; + } + + const int totvert = SCULPT_vertex_count_get(ss); + ss->vertex_info.connected_component = MEM_malloc_arrayN(totvert, sizeof(int), "topology ID"); + + for (int i = 0; i < totvert; i++) { + ss->vertex_info.connected_component[i] = SCULPT_TOPOLOGY_ID_NONE; + } + + int next_id = 0; + for (int i = 0; i < totvert; i++) { + if (ss->vertex_info.connected_component[i] == SCULPT_TOPOLOGY_ID_NONE) { + SculptFloodFill flood; + SCULPT_floodfill_init(ss, &flood); + SCULPT_floodfill_add_initial(&flood, i); + SculptTopologyIDFloodFillData data; + data.next_id = next_id; + SCULPT_floodfill_execute(ss, &flood, SCULPT_connected_components_floodfill_cb, &data); + SCULPT_floodfill_free(&flood); + next_id++; + } + } +} + +void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + + /* Fake neighbors were already initialized with the same distance, so no need to be recalculated. + */ + if (ss->fake_neighbors.fake_neighbor_index && + ss->fake_neighbors.current_max_distance == max_dist) { + return; + } + + sculpt_connected_components_ensure(ob); + SCULPT_fake_neighbor_init(ss, max_dist); + + for (int i = 0; i < totvert; i++) { + const int from_v = i; + + /* This vertex does not have a fake neighbor yet, seach one for it. */ + if (ss->fake_neighbors.fake_neighbor_index[from_v] == FAKE_NEIGHBOR_NONE) { + const int to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist); + if (to_v != -1) { + /* Add the fake neighbor if available. */ + SCULPT_fake_neighbor_add(ss, from_v, to_v); + } + } + } +} + +void SCULPT_fake_neighbors_enable(Object *ob) +{ + SculptSession *ss = ob->sculpt; + BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); + ss->fake_neighbors.use_fake_neighbors = true; +} + +void SCULPT_fake_neighbors_disable(Object *ob) +{ + SculptSession *ss = ob->sculpt; + BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); + ss->fake_neighbors.use_fake_neighbors = false; +} + +void SCULPT_fake_neighbors_free(Object *ob) +{ + SculptSession *ss = ob->sculpt; + sculpt_pose_fake_neighbors_free(ss); +} + void ED_operatortypes_sculpt(void) { WM_operatortype_append(SCULPT_OT_brush_stroke); @@ -7908,4 +8445,8 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_face_sets_init); WM_operatortype_append(SCULPT_OT_cloth_filter); WM_operatortype_append(SCULPT_OT_face_sets_edit); + WM_operatortype_append(SCULPT_OT_sample_color); + WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors); + WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors); + WM_operatortype_append(SCULPT_OT_color_filter); } diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index 7776af11a77..c821685e8b1 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -25,7 +25,7 @@ #include "BLI_blenlib.h" #include "BLI_dial_2d.h" -#include "BLI_ghash.h" +#include "BLI_edgehash.h" #include "BLI_gsqueue.h" #include "BLI_hash.h" #include "BLI_math.h" @@ -106,25 +106,11 @@ #define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024 #define CLOTH_SIMULATION_TIME_STEP 0.01f -static void cloth_brush_constraint_key_get(int r_key[2], const int v1, const int v2) -{ - if (v1 < v2) { - r_key[0] = v1; - r_key[1] = v2; - } - else { - r_key[0] = v2; - r_key[1] = v1; - } -} - static bool cloth_brush_sim_has_length_constraint(SculptClothSimulation *cloth_sim, const int v1, const int v2) { - int constraint[2]; - cloth_brush_constraint_key_get(constraint, v1, v2); - return BLI_gset_haskey(cloth_sim->created_length_constraints, constraint); + return BLI_edgeset_haskey(cloth_sim->created_length_constraints, v1, v2); } static void cloth_brush_add_length_constraint(SculptSession *ss, @@ -149,9 +135,7 @@ static void cloth_brush_add_length_constraint(SculptSession *ss, } /* Add the constraint to the GSet to avoid creating it again. */ - int constraint[2]; - cloth_brush_constraint_key_get(constraint, v1, v2); - BLI_gset_add(cloth_sim->created_length_constraints, constraint); + BLI_edgeset_add(cloth_sim->created_length_constraints, v1, v2); } static void do_cloth_brush_build_constraints_task_cb_ex( @@ -472,8 +456,7 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd, TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, false, totnode); - cloth_sim->created_length_constraints = BLI_gset_new( - BLI_ghashutil_inthash_v2_p, BLI_ghashutil_inthash_v2_cmp, "created length constraints"); + cloth_sim->created_length_constraints = BLI_edgeset_new("created length constraints"); SculptThreadedTaskData build_constraints_data = { .sd = sd, @@ -487,7 +470,7 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd, BLI_task_parallel_range( 0, totnode, &build_constraints_data, do_cloth_brush_build_constraints_task_cb_ex, &settings); - BLI_gset_free(cloth_sim->created_length_constraints, NULL); + BLI_edgeset_free(cloth_sim->created_length_constraints); } static void cloth_brush_satisfy_constraints(SculptSession *ss, @@ -564,7 +547,7 @@ static void cloth_brush_do_simulation_step( }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range( 0, totnode, &solve_simulation_data, do_cloth_brush_solve_simulation_task_cb_ex, &settings); } @@ -639,7 +622,7 @@ static void cloth_brush_apply_brush_foces(Sculpt *sd, Object *ob, PBVHNode **nod } TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range( 0, totnode, &apply_forces_data, do_cloth_brush_apply_forces_task_cb_ex, &settings); } @@ -873,7 +856,7 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent SCULPT_vertex_random_access_init(ss); - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); const int totverts = SCULPT_vertex_count_get(ss); for (int i = 0; i < totverts; i++) { @@ -889,8 +872,7 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings( - &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode); BLI_task_parallel_range( 0, ss->filter_cache->totnode, &data, cloth_filter_apply_forces_task_cb, &settings); @@ -922,10 +904,10 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent SCULPT_vertex_random_access_init(ss); /* Needs mask data to be available as it is used when solving the constraints. */ - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); SCULPT_undo_push_begin("Cloth filter"); - SCULPT_filter_cache_init(ob, sd); + SCULPT_filter_cache_init(ob, sd, SCULPT_UNDO_COORDS); const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass"); const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping"); diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index f071deaa219..463233fd6fb 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -181,7 +181,7 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my) /* Update the active vertex. */ float mouse[2] = {mx, my}; SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); /* Average the edge length of the connected edges to the active vertex. */ int active_vertex = SCULPT_active_vertex_get(ss); diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index 7bb54366204..031b4f8731d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -203,7 +203,7 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); if (ss->cache->alt_smooth) { for (int i = 0; i < 4; i++) { BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings); @@ -269,7 +269,7 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED, false); const int tot_vert = SCULPT_vertex_count_get(ss); float threshold = 0.5f; @@ -630,7 +630,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); PBVH *pbvh = ob->sculpt->pbvh; PBVHNode **nodes; @@ -787,7 +787,7 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); const int tot_vert = SCULPT_vertex_count_get(ss); const int mode = RNA_enum_get(op->ptr, "mode"); @@ -1083,7 +1083,7 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven return OPERATOR_CANCELLED; } - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); PBVH *pbvh = ob->sculpt->pbvh; PBVHNode **nodes; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c new file mode 100644 index 00000000000..5f7805af347 --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -0,0 +1,323 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_hash.h" +#include "BLI_math.h" +#include "BLI_math_color_blend.h" +#include "BLI_task.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_brush.h" +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" +#include "BKE_scene.h" + +#include "IMB_colormanagement.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" +#include "WM_message.h" +#include "WM_toolsystem.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_sculpt.h" +#include "paint_intern.h" +#include "sculpt_intern.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" + +#include "bmesh.h" + +#include <math.h> +#include <stdlib.h> + +typedef enum eSculptColorFilterTypes { + COLOR_FILTER_FILL, + COLOR_FILTER_HUE, + COLOR_FILTER_SATURATION, + COLOR_FILTER_VALUE, + COLOR_FILTER_BRIGHTNESS, + COLOR_FILTER_CONTRAST, + COLOR_FILTER_RED, + COLOR_FILTER_GREEN, + COLOR_FILTER_BLUE, + COLOR_FILTER_SMOOTH, +} eSculptColorFilterTypes; + +EnumPropertyItem prop_color_filter_types[] = { + {COLOR_FILTER_FILL, "FILL", 0, "Fill", "Fill with a specific color"}, + {COLOR_FILTER_HUE, "HUE", 0, "Hue", "Change hue"}, + {COLOR_FILTER_SATURATION, "SATURATION", 0, "Saturation", "Change saturation"}, + {COLOR_FILTER_VALUE, "VALUE", 0, "Value", "Change value"}, + + {COLOR_FILTER_BRIGHTNESS, "BRIGTHNESS", 0, "Brightness", "Change brightness"}, + {COLOR_FILTER_CONTRAST, "CONTRAST", 0, "Contrast", "Change contrast"}, + + {COLOR_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth colors"}, + + {COLOR_FILTER_RED, "RED", 0, "Red", "Change red channel"}, + {COLOR_FILTER_GREEN, "GREEN", 0, "Green", "Change green channel"}, + {COLOR_FILTER_BLUE, "BLUE", 0, "Blue", "Change blue channel"}, + {0, NULL, 0, NULL, NULL}, +}; + +static void color_filter_task_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + const int mode = data->filter_type; + + SculptOrigVertData orig_data; + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + SCULPT_orig_vert_data_update(&orig_data, &vd); + float orig_color[3], final_color[4], hsv_color[3]; + int hue; + float brightness, contrast, gain, delta, offset; + float fade = vd.mask ? *vd.mask : 0.0f; + fade = 1.0f - fade; + fade *= data->filter_strength; + + copy_v3_v3(orig_color, orig_data.col); + + switch (mode) { + case COLOR_FILTER_FILL: { + float fill_color_rgba[4]; + copy_v3_v3(fill_color_rgba, data->filter_fill_color); + fill_color_rgba[3] = 1.0f; + CLAMP(fade, 0.0f, 1.0f); + mul_v4_fl(fill_color_rgba, fade); + blend_color_mix_float(final_color, orig_data.col, fill_color_rgba); + break; + } + case COLOR_FILTER_HUE: + rgb_to_hsv_v(orig_color, hsv_color); + hue = hsv_color[0] + fade; + hsv_color[0] = fabs((hsv_color[0] + fade) - hue); + hsv_to_rgb_v(hsv_color, final_color); + break; + case COLOR_FILTER_SATURATION: + rgb_to_hsv_v(orig_color, hsv_color); + hsv_color[1] = hsv_color[1] + fade; + CLAMP(hsv_color[1], 0.0f, 1.0f); + hsv_to_rgb_v(hsv_color, final_color); + break; + case COLOR_FILTER_VALUE: + rgb_to_hsv_v(orig_color, hsv_color); + hsv_color[2] = hsv_color[2] + fade; + CLAMP(hsv_color[2], 0.0f, 1.0f); + hsv_to_rgb_v(hsv_color, final_color); + break; + case COLOR_FILTER_RED: + orig_color[0] = orig_color[0] + fade; + CLAMP(orig_color[0], 0.0f, 1.0f); + copy_v3_v3(final_color, orig_color); + break; + case COLOR_FILTER_GREEN: + orig_color[1] = orig_color[1] + fade; + CLAMP(orig_color[1], 0.0f, 1.0f); + copy_v3_v3(final_color, orig_color); + break; + case COLOR_FILTER_BLUE: + orig_color[2] = orig_color[2] + fade; + CLAMP(orig_color[2], 0.0f, 1.0f); + copy_v3_v3(final_color, orig_color); + break; + case COLOR_FILTER_BRIGHTNESS: + CLAMP(fade, -1.0f, 1.0f); + brightness = fade; + contrast = 0; + delta = contrast / 2.0f; + gain = 1.0f - delta * 2.0f; + delta *= -1; + offset = gain * (brightness + delta); + for (int i = 0; i < 3; i++) { + final_color[i] = gain * orig_color[i] + offset; + CLAMP(final_color[i], 0.0f, 1.0f); + } + break; + case COLOR_FILTER_CONTRAST: + CLAMP(fade, -1.0f, 1.0f); + brightness = 0; + contrast = fade; + delta = contrast / 2.0f; + gain = 1.0f - delta * 2.0f; + if (contrast > 0) { + gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON); + offset = gain * (brightness - delta); + } + else { + delta *= -1; + offset = gain * (brightness + delta); + } + for (int i = 0; i < 3; i++) { + final_color[i] = gain * orig_color[i] + offset; + CLAMP(final_color[i], 0.0f, 1.0f); + } + break; + case COLOR_FILTER_SMOOTH: { + CLAMP(fade, -1.0f, 1.0f); + float smooth_color[4]; + SCULPT_neighbor_color_average(ss, smooth_color, vd.index); + blend_color_interpolate_float(final_color, vd.col, smooth_color, fade); + break; + } + } + + copy_v3_v3(vd.col, final_color); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; + BKE_pbvh_node_mark_update_color(data->nodes[n]); +} + +static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + const int mode = RNA_enum_get(op->ptr, "type"); + float filter_strength = RNA_float_get(op->ptr, "strength"); + + if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { + SCULPT_undo_push_end(); + SCULPT_filter_cache_free(ss); + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COLOR); + return OPERATOR_FINISHED; + } + + if (event->type != MOUSEMOVE) { + return OPERATOR_RUNNING_MODAL; + } + + float len = event->prevclickx - event->mval[0]; + filter_strength = filter_strength * -len * 0.001f; + + float fill_color[3]; + RNA_float_get_array(op->ptr, "fill_color", fill_color); + IMB_colormanagement_srgb_to_scene_linear_v3(fill_color); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .nodes = ss->filter_cache->nodes, + .filter_type = mode, + .filter_strength = filter_strength, + .filter_fill_color = fill_color, + }; + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + + BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode); + BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, color_filter_task_cb, &settings); + + SCULPT_flush_update_step(C, SCULPT_UPDATE_COLOR); + + return OPERATOR_RUNNING_MODAL; +} + +static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Object *ob = CTX_data_active_object(C); + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + int mode = RNA_enum_get(op->ptr, "type"); + PBVH *pbvh = ob->sculpt->pbvh; + + /* Disable for multires and dyntopo for now */ + if (!ss->pbvh) { + return OPERATOR_CANCELLED; + } + if (BKE_pbvh_type(pbvh) != PBVH_FACES) { + return OPERATOR_CANCELLED; + } + + if (!ss->vcol) { + return OPERATOR_CANCELLED; + } + + SCULPT_undo_push_begin("color filter"); + + bool needs_pmap = mode == COLOR_FILTER_SMOOTH; + BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false, true); + + if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_pmap && !ob->sculpt->pmap) { + return OPERATOR_CANCELLED; + } + + SCULPT_filter_cache_init(ob, sd, SCULPT_UNDO_COLOR); + + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; +} + +void SCULPT_OT_color_filter(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Filter color"; + ot->idname = "SCULPT_OT_color_filter"; + ot->description = "Applies a filter to modify the current sculpt vertex colors"; + + /* api callbacks */ + ot->invoke = sculpt_color_filter_invoke; + ot->modal = sculpt_color_filter_modal; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* rna */ + RNA_def_enum(ot->srna, "type", prop_color_filter_types, COLOR_FILTER_HUE, "Filter type", ""); + RNA_def_float( + ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f); + + PropertyRNA *prop = RNA_def_float_color( + ot->srna, "fill_color", 3, NULL, 0.0f, FLT_MAX, "Fill Color", "fill color", 0.0f, 1.0f); + RNA_def_property_subtype(prop, PROP_COLOR_GAMMA); +} diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index d2a683461a7..83145f5600f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -202,7 +202,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) int totnode; int filter_type = RNA_enum_get(op->ptr, "filter_type"); - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); SCULPT_vertex_random_access_init(ss); @@ -247,7 +247,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) { @@ -276,7 +276,7 @@ void SCULPT_mask_filter_smooth_apply( for (int i = 0; i < smooth_iterations; i++) { TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); } } @@ -432,7 +432,7 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) Sculpt *sd = CTX_data_tool_settings(C)->sculpt; int totnode; - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); SCULPT_vertex_random_access_init(ss); @@ -459,7 +459,7 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); settings.func_reduce = dirty_mask_compute_range_reduce; settings.userdata_chunk = ⦥ diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index fd0f67f040a..494588d0996 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -70,10 +70,10 @@ static void filter_cache_init_task_cb(void *__restrict userdata, SculptThreadedTaskData *data = userdata; PBVHNode *node = data->nodes[i]; - SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS); + SCULPT_undo_push_node(data->ob, node, data->filter_undo_type); } -void SCULPT_filter_cache_init(Object *ob, Sculpt *sd) +void SCULPT_filter_cache_init(Object *ob, Sculpt *sd, const int undo_type) { SculptSession *ss = ob->sculpt; PBVH *pbvh = ob->sculpt->pbvh; @@ -110,11 +110,11 @@ void SCULPT_filter_cache_init(Object *ob, Sculpt *sd) .sd = sd, .ob = ob, .nodes = ss->filter_cache->nodes, + .filter_undo_type = undo_type, }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings( - &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode); BLI_task_parallel_range( 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings); } @@ -475,7 +475,7 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * SCULPT_vertex_random_access_init(ss); bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets); - BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false, false); SculptThreadedTaskData data = { .sd = sd, @@ -486,8 +486,7 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings( - &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode); BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings); if (filter_type == MESH_FILTER_SURFACE_SMOOTH) { @@ -542,7 +541,7 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent SCULPT_vertex_random_access_init(ss); bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets); - BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false, false); const int totvert = SCULPT_vertex_count_get(ss); if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_pmap && !ob->sculpt->pmap) { @@ -551,7 +550,7 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent SCULPT_undo_push_begin("Mesh filter"); - SCULPT_filter_cache_init(ob, sd); + SCULPT_filter_cache_init(ob, sd, SCULPT_UNDO_COORDS); if (use_face_sets) { ss->filter_cache->active_face_set = SCULPT_active_face_set_get(ss); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 0e27658e848..c981f89ada7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -27,6 +27,7 @@ #include "DNA_brush_types.h" #include "DNA_key_types.h" #include "DNA_listBase.h" +#include "DNA_meshdata_types.h" #include "DNA_vec_types.h" #include "BLI_bitmap.h" @@ -56,6 +57,7 @@ typedef enum SculptUpdateType { SCULPT_UPDATE_COORDS = 1 << 0, SCULPT_UPDATE_MASK = 1 << 1, SCULPT_UPDATE_VISIBILITY = 1 << 2, + SCULPT_UPDATE_COLOR = 1 << 3, } SculptUpdateType; void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags); @@ -92,6 +94,7 @@ int SCULPT_vertex_count_get(struct SculptSession *ss); const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index); void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]); float SCULPT_vertex_mask_get(struct SculptSession *ss, int index); +const float *SCULPT_vertex_color_get(SculptSession *ss, int index); #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 typedef struct SculptVertexNeighborIter { @@ -145,6 +148,15 @@ void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]); bool SCULPT_vertex_is_boundary(SculptSession *ss, const int index); +/* Fake Neighbors */ + +#define FAKE_NEIGHBOR_NONE -1 + +void SCULPT_fake_neighbors_ensure(struct Sculpt *sd, Object *ob, const float max_dist); +void SCULPT_fake_neighbors_enable(Object *ob); +void SCULPT_fake_neighbors_disable(Object *ob); +void SCULPT_fake_neighbors_free(struct Object *ob); + /* Sculpt Visibility API */ void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible); @@ -179,15 +191,20 @@ typedef struct { float (*coords)[3]; short (*normals)[3]; const float *vmasks; + float (*colors)[4]; /* Original coordinate, normal, and mask. */ const float *co; const short *no; float mask; + const float *col; } SculptOrigVertData; void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node); void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter); +void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, + Object *ob, + struct SculptUndoNode *unode); /* Utils. */ void SCULPT_calc_brush_plane(struct Sculpt *sd, @@ -305,7 +322,7 @@ float *SCULPT_boundary_automasking_init(Object *ob, float *automask_factor); /* Filters. */ -void SCULPT_filter_cache_init(Object *ob, Sculpt *sd); +void SCULPT_filter_cache_init(Object *ob, Sculpt *sd, const int undo_type); void SCULPT_filter_cache_free(SculptSession *ss); void SCULPT_mask_filter_smooth_apply( @@ -374,6 +391,12 @@ void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr, /* Draw Face Sets Brush. */ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); +/* Paint Brush. */ +void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); + +/* Smear Brush. */ +void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); + /* Smooth Brush. */ void SCULPT_neighbor_average(SculptSession *ss, float avg[3], uint vert); @@ -383,6 +406,7 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index); float SCULPT_neighbor_mask_average(SculptSession *ss, int index); +void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index); void SCULPT_smooth(Sculpt *sd, Object *ob, @@ -427,6 +451,7 @@ typedef enum { SCULPT_UNDO_DYNTOPO_SYMMETRIZE, SCULPT_UNDO_GEOMETRY, SCULPT_UNDO_FACE_SETS, + SCULPT_UNDO_COLOR, } SculptUndoType; /* Storage of geometry for the undo node. @@ -457,6 +482,7 @@ typedef struct SculptUndoNode { float (*co)[3]; float (*orig_co)[3]; short (*no)[3]; + float (*col)[4]; float *mask; int totvert; @@ -556,6 +582,7 @@ typedef struct SculptThreadedTaskData { int filter_type; float filter_strength; + float *filter_fill_color; bool use_area_cos; bool use_area_nos; @@ -568,6 +595,8 @@ typedef struct SculptThreadedTaskData { bool any_vertex_sampled; + float *wet_mix_sampled_color; + float *prev_mask; float *pose_factor; @@ -601,6 +630,7 @@ typedef struct SculptThreadedTaskData { bool dirty_mask_dirty_only; int face_set; + int filter_undo_type; ThreadMutex mutex; @@ -720,6 +750,8 @@ typedef struct StrokeCache { float bstrength; float normal_weight; /* from brush (with optional override) */ + float (*prev_colors)[4]; + /* The rest is temporary storage that isn't saved as a property */ bool first_time; /* Beginning of stroke may do some things special */ @@ -813,6 +845,9 @@ typedef struct StrokeCache { float stroke_local_mat[4][4]; float multiplane_scrape_angle; + float wet_mix_prev_color[4]; + float density_seed; + rcti previous_r; /* previous redraw rectangle */ rcti current_r; /* current redraw rectangle */ @@ -901,6 +936,9 @@ void SCULPT_OT_mesh_filter(struct wmOperatorType *ot); /* Cloth Filter. */ void SCULPT_OT_cloth_filter(struct wmOperatorType *ot); +/* Color Filter. */ +void SCULPT_OT_color_filter(struct wmOperatorType *ot); + /* Mask filter and Dirty Mask. */ void SCULPT_OT_mask_filter(struct wmOperatorType *ot); void SCULPT_OT_dirty_mask(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index cbb198e14a3..60483cc168d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -206,7 +206,7 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * (event->type == EVT_PADENTER && event->val == KM_PRESS)) { /* Smooth iterations. */ - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); const int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations"); SCULPT_mask_filter_smooth_apply( sd, ob, ss->filter_cache->nodes, ss->filter_cache->totnode, smooth_iterations); @@ -289,8 +289,7 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"), }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings( - &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode); BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); ss->filter_cache->mask_update_current_it = mask_expand_update_it; } @@ -365,7 +364,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); int vertex_count = SCULPT_vertex_count_get(ss); @@ -459,8 +458,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"), }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings( - &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode); BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); const char *status_str = TIP_( diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c index f3327706102..503f9429a50 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c @@ -304,7 +304,7 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, MultiplaneScrapeSampleData mssd = {{{0}}}; TaskParallelSettings sample_settings; - BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode); sample_settings.func_reduce = calc_multiplane_scrape_surface_reduce; sample_settings.userdata_chunk = &mssd; sample_settings.userdata_chunk_size = sizeof(MultiplaneScrapeSampleData); @@ -395,7 +395,7 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, plane_from_point_normal_v3(data.multiplane_scrape_planes[0], area_co, plane_no); TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings); } diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c new file mode 100644 index 00000000000..9b38def6b7b --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -0,0 +1,477 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_hash.h" +#include "BLI_math.h" +#include "BLI_math_color_blend.h" +#include "BLI_task.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_brush.h" +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" +#include "BKE_scene.h" + +#include "DEG_depsgraph.h" + +#include "IMB_colormanagement.h" + +#include "WM_api.h" +#include "WM_message.h" +#include "WM_toolsystem.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_sculpt.h" +#include "paint_intern.h" +#include "sculpt_intern.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" + +#include "IMB_imbuf.h" + +#include "bmesh.h" + +#include <math.h> +#include <stdlib.h> + +static void do_color_smooth_task_cb_exec(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = ss->cache->bstrength; + + PBVHVertexIter vd; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + float smooth_color[4]; + SCULPT_neighbor_color_average(ss, smooth_color, vd.index); + blend_color_interpolate_float(vd.col, vd.col, smooth_color, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_paint_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = fabsf(ss->cache->bstrength); + + PBVHVertexIter vd; + PBVHColorBufferNode *color_buffer; + + SculptOrigVertData orig_data; + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + color_buffer = BKE_pbvh_node_color_buffer_get(data->nodes[n]); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + float brush_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + copy_v3_v3(brush_color, BKE_brush_color_get(ss->scene, brush)); + IMB_colormanagement_srgb_to_scene_linear_v3(brush_color); + + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + SCULPT_orig_vert_data_update(&orig_data, &vd); + + bool affect_vertex = false; + float distance_to_stroke_location = 0.0f; + if (brush->tip_roundness < 1.0f) { + affect_vertex = SCULPT_brush_test_cube(&test, vd.co, data->mat, brush->tip_roundness); + distance_to_stroke_location = ss->cache->radius * test.dist; + } + else { + affect_vertex = sculpt_brush_test_sq_fn(&test, vd.co); + distance_to_stroke_location = sqrtf(test.dist); + } + + if (affect_vertex) { + float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + distance_to_stroke_location, + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + /* Density. */ + float noise = 1.0f; + const float density = brush->density; + if (density < 1.0f) { + const float hash_noise = BLI_hash_int_01(ss->cache->density_seed * 1000 * vd.index); + if (hash_noise > density) { + noise = density * hash_noise; + fade = fade * noise; + } + } + + /* Brush paint color, brush test falloff and flow. */ + float paint_color[4]; + float wet_mix_color[4]; + float buffer_color[4]; + + mul_v4_v4fl(paint_color, brush_color, fade * brush->flow); + mul_v4_v4fl(wet_mix_color, data->wet_mix_sampled_color, fade * brush->flow); + + /* Interpolate with the wet_mix color for wet paint mixing. */ + blend_color_interpolate_float(paint_color, paint_color, wet_mix_color, brush->wet_mix); + blend_color_mix_float(color_buffer->color[vd.i], color_buffer->color[vd.i], paint_color); + + /* Final mix over the original color using brush alpha. */ + mul_v4_v4fl(buffer_color, color_buffer->color[vd.i], brush->alpha); + + IMB_blend_color_float(vd.col, orig_data.col, buffer_color, brush->blend); + } + CLAMP4(vd.col, 0.0f, 1.0f); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +typedef struct SampleWetPaintTLSData { + int tot_samples; + float color[4]; +} SampleWetPaintTLSData; + +static void do_sample_wet_paint_task_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + SampleWetPaintTLSData *swptd = tls->userdata_chunk; + PBVHVertexIter vd; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + add_v4_v4(swptd->color, vd.col); + swptd->tot_samples++; + } + } + BKE_pbvh_vertex_iter_end; +} + +static void sample_wet_paint_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + SampleWetPaintTLSData *join = chunk_join; + SampleWetPaintTLSData *swptd = chunk; + + join->tot_samples += swptd->tot_samples; + add_v4_v4(join->color, swptd->color); +} + +void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; + + if (!ss->vcol) { + return; + } + + if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0) { + ss->cache->density_seed = BLI_hash_int_01(ss->cache->location[0] * 1000); + return; + } + + BKE_curvemapping_initialize(brush->curve); + + float area_no[3]; + float mat[4][4]; + float scale[4][4]; + float tmat[4][4]; + + /* If the brush is round the tip does not need to be aligned to the surface, so this saves a + * whole iteration over the affected nodes. */ + if (brush->tip_roundness < 1.0f) { + SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no); + + cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); + mat[0][3] = 0; + cross_v3_v3v3(mat[1], area_no, mat[0]); + mat[1][3] = 0; + copy_v3_v3(mat[2], area_no); + mat[2][3] = 0; + copy_v3_v3(mat[3], ss->cache->location); + mat[3][3] = 1; + normalize_m4(mat); + + scale_m4_fl(scale, ss->cache->radius); + mul_m4_m4m4(tmat, mat, scale); + mul_v3_fl(tmat[1], brush->tip_scale_x); + invert_m4_m4(mat, tmat); + if (is_zero_m4(mat)) { + return; + } + } + + /* Smooth colors mode. */ + if (ss->cache->alt_smooth) { + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .mat = mat, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_color_smooth_task_cb_exec, &settings); + return; + } + + /* Regular Paint mode. */ + + /* Wet paint color sampling. */ + float wet_color[4] = {0.0f}; + if (brush->wet_mix > 0.0f) { + SculptThreadedTaskData task_data = { + .sd = sd, + .ob = ob, + .nodes = nodes, + .brush = brush, + }; + + SampleWetPaintTLSData swptd; + swptd.tot_samples = 0; + zero_v4(swptd.color); + + TaskParallelSettings settings_sample; + BKE_pbvh_parallel_range_settings(&settings_sample, true, totnode); + settings_sample.func_reduce = sample_wet_paint_reduce; + settings_sample.userdata_chunk = &swptd; + settings_sample.userdata_chunk_size = sizeof(SampleWetPaintTLSData); + BLI_task_parallel_range(0, totnode, &task_data, do_sample_wet_paint_task_cb, &settings_sample); + + if (swptd.tot_samples > 0 && is_finite_v4(swptd.color)) { + copy_v4_v4(wet_color, swptd.color); + mul_v4_fl(wet_color, 1.0f / (float)swptd.tot_samples); + CLAMP4(wet_color, 0.0f, 1.0f); + + if (ss->cache->first_time) { + copy_v4_v4(ss->cache->wet_mix_prev_color, wet_color); + } + blend_color_interpolate_float( + wet_color, wet_color, ss->cache->wet_mix_prev_color, brush->wet_persistence); + copy_v4_v4(ss->cache->wet_mix_prev_color, wet_color); + CLAMP4(ss->cache->wet_mix_prev_color, 0.0f, 1.0f); + } + } + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .wet_mix_sampled_color = wet_color, + .mat = mat, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_paint_brush_task_cb_ex, &settings); +} + +static void do_smear_brush_task_cb_exec(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = ss->cache->bstrength; + + PBVHVertexIter vd; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + float current_disp[3]; + float current_disp_norm[3]; + float interp_color[4]; + copy_v4_v4(interp_color, ss->cache->prev_colors[vd.index]); + + sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); + normalize_v3_v3(current_disp_norm, current_disp); + mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + float vertex_disp[3]; + float vertex_disp_norm[3]; + sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co); + const float *neighbor_color = ss->cache->prev_colors[ni.index]; + normalize_v3_v3(vertex_disp_norm, vertex_disp); + if (dot_v3v3(current_disp_norm, vertex_disp_norm) < 0.0f) { + const float color_interp = clamp_f( + -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f); + float color_mix[4]; + copy_v4_v4(color_mix, neighbor_color); + mul_v4_fl(color_mix, color_interp * fade); + blend_color_mix_float(interp_color, interp_color, color_mix); + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + blend_color_interpolate_float(vd.col, ss->cache->prev_colors[vd.index], interp_color, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + copy_v4_v4(ss->cache->prev_colors[vd.index], SCULPT_vertex_color_get(ss, vd.index)); + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; + + if (!ss->vcol) { + return; + } + + const int totvert = SCULPT_vertex_count_get(ss); + + if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0) { + if (!ss->cache->prev_colors) { + ss->cache->prev_colors = MEM_callocN(sizeof(float) * 4 * totvert, "prev colors"); + for (int i = 0; i < totvert; i++) { + copy_v4_v4(ss->cache->prev_colors[i], SCULPT_vertex_color_get(ss, i)); + } + } + } + + BKE_curvemapping_initialize(brush->curve); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + + /* Smooth colors mode. */ + if (ss->cache->alt_smooth) { + BLI_task_parallel_range(0, totnode, &data, do_color_smooth_task_cb_exec, &settings); + } + else { + /* Smear mode. */ + BLI_task_parallel_range(0, totnode, &data, do_smear_store_prev_colors_task_cb_exec, &settings); + BLI_task_parallel_range(0, totnode, &data, do_smear_brush_task_cb_exec, &settings); + } +} diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index a4a87051e03..c9e2b7318d6 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -293,7 +293,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd, PoseGrowFactorTLSData gftd; gftd.pos_count = 0; zero_v3(gftd.pos_avg); - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); settings.func_reduce = pose_brush_grow_factor_reduce; settings.userdata_chunk = &gftd; settings.userdata_chunk_size = sizeof(PoseGrowFactorTLSData); @@ -937,18 +937,32 @@ SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd, const float initial_location[3], const float radius) { + SculptPoseIKChain *ik_chain = NULL; + + const bool use_fake_neighbors = !(br->flag2 & BRUSH_USE_CONNECTED_ONLY); + + if (use_fake_neighbors) { + SCULPT_fake_neighbors_ensure(sd, ob, br->disconnected_distance_max); + SCULPT_fake_neighbors_enable(ob); + } + switch (br->pose_origin_type) { case BRUSH_POSE_ORIGIN_TOPOLOGY: - return pose_ik_chain_init_topology(sd, ob, ss, br, initial_location, radius); + ik_chain = pose_ik_chain_init_topology(sd, ob, ss, br, initial_location, radius); break; case BRUSH_POSE_ORIGIN_FACE_SETS: - return pose_ik_chain_init_face_sets(sd, ob, ss, br, radius); + ik_chain = pose_ik_chain_init_face_sets(sd, ob, ss, br, radius); break; case BRUSH_POSE_ORIGIN_FACE_SETS_FK: return pose_ik_chain_init_face_sets_fk(sd, ob, ss, radius, initial_location); break; } - return NULL; + + if (use_fake_neighbors) { + SCULPT_fake_neighbors_disable(ob); + } + + return ik_chain; } void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br) @@ -975,7 +989,7 @@ void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br data.pose_factor = ss->cache->pose_ik_chain->segments[ik].weights; for (int i = 0; i < br->pose_smooth_iterations; i++) { TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); } } @@ -1198,7 +1212,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); } diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c index 17451cb40ae..aa82ae1d7ad 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.c +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c @@ -226,6 +226,26 @@ float SCULPT_neighbor_mask_average(SculptSession *ss, int index) } } +void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index) +{ + float avg[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + int total = 0; + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { + add_v4_v4(avg, SCULPT_vertex_color_get(ss, ni.index)); + total++; + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + if (total > 0) { + mul_v4_v4fl(result, avg, 1.0f / (float)total); + } + else { + copy_v4_v4(result, SCULPT_vertex_color_get(ss, index)); + } +} + static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) @@ -433,7 +453,7 @@ void SCULPT_smooth(Sculpt *sd, }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); switch (type) { case PBVH_GRIDS: @@ -525,10 +545,15 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex( { SCULPT_orig_vert_data_update(&orig_data, &vd); if (sculpt_brush_test_sq_fn(&test, vd.co)) { - const float fade = - bstrength * - SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); float disp[3]; SCULPT_surface_smooth_laplacian_step(ss, @@ -566,10 +591,15 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { - const float fade = - bstrength * - SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); SCULPT_surface_smooth_displace_step( ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade); } @@ -598,7 +628,7 @@ void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in }; TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); for (int i = 0; i < brush->surface_smooth_iterations; i++) { BLI_task_parallel_range( 0, totnode, &data, SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex, &settings); diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index 59a4695ce18..f616817c330 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -71,12 +71,12 @@ void ED_sculpt_init_transform(struct bContext *C) copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot); SCULPT_undo_push_begin("Transform"); - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); ss->pivot_rot[3] = 1.0f; SCULPT_vertex_random_access_init(ss); - SCULPT_filter_cache_init(ob, sd); + SCULPT_filter_cache_init(ob, sd, SCULPT_UNDO_COORDS); } static void sculpt_transform_task_cb(void *__restrict userdata, @@ -127,7 +127,7 @@ void ED_sculpt_update_modal_transform(struct bContext *C) const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; SCULPT_vertex_random_access_init(ss); - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); SculptThreadedTaskData data = { .sd = sd, @@ -178,8 +178,7 @@ void ED_sculpt_update_modal_transform(struct bContext *C) } TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings( - &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode); BLI_task_parallel_range( 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings); @@ -253,7 +252,7 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op) int mode = RNA_enum_get(op->ptr, "mode"); - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false); /* Pivot to center. */ if (mode == SCULPT_PIVOT_POSITION_ORIGIN) { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index d21552efafe..6ede631eb11 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -205,7 +205,7 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt if (kb) { ob->shapenr = BLI_findindex(&key->block, kb) + 1; - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob); } else { @@ -326,6 +326,29 @@ static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode) return true; } +static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + SculptSession *ss = ob->sculpt; + MVert *mvert; + MPropCol *vcol; + int *index, i; + + if (unode->maxvert) { + /* regular mesh restore */ + index = unode->index; + mvert = ss->mvert; + vcol = ss->vcol; + + for (i = 0; i < unode->totvert; i++) { + copy_v4_v4(vcol[index[i]].color, unode->col[i]); + mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; + } + } + return true; +} + static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode) { ViewLayer *view_layer = CTX_data_view_layer(C); @@ -394,10 +417,7 @@ static void sculpt_undo_bmesh_restore_generic_task_cb( BKE_pbvh_node_mark_redraw(nodes[n]); } -static void sculpt_undo_bmesh_restore_generic(bContext *C, - SculptUndoNode *unode, - Object *ob, - SculptSession *ss) +static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob, SculptSession *ss) { if (unode->applied) { BM_log_undo(ss->bm, ss->bm_log); @@ -411,12 +431,11 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, if (unode->type == SCULPT_UNDO_MASK) { int totnode; PBVHNode **nodes; - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range( 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings); @@ -588,7 +607,7 @@ static int sculpt_undo_bmesh_restore(bContext *C, return true; default: if (ss->bm_log) { - sculpt_undo_bmesh_restore_generic(C, unode, ob, ss); + sculpt_undo_bmesh_restore_generic(unode, ob, ss); return true; } break; @@ -633,7 +652,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase rebuild = true; BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild); - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, need_mask); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, need_mask, false); SCULPT_visibility_sync_all_face_sets_to_vertices(ss); @@ -659,7 +678,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase * ensure object is updated after the node is handled. */ const SculptUndoNode *first_unode = (const SculptUndoNode *)lb->first; if (first_unode->type != SCULPT_UNDO_GEOMETRY) { - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask, false); } if (sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) { @@ -712,10 +731,15 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase break; case SCULPT_UNDO_FACE_SETS: break; + case SCULPT_UNDO_COLOR: + if (sculpt_undo_restore_color(C, unode)) { + update = true; + } + break; case SCULPT_UNDO_GEOMETRY: sculpt_undo_geometry_restore(unode, ob); - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask, false); break; case SCULPT_UNDO_DYNTOPO_BEGIN: @@ -998,6 +1022,12 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert; break; + case SCULPT_UNDO_COLOR: + unode->col = MEM_callocN(sizeof(MPropCol) * allvert, "SculptUndoNode.col"); + + usculpt->undo_size += (sizeof(MPropCol) * sizeof(int)) * allvert; + + break; case SCULPT_UNDO_DYNTOPO_BEGIN: case SCULPT_UNDO_DYNTOPO_END: case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: @@ -1083,6 +1113,18 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode) BKE_pbvh_vertex_iter_end; } +static void sculpt_undo_store_color(Object *ob, SculptUndoNode *unode) +{ + SculptSession *ss = ob->sculpt; + PBVHVertexIter vd; + + BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) + { + copy_v4_v4(unode->col[vd.i], vd.col); + } + BKE_pbvh_vertex_iter_end; +} + static SculptUndoNodeGeometry *sculpt_undo_geometry_get(SculptUndoNode *unode) { if (!unode->geometry_original.is_initialized) { @@ -1203,6 +1245,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: case SCULPT_UNDO_GEOMETRY: case SCULPT_UNDO_FACE_SETS: + case SCULPT_UNDO_COLOR: break; } } @@ -1272,6 +1315,9 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType case SCULPT_UNDO_MASK: sculpt_undo_store_mask(ob, unode); break; + case SCULPT_UNDO_COLOR: + sculpt_undo_store_color(ob, unode); + break; case SCULPT_UNDO_DYNTOPO_BEGIN: case SCULPT_UNDO_DYNTOPO_END: case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 81ac8a16d8a..2e52f3aa8a8 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -771,7 +771,7 @@ static int sound_pack_exec(bContext *C, wmOperator *op) } sound->packedfile = BKE_packedfile_new( - op->reports, sound->name, ID_BLEND_PATH(bmain, &sound->id)); + op->reports, sound->filepath, ID_BLEND_PATH(bmain, &sound->id)); BKE_sound_load(bmain, sound); return OPERATOR_FINISHED; @@ -847,7 +847,8 @@ static int sound_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE "AutoPack is enabled, so image will be packed again on file save"); } - unpack_menu(C, "SOUND_OT_unpack", sound->id.name + 2, sound->name, "sounds", sound->packedfile); + unpack_menu( + C, "SOUND_OT_unpack", sound->id.name + 2, sound->filepath, "sounds", sound->packedfile); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index b390e4b56d6..aa784800be0 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -800,10 +800,17 @@ static void insert_gpencil_keys(bAnimContext *ac, short mode) add_frame_mode = GP_GETFRAME_ADD_NEW; } - /* insert gp frames */ + /* Insert gp frames. */ + bGPdata *gpd_old = NULL; for (ale = anim_data.first; ale; ale = ale->next) { + bGPdata *gpd = (bGPdata *)ale->id; bGPDlayer *gpl = (bGPDlayer *)ale->data; BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode); + /* Check if the gpd changes to tag only once. */ + if (gpd != gpd_old) { + BKE_gpencil_tag(gpd); + gpd_old = gpd; + } } ANIM_animdata_update(ac, &anim_data); @@ -839,6 +846,9 @@ static int actkeys_insertkey_exec(bContext *C, wmOperator *op) } /* set notifier that keyframes have changed */ + if (ac.datatype == ANIMCONT_GPENCIL) { + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + } WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); return OPERATOR_FINISHED; @@ -888,7 +898,7 @@ static void duplicate_action_keys(bAnimContext *ac) duplicate_fcurve_keys((FCurve *)ale->key_data); } else if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_frames_duplicate((bGPDlayer *)ale->data); + ED_gpencil_layer_frames_duplicate((bGPDlayer *)ale->data); } else if (ale->type == ANIMTYPE_MASKLAYER) { ED_masklayer_frames_duplicate((MaskLayer *)ale->data); @@ -964,7 +974,7 @@ static bool delete_action_keys(bAnimContext *ac) bool changed = false; if (ale->type == ANIMTYPE_GPLAYER) { - changed = ED_gplayer_frames_delete((bGPDlayer *)ale->data); + changed = ED_gpencil_layer_frames_delete((bGPDlayer *)ale->data); } else if (ale->type == ANIMTYPE_MASKLAYER) { changed = ED_masklayer_frames_delete((MaskLayer *)ale->data); @@ -1539,7 +1549,7 @@ static void setkeytype_gpencil_keys(bAnimContext *ac, short mode) /* loop through each layer */ for (ale = anim_data.first; ale; ale = ale->next) { if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_frames_keytype_set(ale->data, mode); + ED_gpencil_layer_frames_keytype_set(ale->data, mode); ale->update |= ANIM_UPDATE_DEPS; } } @@ -1740,7 +1750,7 @@ static void snap_action_keys(bAnimContext *ac, short mode) AnimData *adt = ANIM_nla_mapping_get(ac, ale); if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_snap_frames(ale->data, ac->scene, mode); + ED_gpencil_layer_snap_frames(ale->data, ac->scene, mode); } else if (ale->type == ANIMTYPE_MASKLAYER) { ED_masklayer_snap_frames(ale->data, ac->scene, mode); @@ -1870,7 +1880,7 @@ static void mirror_action_keys(bAnimContext *ac, short mode) AnimData *adt = ANIM_nla_mapping_get(ac, ale); if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_mirror_frames(ale->data, ac->scene, mode); + ED_gpencil_layer_mirror_frames(ale->data, ac->scene, mode); } else if (ale->type == ANIMTYPE_MASKLAYER) { /* TODO */ diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index bbb68f632fb..f40b792269b 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -270,7 +270,7 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel) if (test) { for (ale = anim_data.first; ale; ale = ale->next) { if (ale->type == ANIMTYPE_GPLAYER) { - if (ED_gplayer_frame_select_check(ale->data)) { + if (ED_gpencil_layer_frame_select_check(ale->data)) { sel = SELECT_SUBTRACT; break; } @@ -296,7 +296,7 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel) /* Now set the flags */ for (ale = anim_data.first; ale; ale = ale->next) { if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_frame_select_set(ale->data, sel); + ED_gpencil_layer_frame_select_set(ale->data, sel); ale->update |= ANIM_UPDATE_DEPS; } else if (ale->type == ANIMTYPE_MASKLAYER) { @@ -405,14 +405,14 @@ static void box_select_elem( bGPdata *gpd = ale->data; bGPDlayer *gpl; for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - ED_gplayer_frames_select_box(gpl, xmin, xmax, data->selectmode); + ED_gpencil_layer_frames_select_box(gpl, xmin, xmax, data->selectmode); } ale->update |= ANIM_UPDATE_DEPS; break; } #endif case ANIMTYPE_GPLAYER: { - ED_gplayer_frames_select_box(ale->data, xmin, xmax, sel_data->selectmode); + ED_gpencil_layer_frames_select_box(ale->data, xmin, xmax, sel_data->selectmode); ale->update |= ANIM_UPDATE_DEPS; break; } @@ -641,13 +641,13 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b bGPdata *gpd = ale->data; bGPDlayer *gpl; for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - ED_gplayer_frames_select_region(&rdata->ked, ale->data, rdata->mode, rdata->selectmode); + ED_gpencil_layer_frames_select_region(&rdata->ked, ale->data, rdata->mode, rdata->selectmode); } break; } #endif case ANIMTYPE_GPLAYER: { - ED_gplayer_frames_select_region( + ED_gpencil_layer_frames_select_region( &sel_data->ked, ale->data, sel_data->mode, sel_data->selectmode); ale->update |= ANIM_UPDATE_DEPS; break; @@ -972,7 +972,7 @@ static void markers_selectkeys_between(bAnimContext *ac) ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); } else if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_frames_select_box(ale->data, min, max, SELECT_ADD); + ED_gpencil_layer_frames_select_box(ale->data, min, max, SELECT_ADD); ale->update |= ANIM_UPDATE_DEPS; } else if (ale->type == ANIMTYPE_MASKLAYER) { @@ -1008,7 +1008,7 @@ static void columnselect_action_keys(bAnimContext *ac, short mode) ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); for (ale = anim_data.first; ale; ale = ale->next) { - ED_gplayer_make_cfra_list(ale->data, &ked.list, 1); + ED_gpencil_layer_make_cfra_list(ale->data, &ked.list, 1); } } else { @@ -1385,7 +1385,7 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); } else if (ale->type == ANIMTYPE_GPLAYER) { - ED_gplayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode); + ED_gpencil_layer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode); ale->update |= ANIM_UPDATE_DEPS; } else if (ale->type == ANIMTYPE_MASKLAYER) { diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index e92ea906237..079cee290ae 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -128,7 +128,7 @@ static SpaceLink *action_new(const ScrArea *area, const Scene *scene) region->v2d.minzoom = 0.01f; region->v2d.maxzoom = 50; region->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); - region->v2d.scroll |= (V2D_SCROLL_RIGHT); + region->v2d.scroll |= V2D_SCROLL_RIGHT; region->v2d.keepzoom = V2D_LOCKZOOM_Y; region->v2d.keepofs = V2D_KEEPOFS_Y; region->v2d.align = V2D_ALIGN_NO_POS_Y; @@ -181,10 +181,14 @@ static void action_main_region_draw(const bContext *C, ARegion *region) Object *obact = CTX_data_active_object(C); bAnimContext ac; View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; short marker_flag = 0; short cfra_flag = 0; + UI_view2d_view_ortho(v2d); + if (saction->flag & SACTION_DRAWTIME) { + cfra_flag |= DRAWCFRA_UNIT_SECONDS; + } + /* clear and setup matrix */ UI_ThemeClearColor(TH_BACK); GPU_clear(GPU_COLOR_BIT); @@ -204,12 +208,6 @@ static void action_main_region_draw(const bContext *C, ARegion *region) draw_channel_strips(&ac, saction, region); } - /* current frame */ - if (saction->flag & SACTION_DRAWTIME) { - cfra_flag |= DRAWCFRA_UNIT_SECONDS; - } - ANIM_draw_cfra(C, v2d, cfra_flag); - /* markers */ UI_view2d_view_orthoSpecial(region, v2d, 1); @@ -238,11 +236,20 @@ static void action_main_region_draw(const bContext *C, ARegion *region) /* scrubbing region */ ED_time_scrub_draw(region, scene, saction->flag & SACTION_DRAWTIME, true); +} + +static void action_main_region_draw_overlay(const bContext *C, ARegion *region) +{ + /* draw entirely, view changes should be handled here */ + const SpaceAction *saction = CTX_wm_space_action(C); + const Scene *scene = CTX_data_scene(C); + View2D *v2d = ®ion->v2d; + + /* scrubbing region */ + ED_time_scrub_draw_current_frame(region, scene, saction->flag & SACTION_DRAWTIME, true); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); } /* add handlers, stuff you only do once or on area/region changes */ @@ -874,6 +881,7 @@ void ED_spacetype_action(void) art->regionid = RGN_TYPE_WINDOW; art->init = action_main_region_init; art->draw = action_main_region_draw; + art->draw_overlay = action_main_region_draw_overlay; art->listener = action_main_region_listener; art->message_subscribe = saction_main_region_message_subscribe; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index c3b7d65689f..25ff6bbd098 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -54,8 +54,4 @@ if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() -if(WITH_NEW_OBJECT_TYPES) - add_definitions(-DWITH_NEW_OBJECT_TYPES) -endif() - blender_add_lib(bf_editor_space_buttons "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 7e6088bc3cc..ba618083620 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -251,14 +251,12 @@ static int buttons_context_path_data(ButsContextPath *path, int type) else if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (type == -1 || type == OB_GPENCIL)) { return 1; } -#ifdef WITH_NEW_OBJECT_TYPES else if (RNA_struct_is_a(ptr->type, &RNA_Hair) && (type == -1 || type == OB_HAIR)) { return 1; } else if (RNA_struct_is_a(ptr->type, &RNA_PointCloud) && (type == -1 || type == OB_POINTCLOUD)) { return 1; } -#endif else if (RNA_struct_is_a(ptr->type, &RNA_Volume) && (type == -1 || type == OB_VOLUME)) { return 1; } @@ -796,10 +794,8 @@ const char *buttons_context_dir[] = { "line_style", "collection", "gpencil", -#ifdef WITH_NEW_OBJECT_TYPES "hair", "pointcloud", -#endif "volume", NULL, }; @@ -878,7 +874,6 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r set_pointer_type(path, result, &RNA_LightProbe); return 1; } -#ifdef WITH_NEW_OBJECT_TYPES else if (CTX_data_equals(member, "hair")) { set_pointer_type(path, result, &RNA_Hair); return 1; @@ -887,7 +882,6 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r set_pointer_type(path, result, &RNA_PointCloud); return 1; } -#endif else if (CTX_data_equals(member, "volume")) { set_pointer_type(path, result, &RNA_Volume); return 1; diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 187334a5c34..71b86996989 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -30,10 +30,10 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_gpencil_modifier.h" /* Types for registering panels. */ #include "BKE_modifier.h" #include "BKE_screen.h" - -#include "DNA_modifier_types.h" +#include "BKE_shader_fx.h" #include "ED_screen.h" #include "ED_space_api.h" @@ -643,6 +643,21 @@ void ED_spacetype_buttons(void) mti->panelRegister(art); } } + for (int i = 0; i < NUM_GREASEPENCIL_MODIFIER_TYPES; i++) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(i); + if (mti != NULL && mti->panelRegister != NULL) { + mti->panelRegister(art); + } + } + for (int i = 0; i < NUM_SHADER_FX_TYPES; i++) { + if (i == eShaderFxType_Light_deprecated) { + continue; + } + const ShaderFxTypeInfo *fxti = BKE_shaderfx_get_info(i); + if (fxti != NULL && fxti->panelRegister != NULL) { + fxti->panelRegister(art); + } + } /* regions: header */ art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region"); diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c index 84ab5e6524b..c3aca95910b 100644 --- a/source/blender/editors/space_clip/clip_dopesheet_draw.c +++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c @@ -118,7 +118,7 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *region, Scene *scene) MovieTrackingDopesheet *dopesheet = &tracking->dopesheet; MovieTrackingDopesheetChannel *channel; float strip[4], selected_strip[4]; - float height = (dopesheet->tot_channel * CHANNEL_STEP) + (CHANNEL_HEIGHT); + float height = (dopesheet->tot_channel * CHANNEL_STEP) + CHANNEL_HEIGHT; uint keyframe_len = 0; @@ -305,7 +305,7 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *region) MovieTracking *tracking = &clip->tracking; MovieTrackingDopesheet *dopesheet = &tracking->dopesheet; - int height = (dopesheet->tot_channel * CHANNEL_STEP) + (CHANNEL_HEIGHT); + int height = (dopesheet->tot_channel * CHANNEL_STEP) + CHANNEL_HEIGHT; if (height > BLI_rcti_size_y(&v2d->mask)) { /* don't use totrect set, as the width stays the same diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 984aa0a63ad..22707b97afa 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -283,7 +283,7 @@ static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event) } if (clip) { - BLI_strncpy(path, clip->name, sizeof(path)); + BLI_strncpy(path, clip->filepath, sizeof(path)); BLI_path_abs(path, CTX_data_main(C)->name); BLI_path_parent_dir(path); diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index a68e06951f7..54da00a132d 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -96,7 +96,7 @@ static void init_preview_region(const Scene *scene, region->v2d.minzoom = 0.01f; region->v2d.maxzoom = 50; region->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); - region->v2d.scroll |= (V2D_SCROLL_RIGHT); + region->v2d.scroll |= V2D_SCROLL_RIGHT; region->v2d.keepzoom = V2D_LOCKZOOM_Y; region->v2d.keepofs = V2D_KEEPOFS_Y; region->v2d.align = V2D_ALIGN_NO_POS_Y; @@ -1045,7 +1045,6 @@ static void clip_preview_region_init(wmWindowManager *wm, ARegion *region) static void graph_region_draw(const bContext *C, ARegion *region) { View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; SpaceClip *sc = CTX_wm_space_clip(C); Scene *scene = CTX_data_scene(C); short cfra_flag = 0; @@ -1076,9 +1075,7 @@ static void graph_region_draw(const bContext *C, ARegion *region) ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); /* scale indicators */ { @@ -1095,7 +1092,6 @@ static void dopesheet_region_draw(const bContext *C, ARegion *region) SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; short cfra_flag = 0; if (clip) { @@ -1127,9 +1123,7 @@ static void dopesheet_region_draw(const bContext *C, ARegion *region) ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); } static void clip_preview_region_draw(const bContext *C, ARegion *region) diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index d8c097cad37..3c62aeb1759 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -70,7 +70,7 @@ static SpaceLink *console_new(const ScrArea *UNUSED(area), const Scene *UNUSED(s region->regiontype = RGN_TYPE_WINDOW; /* keep in sync with info */ - region->v2d.scroll |= (V2D_SCROLL_RIGHT); + region->v2d.scroll |= V2D_SCROLL_RIGHT; region->v2d.align |= V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y; /* align bottom left */ region->v2d.keepofs |= V2D_LOCKOFS_X; region->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); @@ -208,7 +208,6 @@ static void console_main_region_draw(const bContext *C, ARegion *region) /* draw entirely, view changes should be handled here */ SpaceConsole *sc = CTX_wm_space_console(C); View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; if (BLI_listbase_is_empty(&sc->scrollback)) { WM_operator_name_call((bContext *)C, "CONSOLE_OT_banner", WM_OP_EXEC_DEFAULT, NULL); @@ -230,9 +229,7 @@ static void console_main_region_draw(const bContext *C, ARegion *region) UI_view2d_view_restore(C); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); } static void console_operatortypes(void) diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index d8d7ef01a2e..f60ef2b6aed 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2740,7 +2740,7 @@ static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist) } else { char relname[FILE_MAX + (MAX_ID_NAME - 2) + 3]; - BLI_snprintf(relname, sizeof(relname), "%s | %s", id->lib->name, id->name + 2); + BLI_snprintf(relname, sizeof(relname), "%s | %s", id->lib->filepath, id->name + 2); files->entry->relpath = BLI_strdup(relname); } // files->type |= S_IFREG; diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 21b705cbb44..56f3fd08bae 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -449,7 +449,6 @@ static void file_main_region_draw(const bContext *C, ARegion *region) FileSelectParams *params = ED_fileselect_get_params(sfile); View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; float col[3]; /* Needed, because filelist is not initialized on loading */ @@ -509,9 +508,7 @@ static void file_main_region_draw(const bContext *C, ARegion *region) /* scrollers */ rcti view_rect; ED_fileselect_layout_maskrect(sfile->layout, v2d, &view_rect); - scrollers = UI_view2d_scrollers_calc(v2d, &view_rect); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, &view_rect); } static void file_operatortypes(void) diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index b9c7c529620..052e089942c 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -200,9 +200,7 @@ static void graph_main_region_draw(const bContext *C, ARegion *region) Scene *scene = CTX_data_scene(C); bAnimContext ac; View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; float col[3]; - short cfra_flag = 0; /* clear and setup matrix */ UI_GetThemeColor3fv(TH_BACK, col); @@ -284,14 +282,6 @@ static void graph_main_region_draw(const bContext *C, ARegion *region) immUnbindProgram(); } - if (sipo->mode != SIPO_MODE_DRIVERS) { - /* current frame */ - if (sipo->flag & SIPO_DRAWTIME) { - cfra_flag |= DRAWCFRA_UNIT_SECONDS; - } - ANIM_draw_cfra(C, v2d, cfra_flag); - } - /* markers */ if (sipo->mode != SIPO_MODE_DRIVERS) { UI_view2d_view_orthoSpecial(region, v2d, 1); @@ -316,12 +306,22 @@ static void graph_main_region_draw(const bContext *C, ARegion *region) /* time-scrubbing */ ED_time_scrub_draw(region, scene, display_seconds, false); +} + +static void graph_main_region_draw_overlay(const bContext *C, ARegion *region) +{ + /* draw entirely, view changes should be handled here */ + const SpaceGraph *sipo = CTX_wm_space_graph(C); + const Scene *scene = CTX_data_scene(C); + const bool draw_vert_line = sipo->mode != SIPO_MODE_DRIVERS; + View2D *v2d = ®ion->v2d; + + /* scrubbing region */ + ED_time_scrub_draw_current_frame(region, scene, sipo->flag & SIPO_DRAWTIME, draw_vert_line); /* scrollers */ // FIXME: args for scrollers depend on the type of data being shown... - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); /* scale numbers */ { @@ -358,7 +358,6 @@ static void graph_channel_region_draw(const bContext *C, ARegion *region) { bAnimContext ac; View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; float col[3]; /* clear and setup matrix */ @@ -380,9 +379,7 @@ static void graph_channel_region_draw(const bContext *C, ARegion *region) UI_view2d_view_restore(C); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); } /* add handlers, stuff you only do once or on area/region changes */ @@ -859,6 +856,7 @@ void ED_spacetype_ipo(void) art->regionid = RGN_TYPE_WINDOW; art->init = graph_main_region_init; art->draw = graph_main_region_draw; + art->draw_overlay = graph_main_region_draw_overlay; art->listener = graph_region_listener; art->message_subscribe = graph_region_message_subscribe; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index c9f2ec38354..cb0fdcf23ca 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -191,7 +191,7 @@ int ED_space_image_get_display_channel_mask(ImBuf *ibuf) result &= ~(SI_USE_ALPHA | SI_SHOW_ALPHA); } if (!zbuf) { - result &= ~(SI_SHOW_ZBUF); + result &= ~SI_SHOW_ZBUF; } if (!color) { result &= ~(SI_SHOW_R | SI_SHOW_G | SI_SHOW_B); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 8cb85ce9800..f71c92b4c1f 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1237,7 +1237,7 @@ static Image *image_open_single(Main *bmain, if (!exists) { /* only image path after save, never ibuf */ if (is_relative_path) { - BLI_path_rel(ima->name, relbase); + BLI_path_rel(ima->filepath, relbase); } /* handle multiview images */ @@ -1417,7 +1417,7 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( } if (ima) { - path = ima->name; + path = ima->filepath; } if (RNA_struct_property_is_set(op->ptr, "filepath")) { @@ -1577,7 +1577,7 @@ static int image_replace_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", str); /* we cant do much if the str is longer then FILE_MAX :/ */ - BLI_strncpy(sima->image->name, str, sizeof(sima->image->name)); + BLI_strncpy(sima->image->filepath, str, sizeof(sima->image->filepath)); if (sima->image->source == IMA_SRC_GENERATED) { sima->image->source = IMA_SRC_FILE; @@ -1614,10 +1614,10 @@ static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS } if (!RNA_struct_property_is_set(op->ptr, "relative_path")) { - RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->name)); + RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->filepath)); } - image_filesel(C, op, sima->image->name); + image_filesel(C, op, sima->image->filepath); return OPERATOR_RUNNING_MODAL; } @@ -1777,7 +1777,7 @@ static int image_save_options_init(Main *bmain, /* append UDIM numbering if not present */ if (ima->source == IMA_SRC_TILED && - (BLI_path_sequence_decode(ima->name, NULL, NULL, NULL) != 1001)) { + (BLI_path_sequence_decode(ima->filepath, NULL, NULL, NULL) != 1001)) { int len = strlen(opts->filepath); STR_CONCAT(opts->filepath, len, ".1001"); } @@ -2301,7 +2301,7 @@ static bool image_should_be_saved(Image *ima, bool *is_format_writable) static bool image_has_valid_path(Image *ima) { - return strchr(ima->name, '\\') || strchr(ima->name, '/'); + return strchr(ima->filepath, '\\') || strchr(ima->filepath, '/'); } bool ED_image_should_save_modified(const Main *bmain) @@ -2336,7 +2336,7 @@ int ED_image_save_all_modified_info(const Main *bmain, ReportList *reports) RPT_WARNING, "Packed library image can't be saved: \"%s\" from \"%s\"", ima->id.name + 2, - ima->id.lib->name); + ima->id.lib->filepath); } } else if (!is_format_writable) { @@ -2348,19 +2348,21 @@ int ED_image_save_all_modified_info(const Main *bmain, ReportList *reports) else { if (image_has_valid_path(ima)) { num_saveable_images++; - if (BLI_gset_haskey(unique_paths, ima->name)) { + if (BLI_gset_haskey(unique_paths, ima->filepath)) { BKE_reportf(reports, RPT_WARNING, "Multiple images can't be saved to an identical path: \"%s\"", - ima->name); + ima->filepath); } else { - BLI_gset_insert(unique_paths, BLI_strdup(ima->name)); + BLI_gset_insert(unique_paths, BLI_strdup(ima->filepath)); } } else { - BKE_reportf( - reports, RPT_WARNING, "Image can't be saved, no valid file path: \"%s\"", ima->name); + BKE_reportf(reports, + RPT_WARNING, + "Image can't be saved, no valid file path: \"%s\"", + ima->filepath); } } } @@ -3044,7 +3046,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, - ima->name, + ima->filepath, "textures", BKE_image_has_packedfile(ima) ? ((ImagePackedFile *)ima->packedfiles.first)->packedfile : diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c index 04df0f0d4f0..836830916ed 100644 --- a/source/blender/editors/space_info/space_info.c +++ b/source/blender/editors/space_info/space_info.c @@ -77,7 +77,7 @@ static SpaceLink *info_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen region->regiontype = RGN_TYPE_WINDOW; /* keep in sync with console */ - region->v2d.scroll |= (V2D_SCROLL_RIGHT); + region->v2d.scroll |= V2D_SCROLL_RIGHT; region->v2d.align |= V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y; /* align bottom left */ region->v2d.keepofs |= V2D_LOCKOFS_X; region->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); @@ -139,7 +139,6 @@ static void info_main_region_draw(const bContext *C, ARegion *region) /* draw entirely, view changes should be handled here */ SpaceInfo *sinfo = CTX_wm_space_info(C); View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; /* clear and setup matrix */ UI_ThemeClearColor(TH_BACK); @@ -161,9 +160,7 @@ static void info_main_region_draw(const bContext *C, ARegion *region) UI_view2d_view_restore(C); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); } static void info_operatortypes(void) diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 307b6d9bc21..d0d9f2f57bb 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -407,7 +407,7 @@ static void nla_panel_properties(const bContext *C, Panel *panel) uiItemR(row, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE); // XXX as toggle? /* settings */ - column = uiLayoutColumnWithHeading(layout, true, "Playback"); + column = uiLayoutColumnWithHeading(layout, true, IFACE_("Playback")); row = uiLayoutRow(column, true); uiLayoutSetActive(row, !(RNA_boolean_get(&strip_ptr, "use_animated_influence") || @@ -446,7 +446,7 @@ static void nla_panel_actclip(const bContext *C, Panel *panel) uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Frame Start"), ICON_NONE); uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End"), ICON_NONE); - row = uiLayoutRowWithHeading(layout, false, "Sync Length"); + row = uiLayoutRowWithHeading(layout, false, IFACE_("Sync Length")); uiItemR(row, &strip_ptr, "use_sync_length", 0, "", ICON_NONE); uiItemO(row, IFACE_("Now"), ICON_FILE_REFRESH, "NLA_OT_action_sync_length"); diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index f060693d9f4..b09536e0621 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -120,7 +120,7 @@ static SpaceLink *nla_new(const ScrArea *area, const Scene *scene) region->v2d.minzoom = 0.01f; region->v2d.maxzoom = 50; region->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); - region->v2d.scroll |= (V2D_SCROLL_RIGHT); + region->v2d.scroll |= V2D_SCROLL_RIGHT; region->v2d.keepzoom = V2D_LOCKZOOM_Y; region->v2d.keepofs = V2D_KEEPOFS_Y; region->v2d.align = V2D_ALIGN_NO_POS_Y; @@ -191,7 +191,6 @@ static void nla_channel_region_draw(const bContext *C, ARegion *region) { bAnimContext ac; View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; /* clear and setup matrix */ UI_ThemeClearColor(TH_BACK); @@ -211,9 +210,7 @@ static void nla_channel_region_draw(const bContext *C, ARegion *region) UI_view2d_view_restore(C); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); } /* add handlers, stuff you only do once or on area/region changes */ @@ -237,7 +234,6 @@ static void nla_main_region_draw(const bContext *C, ARegion *region) Scene *scene = CTX_data_scene(C); bAnimContext ac; View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; short cfra_flag = 0; /* clear and setup matrix */ @@ -263,13 +259,10 @@ static void nla_main_region_draw(const bContext *C, ARegion *region) UI_view2d_text_cache_draw(region); } - UI_view2d_view_ortho(v2d); - /* current frame */ if (snla->flag & SNLA_DRAWTIME) { cfra_flag |= DRAWCFRA_UNIT_SECONDS; } - ANIM_draw_cfra(C, v2d, cfra_flag); /* markers */ UI_view2d_view_orthoSpecial(region, v2d, 1); @@ -290,11 +283,20 @@ static void nla_main_region_draw(const bContext *C, ARegion *region) UI_view2d_view_restore(C); ED_time_scrub_draw(region, scene, snla->flag & SNLA_DRAWTIME, true); +} + +static void nla_main_region_draw_overlay(const bContext *C, ARegion *region) +{ + /* draw entirely, view changes should be handled here */ + const SpaceNla *snla = CTX_wm_space_nla(C); + const Scene *scene = CTX_data_scene(C); + View2D *v2d = ®ion->v2d; + + /* scrubbing region */ + ED_time_scrub_draw_current_frame(region, scene, snla->flag & SNLA_DRAWTIME, true); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); } /* add handlers, stuff you only do once or on area/region changes */ @@ -620,6 +622,7 @@ void ED_spacetype_nla(void) art->regionid = RGN_TYPE_WINDOW; art->init = nla_main_region_init; art->draw = nla_main_region_draw; + art->draw_overlay = nla_main_region_draw_overlay; art->listener = nla_main_region_listener; art->message_subscribe = nla_main_region_message_subscribe; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 4e21cdc9d16..f8c30f9a688 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -75,10 +75,6 @@ if(WITH_OPENIMAGEDENOISE) add_definitions(-DWITH_OPENIMAGEDENOISE) endif() -if (WITH_NEW_SIMULATION_TYPE) - add_definitions(-DWITH_NEW_SIMULATION_TYPE) -endif() - add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 01ac3a80871..234ca5d5ce6 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -849,12 +849,35 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, NULL, ICON_NONE); - if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NEW) { + if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_PREETHAM) { + uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, NULL, ICON_NONE); + } + if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_HOSEK) { + uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, NULL, ICON_NONE); uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, NULL, ICON_NONE); } + if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) { + uiItemR(layout, ptr, "sun_disc", DEFAULT_FLAGS, NULL, 0); + + if (RNA_boolean_get(ptr, "sun_disc")) { + uiItemR(layout, ptr, "sun_size", DEFAULT_FLAGS, NULL, ICON_NONE); + } + + uiLayout *col; + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "sun_elevation", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "sun_rotation", DEFAULT_FLAGS, NULL, ICON_NONE); + + uiItemR(layout, ptr, "altitude", DEFAULT_FLAGS, NULL, ICON_NONE); + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "air_density", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "dust_density", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "ozone_density", DEFAULT_FLAGS, NULL, ICON_NONE); + } } static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -991,7 +1014,14 @@ static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, Pointer PointerRNA obptr = CTX_data_pointer_get(C, "active_object"); if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) { PointerRNA dataptr = RNA_pointer_get(&obptr, "data"); - uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL); + + if (RNA_collection_length(&dataptr, "sculpt_vertex_colors")) { + uiItemPointerR( + layout, ptr, "layer_name", &dataptr, "sculpt_vertex_colors", "", ICON_GROUP_VCOL); + } + else { + uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL); + } } else { uiItemL(layout, "No mesh in active object.", ICON_ERROR); diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index bd8950c5085..c3823d8eb27 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -1323,7 +1323,7 @@ static void node_draw_basis(const bContext *C, UI_BTYPE_LABEL, 0, showname, - (int)(rct->xmin + (NODE_MARGIN_X)), + (int)(rct->xmin + NODE_MARGIN_X), (int)(rct->ymax - NODE_DY), (short)(iconofs - rct->xmin - 18.0f), (short)NODE_DY, @@ -1772,7 +1772,6 @@ static void draw_group_overlay(const bContext *C, ARegion *region) void drawnodespace(const bContext *C, ARegion *region) { wmWindow *win = CTX_wm_window(C); - View2DScrollers *scrollers; SpaceNode *snode = CTX_wm_space_node(C); View2D *v2d = ®ion->v2d; @@ -1921,7 +1920,5 @@ void drawnodespace(const bContext *C, ARegion *region) draw_tree_path(snode); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index ac58ec1e636..11d87148713 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1428,11 +1428,15 @@ int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op)) Scene *sce = CTX_data_scene(C); bNode *node; + /* This is actually a test whether scene is used by the compositor or not. + * All the nodes are using same render result, so there is no need to do + * anything smart about check how exactly scene is used. */ for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == (ID *)sce && node->need_exec) { + if (node->id == (ID *)sce) { break; } } + if (node) { ViewLayer *view_layer = BLI_findlink(&sce->view_layers, node->custom1); diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index f339d11b842..562aa6b078c 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -936,11 +936,10 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item, bool free; const EnumPropertyItem *item_src = RNA_enum_node_tree_types_itemf_impl(C, &free); for (const EnumPropertyItem *item_iter = item_src; item_iter->identifier; item_iter++) { -#ifndef WITH_NEW_SIMULATION_TYPE - if (STREQ(item_iter->identifier, "SimulationNodeTree")) { + if (!U.experimental.use_new_particle_system && + STREQ(item_iter->identifier, "SimulationNodeTree")) { continue; } -#endif RNA_enum_item_add(item, totitem, item_iter); } if (free) { diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 82ff9e06194..131491fcc40 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -581,7 +581,8 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op) "it won't be linked to any view layer"); } - BKE_collection_duplicate(bmain, parent, collection, true, true, !linked); + const eDupli_ID_Flags dupli_flags = USER_DUP_OBJECT | (linked ? 0 : U.dupflag); + BKE_collection_duplicate(bmain, parent, collection, dupli_flags, 0); DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C)); diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index c2c9f3a5bfb..70a628eead0 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -907,6 +907,9 @@ static int outliner_item_drag_drop_invoke(bContext *C, return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } + /* Scroll view when dragging near edges */ + WM_operator_name_call(C, "VIEW2D_OT_edge_pan", WM_OP_INVOKE_DEFAULT, NULL); + wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP); if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) { diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 9a9bd610322..5eee97e3fee 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -709,9 +709,9 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) Library *lib = (Library *)tselem->id; char expanded[FILE_MAX]; - BKE_library_filepath_set(bmain, lib, lib->name); + BKE_library_filepath_set(bmain, lib, lib->filepath); - BLI_strncpy(expanded, lib->name, sizeof(expanded)); + BLI_strncpy(expanded, lib->filepath, sizeof(expanded)); BLI_path_abs(expanded, BKE_main_blendfile_path(bmain)); if (!BLI_exists(expanded)) { BKE_reportf(CTX_wm_reports(C), @@ -1657,7 +1657,6 @@ static void outliner_draw_userbuts(uiBlock *block, uiBut *bt; ID *id = tselem->id; const char *tip = NULL; - int icon = ICON_NONE; char buf[16] = ""; int but_flag = UI_BUT_DRAG_LOCK; @@ -1683,18 +1682,16 @@ static void outliner_draw_userbuts(uiBlock *block, UI_but_flag_enable(bt, but_flag); if (id->flag & LIB_FAKEUSER) { - icon = ICON_FILE_TICK; tip = TIP_("Data-block will be retained using a fake user"); } else { - icon = ICON_X; tip = TIP_("Data-block has no users and will be deleted"); } bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, LIB_FAKEUSER, 1, - icon, + ICON_FAKE_USER_OFF, (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS), te->ys, UI_UNIT_X, @@ -1707,25 +1704,6 @@ static void outliner_draw_userbuts(uiBlock *block, tip); UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); UI_but_flag_enable(bt, but_flag); - - bt = uiDefButBitS(block, - UI_BTYPE_ICON_TOGGLE, - LIB_FAKEUSER, - 1, - (id->flag & LIB_FAKEUSER) ? "F" : " ", - (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_FAKEUSER), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &id->flag, - 0, - 0, - 0, - 0, - TIP_("Data-block has a 'fake' user which will keep it in the file " - "even if nothing else uses it")); - UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); - UI_but_flag_enable(bt, but_flag); } } @@ -1864,7 +1842,7 @@ static void outliner_buttons(const bContext *C, len = sizeof(((ModifierData *)0)->name); } else if (tselem->id && GS(tselem->id->name) == ID_LI) { - len = sizeof(((Library *)0)->name); + len = sizeof(((Library *)0)->filepath); } else { len = MAX_ID_NAME - 2; @@ -2288,6 +2266,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.icon = ICON_MATERIAL_DATA; break; case TSE_POSEGRP_BASE: + case TSE_POSEGRP: data.icon = ICON_GROUP_BONE; break; case TSE_SEQUENCE: @@ -2702,7 +2681,7 @@ static void tselem_draw_icon(uiBlock *block, 0.0, 1.0, alpha, - (data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->name : ""); + (data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->filepath : ""); } } @@ -3129,18 +3108,13 @@ static void outliner_draw_tree_element(bContext *C, offsx += 2 * ufac; } - if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) && ID_IS_LINKED(tselem->id)) { - if (tselem->id->tag & LIB_TAG_MISSING) { - UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, - (float)*starty + 2 * ufac, - ICON_LIBRARY_DATA_BROKEN, - alpha_fac); - } - else if (tselem->id->tag & LIB_TAG_INDIRECT) { - UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, - (float)*starty + 2 * ufac, - ICON_LIBRARY_DATA_INDIRECT, - alpha_fac); + if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) || + ((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) { + const BIFIconID lib_icon = UI_library_icon_get(tselem->id); + if (lib_icon != ICON_NONE) { + UI_icon_draw_alpha( + (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, lib_icon, alpha_fac); + offsx += UI_UNIT_X + 4 * ufac; } else { UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, @@ -3171,13 +3145,6 @@ static void outliner_draw_tree_element(bContext *C, } offsx += UI_UNIT_X + 4 * ufac; } - else if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) && ID_IS_OVERRIDE_LIBRARY(tselem->id)) { - UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, - (float)*starty + 2 * ufac, - ICON_LIBRARY_DATA_OVERRIDE, - alpha_fac); - offsx += UI_UNIT_X + 4 * ufac; - } GPU_blend(false); /* name */ diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 3db75d9288b..bee8b28e658 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -191,7 +191,14 @@ static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEv /* Only toggle openclose on the same level as the first clicked element */ if (te->xs == data->x_location) { outliner_item_openclose(te, data->open, false); - ED_region_tag_redraw(region); + + /* Avoid rebuild if possible. */ + if (outliner_element_needs_rebuild_on_open_change(TREESTORE(te))) { + ED_region_tag_redraw(region); + } + else { + ED_region_tag_redraw_no_rebuild(region); + } } } @@ -231,7 +238,13 @@ static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmE (toggle_all && (outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1))); outliner_item_openclose(te, open, toggle_all); - ED_region_tag_redraw(region); + /* Avoid rebuild if possible. */ + if (outliner_element_needs_rebuild_on_open_change(TREESTORE(te))) { + ED_region_tag_redraw(region); + } + else { + ED_region_tag_redraw_no_rebuild(region); + } /* Only toggle once for single click toggling */ if (event->type == LEFTMOUSE) { @@ -532,7 +545,7 @@ static int outliner_id_delete_invoke_do(bContext *C, BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Cannot delete indirectly linked library '%s'", - ((Library *)tselem->id)->filepath); + ((Library *)tselem->id)->filepath_abs); return OPERATOR_CANCELLED; } id_delete(C, reports, te, tselem); @@ -898,12 +911,13 @@ static int lib_relocate( Library *lib = (Library *)tselem->id; char dir[FILE_MAXDIR], filename[FILE_MAX]; - BLI_split_dirfile(lib->filepath, dir, filename, sizeof(dir), sizeof(filename)); + BLI_split_dirfile(lib->filepath_abs, dir, filename, sizeof(dir), sizeof(filename)); - printf("%s, %s\n", tselem->id->name, lib->filepath); + printf("%s, %s\n", tselem->id->name, lib->filepath_abs); - /* We assume if both paths in lib are not the same then lib->name was relative... */ - RNA_boolean_set(&op_props, "relative_path", BLI_path_cmp(lib->filepath, lib->name) != 0); + /* We assume if both paths in lib are not the same then `lib->filepath` was relative. */ + RNA_boolean_set( + &op_props, "relative_path", BLI_path_cmp(lib->filepath_abs, lib->filepath) != 0); RNA_string_set(&op_props, "directory", dir); RNA_string_set(&op_props, "filename", filename); @@ -930,7 +944,7 @@ static int outliner_lib_relocate_invoke_do( BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Cannot relocate indirectly linked library '%s'", - ((Library *)tselem->id)->filepath); + ((Library *)tselem->id)->filepath_abs); return OPERATOR_CANCELLED; } else { diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index f2b64bc2a4b..b590eb75407 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -163,8 +163,7 @@ typedef enum { #define OL_Y_OFFSET 2 #define OL_TOG_USER_BUTS_USERS (UI_UNIT_X * 2.0f + V2D_SCROLL_WIDTH) -#define OL_TOG_USER_BUTS_STATUS (UI_UNIT_X * 3.0f + V2D_SCROLL_WIDTH) -#define OL_TOG_USER_BUTS_FAKEUSER (UI_UNIT_X + V2D_SCROLL_WIDTH) +#define OL_TOG_USER_BUTS_STATUS (UI_UNIT_X + V2D_SCROLL_WIDTH) #define OL_RNA_COLX (UI_UNIT_X * 15) #define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f) @@ -216,6 +215,16 @@ typedef struct TreeViewContext { Object *ob_pose; } TreeViewContext; +typedef enum TreeItemSelectAction { + OL_ITEM_DESELECT = 0, /* Deselect the item */ + OL_ITEM_SELECT = (1 << 0), /* Select the item */ + OL_ITEM_SELECT_DATA = (1 << 1), /* Select object data */ + OL_ITEM_ACTIVATE = (1 << 2), /* Activate the item */ + OL_ITEM_EXTEND = (1 << 3), /* Extend the current selection */ + OL_ITEM_RECURSIVE = (1 << 4), /* Select recursively */ + OL_ITEM_TOGGLE_MODE = (1 << 5) /* Temporary */ +} TreeItemSelectAction; + /* outliner_tree.c ----------------------------------------------- */ void outliner_free_tree(ListBase *tree); @@ -228,6 +237,8 @@ void outliner_build_tree(struct Main *mainvar, struct SpaceOutliner *soops, struct ARegion *region); +bool outliner_element_needs_rebuild_on_open_change(const TreeStoreElem *tselem); + typedef struct IDsSelectedData { struct ListBase selected_array; } IDsSelectedData; @@ -266,21 +277,16 @@ eOLDrawState tree_element_active(struct bContext *C, const eOLSetState set, const bool handle_all_types); -void outliner_item_do_activate_from_tree_element( - struct bContext *C, TreeElement *te, TreeStoreElem *tselem, bool extend, bool recursive); - -void outliner_item_select(struct SpaceOutliner *soops, - const struct TreeElement *te, - const bool extend, - const bool toggle); +void outliner_item_select(struct bContext *C, + struct SpaceOutliner *soops, + struct TreeElement *te, + const short select_flag); void outliner_object_mode_toggle(struct bContext *C, Scene *scene, ViewLayer *view_layer, Base *base); -void outliner_element_activate(struct SpaceOutliner *soops, struct TreeStoreElem *tselem); - bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x); bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x); @@ -495,6 +501,7 @@ TreeElement *outliner_find_parent_element(ListBase *lb, TreeElement *outliner_find_id(struct SpaceOutliner *soops, ListBase *lb, const struct ID *id); TreeElement *outliner_find_posechannel(ListBase *lb, const struct bPoseChannel *pchan); TreeElement *outliner_find_editbone(ListBase *lb, const struct EditBone *ebone); +TreeElement *outliner_search_back_te(TreeElement *te, short idcode); struct ID *outliner_search_back(TreeElement *te, short idcode); bool outliner_tree_traverse(const SpaceOutliner *soops, ListBase *tree, diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index fa8422573ab..8a408a41897 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -111,7 +111,7 @@ static bool do_outliner_activate_common(bContext *C, * If extend is used, we try to have the other compatible selected objects in the new mode as well. * Otherwise only the new object will be active, selected and in the edit mode. */ -static void do_outliner_activate_obdata( +static void do_outliner_item_editmode_toggle( bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend) { Main *bmain = CTX_data_main(C); @@ -159,7 +159,7 @@ static void do_outliner_activate_obdata( } } -static void do_outliner_activate_pose( +static void do_outliner_item_posemode_toggle( bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend) { Main *bmain = CTX_data_main(C); @@ -214,10 +214,42 @@ void outliner_object_mode_toggle(bContext *C, Scene *scene, ViewLayer *view_laye { Object *obact = OBACT(view_layer); if (obact->mode & OB_MODE_EDIT) { - do_outliner_activate_obdata(C, scene, view_layer, base, true); + do_outliner_item_editmode_toggle(C, scene, view_layer, base, true); } else if (obact->mode & OB_MODE_POSE) { - do_outliner_activate_pose(C, scene, view_layer, base, true); + do_outliner_item_posemode_toggle(C, scene, view_layer, base, true); + } +} + +/* Toggle the item's interaction mode if supported */ +static void outliner_item_mode_toggle(bContext *C, + TreeViewContext *tvc, + TreeElement *te, + const bool extend) +{ + TreeStoreElem *tselem = TREESTORE(te); + + if (tselem->type == 0) { + if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) { + Object *ob = (Object *)outliner_search_back(te, ID_OB); + if ((ob != NULL) && (ob->data == tselem->id)) { + Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); + if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { + do_outliner_item_editmode_toggle(C, tvc->scene, tvc->view_layer, base, extend); + } + } + } + else if (ELEM(te->idcode, ID_GD)) { + /* set grease pencil to object mode */ + WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); + } + } + else if (tselem->type == TSE_POSE_BASE) { + Object *ob = (Object *)tselem->id; + Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); + if (base != NULL) { + do_outliner_item_posemode_toggle(C, tvc->scene, tvc->view_layer, base, extend); + } } } @@ -302,28 +334,32 @@ static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_p static eOLDrawState tree_element_set_active_object(bContext *C, Scene *scene, ViewLayer *view_layer, - SpaceOutliner *soops, + SpaceOutliner *UNUSED(soops), TreeElement *te, const eOLSetState set, bool recursive) { TreeStoreElem *tselem = TREESTORE(te); TreeStoreElem *parent_tselem = NULL; + TreeElement *parent_te = NULL; Scene *sce; Base *base; Object *ob = NULL; - TreeElement *te_ob = NULL; /* if id is not object, we search back */ - if (te->idcode == ID_OB) { + if (tselem->type == 0 && te->idcode == ID_OB) { ob = (Object *)tselem->id; } else { - ob = (Object *)outliner_search_back(te, ID_OB); - - /* Don't return when activating children of the previous active object. */ - if (ob == OBACT(view_layer) && set == OL_SETSEL_NONE) { - return OL_DRAWSEL_NONE; + parent_te = outliner_search_back_te(te, ID_OB); + if (parent_te) { + parent_tselem = TREESTORE(parent_te); + ob = (Object *)parent_tselem->id; + + /* Don't return when activating children of the previous active object. */ + if (ob == OBACT(view_layer) && set == OL_SETSEL_NONE) { + return OL_DRAWSEL_NONE; + } } } if (ob == NULL) { @@ -356,11 +392,6 @@ static eOLDrawState tree_element_set_active_object(bContext *C, } } - te_ob = outliner_find_id(soops, &soops->tree, (ID *)ob); - if (te_ob != NULL && te_ob != te) { - parent_tselem = TREESTORE(te_ob); - } - if (base) { if (set == OL_SETSEL_EXTEND) { /* swap select */ @@ -863,8 +894,8 @@ static eOLDrawState tree_element_active_text(bContext *UNUSED(C), return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_pose(bContext *C, - Scene *scene, +static eOLDrawState tree_element_active_pose(bContext *UNUSED(C), + Scene *UNUSED(scene), ViewLayer *view_layer, TreeElement *UNUSED(te), TreeStoreElem *tselem, @@ -879,7 +910,6 @@ static eOLDrawState tree_element_active_pose(bContext *C, } if (set != OL_SETSEL_NONE) { - do_outliner_activate_pose(C, scene, view_layer, base, (set == OL_SETSEL_EXTEND)); } else { if (ob->mode & OB_MODE_POSE) { @@ -1113,13 +1143,6 @@ eOLDrawState tree_element_type_active(bContext *C, /* ================================================ */ -/* Activate a tree store element and set the walk navigation start element */ -void outliner_element_activate(SpaceOutliner *soops, TreeStoreElem *tselem) -{ - outliner_flag_set(&soops->tree, TSE_ACTIVE | TSE_ACTIVE_WALK, false); - tselem->flag |= TSE_ACTIVE | TSE_ACTIVE_WALK; -} - /** * Action when clicking to activate an item (typically under the mouse cursor), * but don't do any cursor intersection checks. @@ -1133,9 +1156,8 @@ static void do_outliner_item_activate_tree_element(bContext *C, TreeStoreElem *tselem, const bool extend, const bool recursive, - const bool is_over_name_icons) + const bool do_activate_data) { - bool do_activate_data = soops->flag & SO_SYNC_SELECT || is_over_name_icons; /* Always makes active object, except for some specific types. */ if (ELEM(tselem->type, TSE_SEQUENCE, @@ -1153,7 +1175,6 @@ static void do_outliner_item_activate_tree_element(bContext *C, /* Support pose mode toggle, keeping the active object as is. */ } else if (do_activate_data) { - /* Only activate when synced selection is enabled */ tree_element_set_active_object(C, tvc->scene, tvc->view_layer, @@ -1164,9 +1185,6 @@ static void do_outliner_item_activate_tree_element(bContext *C, recursive && tselem->type == 0); } - /* Mark as active in the outliner */ - outliner_element_activate(soops, tselem); - if (tselem->type == 0) { // the lib blocks if (do_activate_data == false) { /* Only select in outliner. */ @@ -1216,19 +1234,6 @@ static void do_outliner_item_activate_tree_element(bContext *C, DEG_id_tag_update(&tvc->scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, tvc->scene); } - else if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) { - Object *ob = (Object *)outliner_search_back(te, ID_OB); - if ((ob != NULL) && (ob->data == tselem->id)) { - Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); - if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { - do_outliner_activate_obdata(C, tvc->scene, tvc->view_layer, base, extend); - } - } - } - else if (ELEM(te->idcode, ID_GD)) { - /* set grease pencil to object mode */ - WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); - } else { // rest of types tree_element_active(C, tvc, soops, te, OL_SETSEL_NORMAL, false); } @@ -1239,23 +1244,49 @@ static void do_outliner_item_activate_tree_element(bContext *C, } } -/** - * \param extend: Don't deselect other items, only modify \a te. - * \param toggle: Select \a te when not selected, deselect when selected. - */ -void outliner_item_select(SpaceOutliner *soops, - const TreeElement *te, - const bool extend, - const bool toggle) +/* Select the item using the set flags */ +void outliner_item_select(bContext *C, + SpaceOutliner *soops, + TreeElement *te, + const short select_flag) { TreeStoreElem *tselem = TREESTORE(te); - const short new_flag = (toggle && (tselem->flag & TSE_ACTIVE)) ? (tselem->flag ^ TSE_SELECTED) : - (tselem->flag | TSE_SELECTED); + const bool activate = select_flag & OL_ITEM_ACTIVATE; + const bool extend = select_flag & OL_ITEM_EXTEND; + const bool activate_data = select_flag & OL_ITEM_SELECT_DATA; - if (extend == false) { - outliner_flag_set(&soops->tree, TSE_SELECTED, false); + /* Clear previous active when activating and clear selection when not extending selection */ + const short clear_flag = (activate ? TSE_ACTIVE : 0) | (extend ? 0 : TSE_SELECTED); + if (clear_flag) { + outliner_flag_set(&soops->tree, clear_flag, false); + } + + if (select_flag & OL_ITEM_SELECT) { + tselem->flag |= TSE_SELECTED; + } + else { + tselem->flag &= ~TSE_SELECTED; + } + + if (activate) { + TreeViewContext tvc; + outliner_viewcontext_init(C, &tvc); + + tselem->flag |= TSE_ACTIVE; + do_outliner_item_activate_tree_element(C, + &tvc, + soops, + te, + tselem, + extend, + select_flag & OL_ITEM_RECURSIVE, + activate_data || soops->flag & SO_SYNC_SELECT); + + /* Mode toggle on data activate for now, but move later */ + if (select_flag & OL_ITEM_TOGGLE_MODE) { + outliner_item_mode_toggle(C, &tvc, te, extend); + } } - tselem->flag = new_flag; } static bool do_outliner_range_select_recursive(ListBase *lb, @@ -1298,8 +1329,7 @@ static void do_outliner_range_select(bContext *C, /* If no active element exists, activate the element under the cursor */ if (!active) { - outliner_item_select(soops, cursor, false, false); - outliner_item_do_activate_from_tree_element(C, cursor, TREESTORE(cursor), false, false); + outliner_item_select(C, soops, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE); return; } @@ -1312,14 +1342,13 @@ static void do_outliner_range_select(bContext *C, /* Select active if under cursor */ if (active == cursor) { - TREESTORE(cursor)->flag |= TSE_SELECTED; + outliner_item_select(C, soops, cursor, OL_ITEM_SELECT); return; } - /* If active is not selected, select the element under the cursor */ + /* If active is not selected or visible, select and activate the element under the cursor */ if (!active_selected || !outliner_is_element_visible(active)) { - outliner_item_select(soops, cursor, false, false); - outliner_item_do_activate_from_tree_element(C, cursor, TREESTORE(cursor), false, false); + outliner_item_select(C, soops, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE); return; } @@ -1334,23 +1363,6 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops, } /** - * A version of #outliner_item_do_activate_from_cursor that takes the tree element directly. - * and doesn't depend on the pointer position. - * - * This allows us to simulate clicking on an item without dealing with the mouse cursor. - */ -void outliner_item_do_activate_from_tree_element( - bContext *C, TreeElement *te, TreeStoreElem *tselem, bool extend, bool recursive) -{ - SpaceOutliner *soops = CTX_wm_space_outliner(C); - - TreeViewContext tvc; - outliner_viewcontext_init(C, &tvc); - - do_outliner_item_activate_tree_element(C, &tvc, soops, te, tselem, extend, recursive, false); -} - -/** * Action to run when clicking in the outliner, * * May expend/collapse branches or activate items. @@ -1402,14 +1414,17 @@ static int outliner_item_do_activate_from_cursor(bContext *C, do_outliner_range_select(C, soops, activate_te, extend); } else { - TreeViewContext tvc; - outliner_viewcontext_init(C, &tvc); - const bool is_over_name_icons = outliner_item_is_co_over_name_icons(activate_te, view_mval[0]); - outliner_item_select(soops, activate_te, extend, extend); - do_outliner_item_activate_tree_element( - C, &tvc, soops, activate_te, activate_tselem, extend, false, is_over_name_icons); + /* Always select unless already active and selected */ + const bool select = !extend || !(activate_tselem->flag & TSE_ACTIVE && + activate_tselem->flag & TSE_SELECTED); + + const short select_flag = OL_ITEM_ACTIVATE | (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | + (is_over_name_icons ? OL_ITEM_SELECT_DATA : 0) | + (extend ? OL_ITEM_EXTEND : 0) | OL_ITEM_TOGGLE_MODE; + + outliner_item_select(C, soops, activate_te, select_flag); } changed = true; @@ -1468,23 +1483,19 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot) /* **************** Box Select Tool ****************** */ static void outliner_item_box_select( - SpaceOutliner *soops, Scene *scene, rctf *rectf, TreeElement *te, bool select) + bContext *C, SpaceOutliner *soops, Scene *scene, rctf *rectf, TreeElement *te, bool select) { TreeStoreElem *tselem = TREESTORE(te); if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) { - if (select) { - tselem->flag |= TSE_SELECTED; - } - else { - tselem->flag &= ~TSE_SELECTED; - } + outliner_item_select( + C, soops, te, (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | OL_ITEM_EXTEND); } /* Look at its children. */ if (TSELEM_OPEN(tselem, soops)) { for (te = te->subtree.first; te; te = te->next) { - outliner_item_box_select(soops, scene, rectf, te, select); + outliner_item_box_select(C, soops, scene, rectf, te, select); } } } @@ -1506,7 +1517,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op) UI_view2d_region_to_view_rctf(®ion->v2d, &rectf, &rectf); LISTBASE_FOREACH (TreeElement *, te, &soops->tree) { - outliner_item_box_select(soops, scene, &rectf, te, select); + outliner_item_box_select(C, soops, scene, &rectf, te, select); } DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); @@ -1587,17 +1598,17 @@ static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *soops, } /* Find previous visible element in the tree */ -static TreeElement *outliner_find_previous_element(SpaceOutliner *soops, TreeElement *walk_element) +static TreeElement *outliner_find_previous_element(SpaceOutliner *soops, TreeElement *te) { - if (walk_element->prev) { - walk_element = outliner_find_rightmost_visible_child(soops, walk_element->prev); + if (te->prev) { + te = outliner_find_rightmost_visible_child(soops, te->prev); } - else if (walk_element->parent) { + else if (te->parent) { /* Use parent if at beginning of list */ - walk_element = walk_element->parent; + te = te->parent; } - return walk_element; + return te; } /* Recursively search up the tree until a successor to a given element is found */ @@ -1618,98 +1629,78 @@ static TreeElement *outliner_element_find_successor_in_parents(TreeElement *te) } /* Find next visible element in the tree */ -static TreeElement *outliner_find_next_element(SpaceOutliner *soops, TreeElement *walk_element) +static TreeElement *outliner_find_next_element(SpaceOutliner *soops, TreeElement *te) { - TreeStoreElem *tselem = TREESTORE(walk_element); + TreeStoreElem *tselem = TREESTORE(te); - if (TSELEM_OPEN(tselem, soops) && walk_element->subtree.first) { - walk_element = walk_element->subtree.first; + if (TSELEM_OPEN(tselem, soops) && te->subtree.first) { + te = te->subtree.first; } - else if (walk_element->next) { - walk_element = walk_element->next; + else if (te->next) { + te = te->next; } else { - walk_element = outliner_element_find_successor_in_parents(walk_element); + te = outliner_element_find_successor_in_parents(te); } - return walk_element; + return te; } static TreeElement *do_outliner_select_walk(SpaceOutliner *soops, - TreeElement *walk_element, + TreeElement *te, const int direction, const bool extend, const bool toggle_all) { - TreeStoreElem *tselem = TREESTORE(walk_element); - - if (!extend) { - outliner_flag_set(&soops->tree, TSE_SELECTED, false); - } - tselem->flag &= ~TSE_ACTIVE_WALK; + TreeStoreElem *tselem = TREESTORE(te); switch (direction) { case UI_SELECT_WALK_UP: - walk_element = outliner_find_previous_element(soops, walk_element); + te = outliner_find_previous_element(soops, te); break; case UI_SELECT_WALK_DOWN: - walk_element = outliner_find_next_element(soops, walk_element); + te = outliner_find_next_element(soops, te); break; case UI_SELECT_WALK_LEFT: - outliner_item_openclose(walk_element, false, toggle_all); + outliner_item_openclose(te, false, toggle_all); break; case UI_SELECT_WALK_RIGHT: - outliner_item_openclose(walk_element, true, toggle_all); + outliner_item_openclose(te, true, toggle_all); break; } - TreeStoreElem *tselem_new = TREESTORE(walk_element); - /* If new element is already selected, deselect the previous element */ + TreeStoreElem *tselem_new = TREESTORE(te); if (extend) { tselem->flag = (tselem_new->flag & TSE_SELECTED) ? (tselem->flag & ~TSE_SELECTED) : (tselem->flag | TSE_SELECTED); } - tselem_new->flag |= TSE_SELECTED | TSE_ACTIVE_WALK; - - return walk_element; + return te; } -/* Find walk select element, or set it if it does not exist. - * Changed is set to true if walk element is found, false if it was set */ +/* Find the active element to walk from, or set one if none exists. + * Changed is set to true if the active element is found, or false if it was set */ static TreeElement *find_walk_select_start_element(SpaceOutliner *soops, bool *changed) { - TreeElement *walk_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE_WALK); - + TreeElement *active_te = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE); *changed = false; - /* If no walk element exists, start from active */ - if (!walk_element) { - TreeElement *active_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE); - - /* If no active element exists, use the first element in the tree */ - if (!active_element) { - walk_element = soops->tree.first; - } - else { - walk_element = active_element; - } - + /* If no active element exists, use the first element in the tree */ + if (!active_te) { + active_te = soops->tree.first; *changed = true; } - /* If walk element is not visible, set that element's first visible parent as walk element */ - if (!outliner_is_element_visible(walk_element)) { - TREESTORE(walk_element)->flag &= ~TSE_ACTIVE_WALK; - - while (!outliner_is_element_visible(walk_element)) { - walk_element = walk_element->parent; + /* If the active element is not visible, activate the first visible parent element */ + if (!outliner_is_element_visible(active_te)) { + while (!outliner_is_element_visible(active_te)) { + active_te = active_te->parent; } *changed = true; } - return walk_element; + return active_te; } /* Scroll the outliner when the walk element reaches the top or bottom boundary */ @@ -1738,18 +1729,18 @@ static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEven const bool toggle_all = RNA_boolean_get(op->ptr, "toggle_all"); bool changed; - TreeElement *walk_element = find_walk_select_start_element(soops, &changed); + TreeElement *active_te = find_walk_select_start_element(soops, &changed); - /* If finding the starting walk select element did not move the element, proceed to walk */ + /* If finding the active element did not modify the selection, proceed to walk */ if (!changed) { - walk_element = do_outliner_select_walk(soops, walk_element, direction, extend, toggle_all); - } - else { - TREESTORE(walk_element)->flag |= TSE_SELECTED | TSE_ACTIVE_WALK; + active_te = do_outliner_select_walk(soops, active_te, direction, extend, toggle_all); } + outliner_item_select( + C, soops, active_te, OL_ITEM_SELECT | OL_ITEM_ACTIVATE | (extend ? OL_ITEM_EXTEND : 0)); + /* Scroll outliner to focus on walk element */ - outliner_walk_scroll(region, walk_element); + outliner_walk_scroll(region, active_te); ED_outliner_select_sync_from_outliner(C, soops); ED_region_tag_redraw(region); diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c index 852773d3979..a4be4062746 100644 --- a/source/blender/editors/space_outliner/outliner_sync.c +++ b/source/blender/editors/space_outliner/outliner_sync.c @@ -392,7 +392,6 @@ void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *soops) } static void outliner_select_sync_from_object(ViewLayer *view_layer, - SpaceOutliner *soops, Object *obact, TreeElement *te, TreeStoreElem *tselem) @@ -403,7 +402,7 @@ static void outliner_select_sync_from_object(ViewLayer *view_layer, const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0); if (base && (ob == obact)) { - outliner_element_activate(soops, tselem); + tselem->flag |= TSE_ACTIVE; } else { tselem->flag &= ~TSE_ACTIVE; @@ -417,15 +416,14 @@ static void outliner_select_sync_from_object(ViewLayer *view_layer, } } -static void outliner_select_sync_from_edit_bone(SpaceOutliner *soops, - EditBone *ebone_active, +static void outliner_select_sync_from_edit_bone(EditBone *ebone_active, TreeElement *te, TreeStoreElem *tselem) { EditBone *ebone = (EditBone *)te->directdata; if (ebone == ebone_active) { - outliner_element_activate(soops, tselem); + tselem->flag |= TSE_ACTIVE; } else { tselem->flag &= ~TSE_ACTIVE; @@ -439,8 +437,7 @@ static void outliner_select_sync_from_edit_bone(SpaceOutliner *soops, } } -static void outliner_select_sync_from_pose_bone(SpaceOutliner *soops, - bPoseChannel *pchan_active, +static void outliner_select_sync_from_pose_bone(bPoseChannel *pchan_active, TreeElement *te, TreeStoreElem *tselem) { @@ -448,7 +445,7 @@ static void outliner_select_sync_from_pose_bone(SpaceOutliner *soops, Bone *bone = pchan->bone; if (pchan == pchan_active) { - outliner_element_activate(soops, tselem); + tselem->flag |= TSE_ACTIVE; } else { tselem->flag &= ~TSE_ACTIVE; @@ -462,14 +459,12 @@ static void outliner_select_sync_from_pose_bone(SpaceOutliner *soops, } } -static void outliner_select_sync_from_sequence(SpaceOutliner *soops, - Sequence *sequence_active, - TreeStoreElem *tselem) +static void outliner_select_sync_from_sequence(Sequence *sequence_active, TreeStoreElem *tselem) { Sequence *seq = (Sequence *)tselem->id; if (seq == sequence_active) { - outliner_element_activate(soops, tselem); + tselem->flag |= TSE_ACTIVE; } else { tselem->flag &= ~TSE_ACTIVE; @@ -506,26 +501,26 @@ static void outliner_sync_selection_to_outliner(ViewLayer *view_layer, if (tselem->type == 0 && te->idcode == ID_OB) { if (sync_types->object) { - outliner_select_sync_from_object(view_layer, soops, active_data->object, te, tselem); + outliner_select_sync_from_object(view_layer, active_data->object, te, tselem); } } else if (tselem->type == TSE_EBONE) { if (sync_types->edit_bone) { - outliner_select_sync_from_edit_bone(soops, active_data->edit_bone, te, tselem); + outliner_select_sync_from_edit_bone(active_data->edit_bone, te, tselem); } } else if (tselem->type == TSE_POSE_CHANNEL) { if (sync_types->pose_bone) { - outliner_select_sync_from_pose_bone(soops, active_data->pose_channel, te, tselem); + outliner_select_sync_from_pose_bone(active_data->pose_channel, te, tselem); } } else if (tselem->type == TSE_SEQUENCE) { if (sync_types->sequence) { - outliner_select_sync_from_sequence(soops, active_data->sequence, tselem); + outliner_select_sync_from_sequence(active_data->sequence, tselem); } } else { - tselem->flag &= ~TSE_SELECTED; + tselem->flag &= ~(TSE_SELECTED | TSE_ACTIVE); } /* Sync subtree elements */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index b4c5dd8813a..51b919cd0dc 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -44,6 +44,7 @@ #include "DNA_world_types.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" #include "BLI_utildefines.h" #include "BKE_anim_data.h" @@ -573,8 +574,7 @@ static void merged_element_search_exec_fn(struct bContext *C, void *UNUSED(arg1) SpaceOutliner *soops = CTX_wm_space_outliner(C); TreeElement *te = (TreeElement *)element; - outliner_item_select(soops, te, false, false); - outliner_item_do_activate_from_tree_element(C, te, te->store_elem, false, false); + outliner_item_select(C, soops, te, OL_ITEM_SELECT | OL_ITEM_ACTIVATE); ED_outliner_select_sync_from_outliner(C, soops); } @@ -664,12 +664,13 @@ static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, + TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { /* Don't extend because this toggles, which is nice for Ctrl-Click but not for a menu item. * it's especially confusing when multiple items are selected since some toggle on/off. */ - outliner_item_do_activate_from_tree_element(C, te, tselem, false, true); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + outliner_item_select(C, soops, te, OL_ITEM_SELECT | OL_ITEM_ACTIVATE | OL_ITEM_RECURSIVE); } static void object_deselect_cb(bContext *C, @@ -689,12 +690,8 @@ static void object_deselect_cb(bContext *C, } } -static void outliner_object_delete(bContext *C, - ReportList *reports, - Scene *scene, - TreeStoreElem *tselem) +static void outliner_object_delete_fn(bContext *C, ReportList *reports, Scene *scene, Object *ob) { - Object *ob = (Object *)tselem->id; if (ob) { Main *bmain = CTX_data_main(C); if (ob->id.tag & LIB_TAG_INDIRECT) { @@ -862,7 +859,6 @@ void outliner_do_object_operation_ex(bContext *C, bool select_recurse) { TreeElement *te; - for (te = lb->first; te; te = te->next) { TreeStoreElem *tselem = TREESTORE(te); bool select_handled = false; @@ -1177,82 +1173,6 @@ static void outliner_do_data_operation( } } -static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *scene, Base *base) -{ - Base *child_base, *base_next; - Object *parent; - ViewLayer *view_layer = CTX_data_view_layer(C); - - if (!base) { - return NULL; - } - - for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) { - base_next = child_base->next; - for (parent = child_base->object->parent; parent && (parent != base->object); - parent = parent->parent) { - /* pass */ - } - if (parent) { - base_next = outline_delete_hierarchy(C, reports, scene, child_base); - } - } - - base_next = base->next; - - Main *bmain = CTX_data_main(C); - if (base->object->id.tag & LIB_TAG_INDIRECT) { - BKE_reportf(reports, - RPT_WARNING, - "Cannot delete indirectly linked object '%s'", - base->object->id.name + 2); - return base_next; - } - else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && - ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) { - BKE_reportf(reports, - RPT_WARNING, - "Cannot delete object '%s' from scene '%s', indirectly used objects need at least " - "one user", - base->object->id.name + 2, - scene->id.name + 2); - return base_next; - } - ED_object_base_free_and_unlink(CTX_data_main(C), scene, base->object); - return base_next; -} - -static void object_delete_hierarchy_cb(bContext *C, - ReportList *reports, - Scene *scene, - TreeElement *te, - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *UNUSED(user_data)) -{ - ViewLayer *view_layer = CTX_data_view_layer(C); - Base *base = (Base *)te->directdata; - Object *obedit = CTX_data_edit_object(C); - - if (!base) { - base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id); - } - if (base) { - /* Check also library later. */ - for (; obedit && (obedit != base->object); obedit = obedit->parent) { - /* pass */ - } - if (obedit == base->object) { - ED_object_editmode_exit(C, EM_FREEDATA); - } - - outline_delete_hierarchy(C, reports, scene, base); - } - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); -} - static Base *outline_batch_delete_hierarchy( ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base) { @@ -1305,21 +1225,16 @@ static Base *outline_batch_delete_hierarchy( return base_next; } -static void object_batch_delete_hierarchy_cb(bContext *C, +static void object_batch_delete_hierarchy_fn(bContext *C, ReportList *reports, Scene *scene, - TreeElement *te, - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *UNUSED(user_data)) + Object *ob) { ViewLayer *view_layer = CTX_data_view_layer(C); - Base *base = (Base *)te->directdata; Object *obedit = CTX_data_edit_object(C); - if (!base) { - base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id); - } + Base *base = BKE_view_layer_base_find(view_layer, ob); + if (base) { /* Check also library later. */ for (; obedit && (obedit != base->object); obedit = obedit->parent) { @@ -1343,7 +1258,6 @@ enum { OL_OP_SELECT = 1, OL_OP_DESELECT, OL_OP_SELECT_HIERARCHY, - OL_OP_DELETE_HIERARCHY, OL_OP_REMAP, OL_OP_LOCALIZED, /* disabled, see below */ OL_OP_TOGVIS, @@ -1358,7 +1272,6 @@ static const EnumPropertyItem prop_object_op_types[] = { {OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""}, {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""}, {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""}, - {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, {OL_OP_REMAP, "REMAP", 0, @@ -1372,7 +1285,6 @@ static const EnumPropertyItem prop_object_op_types[] = { static int outliner_object_operation_exec(bContext *C, wmOperator *op) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); wmWindow *win = CTX_wm_window(C); @@ -1413,43 +1325,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) str = "Deselect Objects"; selection_changed = true; } - else if (event == OL_OP_DELETE_HIERARCHY) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const Base *basact_prev = BASACT(view_layer); - - /* Keeping old 'safe and slow' code for a bit (new one enabled on 28/01/2019). */ - if (G.debug_value == 666) { - outliner_do_object_operation_ex( - C, op->reports, scene, soops, &soops->tree, object_delete_hierarchy_cb, NULL, false); - } - else { - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - - outliner_do_object_operation_ex(C, - op->reports, - scene, - soops, - &soops->tree, - object_batch_delete_hierarchy_cb, - NULL, - false); - - BKE_id_multi_tagged_delete(bmain); - } - - /* XXX: See outliner_delete_exec comment below. */ - outliner_cleanup_tree(soops); - - DEG_relations_tag_update(bmain); - str = "Delete Object Hierarchy"; - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - if (basact_prev != BASACT(view_layer)) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); - } - selection_changed = true; - } else if (event == OL_OP_REMAP) { outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth trick @@ -1513,22 +1388,38 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) /** \name Delete Object/Collection Operator * \{ */ -static void outliner_objects_delete( - bContext *C, Scene *scene, SpaceOutliner *soops, ReportList *reports, ListBase *lb) +typedef void (*OutlinerDeleteFunc)(bContext *C, ReportList *reports, Scene *scene, Object *ob); + +static void outliner_do_object_delete(bContext *C, + ReportList *reports, + Scene *scene, + GSet *objects_to_delete, + OutlinerDeleteFunc delete_fn) { - LISTBASE_FOREACH (TreeElement *, te, lb) { - TreeStoreElem *tselem = TREESTORE(te); + GSetIterator objects_to_delete_iter; + GSET_ITER (objects_to_delete_iter, objects_to_delete) { + Object *ob = (Object *)BLI_gsetIterator_getKey(&objects_to_delete_iter); - if (tselem->flag & TSE_SELECTED) { - if (tselem->type == 0 && te->idcode == ID_OB) { - outliner_object_delete(C, reports, scene, tselem); - } - } + delete_fn(C, reports, scene, ob); + } +} - if (TSELEM_OPEN(tselem, soops)) { - outliner_objects_delete(C, scene, soops, reports, &te->subtree); - } +static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void *customdata) +{ + GSet *objects_to_delete = (GSet *)customdata; + TreeStoreElem *tselem = TREESTORE(te); + + if (outliner_is_collection_tree_element(te)) { + return TRAVERSE_CONTINUE; } + + if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + return TRAVERSE_SKIP_CHILDS; + } + + BLI_gset_add(objects_to_delete, tselem->id); + + return TRAVERSE_CONTINUE; } static int outliner_delete_exec(bContext *C, wmOperator *op) @@ -1537,12 +1428,32 @@ static int outliner_delete_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); SpaceOutliner *soops = CTX_wm_space_outliner(C); struct wmMsgBus *mbus = CTX_wm_message_bus(C); - ViewLayer *view_layer = CTX_data_view_layer(C); const Base *basact_prev = BASACT(view_layer); - outliner_collection_delete(C, bmain, scene, op->reports, false); - outliner_objects_delete(C, scene, soops, op->reports, &soops->tree); + const bool delete_hierarchy = RNA_boolean_get(op->ptr, "hierarchy"); + + /* Get selected objects skipping duplicates to prevent deleting objects linked to multiple + * collections twice */ + GSet *objects_to_delete = BLI_gset_ptr_new(__func__); + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, outliner_find_objects_to_delete, objects_to_delete); + + if (delete_hierarchy) { + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + outliner_do_object_delete( + C, op->reports, scene, objects_to_delete, object_batch_delete_hierarchy_fn); + + BKE_id_multi_tagged_delete(bmain); + } + else { + outliner_do_object_delete(C, op->reports, scene, objects_to_delete, outliner_object_delete_fn); + } + + BLI_gset_free(objects_to_delete, NULL); + + outliner_collection_delete(C, bmain, scene, op->reports, delete_hierarchy); /* Tree management normally happens from draw_outliner(), but when * you're clicking too fast on Delete object from context menu in @@ -1579,6 +1490,11 @@ void OUTLINER_OT_delete(wmOperatorType *ot) /* flags */ ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index d6efe683673..bc272431e3a 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -235,6 +235,17 @@ static TreeElement *outliner_add_element( /* -------------------------------------------------------- */ +/** + * Check if an element type needs a full rebuild if the open/collapsed state changes. + * These element types don't add children if collapsed. + * + * This current check isn't great really. A per element-type flag would be preferable. + */ +bool outliner_element_needs_rebuild_on_open_change(const TreeStoreElem *tselem) +{ + return ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_KEYMAP); +} + /* special handling of hierarchical non-lib data */ static void outliner_add_bone( SpaceOutliner *soops, ListBase *lb, ID *id, Bone *curBone, TreeElement *parent, int *a) @@ -538,7 +549,7 @@ static void outliner_add_id_contents(SpaceOutliner *soops, /* expand specific data always */ switch (GS(id->name)) { case ID_LI: { - te->name = ((Library *)id)->name; + te->name = ((Library *)id)->filepath; break; } case ID_SCE: { @@ -786,8 +797,13 @@ static void outliner_add_id_contents(SpaceOutliner *soops, } } -// TODO: this function needs to be split up! It's getting a bit too large... -// Note: "ID" is not always a real ID +/** + * TODO: this function needs to be split up! It's getting a bit too large... + * + * \note: "ID" is not always a real ID + * \note: If child items are only added to the tree if the item is open, the TSE_ type _must_ be + * added to #outliner_element_needs_rebuild_on_open_change(). + */ static TreeElement *outliner_add_element( SpaceOutliner *soops, ListBase *lb, void *idv, TreeElement *parent, short type, short index) { @@ -854,7 +870,7 @@ static TreeElement *outliner_add_element( else { /* do here too, for blend file viewer, own ID_LI then shows file name */ if (GS(id->name) == ID_LI) { - te->name = ((Library *)id)->name; + te->name = ((Library *)id)->filepath; } else { te->name = id->name + 2; // default, can be overridden by Library or non-ID data @@ -2340,8 +2356,10 @@ void outliner_build_tree( for (lib = mainvar->libraries.first; lib; lib = lib->id.next) { ten = outliner_add_library_contents(mainvar, soops, &soops->tree, lib); - BLI_assert(ten != NULL); - lib->id.newid = (ID *)ten; + /* NULL-check matters, due to filtering there may not be a new element. */ + if (ten) { + lib->id.newid = (ID *)ten; + } } /* make hierarchy */ ten = soops->tree.first; diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index a058c30cef2..a120718e36b 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -84,12 +84,24 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops, /* co_y is inside this element */ return te_iter; } - else if (TSELEM_OPEN(te_iter->store_elem, soops)) { - /* co_y is lower than current element, possibly inside children */ - TreeElement *te_sub = outliner_find_item_at_y(soops, &te_iter->subtree, view_co_y); - if (te_sub) { - return te_sub; - } + + if (BLI_listbase_is_empty(&te_iter->subtree) || !TSELEM_OPEN(TREESTORE(te_iter), soops)) { + /* No need for recursion. */ + continue; + } + + /* If the coordinate is lower than the next element, we can continue with that one and skip + * recursion too. */ + const TreeElement *te_next = te_iter->next; + if (te_next && (view_co_y < (te_next->ys + UI_UNIT_Y))) { + continue; + } + + /* co_y is lower than current element (but not lower than the next one), possibly inside + * children */ + TreeElement *te_sub = outliner_find_item_at_y(soops, &te_iter->subtree, view_co_y); + if (te_sub) { + return te_sub; } } } @@ -256,7 +268,7 @@ TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone) return NULL; } -ID *outliner_search_back(TreeElement *te, short idcode) +TreeElement *outliner_search_back_te(TreeElement *te, short idcode) { TreeStoreElem *tselem; te = te->parent; @@ -264,13 +276,26 @@ ID *outliner_search_back(TreeElement *te, short idcode) while (te) { tselem = TREESTORE(te); if (tselem->type == 0 && te->idcode == idcode) { - return tselem->id; + return te; } te = te->parent; } return NULL; } +ID *outliner_search_back(TreeElement *te, short idcode) +{ + TreeElement *search_te; + TreeStoreElem *tselem; + + search_te = outliner_search_back_te(te, idcode); + if (search_te) { + tselem = TREESTORE(search_te); + return tselem->id; + } + return NULL; +} + /** * Iterate over all tree elements (pre-order traversal), executing \a func callback for * each tree element matching the optional filters. diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 9450136b6a6..aa1663dff01 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -84,7 +84,6 @@ static void outliner_main_region_init(wmWindowManager *wm, ARegion *region) static void outliner_main_region_draw(const bContext *C, ARegion *region) { View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; /* clear */ UI_ThemeClearColor(TH_BACK); @@ -96,9 +95,7 @@ static void outliner_main_region_draw(const bContext *C, ARegion *region) UI_view2d_view_restore(C); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + UI_view2d_scrollers_draw(v2d, NULL); } static void outliner_main_region_free(ARegion *UNUSED(region)) @@ -215,7 +212,7 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win), } break; case NC_SCREEN: - if (ELEM(wmn->data, ND_LAYER)) { + if (ELEM(wmn->data, ND_LAYOUTDELETE, ND_LAYER)) { ED_region_tag_redraw(region); } break; @@ -398,7 +395,7 @@ static void outliner_deactivate(struct ScrArea *area) /* Remove hover highlights */ SpaceOutliner *soops = area->spacedata.first; outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED, false); - ED_region_tag_redraw(BKE_area_find_region_type(area, RGN_TYPE_WINDOW)); + ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW)); } /* only called once, from space_api/spacetypes.c */ diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 1f06ab68516..1af552680a3 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -697,7 +697,8 @@ static void draw_seq_text(View2D *v2d, str_len = 0; } else if (seq->sound) { - str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d", name, seq->sound->name, seq->len); + str_len = BLI_snprintf( + str, sizeof(str), "%s: %s | %d", name, seq->sound->filepath, seq->len); } else { str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); @@ -2257,7 +2258,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region) Editing *ed = BKE_sequencer_editing_get(scene, false); SpaceSeq *sseq = CTX_wm_space_seq(C); View2D *v2d = ®ion->v2d; - View2DScrollers *scrollers; short cfra_flag = 0; float col[3]; @@ -2299,9 +2299,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region) cfra_flag |= DRAWCFRA_UNIT_SECONDS; } - /* Draw the current frame indicator. */ - ANIM_draw_cfra(C, v2d, cfra_flag); - /* Draw overlap frame frame indicator. */ if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) { int cfra_over = (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) ? @@ -2345,9 +2342,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region) ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW); UI_view2d_view_restore(C); ED_time_scrub_draw(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true); - scrollers = UI_view2d_scrollers_calc(v2d, NULL); - UI_view2d_scrollers_draw(v2d, scrollers); - UI_view2d_scrollers_free(scrollers); /* Draw channel numbers. */ { @@ -2357,3 +2351,13 @@ void draw_timeline_seq(const bContext *C, ARegion *region) UI_view2d_draw_scale_y__block(region, v2d, &rect, TH_SCROLL_TEXT); } } + +void draw_timeline_seq_display(const bContext *C, ARegion *region) +{ + const Scene *scene = CTX_data_scene(C); + const SpaceSeq *sseq = CTX_wm_space_seq(C); + View2D *v2d = ®ion->v2d; + + ED_time_scrub_draw_current_frame(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true); + UI_view2d_scrollers_draw(v2d, NULL); +} diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 9311cbed265..f74a4eae3bb 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -673,6 +673,14 @@ int seq_effect_find_selected(Scene *scene, *r_selseq2 = seq2; *r_selseq3 = seq3; + /* TODO(Richard): This function needs some refactoring, this is just quick hack for T73828. */ + if (BKE_sequence_effect_get_num_inputs(type) < 3) { + *r_selseq3 = NULL; + } + if (BKE_sequence_effect_get_num_inputs(type) < 2) { + *r_selseq2 = NULL; + } + return 1; } @@ -1403,14 +1411,21 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); } } - else if (seq->type & SEQ_TYPE_EFFECT) { + } + + /* Recalculate bounds of effect strips. */ + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if (seq->type & SEQ_TYPE_EFFECT) { if (seq->seq1 && (seq->seq1->flag & SELECT)) { + BKE_sequencer_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); BKE_sequence_calc(scene, seq); } else if (seq->seq2 && (seq->seq2->flag & SELECT)) { + BKE_sequencer_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); BKE_sequence_calc(scene, seq); } else if (seq->seq3 && (seq->seq3->flag & SELECT)) { + BKE_sequencer_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); BKE_sequence_calc(scene, seq); } } @@ -2218,6 +2233,11 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op) Sequence *seq1, *seq2, *seq3, *last_seq = BKE_sequencer_active_get(scene); const char *error_msg; + if (BKE_sequence_effect_get_num_inputs(last_seq->type) != 0) { + BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: strip has no inputs"); + return OPERATOR_CANCELLED; + } + if (!seq_effect_find_selected( scene, last_seq, last_seq->type, &seq1, &seq2, &seq3, &error_msg)) { BKE_report(op->reports, RPT_ERROR, error_msg); @@ -3433,6 +3453,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) * on the actual data-blocks. */ BKE_sequencer_base_clipboard_pointers_restore(&seqbase_clipboard, bmain); BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, 0, 0); + BKE_sequencer_base_clipboard_pointers_store(bmain, &seqbase_clipboard); iseq_first = nseqbase.first; @@ -3451,6 +3472,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) } DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); ED_outliner_select_sync_from_sequence_tag(C); @@ -3925,7 +3947,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) } char filepath[FILE_MAX]; RNA_string_get(op->ptr, "filepath", filepath); - BLI_strncpy(sound->name, filepath, sizeof(sound->name)); + BLI_strncpy(sound->filepath, filepath, sizeof(sound->filepath)); BKE_sound_load(bmain, sound); } else { diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 12533dbc74f..fee07e8941d 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -43,6 +43,7 @@ struct wmOperator; /* sequencer_draw.c */ void draw_timeline_seq(const struct bContext *C, struct ARegion *region); +void draw_timeline_seq_display(const struct bContext *C, struct ARegion *region); void sequencer_draw_preview(const struct bContext *C, struct Scene *scene, struct ARegion *region, diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 2686edd58a5..85b70354ab3 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -409,32 +409,15 @@ static int sequencer_select_exec(bContext *C, wmOperator *op) /* Select left, right or overlapping the current frame. */ if (side_of_frame) { /* Use different logic for this. */ - float x; if (extend == false) { ED_sequencer_deselect_all(scene); } - /* 10px margin around current frame to select under the current frame with mouse. */ - float margin = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask) * 10; - x = UI_view2d_region_to_view_x(v2d, mval[0]); - if (x >= CFRA - margin && x <= CFRA + margin) { - x = CFRA; - } + const float x = UI_view2d_region_to_view_x(v2d, mval[0]); SEQP_BEGIN (ed, seq) { - bool test = false; - /* FIXME(campbell): this functionality is only in the sequencer, - * either we should support this for all timeline views or remove it. */ - if ((x == CFRA) && (seq->startdisp <= CFRA) && (seq->enddisp >= CFRA)) { - /* Select overlapping the current frame. */ - test = true; - } - else if ((x < CFRA && seq->enddisp <= CFRA) || (x > CFRA && seq->startdisp >= CFRA)) { + if (((x < CFRA) && (seq->enddisp <= CFRA)) || ((x >= CFRA) && (seq->startdisp >= CFRA))) { /* Select left or right. */ - test = true; - } - - if (test) { seq->flag |= SELECT; recurs_sel_seq(seq); } @@ -1023,7 +1006,6 @@ static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op) void SEQUENCER_OT_select_side_of_frame(wmOperatorType *ot) { static const EnumPropertyItem sequencer_select_left_right_types[] = { - {0, "OVERLAP", 0, "Overlap", "Select overlapping the current frame"}, {-1, "LEFT", 0, "Left", "Select to the left of the current frame"}, {1, "RIGHT", 0, "Right", "Select to the right of the current frame"}, {0, NULL, 0, NULL, NULL}, diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index f52cfdd34c0..368f9c1af19 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -521,6 +521,12 @@ static void sequencer_main_region_draw(const bContext *C, ARegion *region) draw_timeline_seq(C, region); } +/* Strip editing timeline. */ +static void sequencer_main_region_draw_overlay(const bContext *C, ARegion *region) +{ + draw_timeline_seq_display(C, region); +} + static void sequencer_main_region_listener(wmWindow *UNUSED(win), ScrArea *UNUSED(area), ARegion *region, @@ -865,6 +871,7 @@ void ED_spacetype_sequencer(void) art->regionid = RGN_TYPE_WINDOW; art->init = sequencer_main_region_init; art->draw = sequencer_main_region_draw; + art->draw_overlay = sequencer_main_region_draw_overlay; art->listener = sequencer_main_region_listener; art->message_subscribe = sequencer_main_region_message_subscribe; art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index e50b25de412..c0343900f8b 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -85,7 +85,7 @@ static void test_line_start(char c, bool *r_last_state) /** * This function converts the indentation tabs from a buffer to spaces. - * \param buf: A pointer to a cstring. + * \param in_buf: A pointer to a cstring. * \param tab_size: The size, in spaces, of the tab character. */ static char *buf_tabs_to_spaces(const char *in_buf, const int tab_size) @@ -370,7 +370,7 @@ static int text_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e { Main *bmain = CTX_data_main(C); Text *text = CTX_data_edit_text(C); - const char *path = (text && text->name) ? text->name : BKE_main_blendfile_path(bmain); + const char *path = (text && text->filepath) ? text->filepath : BKE_main_blendfile_path(bmain); if (RNA_struct_property_is_set(op->ptr, "filepath")) { return text_open_exec(C, op); @@ -428,6 +428,13 @@ static int text_reload_exec(bContext *C, wmOperator *op) const int orig_curl = BLI_findindex(&text->lines, text->curl); const int orig_curc = text->curc; + /* Don't make this part of 'poll', since 'Alt-R' will type 'R', + * if poll checks for the filename. */ + if (text->filepath == NULL) { + BKE_report(op->reports, RPT_ERROR, "This text has not been saved"); + return OPERATOR_CANCELLED; + } + if (!BKE_text_reload(text)) { BKE_report(op->reports, RPT_ERROR, "Could not reopen file"); return OPERATOR_CANCELLED; @@ -536,10 +543,7 @@ static int text_make_internal_exec(bContext *C, wmOperator *UNUSED(op)) text->flags |= TXT_ISMEM | TXT_ISDIRTY; - if (text->name) { - MEM_freeN(text->name); - text->name = NULL; - } + MEM_SAFE_FREE(text->filepath); text_update_cursor_moved(C); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -576,7 +580,7 @@ static bool text_save_poll(bContext *C) return 0; } - return (text->name != NULL && !(text->flags & TXT_ISMEM)); + return (text->filepath != NULL && !(text->flags & TXT_ISMEM)); } static void txt_write_file(Main *bmain, Text *text, ReportList *reports) @@ -586,7 +590,7 @@ static void txt_write_file(Main *bmain, Text *text, ReportList *reports) BLI_stat_t st; char filepath[FILE_MAX]; - BLI_strncpy(filepath, text->name, FILE_MAX); + BLI_strncpy(filepath, text->filepath, FILE_MAX); BLI_path_abs(filepath, BKE_main_blendfile_path(bmain)); fp = BLI_fopen(filepath, "w"); @@ -669,10 +673,10 @@ static int text_save_as_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", str); - if (text->name) { - MEM_freeN(text->name); + if (text->filepath) { + MEM_freeN(text->filepath); } - text->name = BLI_strdup(str); + text->filepath = BLI_strdup(str); text->flags &= ~TXT_ISMEM; txt_write_file(bmain, text, op->reports); @@ -693,8 +697,8 @@ static int text_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE return text_save_as_exec(C, op); } - if (text->name) { - str = text->name; + if (text->filepath) { + str = text->filepath; } else if (text->flags & TXT_ISMEM) { str = text->id.name + 2; @@ -3621,9 +3625,57 @@ void TEXT_OT_find(wmOperatorType *ot) /** \name Replace Operator * \{ */ +static int text_replace_all(bContext *C) +{ + SpaceText *st = CTX_wm_space_text(C); + Text *text = st->text; + const int flags = st->flags; + int found = 0; + + if (!st->findstr[0]) { + return OPERATOR_CANCELLED; + } + + const int orig_curl = BLI_findindex(&text->lines, text->curl); + const int orig_curc = text->curc; + bool has_sel = txt_has_sel(text); + + txt_move_toline(text, 0, false); + + found = txt_find_string(text, st->findstr, 0, flags & ST_MATCH_CASE); + if (found) { + ED_text_undo_push_init(C); + + do { + txt_insert_buf(text, st->replacestr); + if (text->curl && text->curl->format) { + MEM_freeN(text->curl->format); + text->curl->format = NULL; + } + found = txt_find_string(text, st->findstr, 0, flags & ST_MATCH_CASE); + } while (found); + + WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); + text_drawcache_tag_update(CTX_wm_space_text(C), 1); + } + else { + /* Restore position */ + txt_move_to(text, orig_curl, orig_curc, has_sel); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + static int text_replace_exec(bContext *C, wmOperator *op) { - return text_find_and_replace(C, op, TEXT_REPLACE); + bool replace_all = RNA_boolean_get(op->ptr, "all"); + if (replace_all) { + return text_replace_all(C); + } + else { + return text_find_and_replace(C, op, TEXT_REPLACE); + } } void TEXT_OT_replace(wmOperatorType *ot) @@ -3639,6 +3691,11 @@ void TEXT_OT_replace(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_UNDO; + + /* properties */ + PropertyRNA *prop; + prop = RNA_def_boolean(ot->srna, "all", false, "Replace all", "Replace all occurrences"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /** \} */ diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index daa3f641404..aeabe68c2d0 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -182,7 +182,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph copy_qt_qt(vctrl->rot_backup, rv3d->viewquat); copy_v3_v3(vctrl->ofs_backup, rv3d->ofs); - /* the dist defines a vector that is infront of the offset + /* The dist defines a vector that is in front of the offset * to rotate the view about. * this is no good for fly mode because we * want to rotate about the viewers center. diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index fac378ae104..b3165c9fc78 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -2376,7 +2376,7 @@ void ED_view3d_datamask(const bContext *C, { if (ELEM(v3d->shading.type, OB_TEXTURE, OB_MATERIAL, OB_RENDER)) { r_cddata_masks->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; - r_cddata_masks->vmask |= CD_MASK_ORCO; + r_cddata_masks->vmask |= CD_MASK_ORCO | CD_MASK_PROP_COLOR; } else if (v3d->shading.type == OB_SOLID) { if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) { @@ -2384,6 +2384,7 @@ void ED_view3d_datamask(const bContext *C, } if (v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR) { r_cddata_masks->lmask |= CD_MASK_MLOOPCOL; + r_cddata_masks->vmask |= CD_MASK_ORCO | CD_MASK_PROP_COLOR; } } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index edd75d8e561..3c3dea1509d 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4988,7 +4988,7 @@ void ED_view3d_cursor3d_position(bContext *C, ED_view3d_calc_zfac(rv3d, cursor_co, &flip); - /* reset the depth based on the view offset (we _know_ the offset is infront of us) */ + /* Reset the depth based on the view offset (we _know_ the offset is in front of us). */ if (flip) { negate_v3_v3(cursor_co, rv3d->ofs); /* re initialize, no need to check flip again */ diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index 06d1a033a0d..506969443fd 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -55,6 +55,10 @@ #include "view3d_intern.h" /* own include */ +/* -------------------------------------------------------------------- */ +/** \name Modal Key-map + * \{ */ + /* NOTE: these defines are saved in keymap files, * do not change values but just add new ones */ enum { @@ -138,6 +142,12 @@ void fly_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Fly Structs + * \{ */ + typedef struct FlyInfo { /* context stuff */ RegionView3D *rv3d; @@ -205,6 +215,12 @@ typedef struct FlyInfo { } FlyInfo; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Fly Drawing + * \{ */ + /* prototypes */ #ifdef WITH_INPUT_NDOF static void flyApply_ndof(bContext *C, FlyInfo *fly, bool is_confirm); @@ -278,6 +294,12 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(regio immUnbindProgram(); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Fly Logic + * \{ */ + /* FlyInfo->state */ enum { FLY_RUNNING = 0, @@ -1034,6 +1056,12 @@ static void flyApply_ndof(bContext *C, FlyInfo *fly, bool is_confirm) } #endif /* WITH_INPUT_NDOF */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Fly Operator + * \{ */ + static int fly_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -1128,3 +1156,5 @@ void VIEW3D_OT_fly(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING; } + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 829d793333e..f2e42cd1725 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -209,7 +209,7 @@ static void uiTemplatePaintModeSelection(uiLayout *layout, struct bContext *C) PointerRNA meshptr; RNA_pointer_create(ob->data, &RNA_Mesh, ob->data, &meshptr); - if (ob->mode & (OB_MODE_TEXTURE_PAINT)) { + if (ob->mode & OB_MODE_TEXTURE_PAINT) { uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); } else { diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index f2b78bc2aaf..131fbbc02ee 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -936,6 +936,8 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve RNA_float_set_array(&op_props, "rotation", rotation); RNA_float_set_array(&op_props, "location", location); RNA_float_set_array(&op_props, "scale", scale); + /* Always use default size here. */ + RNA_float_set(&op_props, "size", 2.0f); WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props); WM_operator_properties_free(&op_props); } diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index 3a0f0f468fc..f4ec9a22520 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -557,9 +557,9 @@ void ED_view3d_win_to_3d(const View3D *v3d, copy_v3_v3(ray_origin, rv3d->viewinv[3]); ED_view3d_win_to_vector(region, mval, ray_direction); - /* note, we could use isect_line_plane_v3() - * however we want the intersection to be infront of the view no matter what, - * so apply the unsigned factor instead */ + /* Note: we could use #isect_line_plane_v3() + * however we want the intersection to be in front of the view no matter what, + * so apply the unsigned factor instead. */ plane_from_point_normal_v3(plane, depth_pt, rv3d->viewinv[2]); isect_ray_plane_v3(ray_origin, ray_direction, plane, &lambda, false); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 1bdb8268c23..9e235d72f26 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -3007,7 +3007,7 @@ static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectO continue; } - if (metaelem_id != (hitresult & 0xFFFF0000 & ~(MBALLSEL_ANY))) { + if (metaelem_id != (hitresult & 0xFFFF0000 & ~MBALLSEL_ANY)) { continue; } diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 437c0dd4035..91b2971585d 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -850,12 +850,12 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) return false; } - if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN) { - mul_v3_fl(centroid, 1.0f / (float)count); - copy_v3_v3(cursor, centroid); + if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_BOUNDS) { + mid_v3_v3v3(cursor, min, max); } else { - mid_v3_v3v3(cursor, min, max); + mul_v3_fl(centroid, 1.0f / (float)count); + copy_v3_v3(cursor, centroid); } return true; } diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 377e8c58ba3..15d6a43d105 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -94,7 +94,7 @@ bool ED_view3d_has_workbench_in_texture_color(const Scene *scene, if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) { return true; } - if (ob->mode == OB_MODE_TEXTURE_PAINT) { + if (ob && ob->mode == OB_MODE_TEXTURE_PAINT) { return true; } } diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 7aefd173953..50fa573423a 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -65,6 +65,10 @@ /* ensure the target position is one we can reach, see: T45771 */ #define USE_PIXELSIZE_NATIVE_SUPPORT +/* -------------------------------------------------------------------- */ +/** \name Modal Key-map + * \{ */ + /* NOTE: these defines are saved in keymap files, * do not change values but just add new ones */ enum { @@ -173,6 +177,12 @@ void walk_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "VIEW3D_OT_walk"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Walk Structs + * \{ */ + typedef struct WalkTeleport { eWalkTeleportState state; float duration; /* from user preferences */ @@ -283,6 +293,12 @@ typedef struct WalkInfo { } WalkInfo; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Walk Drawing + * \{ */ + /* prototypes */ #ifdef WITH_INPUT_NDOF static void walkApply_ndof(bContext *C, WalkInfo *walk, bool is_confirm); @@ -340,6 +356,12 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *region, voi immUnbindProgram(); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Walk Logic + * \{ */ + static void walk_navigation_mode_set(WalkInfo *walk, eWalkMethod mode) { if (mode == WALK_MODE_FREE) { @@ -1343,7 +1365,12 @@ static void walkApply_ndof(bContext *C, WalkInfo *walk, bool is_confirm) } #endif /* WITH_INPUT_NDOF */ -/****** walk operator ******/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Walk Operator + * \{ */ + static int walk_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -1438,3 +1465,5 @@ void VIEW3D_OT_walk(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING; } + +/** \} */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b02b1814c67..eb60273fc79 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -526,8 +526,11 @@ static void viewRedrawPost(bContext *C, TransInfo *t) } /* redraw UV editor */ - if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) && - (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { + const char uvcalc_correct_flag = ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) ? + UVCALC_TRANSFORM_CORRECT_SLIDE : + UVCALC_TRANSFORM_CORRECT; + + if ((t->data_type == TC_MESH_VERTS) && (t->settings->uvcalc_flag & uvcalc_correct_flag)) { WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } @@ -1591,17 +1594,24 @@ static void drawTransformPixel(const struct bContext *C, ARegion *region, void * void saveTransform(bContext *C, TransInfo *t, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); - int proportional = 0; PropertyRNA *prop; if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) && ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) { /* When redoing these modes the first time, it's more convenient to save - * the Global orientation. */ - mul_m3_v3(t->spacemtx, t->values_final); - unit_m3(t->spacemtx); + * in the Global orientation. */ + if (t->mode == TFM_TRANSLATION) { + mul_m3_v3(t->spacemtx, t->values_final); + } + else { + float tmat[3][3], sizemat[3][3]; + size_to_mat3(sizemat, t->values_final); + mul_m3_m3m3(tmat, t->spacemtx, sizemat); + mat3_to_size(t->values_final, tmat); + } BLI_assert(t->orient_curr == 0); + unit_m3(t->spacemtx); t->orient[0].type = V3D_ORIENT_GLOBAL; } @@ -1619,15 +1629,17 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } + bool use_prop_edit = false; + int prop_edit_flag = 0; if (t->flag & T_PROP_EDIT_ALL) { if (t->flag & T_PROP_EDIT) { - proportional |= PROP_EDIT_USE; + use_prop_edit = true; } if (t->flag & T_PROP_CONNECTED) { - proportional |= PROP_EDIT_CONNECTED; + prop_edit_flag |= PROP_EDIT_CONNECTED; } if (t->flag & T_PROP_PROJECTED) { - proportional |= PROP_EDIT_PROJECTED; + prop_edit_flag |= PROP_EDIT_PROJECTED; } } @@ -1639,20 +1651,27 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if (!(t->options & CTX_NO_PET)) { if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit")) && !RNA_property_is_set(op->ptr, prop)) { + const Object *obact = OBACT(t->view_layer); + if (t->spacetype == SPACE_GRAPH) { - ts->proportional_fcurve = proportional; + ts->proportional_fcurve = use_prop_edit; } else if (t->spacetype == SPACE_ACTION) { - ts->proportional_action = proportional; - } - else if (t->obedit_type != -1) { - ts->proportional_edit = proportional; + ts->proportional_action = use_prop_edit; } else if (t->options & CTX_MASK) { - ts->proportional_mask = proportional != 0; + ts->proportional_mask = use_prop_edit; } - else if ((t->options & CTX_CURSOR) == 0) { - ts->proportional_objects = proportional != 0; + else if (obact && obact->mode == OB_MODE_OBJECT) { + ts->proportional_objects = use_prop_edit; + } + else { + if (use_prop_edit) { + ts->proportional_edit |= PROP_EDIT_USE; + } + else { + ts->proportional_edit &= ~PROP_EDIT_USE; + } } } @@ -1685,9 +1704,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) { - RNA_property_boolean_set(op->ptr, prop, proportional & PROP_EDIT_USE); - RNA_boolean_set(op->ptr, "use_proportional_connected", proportional & PROP_EDIT_CONNECTED); - RNA_boolean_set(op->ptr, "use_proportional_projected", proportional & PROP_EDIT_PROJECTED); + RNA_property_boolean_set(op->ptr, prop, use_prop_edit); + RNA_boolean_set(op->ptr, "use_proportional_connected", prop_edit_flag & PROP_EDIT_CONNECTED); + RNA_boolean_set(op->ptr, "use_proportional_projected", prop_edit_flag & PROP_EDIT_PROJECTED); RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode); RNA_float_set(op->ptr, "proportional_size", t->prop_size); } @@ -1768,7 +1787,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) { RNA_property_boolean_set( - op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0); + op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE) != 0); } } @@ -1819,6 +1838,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve int options = 0; PropertyRNA *prop; + mode = transform_mode_really_used(C, mode); + t->context = C; /* added initialize, for external calls to set stuff in TransInfo, like undo string */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 838c1880881..66b90eb159f 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -79,6 +79,27 @@ static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3]) } /* ************************** CONSTRAINTS ************************* */ +#define CONSTRAIN_EPSILON 0.0001f + +static void constraint_plane_calc(TransInfo *t, float r_plane[4]) +{ + const float *constraint_vector[2]; + int n = 0; + for (int i = 0; i < 3; i++) { + if (t->con.mode & (CON_AXIS0 << i)) { + constraint_vector[n++] = t->spacemtx[i]; + if (n == 2) { + break; + } + } + } + BLI_assert(n == 2); + + cross_v3_v3v3(r_plane, constraint_vector[0], constraint_vector[1]); + normalize_v3(r_plane); + r_plane[3] = -dot_v3v3(r_plane, t->center_global); +} + static void constraintValuesFinal(TransInfo *t, float vec[3]) { int mode = t->con.mode; @@ -297,32 +318,83 @@ static void axisProjection(const TransInfo *t, } /** - * Return true if the 2x axis are both aligned when projected into the view. - * In this case, we can't usefully project the cursor onto the plane. + * Snap to the intersection between the edge direction and the constraint plane. */ -static bool isPlaneProjectionViewAligned(const TransInfo *t) +static void constraint_snap_plane_to_edge(const TransInfo *t, const float plane[4], float r_out[3]) { - const float eps = 0.001f; - const float *constraint_vector[2]; - int n = 0; - for (int i = 0; i < 3; i++) { - if (t->con.mode & (CON_AXIS0 << i)) { - constraint_vector[n++] = t->spacemtx[i]; - if (n == 2) { - break; - } - } + float lambda; + const float *edge_snap_point = t->tsnap.snapPoint; + const float *edge_dir = t->tsnap.snapNormal; + bool is_aligned = fabsf(dot_v3v3(edge_dir, plane)) < CONSTRAIN_EPSILON; + if (!is_aligned && isect_ray_plane_v3(edge_snap_point, edge_dir, plane, &lambda, false)) { + madd_v3_v3v3fl(r_out, edge_snap_point, edge_dir, lambda); + sub_v3_v3(r_out, t->tsnap.snapTarget); } - BLI_assert(n == 2); +} + +/** + * Snap to the nearest point between the snap point and the line that + * intersects the face plane with the constraint plane. + */ +static void constraint_snap_plane_to_face(const TransInfo *t, const float plane[4], float r_out[3]) +{ + float face_plane[4], isect_orig[3], isect_dir[3]; + const float *face_snap_point = t->tsnap.snapPoint; + const float *face_normal = t->tsnap.snapNormal; + plane_from_point_normal_v3(face_plane, face_snap_point, face_normal); + bool is_aligned = fabsf(dot_v3v3(plane, face_plane)) > (1.0f - CONSTRAIN_EPSILON); + if (!is_aligned && isect_plane_plane_v3(plane, face_plane, isect_orig, isect_dir)) { + closest_to_ray_v3(r_out, face_snap_point, isect_orig, isect_dir); + sub_v3_v3(r_out, t->tsnap.snapTarget); + } +} - float view_to_plane[3], plane_normal[3]; +/** + * Snap to the nearest point on the axis to the edge/line element. + */ +void transform_constraint_snap_axis_to_edge(const TransInfo *t, + const float axis[3], + float r_out[3]) +{ + float lambda; + const float *edge_snap_point = t->tsnap.snapPoint; + const float *edge_dir = t->tsnap.snapNormal; + bool is_aligned = fabsf(dot_v3v3(axis, edge_dir)) > (1.0f - CONSTRAIN_EPSILON); + if (!is_aligned && + isect_ray_ray_v3(t->tsnap.snapTarget, axis, edge_snap_point, edge_dir, &lambda, NULL)) { + mul_v3_v3fl(r_out, axis, lambda); + } +} - getViewVector(t, t->center_global, view_to_plane); +/** + * Snap to the intersection of the axis and the plane defined by the face. + */ +void transform_constraint_snap_axis_to_face(const TransInfo *t, + const float axis[3], + float r_out[3]) +{ + float lambda; + float face_plane[4]; + const float *face_snap_point = t->tsnap.snapPoint; + const float *face_normal = t->tsnap.snapNormal; + plane_from_point_normal_v3(face_plane, face_snap_point, face_normal); + bool is_aligned = fabsf(dot_v3v3(axis, face_plane)) < CONSTRAIN_EPSILON; + if (!is_aligned && isect_ray_plane_v3(t->tsnap.snapTarget, axis, face_plane, &lambda, false)) { + mul_v3_v3fl(r_out, axis, lambda); + } +} - cross_v3_v3v3(plane_normal, constraint_vector[0], constraint_vector[1]); - normalize_v3(plane_normal); +/** + * Return true if the 2x axis are both aligned when projected into the view. + * In this case, we can't usefully project the cursor onto the plane. + */ +static bool isPlaneProjectionViewAligned(const TransInfo *t, float plane[4]) +{ + const float eps = 0.001f; + float view_to_plane[3]; + getViewVector(t, t->center_global, view_to_plane); - float factor = dot_v3v3(plane_normal, view_to_plane); + float factor = dot_v3v3(plane, view_to_plane); return fabsf(factor) < eps; } @@ -361,14 +433,31 @@ static void applyAxisConstraintVec( copy_v3_v3(out, in); if (!td && t->con.mode & CON_APPLY) { mul_m3_v3(t->con.pmtx, out); + bool is_snap_to_edge = false, is_snap_to_face = false; + if (activeSnap(t)) { + is_snap_to_edge = (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) != 0; + is_snap_to_face = (t->tsnap.snapElem & SCE_SNAP_MODE_FACE) != 0; + } - // With snap, a projection is alright, no need to correct for view alignment - if (!validSnap(t)) { + /* With snap points, a projection is alright, no adjustments needed. */ + if (!validSnap(t) || is_snap_to_edge || is_snap_to_face) { const int dims = getConstraintSpaceDimension(t); if (dims == 2) { if (!is_zero_v3(out)) { - if (!isPlaneProjectionViewAligned(t)) { - planeProjection(t, in, out); + float plane[4]; + constraint_plane_calc(t, plane); + + if (is_snap_to_edge) { + constraint_snap_plane_to_edge(t, plane, out); + } + else if (is_snap_to_face) { + constraint_snap_plane_to_face(t, plane, out); + } + else { + /* View alignment correction. */ + if (!isPlaneProjectionViewAligned(t, plane)) { + planeProjection(t, in, out); + } } } } @@ -384,7 +473,17 @@ static void applyAxisConstraintVec( else if (t->con.mode & CON_AXIS2) { copy_v3_v3(c, t->spacemtx[2]); } - axisProjection(t, c, in, out); + + if (is_snap_to_edge) { + transform_constraint_snap_axis_to_edge(t, c, out); + } + else if (is_snap_to_face) { + transform_constraint_snap_axis_to_face(t, c, out); + } + else { + /* View alignment correction. */ + axisProjection(t, c, in, out); + } } } postConstraintChecks(t, out); @@ -779,12 +878,21 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformThemeColor(TH_GRID); + immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + GPU_blend(true); + + immUniform2fv("viewportSize", &viewport[2]); + immUniform1f("lineWidth", 3.0f * U.pixelsize); + + immUniformThemeColorShadeAlpha(TH_GRID, -20, 255); + imm_drawcircball(t->center_global, t->prop_size, imat, pos); - GPU_logic_op_invert_set(true); + immUniform1f("lineWidth", 1.0f * U.pixelsize); + immUniformThemeColorShadeAlpha(TH_GRID, 20, 255); imm_drawcircball(t->center_global, t->prop_size, imat, pos); - GPU_logic_op_invert_set(false); immUnbindProgram(); diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h index c41b9361ca4..282060af2c3 100644 --- a/source/blender/editors/transform/transform_constraints.h +++ b/source/blender/editors/transform/transform_constraints.h @@ -27,6 +27,12 @@ struct TransInfo; void constraintNumInput(TransInfo *t, float vec[3]); +void transform_constraint_snap_axis_to_edge(const TransInfo *t, + const float axis[3], + float r_out[3]); +void transform_constraint_snap_axis_to_face(const TransInfo *t, + const float axis[3], + float r_out[3]); void setConstraint(TransInfo *t, int mode, const char text[]); void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]); void setLocalConstraint(TransInfo *t, int mode, const char text[]); diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 064057990e0..5d1fd1543df 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -774,7 +774,7 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list) bConstraint *con; /* loop through constraints, checking if there's one of the mentioned - * constraints needing special crazyspace corrections + * constraints needing special crazy-space corrections */ if (list) { for (con = list->first; con; con = con->next) { @@ -1148,21 +1148,6 @@ void createTransData(bContext *C, TransInfo *t) } t->flag |= T_OBJECT; - - /* Check if we're transforming the camera from the camera */ - if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { - View3D *v3d = t->view; - RegionView3D *rv3d = t->region->regiondata; - if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) { - /* we could have a flag to easily check an object is being transformed */ - if (v3d->camera->id.tag & LIB_TAG_DOIT) { - t->flag |= T_CAMERA; - } - } - else if (v3d->ob_center && v3d->ob_center->id.tag & LIB_TAG_DOIT) { - t->flag |= T_CAMERA; - } - } convert_type = TC_OBJECT; } @@ -1175,6 +1160,7 @@ void createTransData(bContext *C, TransInfo *t) break; case TC_POSE: createTransPose(t); + /* Disable PET, its not usable in pose mode yet [#32444] */ init_prop_edit = false; break; case TC_ARMATURE_VERTS: @@ -1224,6 +1210,20 @@ void createTransData(bContext *C, TransInfo *t) break; case TC_OBJECT: createTransObject(C, t); + /* Check if we're transforming the camera from the camera */ + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + View3D *v3d = t->view; + RegionView3D *rv3d = t->region->regiondata; + if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) { + /* we could have a flag to easily check an object is being transformed */ + if (v3d->camera->id.tag & LIB_TAG_DOIT) { + t->flag |= T_CAMERA; + } + } + else if (v3d->ob_center && v3d->ob_center->id.tag & LIB_TAG_DOIT) { + t->flag |= T_CAMERA; + } + } break; case TC_OBJECT_TEXSPACE: createTransTexspace(t); @@ -1292,18 +1292,9 @@ void createTransData(bContext *C, TransInfo *t) * and are still added into transform data. */ sort_trans_data_selected_first(t); } - } - - /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */ - if (t->mode == TFM_BONESIZE) { - t->flag &= ~(T_EDIT | T_POINTS); - t->flag |= T_POSE; - t->obedit_type = -1; - t->data_type = TC_NONE; - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - tc->poseobj = tc->obedit; - tc->obedit = NULL; + if (!init_prop_edit) { + t->flag &= ~T_PROP_EDIT_ALL; } } diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index a94bd609d94..f7eea286983 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -47,7 +47,7 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize); void clipUVData(TransInfo *t); /* transform_convert_mesh.c */ -void trans_mesh_customdata_correction_init(TransInfo *t, struct TransDataContainer *tc); +void trans_mesh_customdata_correction_init(TransInfo *t); /* transform_convert_sequencer.c */ int transform_convert_sequencer_get_snap_bound(TransInfo *t); diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 75b51b3d2c4..f721ed0b866 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -553,8 +553,7 @@ static void pose_mirror_info_init(PoseInitData_Mirror *pid, /** \name Convert Armature * \{ */ -static void add_pose_transdata( - TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td) +static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransData *td) { Bone *bone = pchan->bone; float pmat[3][3], omat[3][3]; @@ -667,20 +666,16 @@ static void add_pose_transdata( mul_m3_m3m3(td->axismtx, omat, pmat); normalize_m3(td->axismtx); - if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) { - bArmature *arm = tc->poseobj->data; - - if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) { - td->loc = NULL; - td->val = &bone->dist; - td->ival = bone->dist; - } - else { - // abusive storage of scale in the loc pointer :) - td->loc = &bone->xwidth; - copy_v3_v3(td->iloc, td->loc); - td->val = NULL; - } + if (t->mode == TFM_BONE_ENVELOPE_DIST) { + td->loc = NULL; + td->val = &bone->dist; + td->ival = bone->dist; + } + else if (t->mode == TFM_BONESIZE) { + // abusive storage of scale in the loc pointer :) + td->loc = &bone->xwidth; + copy_v3_v3(td->iloc, td->loc); + td->val = NULL; } /* in this case we can do target-less IK grabbing */ @@ -836,7 +831,7 @@ void createTransPose(TransInfo *t) td = tc->data; LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { if (pchan->bone->flag & BONE_TRANSFORM) { - add_pose_transdata(t, pchan, ob, tc, td); + add_pose_transdata(t, pchan, ob, td); td++; } } @@ -862,8 +857,6 @@ void createTransPose(TransInfo *t) } t->flag |= T_POSE; - /* disable PET, its not usable in pose mode yet [#32444] */ - t->flag &= ~T_PROP_EDIT_ALL; } void createTransArmatureVerts(TransInfo *t) @@ -988,7 +981,7 @@ void createTransArmatureVerts(TransInfo *t) } else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) { if (ebo->flag & BONE_SELECTED) { - if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) { + if (t->mode == TFM_BONE_ENVELOPE_DIST) { td->loc = NULL; td->val = &ebo->dist; td->ival = ebo->dist; diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index 6c03f86f883..37e37072ed7 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -87,7 +87,7 @@ void createTransCurveVerts(TransInfo *t) t->data_len_all = 0; - /* Count control points (one per bez-triple) if any number of handles are selected. + /* Count control points (one per #BezTriple) if any number of handles are selected. * Needed for #transform_around_single_fallback_ex. */ int data_len_all_pt = 0; diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c index 66c27bca207..6f34c49bdac 100644 --- a/source/blender/editors/transform/transform_convert_mask.c +++ b/source/blender/editors/transform/transform_convert_mask.c @@ -149,7 +149,7 @@ static void MaskPointToTransData(Scene *scene, /* CV coords are scaled by aspects. this is needed for rotations and * proportional editing to be consistent with the stretched CV coords - * that are displayed. this also means that for display and numinput, + * that are displayed. this also means that for display and number-input, * and when the CV coords are flushed, these are converted each time */ mul_v2_m3v2(td2d->loc, parent_matrix, bezt->vec[i]); td2d->loc[0] *= asp[0]; diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 27ddad262f7..1c286415ea6 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -50,10 +50,11 @@ /* Own include. */ #include "transform_convert.h" -/* Used for both mirror epsilon and TD_MIRROR_EDGE_ */ -#define TRANSFORM_MAXDIST_MIRROR 0.00002f +/* -------------------------------------------------------------------- */ +/** \name Island Creation + * + * \{ */ -/* when transforming islands */ struct TransIslandData { float (*center)[3]; float (*axismtx)[3][3]; @@ -61,8 +62,186 @@ struct TransIslandData { int *island_vert_map; }; +static void editmesh_islands_info_calc(BMEditMesh *em, + const bool calc_single_islands, + const bool calc_island_center, + const bool calc_island_axismtx, + struct TransIslandData *r_island_data) +{ + BMesh *bm = em->bm; + char htype; + char itype; + int i; + + /* group vars */ + float(*center)[3] = NULL; + float(*axismtx)[3][3] = NULL; + int *groups_array; + int(*group_index)[2]; + int group_tot; + void **ele_array; + + int *vert_map; + + if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { + groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__); + group_tot = BM_mesh_calc_edge_groups( + bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT); + + htype = BM_EDGE; + itype = BM_VERTS_OF_EDGE; + } + else { /* (bm->selectmode & SCE_SELECT_FACE) */ + groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); + group_tot = BM_mesh_calc_face_groups( + bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT, BM_VERT); + + htype = BM_FACE; + itype = BM_VERTS_OF_FACE; + } + + if (calc_island_center) { + center = MEM_mallocN(sizeof(*center) * group_tot, __func__); + } + + if (calc_island_axismtx) { + axismtx = MEM_mallocN(sizeof(*axismtx) * group_tot, __func__); + } + + vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__); + /* we shouldn't need this, but with incorrect selection flushing + * its possible we have a selected vertex that's not in a face, + * for now best not crash in that case. */ + copy_vn_i(vert_map, bm->totvert, -1); + + BM_mesh_elem_table_ensure(bm, htype); + ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable; + + BM_mesh_elem_index_ensure(bm, BM_VERT); + + /* may be an edge OR a face array */ + for (i = 0; i < group_tot; i++) { + BMEditSelection ese = {NULL}; + + const int fg_sta = group_index[i][0]; + const int fg_len = group_index[i][1]; + float co[3], no[3], tangent[3]; + int j; + + zero_v3(co); + zero_v3(no); + zero_v3(tangent); + + ese.htype = htype; + + /* loop on each face or edge in this group: + * - assign r_vert_map + * - calculate (co, no) + */ + for (j = 0; j < fg_len; j++) { + ese.ele = ele_array[groups_array[fg_sta + j]]; + + if (center) { + float tmp_co[3]; + BM_editselection_center(&ese, tmp_co); + add_v3_v3(co, tmp_co); + } + + if (axismtx) { + float tmp_no[3], tmp_tangent[3]; + BM_editselection_normal(&ese, tmp_no); + BM_editselection_plane(&ese, tmp_tangent); + add_v3_v3(no, tmp_no); + add_v3_v3(tangent, tmp_tangent); + } + + { + /* setup vertex map */ + BMIter iter; + BMVert *v; + + /* connected edge-verts */ + BM_ITER_ELEM (v, &iter, ese.ele, itype) { + vert_map[BM_elem_index_get(v)] = i; + } + } + } + + if (center) { + mul_v3_v3fl(center[i], co, 1.0f / (float)fg_len); + } + + if (axismtx) { + if (createSpaceNormalTangent(axismtx[i], no, tangent)) { + /* pass */ + } + else { + if (normalize_v3(no) != 0.0f) { + axis_dominant_v3_to_m3(axismtx[i], no); + invert_m3(axismtx[i]); + } + else { + unit_m3(axismtx[i]); + } + } + } + } + + MEM_freeN(groups_array); + MEM_freeN(group_index); + + /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */ + if (calc_single_islands) { + BMIter viter; + BMVert *v; + int group_tot_single = 0; + + BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { + group_tot_single += 1; + } + } + + if (group_tot_single != 0) { + if (center) { + center = MEM_reallocN(center, sizeof(*center) * (group_tot + group_tot_single)); + } + if (axismtx) { + axismtx = MEM_reallocN(axismtx, sizeof(*axismtx) * (group_tot + group_tot_single)); + } + + BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { + vert_map[i] = group_tot; + if (center) { + copy_v3_v3(center[group_tot], v->co); + } + if (axismtx) { + if (is_zero_v3(v->no) != 0.0f) { + axis_dominant_v3_to_m3(axismtx[group_tot], v->no); + invert_m3(axismtx[group_tot]); + } + else { + unit_m3(axismtx[group_tot]); + } + } + + group_tot += 1; + } + } + } + } + + r_island_data->axismtx = axismtx; + r_island_data->center = center; + r_island_data->island_tot = group_tot; + r_island_data->island_vert_map = vert_map; +} + +/** \} */ + /* -------------------------------------------------------------------- */ -/** \name Edit Mesh Verts Transform Creation +/** \name Connectivity Distance for Proportional Editing * * \{ */ @@ -243,171 +422,25 @@ static void editmesh_set_connectivity_distance(BMesh *bm, } } -static void editmesh_islands_info_calc(BMEditMesh *em, - const bool calc_single_islands, - const bool calc_island_axismtx, - struct TransIslandData *r_island_data) -{ - BMesh *bm = em->bm; - char htype; - char itype; - int i; - - /* group vars */ - float(*center)[3]; - float(*axismtx)[3][3] = NULL; - int *groups_array; - int(*group_index)[2]; - int group_tot; - void **ele_array; - - int *vert_map; - - if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { - groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__); - group_tot = BM_mesh_calc_edge_groups( - bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT); - - htype = BM_EDGE; - itype = BM_VERTS_OF_EDGE; - } - else { /* (bm->selectmode & SCE_SELECT_FACE) */ - groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); - group_tot = BM_mesh_calc_face_groups( - bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT, BM_VERT); - - htype = BM_FACE; - itype = BM_VERTS_OF_FACE; - } - - center = MEM_mallocN(sizeof(*center) * group_tot, __func__); - - if (calc_island_axismtx) { - axismtx = MEM_mallocN(sizeof(*axismtx) * group_tot, __func__); - } - - vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__); - /* we shouldn't need this, but with incorrect selection flushing - * its possible we have a selected vertex that's not in a face, - * for now best not crash in that case. */ - copy_vn_i(vert_map, bm->totvert, -1); - - BM_mesh_elem_table_ensure(bm, htype); - ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable; - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - /* may be an edge OR a face array */ - for (i = 0; i < group_tot; i++) { - BMEditSelection ese = {NULL}; - - const int fg_sta = group_index[i][0]; - const int fg_len = group_index[i][1]; - float co[3], no[3], tangent[3]; - int j; - - zero_v3(co); - zero_v3(no); - zero_v3(tangent); - - ese.htype = htype; - - /* loop on each face or edge in this group: - * - assign r_vert_map - * - calculate (co, no) - */ - for (j = 0; j < fg_len; j++) { - float tmp_co[3], tmp_no[3], tmp_tangent[3]; - - ese.ele = ele_array[groups_array[fg_sta + j]]; - - BM_editselection_center(&ese, tmp_co); - add_v3_v3(co, tmp_co); - - if (axismtx) { - BM_editselection_normal(&ese, tmp_no); - BM_editselection_plane(&ese, tmp_tangent); - add_v3_v3(no, tmp_no); - add_v3_v3(tangent, tmp_tangent); - } - - { - /* setup vertex map */ - BMIter iter; - BMVert *v; - - /* connected edge-verts */ - BM_ITER_ELEM (v, &iter, ese.ele, itype) { - vert_map[BM_elem_index_get(v)] = i; - } - } - } - - mul_v3_v3fl(center[i], co, 1.0f / (float)fg_len); - - if (axismtx) { - if (createSpaceNormalTangent(axismtx[i], no, tangent)) { - /* pass */ - } - else { - if (normalize_v3(no) != 0.0f) { - axis_dominant_v3_to_m3(axismtx[i], no); - invert_m3(axismtx[i]); - } - else { - unit_m3(axismtx[i]); - } - } - } - } - - MEM_freeN(groups_array); - MEM_freeN(group_index); - - /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */ - if (calc_single_islands) { - BMIter viter; - BMVert *v; - int group_tot_single = 0; - - BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { - group_tot_single += 1; - } - } - - if (group_tot_single != 0) { - center = MEM_reallocN(center, sizeof(*center) * (group_tot + group_tot_single)); - if (axismtx) { - axismtx = MEM_reallocN(axismtx, sizeof(*axismtx) * (group_tot + group_tot_single)); - } +/** \} */ - BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { - vert_map[i] = group_tot; - copy_v3_v3(center[group_tot], v->co); +/* -------------------------------------------------------------------- */ +/** \name TransDataMirror Creation + * + * \{ */ - if (axismtx) { - if (is_zero_v3(v->no) != 0.0f) { - axis_dominant_v3_to_m3(axismtx[group_tot], v->no); - invert_m3(axismtx[group_tot]); - } - else { - unit_m3(axismtx[group_tot]); - } - } +/* Used for both mirror epsilon and TD_MIRROR_EDGE_ */ +#define TRANSFORM_MAXDIST_MIRROR 0.00002f - group_tot += 1; - } - } - } - } +struct MirrorDataVert { + int index; + int flag; +}; - r_island_data->axismtx = axismtx; - r_island_data->center = center; - r_island_data->island_tot = group_tot; - r_island_data->island_vert_map = vert_map; -} +struct TransMirrorData { + struct MirrorDataVert *vert_map; + int mirror_elem_len; +}; static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon) { @@ -423,172 +456,124 @@ static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const fl return true; } -static TransDataMirror *editmesh_mirror_data_calc(BMEditMesh *em, - bool use_select, - const bool use_topology, - const bool mirror_axis[3], - int *r_mirror_data_len, - BLI_bitmap **r_mirror_bitmap) +static void editmesh_mirror_data_calc(BMEditMesh *em, + const bool use_select, + const bool use_topology, + const bool mirror_axis[3], + struct TransMirrorData *r_mirror_data) { - BMesh *bm = em->bm; - int *index[3] = {NULL}; - int i; - - bool test_selected_only = use_select && (mirror_axis[0] + mirror_axis[1] + mirror_axis[2]) == 1; - for (i = 0; i < 3; i++) { - if (mirror_axis[i]) { - index[i] = MEM_mallocN(bm->totvert * sizeof(int), __func__); - EDBM_verts_mirror_cache_begin_ex( - em, i, false, test_selected_only, use_topology, TRANSFORM_MAXDIST_MIRROR, index[i]); - } - } + struct MirrorDataVert *vert_map; + BMesh *bm = em->bm; BMVert *eve; BMIter iter; + int i, flag, totvert = bm->totvert; - int quadrant[3]; - { - float select_sum[3] = {0}; - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - continue; - } - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - add_v3_v3(select_sum, eve->co); - } - } - - for (i = 0; i < 3; i++) { - if (mirror_axis[i]) { - quadrant[i] = select_sum[i] >= 0.0f ? 1 : -1; - } - else { - quadrant[i] = 0; - } - } - } + vert_map = MEM_mallocN(totvert * sizeof(*vert_map), __func__); - /* Tag only elements that will be transformed within the quadrant. */ + float select_sum[3] = {0}; BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { + vert_map[i] = (struct MirrorDataVert){-1, 0}; if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { continue; } - if ((!use_select || BM_elem_flag_test(eve, BM_ELEM_SELECT)) && - is_in_quadrant_v3(eve->co, quadrant, TRANSFORM_MAXDIST_MIRROR)) { - BM_elem_flag_enable(eve, BM_ELEM_TAG); - BM_elem_index_set(eve, i); + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + add_v3_v3(select_sum, eve->co); + } + } + + /* Tag only elements that will be transformed within the quadrant. */ + int quadrant[3]; + for (int a = 0; a < 3; a++) { + if (mirror_axis[a]) { + quadrant[a] = select_sum[a] >= 0.0f ? 1 : -1; } else { - BM_elem_flag_disable(eve, BM_ELEM_TAG); - BM_elem_index_set(eve, -1); + quadrant[a] = 0; } } + uint mirror_elem_len = 0; + int *index[3] = {NULL, NULL, NULL}; + bool test_selected_only = use_select && (mirror_axis[0] + mirror_axis[1] + mirror_axis[2]) == 1; for (int a = 0; a < 3; a++) { - int *index_iter = index[a]; - if (index_iter == NULL) { + if (!mirror_axis[a]) { continue; } + + index[a] = MEM_mallocN(totvert * sizeof(*index[a]), __func__); + EDBM_verts_mirror_cache_begin_ex( + em, a, false, test_selected_only, use_topology, TRANSFORM_MAXDIST_MIRROR, index[a]); + + flag = TD_MIRROR_X << a; BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { + int i_mirr = index[a][i]; + if (i_mirr < 0) { + continue; + } if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { continue; } - if (test_selected_only && !BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + if (use_select && !BM_elem_flag_test(eve, BM_ELEM_SELECT)) { continue; } - int elem_index = BM_elem_index_get(eve); - if (elem_index != -1) { - int i_mirr = index_iter[i]; - if (i_mirr >= 0) { - BMVert *vmir = BM_vert_at_index(bm, i_mirr); - BM_elem_index_set(vmir, elem_index); - - /* The slot of this element in the index array no longer needs to be read. - * Use to set the mirror sign. */ - if (index[0] && a > 0) { - index[0][i_mirr] = index[0][i]; - } - if (index[1] && a > 1) { - index[1][i_mirr] = index[1][i]; - } - /* Use -2 to differ from -1, but both can work. */ - index_iter[i_mirr] = -2; - } + if (!is_in_quadrant_v3(eve->co, quadrant, TRANSFORM_MAXDIST_MIRROR)) { + continue; } - } - } - /* Count mirror elements. */ - uint mirror_elem_len = 0; - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN | BM_ELEM_TAG)) { - /* Not a mirror element. */ - BM_elem_index_set(eve, -1); - continue; - } - int elem_index = BM_elem_index_get(eve); - if (elem_index != -1) { + vert_map[i_mirr] = (struct MirrorDataVert){i, flag}; mirror_elem_len++; } } - TransDataMirror *td_mirror_iter, *td_mirror = NULL; - if (mirror_elem_len != 0) { - td_mirror = MEM_mallocN(mirror_elem_len * sizeof(*td_mirror), __func__); - td_mirror_iter = &td_mirror[0]; - - *r_mirror_bitmap = BLI_BITMAP_NEW(bm->totvert, __func__); - - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - int elem_index = BM_elem_index_get(eve); - if (elem_index != -1) { - BMVert *v_src = BM_vert_at_index(bm, elem_index); + if (mirror_elem_len) { + for (int a = 0; a < 3; a++) { + if (!mirror_axis[a]) { + continue; + } - int flag = 0; - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - flag |= TD_SELECTED; - } - if (index[0] && index[0][i] == -2) { - flag |= TD_MIRROR_X; - } - if (index[1] && index[1][i] == -2) { - flag |= TD_MIRROR_Y; + flag = TD_MIRROR_X << a; + for (i = 0; i < totvert; i++) { + int i_mirr = index[a][i]; + if (i_mirr < 0) { + continue; } - if (index[2] && index[2][i] == -2) { - flag |= TD_MIRROR_Z; + if (vert_map[i].index != -1 && !(vert_map[i].flag & flag)) { + if (vert_map[i_mirr].index == -1) { + mirror_elem_len++; + } + vert_map[i_mirr].index = vert_map[i].index; + vert_map[i_mirr].flag |= vert_map[i].flag | flag; } - - td_mirror_iter->extra = eve; - td_mirror_iter->loc = eve->co; - copy_v3_v3(td_mirror_iter->iloc, eve->co); - td_mirror_iter->flag = flag; - td_mirror_iter->loc_src = v_src->co; - /** `center` will be set in the main createTransEditVerts loop. - * copy_v3_v3(td_mirror_iter->center, eve->co); */ - - td_mirror_iter++; - - BLI_BITMAP_ENABLE(*r_mirror_bitmap, i); } } } + else { + MEM_freeN(vert_map); + vert_map = NULL; + } MEM_SAFE_FREE(index[0]); MEM_SAFE_FREE(index[1]); MEM_SAFE_FREE(index[2]); - bm->elem_index_dirty |= BM_VERT; - *r_mirror_data_len = mirror_elem_len; - return td_mirror; + r_mirror_data->vert_map = vert_map; + r_mirror_data->mirror_elem_len = mirror_elem_len; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Edit Mesh Verts Transform Creation + * + * \{ */ + static void transdata_center_get(const struct TransIslandData *island_data, const int island_index, - const bool no_island_center, const float iloc[3], float r_center[3]) { - if (island_index != -1 && !no_island_center) { + if (island_data->center && island_index != -1) { copy_v3_v3(r_center, island_data->center[island_index]); } else { @@ -604,8 +589,7 @@ static void VertsToTransData(TransInfo *t, BMVert *eve, float *bweight, const struct TransIslandData *island_data, - const int island_index, - const bool no_island_center) + const int island_index) { float *no, _no[3]; BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0); @@ -626,7 +610,7 @@ static void VertsToTransData(TransInfo *t, no = eve->no; } - transdata_center_get(island_data, island_index, no_island_center, td->iloc, td->center); + transdata_center_get(island_data, island_index, td->iloc, td->center); if ((island_index != -1) && island_data->axismtx) { copy_m3_m3(td->axismtx, island_data->axismtx[island_index]); @@ -676,31 +660,12 @@ void createTransEditVerts(TransInfo *t) BMesh *bm = em->bm; BMVert *eve; BMIter iter; - float(*mappedcos)[3] = NULL, (*quats)[4] = NULL; - float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL; - float *dists = NULL; + float mtx[3][3], smtx[3][3]; int a; const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0; - int cd_vert_bweight_offset = -1; struct TransIslandData island_data = {NULL}; - - /* Snap rotation along normal needs a common axis for whole islands, - * otherwise one get random crazy results, see T59104. - * However, we do not want to use the island center for the pivot/translation reference. */ - const bool is_snap_rotate = ((t->mode == TFM_TRANSLATION) && - /* There is not guarantee that snapping - * is initialized yet at this point... */ - (usingSnappingNormal(t) || - (t->settings->snap_flag & SCE_SNAP_ROTATE) != 0) && - (t->around != V3D_AROUND_LOCAL_ORIGINS)); - /* Even for translation this is needed because of island-orientation, see: T51651. */ - const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) || is_snap_rotate; - /* Original index of our connected vertex when connected distances are calculated. - * Optional, allocate if needed. */ - int *dists_index = NULL; - - BLI_bitmap *mirror_bitmap = NULL; + struct TransMirrorData mirror_data = {NULL}; /** * Quick check if we can transform. @@ -711,20 +676,7 @@ void createTransEditVerts(TransInfo *t) /* Support other objects using PET to adjust these, unless connected is enabled. */ if ((!prop_mode || (prop_mode & T_PROP_CONNECTED)) && (bm->totvertsel == 0)) { - goto cleanup; - } - - if (t->mode == TFM_BWEIGHT) { - BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT); - cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); - } - - if (tc->use_mirror_axis_any) { - bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - bool use_select = (t->flag & T_PROP_EDIT) == 0; - bool mirror_axis[3] = {tc->use_mirror_axis_x, tc->use_mirror_axis_y, tc->use_mirror_axis_z}; - tc->data_mirror = editmesh_mirror_data_calc( - em, use_select, use_topology, mirror_axis, &tc->data_mirror_len, &mirror_bitmap); + continue; } int data_len = 0; @@ -734,44 +686,41 @@ void createTransEditVerts(TransInfo *t) data_len++; } } - - if (data_len == 0) { - goto cleanup; - } - - /* allocating scratch arrays */ - if (prop_mode & T_PROP_CONNECTED) { - dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__); - if (is_island_center) { - dists_index = MEM_mallocN(em->bm->totvert * sizeof(int), __func__); - } - } } else { data_len = bm->totvertsel; } - if (mirror_bitmap) { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { - if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - if (BLI_BITMAP_TEST(mirror_bitmap, a)) { - data_len--; - } - } - } + if (data_len == 0) { + continue; } - BLI_assert(data_len != 0); + /* Snap rotation along normal needs a common axis for whole islands, + * otherwise one get random crazy results, see T59104. + * However, we do not want to use the island center for the pivot/translation reference. */ + const bool is_snap_rotate = ((t->mode == TFM_TRANSLATION) && + /* There is not guarantee that snapping + * is initialized yet at this point... */ + (usingSnappingNormal(t) || + (t->settings->snap_flag & SCE_SNAP_ROTATE) != 0) && + (t->around != V3D_AROUND_LOCAL_ORIGINS)); - tc->data_len = data_len; - tc->data = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)"); - if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) { - /* warning, this is overkill, we only need 2 extra floats, - * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill - * since we may not use the 'alt' transform mode to maintain shell thickness, - * but with generic transform code its hard to lazy init vars */ - tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), - "TransObData ext"); + /* Even for translation this is needed because of island-orientation, see: T51651. */ + const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) || is_snap_rotate; + if (is_island_center) { + /* In this specific case, near-by vertices will need to know + * the island of the nearest connected vertex. */ + const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) && + (t->around == V3D_AROUND_LOCAL_ORIGINS) && + (em->selectmode & SCE_SELECT_VERTEX)); + + const bool calc_island_center = !is_snap_rotate; + /* The island axismtx is only necessary in some modes. + * TODO(Germano): Extend the list to exclude other modes. */ + const bool calc_island_axismtx = !ELEM(t->mode, TFM_SHRINKFATTEN); + + editmesh_islands_info_calc( + em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data); } copy_m3_m4(mtx, tc->obedit->obmat); @@ -779,26 +728,58 @@ void createTransEditVerts(TransInfo *t) * matrix inversion still works and we can still moving along the other */ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); + /* Original index of our connected vertex when connected distances are calculated. + * Optional, allocate if needed. */ + int *dists_index = NULL; + float *dists = NULL; if (prop_mode & T_PROP_CONNECTED) { + dists = MEM_mallocN(bm->totvert * sizeof(float), __func__); + if (is_island_center) { + dists_index = MEM_mallocN(bm->totvert * sizeof(int), __func__); + } editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index); } - if (is_island_center) { - /* In this specific case, near-by vertices will need to know - * the island of the nearest connected vertex. */ - const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) && - (t->around == V3D_AROUND_LOCAL_ORIGINS) && - (em->selectmode & SCE_SELECT_VERTEX)); + /* Create TransDataMirror. */ + if (tc->use_mirror_axis_any) { + bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + bool use_select = (t->flag & T_PROP_EDIT) == 0; + bool mirror_axis[3] = {tc->use_mirror_axis_x, tc->use_mirror_axis_y, tc->use_mirror_axis_z}; + editmesh_mirror_data_calc(em, use_select, use_topology, mirror_axis, &mirror_data); - /* The island axismtx is only necessary in some modes. - * TODO(Germano): Extend the list to exclude other modes. */ - const bool calc_island_axismtx = !ELEM(t->mode, TFM_SHRINKFATTEN); + if (mirror_data.vert_map) { + tc->data_mirror_len = mirror_data.mirror_elem_len; + tc->data_mirror = MEM_mallocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror), + __func__); + + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { + if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + if (mirror_data.vert_map[a].index != -1) { + data_len--; + } + } + } + } + } - editmesh_islands_info_calc(em, calc_single_islands, calc_island_axismtx, &island_data); + /* Create TransData. */ + BLI_assert(data_len >= 1); + tc->data_len = data_len; + tc->data = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)"); + if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) { + /* warning, this is overkill, we only need 2 extra floats, + * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill + * since we may not use the 'alt' transform mode to maintain shell thickness, + * but with generic transform code its hard to lazy init vars */ + tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), + "TransObData ext"); } /* detect CrazySpace [tm] */ + float(*quats)[4] = NULL; + float(*defmats)[3][3] = NULL; if (BKE_modifiers_get_cage_index(t->scene, tc->obedit, NULL, 1) != -1) { + float(*defcos)[3] = NULL; int totleft = -1; if (BKE_modifiers_is_correctable_deformed(t->scene, tc->obedit)) { BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context)); @@ -813,16 +794,17 @@ void createTransEditVerts(TransInfo *t) t->depsgraph, scene_eval, obedit_eval, em_eval, &defmats, &defcos); } - /* if we still have more modifiers, also do crazyspace - * correction with quats, relative to the coordinates after - * the modifiers that support deform matrices (defcos) */ + /* If we still have more modifiers, also do crazy-space + * correction with \a quats, relative to the coordinates after + * the modifiers that support deform matrices \a defcos. */ -#if 0 /* TODO, fix crazyspace+extrude so it can be enabled for general use - campbell */ +#if 0 /* TODO, fix crazy-space & extrude so it can be enabled for general use - campbell */ if ((totleft > 0) || (totleft == -1)) #else if (totleft > 0) #endif { + float(*mappedcos)[3] = NULL; mappedcos = BKE_crazyspace_get_mapped_editverts(t->depsgraph, tc->obedit); quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats"); BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode); @@ -836,6 +818,12 @@ void createTransEditVerts(TransInfo *t) } } + int cd_vert_bweight_offset = -1; + if (t->mode == TFM_BWEIGHT) { + BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT); + cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); + } + TransData *tob = tc->data; TransDataMirror *td_mirror = tc->data_mirror; BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { @@ -849,9 +837,20 @@ void createTransEditVerts(TransInfo *t) island_index = island_data.island_vert_map[connected_index]; } - if (mirror_bitmap && BLI_BITMAP_TEST(mirror_bitmap, a)) { - transdata_center_get( - &island_data, island_index, is_snap_rotate, td_mirror->iloc, td_mirror->center); + if (mirror_data.vert_map && mirror_data.vert_map[a].index != -1) { + int elem_index = mirror_data.vert_map[a].index; + BMVert *v_src = BM_vert_at_index(bm, elem_index); + + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + mirror_data.vert_map[a].flag |= TD_SELECTED; + } + + td_mirror->extra = eve; + td_mirror->loc = eve->co; + copy_v3_v3(td_mirror->iloc, eve->co); + td_mirror->flag = mirror_data.vert_map[a].flag; + td_mirror->loc_src = v_src->co; + transdata_center_get(&island_data, island_index, td_mirror->iloc, td_mirror->center); td_mirror++; } @@ -862,8 +861,7 @@ void createTransEditVerts(TransInfo *t) /* Do not use the island center in case we are using islands * only to get axis for snap/rotate to normal... */ - VertsToTransData( - t, tob, tx, em, eve, bweight, &island_data, island_index, is_snap_rotate); + VertsToTransData(t, tob, tx, em, eve, bweight, &island_data, island_index); if (tx) { tx++; } @@ -933,17 +931,15 @@ void createTransEditVerts(TransInfo *t) if (island_data.center) { MEM_freeN(island_data.center); } - if (island_data.axismtx) { MEM_freeN(island_data.axismtx); } - if (island_data.island_vert_map) { MEM_freeN(island_data.island_vert_map); } - - cleanup: - /* crazy space free */ + if (mirror_data.vert_map) { + MEM_freeN(mirror_data.vert_map); + } if (quats) { MEM_freeN(quats); } @@ -956,9 +952,6 @@ void createTransEditVerts(TransInfo *t) if (dists_index) { MEM_freeN(dists_index); } - if (mirror_bitmap) { - MEM_freeN(mirror_bitmap); - } } } @@ -1075,99 +1068,118 @@ static void create_trans_vert_customdata_layer(BMVert *v, BLI_ghash_insert(tcld->origverts, v, r_tcld_vert); } -void trans_mesh_customdata_correction_init(TransInfo *t, TransDataContainer *tc) +static void trans_mesh_customdata_correction_init_container(TransInfo *t, TransDataContainer *tc) { if (tc->custom.type.data) { /* Custom data correction has initiated before. */ BLI_assert(tc->custom.type.free_cb == trans_mesh_customdata_free_cb); return; } - int i; + + if (!ELEM(t->mode, + TFM_TRANSLATION, + TFM_ROTATION, + TFM_RESIZE, + TFM_TOSPHERE, + TFM_SHEAR, + TFM_BEND, + TFM_SHRINKFATTEN, + TFM_TRACKBALL, + TFM_PUSHPULL, + TFM_ALIGN)) { + /* Currently only modes that change the position of vertices are supported. */ + return; + } BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); BMesh *bm = em->bm; - bool use_origfaces; - int cd_loop_mdisp_offset; - { - const bool has_layer_math = CustomData_has_math(&bm->ldata); - cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); - if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) && - /* don't do this at all for non-basis shape keys, too easy to - * accidentally break uv maps or vertex colors then */ - (bm->shapenr <= 1) && (has_layer_math || (cd_loop_mdisp_offset != -1))) { - use_origfaces = true; - } - else { - use_origfaces = false; - cd_loop_mdisp_offset = -1; - } + if (bm->shapenr > 1) { + /* Don't do this at all for non-basis shape keys, too easy to + * accidentally break uv maps or vertex colors then */ + /* create copies of faces for customdata projection. */ + return; } - if (use_origfaces) { - /* create copies of faces for customdata projection */ - bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); - - struct GHash *origfaces = BLI_ghash_ptr_new(__func__); - struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default, - &((struct BMeshCreateParams){ - .use_toolflags = false, - })); - - /* we need to have matching customdata */ - BM_mesh_copy_init_customdata(bm_origfaces, bm, NULL); - - int *layer_math_map = NULL; - int layer_index_dst = 0; - { - /* TODO: We don't need `sod->layer_math_map` when there are no loops linked - * to one of the sliding vertices. */ - if (CustomData_has_math(&bm->ldata)) { - /* over alloc, only 'math' layers are indexed */ - layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__); - for (i = 0; i < bm->ldata.totlayer; i++) { - if (CustomData_layer_has_math(&bm->ldata, i)) { - layer_math_map[layer_index_dst++] = i; - } + const bool has_layer_math = CustomData_has_math(&bm->ldata); + const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); + if (!has_layer_math && (cd_loop_mdisp_offset == -1)) { + return; + } + + bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); + + struct GHash *origfaces = BLI_ghash_ptr_new(__func__); + struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default, + &((struct BMeshCreateParams){ + .use_toolflags = false, + })); + + /* we need to have matching customdata */ + BM_mesh_copy_init_customdata(bm_origfaces, bm, NULL); + + int *layer_math_map = NULL; + int layer_math_map_len = 0; + { + /* TODO: We don't need `sod->layer_math_map` when there are no loops linked + * to one of the sliding vertices. */ + if (has_layer_math) { + /* over alloc, only 'math' layers are indexed */ + layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__); + for (int i = 0; i < bm->ldata.totlayer; i++) { + if (CustomData_layer_has_math(&bm->ldata, i)) { + layer_math_map[layer_math_map_len++] = i; } - BLI_assert(layer_index_dst != 0); } + BLI_assert(layer_math_map_len != 0); } + } - struct TransCustomDataLayer *tcld; - tc->custom.type.data = tcld = MEM_mallocN(sizeof(*tcld), __func__); - tc->custom.type.free_cb = trans_mesh_customdata_free_cb; - - tcld->bm = bm; - tcld->origfaces = origfaces; - tcld->bm_origfaces = bm_origfaces; - tcld->cd_loop_mdisp_offset = cd_loop_mdisp_offset; - tcld->layer_math_map = layer_math_map; - tcld->layer_math_map_num = layer_index_dst; - tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + struct TransCustomDataLayer *tcld = MEM_mallocN(sizeof(*tcld), __func__); + int data_len = tc->data_len + tc->data_mirror_len; - int data_len = tc->data_len + tc->data_mirror_len; - struct GHash *origverts = BLI_ghash_ptr_new_ex(__func__, data_len); - tcld->origverts = origverts; + tcld->bm = bm; + tcld->origfaces = origfaces; + tcld->bm_origfaces = bm_origfaces; + tcld->cd_loop_mdisp_offset = cd_loop_mdisp_offset; + tcld->layer_math_map = layer_math_map; + tcld->layer_math_map_num = layer_math_map_len; + tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + tcld->origverts = BLI_ghash_ptr_new_ex(__func__, data_len); + tcld->data = BLI_memarena_alloc(tcld->arena, data_len * sizeof(*tcld->data)); + tcld->data_len = data_len; - struct TransCustomDataLayerVert *tcld_vert, *tcld_vert_iter; - tcld_vert = BLI_memarena_alloc(tcld->arena, data_len * sizeof(*tcld_vert)); - tcld_vert_iter = &tcld_vert[0]; + { + /* Setup Verts. */ + struct TransCustomDataLayerVert *tcld_vert_iter = &tcld->data[0]; - TransData *tob; - for (i = tc->data_len, tob = tc->data; i--; tob++, tcld_vert_iter++) { + TransData *tob = tc->data; + for (int i = tc->data_len; i--; tob++, tcld_vert_iter++) { BMVert *v = tob->extra; create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter); } TransDataMirror *td_mirror = tc->data_mirror; - for (i = tc->data_mirror_len; i--; td_mirror++, tcld_vert_iter++) { + for (int i = tc->data_mirror_len; i--; td_mirror++, tcld_vert_iter++) { BMVert *v = td_mirror->extra; create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter); } + } + + tc->custom.type.data = tcld; + tc->custom.type.free_cb = trans_mesh_customdata_free_cb; +} + +void trans_mesh_customdata_correction_init(TransInfo *t) +{ + const char uvcalc_correct_flag = ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) ? + UVCALC_TRANSFORM_CORRECT_SLIDE : + UVCALC_TRANSFORM_CORRECT; - tcld->data = tcld_vert; - tcld->data_len = data_len; + if (t->settings->uvcalc_flag & uvcalc_correct_flag) { + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + trans_mesh_customdata_correction_init_container(t, tc); + } } } @@ -1187,19 +1199,17 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa BMesh *bm = tcld->bm; BMVert *v = tcld_vert->v; const float *co_orig_3d = tcld_vert->co_orig_3d; - struct LinkNode **cd_loop_groups = tcld_vert->cd_loop_groups; BMIter liter; int j, l_num; float *loop_weights; const bool is_moved = (len_squared_v3v3(v->co, co_orig_3d) > FLT_EPSILON); - const bool do_loop_weight = tcld->layer_math_map_num && is_moved; - const bool do_loop_mdisps = is_final && is_moved && (tcld->cd_loop_mdisp_offset != -1); + const bool do_loop_weight = is_moved && tcld->layer_math_map_num; const float *v_proj_axis = v->no; /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */ float v_proj[3][3]; - if (do_loop_weight || do_loop_mdisps) { + if (do_loop_weight) { project_plane_normalized_v3_v3v3(v_proj[1], co_orig_3d, v_proj_axis); } @@ -1264,6 +1274,7 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa } } + struct LinkNode **cd_loop_groups = tcld_vert->cd_loop_groups; if (tcld->layer_math_map_num && cd_loop_groups) { if (do_loop_weight) { for (j = 0; j < tcld->layer_math_map_num; j++) { @@ -1283,6 +1294,7 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa * Interpolate from every other loop (not ideal) * However values will only be taken from loops which overlap other mdisps. * */ + const bool do_loop_mdisps = is_moved && is_final && (tcld->cd_loop_mdisp_offset != -1); if (do_loop_mdisps) { float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num); BMLoop *l; @@ -1386,13 +1398,9 @@ void recalcData_mesh(TransInfo *t) } } - if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - trans_mesh_customdata_correction_apply(tc, false); - } - } - FOREACH_TRANS_DATA_CONTAINER (t, tc) { + trans_mesh_customdata_correction_apply(tc, false); + DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); EDBM_mesh_normals_update(em); @@ -1408,18 +1416,9 @@ void recalcData_mesh(TransInfo *t) void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) { const bool canceled = (t->state == TRANS_CANCEL); + const bool use_automerge = !canceled && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0; - if (canceled) { - /* Exception, edge slide transformed UVs too. */ - if (t->mode == TFM_EDGE_SLIDE) { - doEdgeSlide(t, 0.0f); - } - else if (t->mode == TFM_VERT_SLIDE) { - doVertSlide(t, 0.0f); - } - } - - if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + if (TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.type.data != NULL) { /* Handle multires re-projection, done * on transform completion since it's * really slow -joeedh. */ @@ -1428,10 +1427,8 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) } } - bool use_automerge = !canceled && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0; if (use_automerge) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); BMesh *bm = em->bm; char hflag; diff --git a/source/blender/editors/transform/transform_data.h b/source/blender/editors/transform/transform_data.h index bc95fdad59c..48ed9ecf34b 100644 --- a/source/blender/editors/transform/transform_data.h +++ b/source/blender/editors/transform/transform_data.h @@ -88,8 +88,8 @@ typedef struct TransDataExtension { * It is the same but without the #Bone.bone_mat, see #TD_PBONE_LOCAL_MTX_C. */ float l_smtx[3][3]; /** The rotscale matrix of pose bone, to allow using snap-align in translation mode, - * when td->mtx is the loc pose bone matrix (and hence can't be used to apply - * rotation in some cases, namely when a bone is in "NoLocal" or "Hinge" mode)... */ + * when #TransData.mtx is the loc pose bone matrix (and hence can't be used to apply + * rotation in some cases, namely when a bone is in "No-Local" or "Hinge" mode)... */ float r_mtx[3][3]; /** Inverse of previous one. */ float r_smtx[3][3]; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 78c47014d62..cce6ef1f3bd 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -131,21 +131,6 @@ void resetTransRestrictions(TransInfo *t) t->flag &= ~T_ALL_RESTRICTIONS; } -static int initTransInfo_edit_pet_to_flag(const int proportional) -{ - int flag = 0; - if (proportional & PROP_EDIT_USE) { - flag |= T_PROP_EDIT; - } - if (proportional & PROP_EDIT_CONNECTED) { - flag |= T_PROP_CONNECTED; - } - if (proportional & PROP_EDIT_PROJECTED) { - flag |= T_PROP_PROJECTED; - } - return flag; -} - void initTransDataContainers_FromObjectData(TransInfo *t, Object *obact, Object **objects, @@ -390,15 +375,15 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve if (op && ((prop = RNA_struct_find_property(op->ptr, "correct_uv")))) { if (RNA_property_is_set(op->ptr, prop)) { if (RNA_property_boolean_get(op->ptr, prop)) { - t->settings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT; + t->settings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT_SLIDE; } else { - t->settings->uvcalc_flag &= ~UVCALC_TRANSFORM_CORRECT; + t->settings->uvcalc_flag &= ~UVCALC_TRANSFORM_CORRECT_SLIDE; } } else { RNA_property_boolean_set( - op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0); + op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE) != 0); } } } @@ -550,7 +535,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve orient_types[2] = orient_type_scene; } else { - if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode))) { + if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode)) && + (t->mode != TFM_ALIGN)) { orient_types[0] = V3D_ORIENT_VIEW; } else { @@ -636,45 +622,45 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */ if (op && (prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) { if (RNA_property_is_set(op->ptr, prop)) { - int proportional = 0; if (RNA_property_boolean_get(op->ptr, prop)) { - proportional |= PROP_EDIT_USE; + t->flag |= T_PROP_EDIT; if (RNA_boolean_get(op->ptr, "use_proportional_connected")) { - proportional |= PROP_EDIT_CONNECTED; + t->flag |= T_PROP_CONNECTED; } if (RNA_boolean_get(op->ptr, "use_proportional_projected")) { - proportional |= PROP_EDIT_PROJECTED; + t->flag |= T_PROP_PROJECTED; } } - t->flag |= initTransInfo_edit_pet_to_flag(proportional); } else { /* use settings from scene only if modal */ if (t->flag & T_MODAL) { if ((t->options & CTX_NO_PET) == 0) { + bool use_prop_edit = false; if (t->spacetype == SPACE_GRAPH) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_fcurve); + use_prop_edit = ts->proportional_fcurve; } else if (t->spacetype == SPACE_ACTION) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action); + use_prop_edit = ts->proportional_action; } - else if (t->obedit_type != -1) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_edit); + else if (t->options & CTX_MASK) { + use_prop_edit = ts->proportional_mask; } - else if (t->options & CTX_GPENCIL_STROKES) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_edit); + else if (obact && obact->mode == OB_MODE_OBJECT) { + use_prop_edit = ts->proportional_objects; } - else if (t->options & CTX_MASK) { - if (ts->proportional_mask) { - t->flag |= T_PROP_EDIT; - - if (ts->proportional_edit & PROP_EDIT_CONNECTED) { - t->flag |= T_PROP_CONNECTED; - } - } + else { + use_prop_edit = (ts->proportional_edit & PROP_EDIT_USE) != 0; } - else if (!(t->options & CTX_CURSOR) && ts->proportional_objects) { + + if (use_prop_edit) { t->flag |= T_PROP_EDIT; + if (ts->proportional_edit & PROP_EDIT_CONNECTED) { + t->flag |= T_PROP_CONNECTED; + } + if (ts->proportional_edit & PROP_EDIT_PROJECTED) { + t->flag |= T_PROP_PROJECTED; + } } } } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index f028044809f..831ea90b4e4 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -50,6 +50,23 @@ /* Own include. */ #include "transform_mode.h" +int transform_mode_really_used(bContext *C, int mode) +{ + if (mode == TFM_BONESIZE) { + Object *ob = CTX_data_active_object(C); + BLI_assert(ob); + if (ob->type != OB_ARMATURE) { + return TFM_RESIZE; + } + bArmature *arm = ob->data; + if (arm->drawtype == ARM_ENVELOPE) { + return TFM_BONE_ENVELOPE_DIST; + } + } + + return mode; +} + bool transdata_check_local_center(TransInfo *t, short around) { return ((around == V3D_AROUND_LOCAL_ORIGINS) && @@ -1174,25 +1191,12 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) case TFM_CREASE: initCrease(t); break; - case TFM_BONESIZE: { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */ - /* Note: we have to pick one, use the active object. */ - TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t); - bArmature *arm = tc->poseobj->data; - if (arm->drawtype == ARM_ENVELOPE) { - initBoneEnvelope(t); - t->mode = TFM_BONE_ENVELOPE_DIST; - } - else { - initBoneSize(t); - } + case TFM_BONESIZE: + initBoneSize(t); break; - } case TFM_BONE_ENVELOPE: - initBoneEnvelope(t); - break; case TFM_BONE_ENVELOPE_DIST: initBoneEnvelope(t); - t->mode = TFM_BONE_ENVELOPE_DIST; break; case TFM_EDGE_SLIDE: case TFM_VERT_SLIDE: { @@ -1267,6 +1271,12 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) break; } + if (t->data_type == TC_MESH_VERTS) { + /* Init Custom Data correction. + * Ideally this should be called when creating the TransData. */ + trans_mesh_customdata_correction_init(t); + } + /* TODO(germano): Some of these operations change the `t->mode`. * This can be bad for Redo. * BLI_assert(t->mode == mode); */ diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index 464deff983b..5cda8e3063a 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -26,6 +26,7 @@ #define __TRANSFORM_MODE_H__ struct AnimData; +struct bContext; struct LinkNode; struct TransData; struct TransDataContainer; @@ -40,6 +41,7 @@ typedef struct TransDataGenericSlideVert { } TransDataGenericSlideVert; /* transform_mode.c */ +int transform_mode_really_used(struct bContext *C, int mode); bool transdata_check_local_center(TransInfo *t, short around); bool transform_mode_is_changeable(const int mode); void protectedTransBits(short protectflag, float vec[3]); @@ -95,7 +97,6 @@ void initSeqSlide(TransInfo *t); /* transform_mode_edge_slide.c */ void drawEdgeSlide(TransInfo *t); -void doEdgeSlide(TransInfo *t, float perc); void initEdgeSlide_ex( TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp); void initEdgeSlide(TransInfo *t); @@ -153,7 +154,6 @@ void initTranslation(TransInfo *t); /* transform_mode_vert_slide.c */ void drawVertSlide(TransInfo *t); -void doVertSlide(TransInfo *t, float perc); void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp); void initVertSlide(TransInfo *t); #endif diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c index 77850e74785..2c2253630c0 100644 --- a/source/blender/editors/transform/transform_mode_bbone_resize.c +++ b/source/blender/editors/transform/transform_mode_bbone_resize.c @@ -132,6 +132,11 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2])) if (t->con.applySize) { t->con.applySize(t, NULL, NULL, mat); + for (i = 0; i < 3; i++) { + if (!(t->con.mode & (CON_AXIS0 << i))) { + t->values_final[i] = 1.0f; + } + } } copy_m3_m3(t->mat, mat); // used in gizmo diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c index 7045d190478..b7a34769f5a 100644 --- a/source/blender/editors/transform/transform_mode_boneenvelope.c +++ b/source/blender/editors/transform/transform_mode_boneenvelope.c @@ -96,7 +96,6 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) void initBoneEnvelope(TransInfo *t) { - t->mode = TFM_BONE_ENVELOPE; t->transform = applyBoneEnvelope; initMouseInputMode(t, &t->mouse, INPUT_SPRING); diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index 42f75f041b9..ed22afc404e 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -50,6 +50,7 @@ #include "BLT_translation.h" #include "transform.h" +#include "transform_constraints.h" #include "transform_convert.h" #include "transform_mode.h" #include "transform_snap.h" @@ -96,24 +97,28 @@ typedef struct EdgeSlideParams { } EdgeSlideParams; /** - * Get the first valid EdgeSlideData. + * Get the first valid TransDataContainer *. * * Note we cannot trust TRANS_DATA_CONTAINER_FIRST_OK because of multi-object that * may leave items with invalid custom data in the transform data container. */ -static EdgeSlideData *edgeSlideFirstGet(TransInfo *t) +static TransDataContainer *edge_slide_container_first_ok(TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - if (sld == NULL) { - continue; + if (tc->custom.mode.data) { + return tc; } - return sld; } BLI_assert(!"Should never happen, at least one EdgeSlideData should be valid"); return NULL; } +static EdgeSlideData *edgeSlideFirstGet(TransInfo *t) +{ + TransDataContainer *tc = edge_slide_container_first_ok(t); + return tc->custom.mode.data; +} + static void calcEdgeSlideCustomPoints(struct TransInfo *t) { EdgeSlideData *sld = edgeSlideFirstGet(t); @@ -1129,132 +1134,226 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven void drawEdgeSlide(TransInfo *t) { - if ((t->mode == TFM_EDGE_SLIDE) && edgeSlideFirstGet(t)) { - const EdgeSlideParams *slp = t->custom.mode.data; - EdgeSlideData *sld = edgeSlideFirstGet(t); - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); + if (t->mode != TFM_EDGE_SLIDE) { + return; + } - /* Even mode */ - if ((slp->use_even == true) || (is_clamp == false)) { - const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; + EdgeSlideData *sld = edgeSlideFirstGet(t); + if (sld == NULL) { + return; + } - GPU_depth_test(false); + const EdgeSlideParams *slp = t->custom.mode.data; + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - GPU_blend(true); - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; - GPU_matrix_push(); - GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + GPU_depth_test(false); - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_blend(true); + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + GPU_matrix_push(); + GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); - if (slp->use_even == true) { - float co_a[3], co_b[3], co_mark[3]; - TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; - const float fac = (slp->perc + 1.0f) / 2.0f; - const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f; - const float guide_size = ctrl_size - 0.5f; - const int alpha_shade = -30; + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]); - add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - GPU_line_width(line_size); - immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - immBeginAtMost(GPU_PRIM_LINES, 4); - if (curr_sv->v_side[0]) { - immVertex3fv(pos, curr_sv->v_side[0]->co); - immVertex3fv(pos, curr_sv->v_co_orig); - } + if (slp->use_even == true) { + /* Even mode */ + float co_a[3], co_b[3], co_mark[3]; + TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; + const float fac = (slp->perc + 1.0f) / 2.0f; + const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f; + const float guide_size = ctrl_size - 0.5f; + const int alpha_shade = -30; + + add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]); + add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]); + + GPU_line_width(line_size); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + immBeginAtMost(GPU_PRIM_LINES, 4); + if (curr_sv->v_side[0]) { + immVertex3fv(pos, curr_sv->v_side[0]->co); + immVertex3fv(pos, curr_sv->v_co_orig); + } + if (curr_sv->v_side[1]) { + immVertex3fv(pos, curr_sv->v_side[1]->co); + immVertex3fv(pos, curr_sv->v_co_orig); + } + immEnd(); + + { + float *co_test = NULL; + if (slp->flipped) { if (curr_sv->v_side[1]) { - immVertex3fv(pos, curr_sv->v_side[1]->co); - immVertex3fv(pos, curr_sv->v_co_orig); + co_test = curr_sv->v_side[1]->co; } - immEnd(); - - { - float *co_test = NULL; - if (slp->flipped) { - if (curr_sv->v_side[1]) { - co_test = curr_sv->v_side[1]->co; - } - } - else { - if (curr_sv->v_side[0]) { - co_test = curr_sv->v_side[0]->co; - } - } - - if (co_test != NULL) { - immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); - GPU_point_size(ctrl_size); - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, co_test); - immEnd(); - } + } + else { + if (curr_sv->v_side[0]) { + co_test = curr_sv->v_side[0]->co; } + } - immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); - GPU_point_size(guide_size); + if (co_test != NULL) { + immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); + GPU_point_size(ctrl_size); immBegin(GPU_PRIM_POINTS, 1); - interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac); - immVertex3fv(pos, co_mark); + immVertex3fv(pos, co_test); immEnd(); } + } + + immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); + GPU_point_size(guide_size); + immBegin(GPU_PRIM_POINTS, 1); + interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac); + immVertex3fv(pos, co_mark); + immEnd(); + } + else if (is_clamp == false) { + const int side_index = sld->curr_side_unclamp; + TransDataEdgeSlideVert *sv; + int i; + const int alpha_shade = -160; + + GPU_line_width(line_size); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + immBegin(GPU_PRIM_LINES, sld->totsv * 2); + + /* TODO(campbell): Loop over all verts */ + sv = sld->sv; + for (i = 0; i < sld->totsv; i++, sv++) { + float a[3], b[3]; + + if (!is_zero_v3(sv->dir_side[side_index])) { + copy_v3_v3(a, sv->dir_side[side_index]); + } else { - if (is_clamp == false) { - const int side_index = sld->curr_side_unclamp; - TransDataEdgeSlideVert *sv; - int i; - const int alpha_shade = -160; + copy_v3_v3(a, sv->dir_side[!side_index]); + } - GPU_line_width(line_size); - immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - immBegin(GPU_PRIM_LINES, sld->totsv * 2); + mul_v3_fl(a, 100.0f); + negate_v3_v3(b, a); + add_v3_v3(a, sv->v_co_orig); + add_v3_v3(b, sv->v_co_orig); - /* TODO(campbell): Loop over all verts */ - sv = sld->sv; - for (i = 0; i < sld->totsv; i++, sv++) { - float a[3], b[3]; + immVertex3fv(pos, a); + immVertex3fv(pos, b); + } + immEnd(); + } + else { + /* Common case. */ + TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; + const int alpha_shade = -160; + + float co_dir[3]; + add_v3_v3v3(co_dir, curr_sv->v_co_orig, curr_sv->dir_side[sld->curr_side_unclamp]); + + GPU_line_width(line_size); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + immBeginAtMost(GPU_PRIM_LINES, 2); + immVertex3fv(pos, curr_sv->v_co_orig); + immVertex3fv(pos, co_dir); + immEnd(); + } - if (!is_zero_v3(sv->dir_side[side_index])) { - copy_v3_v3(a, sv->dir_side[side_index]); - } - else { - copy_v3_v3(a, sv->dir_side[!side_index]); - } + immUnbindProgram(); - mul_v3_fl(a, 100.0f); - negate_v3_v3(b, a); - add_v3_v3(a, sv->v_co_orig); - add_v3_v3(b, sv->v_co_orig); + GPU_matrix_pop(); - immVertex3fv(pos, a); - immVertex3fv(pos, b); - } - immEnd(); - } - else { - BLI_assert(0); - } - } + GPU_blend(false); - immUnbindProgram(); + GPU_depth_test(true); +} - GPU_matrix_pop(); +static void edge_slide_snap_apply(TransInfo *t, float *value) +{ + TransDataContainer *tc = edge_slide_container_first_ok(t); + EdgeSlideParams *slp = t->custom.mode.data; + EdgeSlideData *sld_active = tc->custom.mode.data; + TransDataEdgeSlideVert *sv = &sld_active->sv[sld_active->curr_sv_index]; + float snap_point[3], co_orig[3], co_dest[2][3], dvec[3]; + + copy_v3_v3(co_orig, sv->v_co_orig); + add_v3_v3v3(co_dest[0], co_orig, sv->dir_side[0]); + add_v3_v3v3(co_dest[1], co_orig, sv->dir_side[1]); + if (tc->use_local_mat) { + mul_m4_v3(tc->mat, co_orig); + mul_m4_v3(tc->mat, co_dest[0]); + mul_m4_v3(tc->mat, co_dest[1]); + } - GPU_blend(false); + getSnapPoint(t, dvec); + sub_v3_v3(dvec, t->tsnap.snapTarget); + add_v3_v3v3(snap_point, co_orig, dvec); - GPU_depth_test(true); + float perc = *value; + int side_index; + float t_mid; + if (slp->use_even == false) { + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); + if (is_clamp) { + side_index = perc < 0.0f; + } + else { + side_index = sld_active->curr_side_unclamp; } } + else { + /* Could be pre-calculated. */ + t_mid = line_point_factor_v3((float[3]){0.0f, 0.0f, 0.0f}, sv->dir_side[0], sv->dir_side[1]); + + float t_snap = line_point_factor_v3(snap_point, co_dest[0], co_dest[1]); + side_index = t_snap >= t_mid; + } + + if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) { + float co_dir[3]; + sub_v3_v3v3(co_dir, co_dest[side_index], co_orig); + if (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) { + transform_constraint_snap_axis_to_edge(t, co_dir, dvec); + } + else { + transform_constraint_snap_axis_to_face(t, co_dir, dvec); + } + add_v3_v3v3(snap_point, co_orig, dvec); + } + + perc = line_point_factor_v3(snap_point, co_orig, co_dest[side_index]); + if (slp->use_even == false) { + if (side_index) { + perc *= -1; + } + } + else { + if (!side_index) { + perc = (1.0f - perc) * t_mid; + } + else { + perc = perc * (1.0f - t_mid) + t_mid; + } + + if (slp->flipped) { + perc = 1.0f - perc; + } + + perc = (2 * perc) - 1.0f; + + if (!slp->flipped) { + perc *= -1; + } + } + + *value = perc; } -void doEdgeSlide(TransInfo *t, float perc) +static void doEdgeSlide(TransInfo *t, float perc) { EdgeSlideParams *slp = t->custom.mode.data; EdgeSlideData *sld_active = edgeSlideFirstGet(t); @@ -1365,6 +1464,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) final = t->values[0]; + applySnapping(t, &final); snapGridIncrement(t, &final); /* only do this so out of range values are not displayed */ @@ -1413,6 +1513,8 @@ void initEdgeSlide_ex( t->mode = TFM_EDGE_SLIDE; t->transform = applyEdgeSlide; t->handleEvent = handleEventEdgeSlide; + t->tsnap.applySnap = edge_slide_snap_apply; + t->tsnap.distance = transform_snap_distance_len_squared_fn; { EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); @@ -1432,16 +1534,13 @@ void initEdgeSlide_ex( t->custom.mode.use_free = true; } - if (use_double_side) { - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - sld = use_double_side ? createEdgeSlideVerts_double_side(t, tc) : - createEdgeSlideVerts_single_side(t, tc); - if (sld) { - tc->custom.mode.data = sld; - tc->custom.mode.free_cb = freeEdgeSlideVerts; - trans_mesh_customdata_correction_init(t, tc); - ok = true; - } + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + sld = use_double_side ? createEdgeSlideVerts_double_side(t, tc) : + createEdgeSlideVerts_single_side(t, tc); + if (sld) { + tc->custom.mode.data = sld; + tc->custom.mode.free_cb = freeEdgeSlideVerts; + ok = true; } } diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c index ebce32a598e..5fb46b30e0d 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -44,6 +44,39 @@ /** \name Transform Resize * \{ */ +static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]) +{ + float d1[3], d2[3], len_d1; + + sub_v3_v3v3(d1, p1, t->center_global); + sub_v3_v3v3(d2, p2, t->center_global); + + if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { + mul_m3_v3(t->con.pmtx, d1); + mul_m3_v3(t->con.pmtx, d2); + } + + project_v3_v3v3(d1, d1, d2); + + len_d1 = len_v3(d1); + + /* Use 'invalid' dist when `center == p1` (after projecting), + * in this case scale will _never_ move the point in relation to the center, + * so it makes no sense to take it into account when scaling. see: T46503 */ + return len_d1 != 0.0f ? len_v3(d2) / len_d1 : TRANSFORM_DIST_INVALID; +} + +static void ApplySnapResize(TransInfo *t, float vec[3]) +{ + float point[3]; + getSnapPoint(t, point); + + float dist = ResizeBetween(t, t->tsnap.snapTarget, point); + if (dist != TRANSFORM_DIST_INVALID) { + copy_v3_fl(vec, dist); + } +} + static void applyResize(TransInfo *t, const int UNUSED(mval[2])) { float mat[3][3]; @@ -134,6 +167,8 @@ void initResize(TransInfo *t) { t->mode = TFM_RESIZE; t->transform = applyResize; + t->tsnap.applySnap = ApplySnapResize; + t->tsnap.distance = ResizeBetween; initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 6480cb6c30e..4fa5dffc473 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -42,6 +42,67 @@ /** \name Transform Rotation * \{ */ +static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3]) +{ + float angle, start[3], end[3]; + + sub_v3_v3v3(start, p1, t->center_global); + sub_v3_v3v3(end, p2, t->center_global); + + // Angle around a constraint axis (error prone, will need debug) + if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { + float axis[3], tmp[3]; + + t->con.applyRot(t, NULL, NULL, axis, NULL); + + project_v3_v3v3(tmp, end, axis); + sub_v3_v3v3(end, end, tmp); + + project_v3_v3v3(tmp, start, axis); + sub_v3_v3v3(start, start, tmp); + + normalize_v3(end); + normalize_v3(start); + + cross_v3_v3v3(tmp, start, end); + + if (dot_v3v3(tmp, axis) < 0.0f) { + angle = -acosf(dot_v3v3(start, end)); + } + else { + angle = acosf(dot_v3v3(start, end)); + } + } + else { + float mtx[3][3]; + + copy_m3_m4(mtx, t->viewmat); + + mul_m3_v3(mtx, end); + mul_m3_v3(mtx, start); + + angle = atan2f(start[1], start[0]) - atan2f(end[1], end[0]); + } + + if (angle > (float)M_PI) { + angle = angle - 2 * (float)M_PI; + } + else if (angle < -((float)M_PI)) { + angle = 2.0f * (float)M_PI + angle; + } + + return angle; +} + +static void ApplySnapRotation(TransInfo *t, float *value) +{ + float point[3]; + getSnapPoint(t, point); + + float dist = RotationBetween(t, t->tsnap.snapTarget, point); + *value = dist; +} + static float large_rotation_limit(float angle) { /* Limit rotation to 1001 turns max @@ -173,6 +234,8 @@ void initRotation(TransInfo *t) { t->mode = TFM_ROTATION; t->transform = applyRotation; + t->tsnap.applySnap = ApplySnapRotation; + t->tsnap.distance = RotationBetween; setInputPostFct(&t->mouse, postInputRotation); initMouseInputMode(t, &t->mouse, INPUT_ANGLE); diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 60caa257a40..aee05197f10 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -34,6 +34,7 @@ #include "BKE_report.h" #include "BKE_unit.h" +#include "ED_node.h" #include "ED_screen.h" #include "WM_api.h" @@ -214,6 +215,34 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ } } +static void ApplySnapTranslation(TransInfo *t, float vec[3]) +{ + float point[3]; + getSnapPoint(t, point); + + if (t->spacetype == SPACE_NODE) { + char border = t->tsnap.snapNodeBorder; + if (border & (NODE_LEFT | NODE_RIGHT)) { + vec[0] = point[0] - t->tsnap.snapTarget[0]; + } + if (border & (NODE_BOTTOM | NODE_TOP)) { + vec[1] = point[1] - t->tsnap.snapTarget[1]; + } + } + else { + if (t->spacetype == SPACE_VIEW3D) { + if (t->options & CTX_PAINT_CURVE) { + if (ED_view3d_project_float_global(t->region, point, point, V3D_PROJ_TEST_NOP) != + V3D_PROJ_RET_OK) { + zero_v3(point); /* no good answer here... */ + } + } + } + + sub_v3_v3v3(vec, point, t->tsnap.snapTarget); + } +} + static void applyTranslationValue(TransInfo *t, const float vec[3]) { const bool apply_snap_align_rotation = usingSnappingNormal( @@ -376,6 +405,8 @@ void initTranslation(TransInfo *t) } t->transform = applyTranslation; + t->tsnap.applySnap = ApplySnapTranslation; + t->tsnap.distance = transform_snap_distance_len_squared_fn; initMouseInputMode(t, &t->mouse, INPUT_VECTOR); diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c index 62415b1ddc6..4b75c362da9 100644 --- a/source/blender/editors/transform/transform_mode_vert_slide.c +++ b/source/blender/editors/transform/transform_mode_vert_slide.c @@ -47,6 +47,7 @@ #include "BLT_translation.h" #include "transform.h" +#include "transform_constraints.h" #include "transform_convert.h" #include "transform_mode.h" #include "transform_snap.h" @@ -491,7 +492,7 @@ void drawVertSlide(TransInfo *t) } } -void doVertSlide(TransInfo *t, float perc) +static void doVertSlide(TransInfo *t, float perc) { VertSlideParams *slp = t->custom.mode.data; @@ -538,6 +539,37 @@ void doVertSlide(TransInfo *t, float perc) } } +static void vert_slide_snap_apply(TransInfo *t, float *value) +{ + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t); + VertSlideData *sld = tc->custom.mode.data; + TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index]; + + float snap_point[3], co_orig_3d[3], co_curr_3d[3], dvec[3]; + copy_v3_v3(co_orig_3d, sv->co_orig_3d); + copy_v3_v3(co_curr_3d, sv->co_link_orig_3d[sv->co_link_curr]); + if (tc->use_local_mat) { + mul_m4_v3(tc->mat, co_orig_3d); + mul_m4_v3(tc->mat, co_curr_3d); + } + + getSnapPoint(t, dvec); + sub_v3_v3(dvec, t->tsnap.snapTarget); + if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) { + float co_dir_3d[3]; + sub_v3_v3v3(co_dir_3d, co_curr_3d, co_orig_3d); + if (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) { + transform_constraint_snap_axis_to_edge(t, co_dir_3d, dvec); + } + else { + transform_constraint_snap_axis_to_face(t, co_dir_3d, dvec); + } + } + + add_v3_v3v3(snap_point, co_orig_3d, dvec); + *value = line_point_factor_v3(snap_point, co_orig_3d, co_curr_3d); +} + static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) { char str[UI_MAX_DRAW_STR]; @@ -551,6 +583,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) final = t->values[0]; + applySnapping(t, &final); snapGridIncrement(t, &final); /* only do this so out of range values are not displayed */ @@ -596,6 +629,8 @@ void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp) t->mode = TFM_VERT_SLIDE; t->transform = applyVertSlide; t->handleEvent = handleEventVertSlide; + t->tsnap.applySnap = vert_slide_snap_apply; + t->tsnap.distance = transform_snap_distance_len_squared_fn; { VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); @@ -617,7 +652,6 @@ void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp) if (sld) { tc->custom.mode.data = sld; tc->custom.mode.free_cb = freeVertSlideVerts; - trans_mesh_customdata_correction_init(t, tc); ok = true; } } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 95249f4d17b..f86bcc41bee 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -1049,11 +1049,11 @@ static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = ED_operator_editarmature; + ot->poll = ED_operator_object_active; ot->poll_property = transform_poll_property; RNA_def_float_translation( - ot->srna, "value", 2, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX); + ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX); WM_operatortype_props_advanced_begin(ot); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index b508507cd4e..2943c3cb8ea 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -22,23 +22,13 @@ */ #include <float.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> #include "PIL_time.h" -#include "DNA_node_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" #include "BLI_blenlib.h" #include "BLI_math.h" -#include "BLI_utildefines.h" #include "GPU_immediate.h" #include "GPU_state.h" @@ -58,7 +48,6 @@ #include "ED_node.h" #include "ED_transform_snap_object_context.h" #include "ED_uvedit.h" -#include "ED_view3d.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -80,10 +69,6 @@ static void setSnappingCallback(TransInfo *t); -static void ApplySnapTranslation(TransInfo *t, float vec[3]); -static void ApplySnapRotation(TransInfo *t, float *vec); -static void ApplySnapResize(TransInfo *t, float vec[2]); - /* static void CalcSnapGrid(TransInfo *t, float *vec); */ static void CalcSnapGeometry(TransInfo *t, float *vec); @@ -92,10 +77,6 @@ static void TargetSnapCenter(TransInfo *t); static void TargetSnapClosest(TransInfo *t); static void TargetSnapActive(TransInfo *t); -static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3]); -static float TranslationBetween(TransInfo *t, const float p1[3], const float p2[3]); -static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]); - /** \} */ /* -------------------------------------------------------------------- */ @@ -143,6 +124,12 @@ bool transformModeUseSnap(const TransInfo *t) if (t->mode == TFM_RESIZE) { return (ts->snap_transform_mode_flag & SCE_SNAP_TRANSFORM_MODE_SCALE) != 0; } + if (t->mode == TFM_VERT_SLIDE) { + return true; + } + if (t->mode == TFM_EDGE_SLIDE) { + return true; + } return false; } @@ -476,7 +463,6 @@ void resetSnapping(TransInfo *t) t->tsnap.modeSelect = 0; t->tsnap.target = 0; t->tsnap.last = 0; - t->tsnap.applySnap = NULL; t->tsnap.snapNormal[0] = 0; t->tsnap.snapNormal[1] = 0; @@ -557,35 +543,32 @@ static void initSnappingMode(TransInfo *t) t->tsnap.mode = ts->snap_mode; } - if ((t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) && /* Only 3D view or UV */ - (t->flag & T_CAMERA) == 0) /* Not with camera selected in camera view */ - { + if ((t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) && (t->flag & T_CAMERA) == 0) { + /* Only 3D view or UV. */ + /* Not with camera selected in camera view. */ + setSnappingCallback(t); - /* Edit mode */ - if (t->tsnap.applySnap != NULL && // A snapping function actually exist - ((obedit_type != -1) && - /* Temporary limited to edit mode meshes, armature, curves, metaballs. */ - ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL))) { - /* Exclude editmesh if using proportional edit */ + if ((obedit_type != -1) && + ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) { + /* Edit mode */ + /* Temporary limited to edit mode meshes, armature, curves, metaballs. */ + if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) { + /* Exclude editmesh if using proportional edit */ t->tsnap.modeSelect = SNAP_NOT_ACTIVE; } else { t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE; } } - /* Particles edit mode*/ - else if (t->tsnap.applySnap != NULL && // A snapping function actually exist - ((obedit_type == -1) && base_act && base_act->object && - base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { + else if ((obedit_type == -1) && base_act && base_act->object && + (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { + /* Particles edit mode. */ t->tsnap.modeSelect = SNAP_ALL; } - /* Object mode */ - else if (t->tsnap.applySnap != NULL && // A snapping function actually exist - (obedit_type == -1)) // Object Mode - { - + else if (obedit_type == -1) { + /* Object mode */ if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) { /* In "Edit Strokes" mode, * snap tool can perform snap to selected or active objects (see T49632) @@ -605,14 +588,7 @@ static void initSnappingMode(TransInfo *t) } else if (t->spacetype == SPACE_NODE) { setSnappingCallback(t); - - if (t->tsnap.applySnap != NULL) { - t->tsnap.modeSelect = SNAP_NOT_SELECTED; - } - else { - /* Grid if snap is not possible */ - t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; - } + t->tsnap.modeSelect = SNAP_NOT_SELECTED; } else if (t->spacetype == SPACE_SEQ) { /* We do our own snapping currently, so nothing here */ @@ -720,8 +696,13 @@ static void setSnappingCallback(TransInfo *t) t->tsnap.targetSnap = TargetSnapClosest; break; case SCE_SNAP_TARGET_CENTER: - t->tsnap.targetSnap = TargetSnapCenter; - break; + if (!ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) { + t->tsnap.targetSnap = TargetSnapCenter; + break; + } + /* Can't do TARGET_CENTER with these modes, + * use TARGET_MEDIAN instead. */ + ATTR_FALLTHROUGH; case SCE_SNAP_TARGET_MEDIAN: t->tsnap.targetSnap = TargetSnapMedian; break; @@ -729,36 +710,6 @@ static void setSnappingCallback(TransInfo *t) t->tsnap.targetSnap = TargetSnapActive; break; } - - switch (t->mode) { - case TFM_TRANSLATION: - t->tsnap.applySnap = ApplySnapTranslation; - t->tsnap.distance = TranslationBetween; - break; - case TFM_ROTATION: - t->tsnap.applySnap = ApplySnapRotation; - t->tsnap.distance = RotationBetween; - - // Can't do TARGET_CENTER with rotation, use TARGET_MEDIAN instead - if (t->tsnap.target == SCE_SNAP_TARGET_CENTER) { - t->tsnap.target = SCE_SNAP_TARGET_MEDIAN; - t->tsnap.targetSnap = TargetSnapMedian; - } - break; - case TFM_RESIZE: - t->tsnap.applySnap = ApplySnapResize; - t->tsnap.distance = ResizeBetween; - - // Can't do TARGET_CENTER with resize, use TARGET_MEDIAN instead - if (t->tsnap.target == SCE_SNAP_TARGET_CENTER) { - t->tsnap.target = SCE_SNAP_TARGET_MEDIAN; - t->tsnap.targetSnap = TargetSnapMedian; - } - break; - default: - t->tsnap.applySnap = NULL; - break; - } } void addSnapPoint(TransInfo *t) @@ -859,145 +810,6 @@ void getSnapPoint(const TransInfo *t, float vec[3]) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Apply Snap - * \{ */ - -static void ApplySnapTranslation(TransInfo *t, float vec[3]) -{ - float point[3]; - getSnapPoint(t, point); - - if (t->spacetype == SPACE_NODE) { - char border = t->tsnap.snapNodeBorder; - if (border & (NODE_LEFT | NODE_RIGHT)) { - vec[0] = point[0] - t->tsnap.snapTarget[0]; - } - if (border & (NODE_BOTTOM | NODE_TOP)) { - vec[1] = point[1] - t->tsnap.snapTarget[1]; - } - } - else { - if (t->spacetype == SPACE_VIEW3D) { - if (t->options & CTX_PAINT_CURVE) { - if (ED_view3d_project_float_global(t->region, point, point, V3D_PROJ_TEST_NOP) != - V3D_PROJ_RET_OK) { - zero_v3(point); /* no good answer here... */ - } - } - } - - sub_v3_v3v3(vec, point, t->tsnap.snapTarget); - } -} - -static void ApplySnapRotation(TransInfo *t, float *value) -{ - float point[3]; - getSnapPoint(t, point); - - float dist = RotationBetween(t, t->tsnap.snapTarget, point); - *value = dist; -} - -static void ApplySnapResize(TransInfo *t, float vec[3]) -{ - float point[3]; - getSnapPoint(t, point); - - float dist = ResizeBetween(t, t->tsnap.snapTarget, point); - if (dist != TRANSFORM_DIST_INVALID) { - copy_v3_fl(vec, dist); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Distance - * \{ */ - -static float TranslationBetween(TransInfo *UNUSED(t), const float p1[3], const float p2[3]) -{ - return len_squared_v3v3(p1, p2); -} - -static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3]) -{ - float angle, start[3], end[3]; - - sub_v3_v3v3(start, p1, t->center_global); - sub_v3_v3v3(end, p2, t->center_global); - - // Angle around a constraint axis (error prone, will need debug) - if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { - float axis[3], tmp[3]; - - t->con.applyRot(t, NULL, NULL, axis, NULL); - - project_v3_v3v3(tmp, end, axis); - sub_v3_v3v3(end, end, tmp); - - project_v3_v3v3(tmp, start, axis); - sub_v3_v3v3(start, start, tmp); - - normalize_v3(end); - normalize_v3(start); - - cross_v3_v3v3(tmp, start, end); - - if (dot_v3v3(tmp, axis) < 0.0f) { - angle = -acosf(dot_v3v3(start, end)); - } - else { - angle = acosf(dot_v3v3(start, end)); - } - } - else { - float mtx[3][3]; - - copy_m3_m4(mtx, t->viewmat); - - mul_m3_v3(mtx, end); - mul_m3_v3(mtx, start); - - angle = atan2f(start[1], start[0]) - atan2f(end[1], end[0]); - } - - if (angle > (float)M_PI) { - angle = angle - 2 * (float)M_PI; - } - else if (angle < -((float)M_PI)) { - angle = 2.0f * (float)M_PI + angle; - } - - return angle; -} - -static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]) -{ - float d1[3], d2[3], len_d1; - - sub_v3_v3v3(d1, p1, t->center_global); - sub_v3_v3v3(d2, p2, t->center_global); - - if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { - mul_m3_v3(t->con.pmtx, d1); - mul_m3_v3(t->con.pmtx, d2); - } - - project_v3_v3v3(d1, d1, d2); - - len_d1 = len_v3(d1); - - /* Use 'invalid' dist when `center == p1` (after projecting), - * in this case scale will _never_ move the point in relation to the center, - * so it makes no sense to take it into account when scaling. see: T46503 */ - return len_d1 != 0.0f ? len_v3(d2) / len_d1 : TRANSFORM_DIST_INVALID; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Calc Snap (Generic) * \{ */ @@ -1734,3 +1546,16 @@ static void applyGridIncrement( } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generic callbacks + * \{ */ + +float transform_snap_distance_len_squared_fn(TransInfo *UNUSED(t), + const float p1[3], + const float p2[3]) +{ + return len_squared_v3v3(p1, p2); +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index c088cf80f0d..688661bc2cb 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -87,4 +87,6 @@ void addSnapPoint(TransInfo *t); eRedrawFlag updateSelectedSnapPoint(TransInfo *t); void removeSnapPoint(TransInfo *t); +float transform_snap_distance_len_squared_fn(TransInfo *t, const float p1[3], const float p2[3]); + #endif /* __TRANSFORM_SNAP_H__ */ diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 08ef5109a74..4198b4c02a3 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -367,17 +367,15 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, * \{ */ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, - bool use_obedit, - bool use_backface_culling, Object *ob, float obmat[4][4], + bool use_obedit, + bool use_backface_culling, + bool is_object_active, void *data); /** * Walks through all objects in the scene to create the list of objects to snap. - * - * \param sctx: Snap context to store data. - * \param snap_select: from enum #eSnapSelect. */ static void iter_snap_objects(SnapObjectContext *sctx, Depsgraph *depsgraph, @@ -393,7 +391,6 @@ static void iter_snap_objects(SnapObjectContext *sctx, Base *base_act = view_layer->basact; for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { - if (!BASE_VISIBLE(v3d, base)) { continue; } @@ -405,13 +402,14 @@ static void iter_snap_objects(SnapObjectContext *sctx, continue; } + const bool is_object_active = (base == base_act); if (snap_select == SNAP_NOT_SELECTED) { if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) { continue; } } else if (snap_select == SNAP_NOT_ACTIVE) { - if (base == base_act) { + if (is_object_active) { continue; } } @@ -421,14 +419,24 @@ static void iter_snap_objects(SnapObjectContext *sctx, DupliObject *dupli_ob; ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval); for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { - sob_callback( - sctx, use_object_edit_cage, use_backface_culling, dupli_ob->ob, dupli_ob->mat, data); + sob_callback(sctx, + dupli_ob->ob, + dupli_ob->mat, + use_object_edit_cage, + use_backface_culling, + is_object_active, + data); } free_object_duplilist(lb); } - sob_callback( - sctx, use_object_edit_cage, use_backface_culling, obj_eval, obj_eval->obmat, data); + sob_callback(sctx, + obj_eval, + obj_eval->obmat, + use_object_edit_cage, + use_backface_culling, + is_object_active, + data); } } @@ -956,10 +964,11 @@ struct RaycastObjUserData { * \note Duplicate args here are documented at #snapObjectsRay */ static void raycast_obj_fn(SnapObjectContext *sctx, - bool use_obedit, - bool use_backface_culling, Object *ob, float obmat[4][4], + bool use_obedit, + bool use_backface_culling, + bool is_object_active, void *data) { struct RaycastObjUserData *dt = data; @@ -1032,24 +1041,26 @@ static void raycast_obj_fn(SnapObjectContext *sctx, case OB_CURVE: case OB_SURF: case OB_FONT: { - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); - if (mesh_eval) { - retval = raycastMesh(sctx, - dt->ray_start, - dt->ray_dir, - ob, - mesh_eval, - obmat, - ob_index, - false, - use_backface_culling, - ray_depth, - dt->r_loc, - dt->r_no, - dt->r_index, - dt->r_hit_list); - break; + if (!is_object_active) { + Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + if (mesh_eval) { + retval = raycastMesh(sctx, + dt->ray_start, + dt->ray_dir, + ob, + mesh_eval, + obmat, + ob_index, + false, + use_backface_culling, + ray_depth, + dt->r_loc, + dt->r_no, + dt->r_index, + dt->r_hit_list); + } } + break; } } @@ -1071,9 +1082,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx, * Walks through all objects in the scene to find the `hit` on object surface. * * \param sctx: Snap context to store data. - * \param snap_select: from enum eSnapSelect. - * \param use_object_edit_cage: Uses the coordinates of BMesh(if any) to do the snapping. - * \param obj_list: List with objects to snap (created in `create_object_list`). + * \param params: Snapping behavior. * * Read/Write Args * --------------- @@ -2054,15 +2063,15 @@ static short snapCurve(SnapData *snapdata, } /* may extend later (for now just snaps to empty center) */ -static short snapEmpty(SnapData *snapdata, - Object *ob, - const float obmat[4][4], - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float *UNUSED(r_no), - int *r_index) +static short snap_object_center(SnapData *snapdata, + Object *ob, + const float obmat[4][4], + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], + float *UNUSED(r_no), + int *r_index) { short retval = 0; @@ -2117,7 +2126,7 @@ static short snapCamera(const SnapObjectContext *sctx, float *dist_px, /* return args */ float r_loc[3], - float *UNUSED(r_no), + float *r_no, int *r_index) { short retval = 0; @@ -2132,7 +2141,7 @@ static short snapCamera(const SnapObjectContext *sctx, MovieTracking *tracking; if (clip == NULL) { - return retval; + return snap_object_center(snapdata, object, obmat, dist_px, r_loc, r_no, r_index); } if (object->transflag & OB_DUPLI) { return retval; @@ -2650,11 +2659,12 @@ struct SnapObjUserData { * * \note Duplicate args here are documented at #snapObjectsRay */ -static void sanp_obj_fn(SnapObjectContext *sctx, - bool use_obedit, - bool use_backface_culling, +static void snap_obj_fn(SnapObjectContext *sctx, Object *ob, float obmat[4][4], + bool use_obedit, + bool use_backface_culling, + bool UNUSED(is_object_active), void *data) { struct SnapObjUserData *dt = data; @@ -2729,10 +2739,10 @@ static void sanp_obj_fn(SnapObjectContext *sctx, break; } case OB_EMPTY: - retval = snapEmpty(dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); - break; case OB_GPENCIL: - retval = snapEmpty(dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); + case OB_LAMP: + retval = snap_object_center( + dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; case OB_CAMERA: retval = snapCamera( @@ -2800,7 +2810,7 @@ static short snapObjectsRay(SnapObjectContext *sctx, .ret = 0, }; - iter_snap_objects(sctx, depsgraph, params, sanp_obj_fn, &data); + iter_snap_objects(sctx, depsgraph, params, snap_obj_fn, &data); return data.ret; } @@ -3205,7 +3215,7 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, * \param mval: Screenspace coordinate. * \param prev_co: Coordinate for perpendicular point calculation (optional). * \param dist_px: Maximum distance to snap (in pixels). - * \param r_co: hit location. + * \param r_loc: hit location. * \param r_no: hit normal (optional). * \return Snap success */ diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 897e2f13774..df6e4f70e99 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -409,70 +409,49 @@ static void draw_uvs(SpaceImage *sima, GPU_blend(true); } - switch (sima->dt_uv) { - case SI_UVDT_DASH: { - float dash_colors[2][4] = { - {0.56f, 0.56f, 0.56f, overlay_alpha}, - {0.07f, 0.07f, 0.07f, overlay_alpha}, - }; - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - - GPU_line_width(1.0f); - GPU_batch_program_set_builtin(batch->edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); - GPU_batch_uniform_4fv_array(batch->edges, "colors", 2, (float *)dash_colors); - GPU_batch_uniform_2f(batch->edges, - "viewport_size", - viewport_size[2] / UI_DPI_FAC, - viewport_size[3] / UI_DPI_FAC); - GPU_batch_uniform_1i(batch->edges, "colors_len", 2); /* "advanced" mode */ - GPU_batch_uniform_1f(batch->edges, "dash_width", 4.0f); - GPU_batch_uniform_1f(batch->edges, "dash_factor", 0.5f); - GPU_batch_draw(batch->edges); - break; - } - case SI_UVDT_BLACK: - case SI_UVDT_WHITE: - case SI_UVDT_OUTLINE: { - /* We could modify the vbo's data filling - * instead of modifying the provoking vert. */ - glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); - - UI_GetThemeColor3fv(TH_EDGE_SELECT, col2); - col2[3] = overlay_alpha; - - GPU_batch_program_set_builtin( - batch->edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES); - - if (sima->dt_uv == SI_UVDT_OUTLINE) { - /* Black Outline. */ - GPU_line_width(3.0f); - GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, overlay_alpha); - GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, overlay_alpha); - GPU_batch_draw(batch->edges); - - UI_GetThemeColor3fv(TH_WIRE_EDIT, col1); - } - else if (sima->dt_uv == SI_UVDT_WHITE) { - copy_v3_fl3(col1, 1.0f, 1.0f, 1.0f); - } - else { - copy_v3_fl3(col1, 0.0f, 0.0f, 0.0f); - } - col1[3] = overlay_alpha; + { + /* We could modify the vbo's data filling + * instead of modifying the provoking vert. */ + glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); + + UI_GetThemeColor3fv(TH_EDGE_SELECT, col2); + col2[3] = overlay_alpha; - /* Inner Line. Use depth test to insure selection is drawn on top. */ - GPU_depth_test(true); - GPU_line_width(1.0f); - GPU_batch_uniform_4fv(batch->edges, "edgeColor", col1); - GPU_batch_uniform_4fv(batch->edges, "selectColor", col2); + float dash_width = (sima->dt_uv & SI_UVDT_DASH) ? (4.0f * UI_DPI_FAC) : 9999.0f; + + GPU_batch_program_set_builtin( + batch->edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES); + + if (sima->dt_uv == SI_UVDT_OUTLINE) { + /* Black Outline. */ + GPU_line_width(3.0f); + GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, overlay_alpha); + GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, overlay_alpha); + GPU_batch_uniform_1f(batch->edges, "dashWidth", dash_width); GPU_batch_draw(batch->edges); - GPU_depth_test(false); - glProvokingVertex(GL_LAST_VERTEX_CONVENTION); - break; + UI_GetThemeColor3fv(TH_WIRE_EDIT, col1); + } + else if (sima->dt_uv == SI_UVDT_BLACK) { + copy_v3_fl3(col1, 0.0f, 0.0f, 0.0f); } + else { + copy_v3_fl3(col1, 1.0f, 1.0f, 1.0f); + } + col1[3] = overlay_alpha; + + /* Inner Line. Use depth test to insure selection is drawn on top. */ + GPU_depth_test(true); + GPU_line_width(1.0f); + GPU_batch_uniform_4fv(batch->edges, "edgeColor", col1); + GPU_batch_uniform_4fv(batch->edges, "selectColor", col2); + GPU_batch_uniform_1f(batch->edges, "dashWidth", dash_width); + GPU_batch_draw(batch->edges); + GPU_depth_test(false); + + glProvokingVertex(GL_LAST_VERTEX_CONVENTION); } + if (sima->flag & SI_SMOOTH_UV) { GPU_line_smooth(false); GPU_blend(false); @@ -481,6 +460,7 @@ static void draw_uvs(SpaceImage *sima, GPU_blend(false); } } + if (batch->verts || batch->facedots) { UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2); if (batch->verts) { diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index 7bceb036846..996906826e9 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -795,7 +795,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) // sets the id of the rep rep->setId(Id(id, 0)); rep->setName(ob->id.name + 2); - rep->setLibraryPath(ob->id.lib ? ob->id.lib->name : ""); + rep->setLibraryPath(ob->id.lib ? ob->id.lib->filepath : ""); const BBox<Vec3r> bbox = BBox<Vec3r>(Vec3r(ls.minBBox[0], ls.minBBox[1], ls.minBBox[2]), Vec3r(ls.maxBBox[0], ls.maxBBox[1], ls.maxBBox[2])); diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp index 0f4263162a6..26070a88e5d 100644 --- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp +++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp @@ -341,8 +341,8 @@ static void prepare(Render *re, ViewLayer *view_layer, Depsgraph *depsgraph) const char *id_name = module_conf->script->id.name + 2; if (G.debug & G_DEBUG_FREESTYLE) { cout << " " << layer_count + 1 << ": " << id_name; - if (module_conf->script->name) { - cout << " (" << module_conf->script->name << ")"; + if (module_conf->script->filepath) { + cout << " (" << module_conf->script->filepath << ")"; } cout << endl; } diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp index e7fe660cf93..33078e6ba6a 100644 --- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp +++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp @@ -267,7 +267,7 @@ static PyObject *Freestyle_evaluateCurveMappingF(PyObject * /*self*/, PyObject * BKE_curvemapping_initialize(cumap); /* disable extrapolation if enabled */ if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE)) { - cumap->flag &= ~(CUMA_EXTEND_EXTRAPOLATE); + cumap->flag &= ~CUMA_EXTEND_EXTRAPOLATE; BKE_curvemapping_changed(cumap, 0); } return PyFloat_FromDouble(BKE_curvemapping_evaluateF(cumap, cur, value)); diff --git a/source/blender/freestyle/intern/view_map/AutoPtrHelper.h b/source/blender/freestyle/intern/view_map/AutoPtrHelper.h index 9da109ab2a6..fb2a9d73d13 100644 --- a/source/blender/freestyle/intern/view_map/AutoPtrHelper.h +++ b/source/blender/freestyle/intern/view_map/AutoPtrHelper.h @@ -26,7 +26,6 @@ namespace Freestyle { -#if __cplusplus > 199711L template<typename T> class AutoPtr : public std::unique_ptr<T> { public: AutoPtr() : std::unique_ptr<T>() @@ -36,26 +35,16 @@ template<typename T> class AutoPtr : public std::unique_ptr<T> { { } - /* TODO(sergey): Is there more clear way to do this? */ + /* Mimic behavior of legacy auto_ptr. + * Keep implementation as small as possible, hens delete assignment operator. */ + template<typename X> AutoPtr(AutoPtr<X> &other) : std::unique_ptr<T>(other.get()) { other.release(); } + + template<typename X> AutoPtr &operator=(AutoPtr<X> &other) = delete; }; -#else -template<typename T> class AutoPtr : public std::auto_ptr<T> { - public: - AutoPtr() : std::auto_ptr<T>() - { - } - AutoPtr(T *ptr) : std::auto_ptr<T>(ptr) - { - } - AutoPtr(std::auto_ptr_ref<T> ref) : std::auto_ptr<T>(ref) - { - } -}; -#endif } /* namespace Freestyle */ diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp index 40ab3ada777..c3c43ce6722 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp @@ -2273,10 +2273,10 @@ void ViewMapBuilder::ComputeIntersections(ViewMap *ioViewMap, #endif } -struct less_SVertex2D : public binary_function<SVertex *, SVertex *, bool> { +struct less_SVertex2D { real epsilon; - less_SVertex2D(real eps) : binary_function<SVertex *, SVertex *, bool>() + less_SVertex2D(real eps) { epsilon = eps; } @@ -2303,10 +2303,10 @@ struct less_SVertex2D : public binary_function<SVertex *, SVertex *, bool> { typedef Segment<FEdge *, Vec3r> segment; typedef Intersection<segment> intersection; -struct less_Intersection : public binary_function<intersection *, intersection *, bool> { +struct less_Intersection { segment *edge; - less_Intersection(segment *iEdge) : binary_function<intersection *, intersection *, bool>() + less_Intersection(segment *iEdge) { edge = iEdge; } diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt index 9ce1d3ac2fe..703d3c393e8 100644 --- a/source/blender/functions/CMakeLists.txt +++ b/source/blender/functions/CMakeLists.txt @@ -27,10 +27,26 @@ set(INC_SYS ) set(SRC + intern/attributes_ref.cc intern/cpp_types.cc + intern/multi_function.cc + intern/multi_function_network.cc + intern/multi_function_network_evaluation.cc + FN_array_spans.hh + FN_attributes_ref.hh FN_cpp_type.hh FN_cpp_types.hh + FN_multi_function.hh + FN_multi_function_builder.hh + FN_multi_function_context.hh + FN_multi_function_data_type.hh + FN_multi_function_network.hh + FN_multi_function_network_evaluation.hh + FN_multi_function_param_type.hh + FN_multi_function_params.hh + FN_multi_function_signature.hh + FN_spans.hh ) set(LIB diff --git a/source/blender/functions/FN_array_spans.hh b/source/blender/functions/FN_array_spans.hh new file mode 100644 index 00000000000..acd3e921b50 --- /dev/null +++ b/source/blender/functions/FN_array_spans.hh @@ -0,0 +1,209 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_ARRAY_SPANS_HH__ +#define __FN_ARRAY_SPANS_HH__ + +/** \file + * \ingroup fn + * + * An ArraySpan is a span where every element contains an array (instead of a single element as is + * the case in a normal span). It's main use case is to reference many small arrays. + */ + +#include "FN_spans.hh" + +namespace blender { +namespace fn { + +/** + * Depending on the use case, the referenced data might have a different structure. More + * categories can be added when necessary. + */ +enum class VArraySpanCategory { + SingleArray, + StartsAndSizes, +}; + +template<typename T> class VArraySpanBase { + protected: + uint m_virtual_size; + VArraySpanCategory m_category; + + union { + struct { + const T *start; + uint size; + } single_array; + struct { + const T *const *starts; + const uint *sizes; + } starts_and_sizes; + } m_data; + + public: + bool is_single_array() const + { + switch (m_category) { + case VArraySpanCategory::SingleArray: + return true; + case VArraySpanCategory::StartsAndSizes: + return m_virtual_size == 1; + } + BLI_assert(false); + return false; + } + + bool is_empty() const + { + return this->m_virtual_size == 0; + } + + uint size() const + { + return this->m_virtual_size; + } +}; + +/** + * A virtual array span. Every element of this span contains a virtual span. So it behaves like + * a blender::Span, but might not be backed up by an actual array. + */ +template<typename T> class VArraySpan : public VArraySpanBase<T> { + private: + friend class GVArraySpan; + + VArraySpan(const VArraySpanBase<void> &other) + { + memcpy(this, &other, sizeof(VArraySpanBase<void>)); + } + + public: + VArraySpan() + { + this->m_virtual_size = 0; + this->m_category = VArraySpanCategory::StartsAndSizes; + this->m_data.starts_and_sizes.starts = nullptr; + this->m_data.starts_and_sizes.sizes = nullptr; + } + + VArraySpan(Span<T> span, uint virtual_size) + { + this->m_virtual_size = virtual_size; + this->m_category = VArraySpanCategory::SingleArray; + this->m_data.single_array.start = span.data(); + this->m_data.single_array.size = span.size(); + } + + VArraySpan(Span<const T *> starts, Span<uint> sizes) + { + BLI_assert(starts.size() == sizes.size()); + this->m_virtual_size = starts.size(); + this->m_category = VArraySpanCategory::StartsAndSizes; + this->m_data.starts_and_sizes.starts = starts.begin(); + this->m_data.starts_and_sizes.sizes = sizes.begin(); + } + + VSpan<T> operator[](uint index) const + { + BLI_assert(index < this->m_virtual_size); + switch (this->m_category) { + case VArraySpanCategory::SingleArray: + return VSpan<T>(Span<T>(this->m_data.single_array.start, this->m_data.single_array.size)); + case VArraySpanCategory::StartsAndSizes: + return VSpan<T>(Span<T>(this->m_data.starts_and_sizes.starts[index], + this->m_data.starts_and_sizes.sizes[index])); + } + BLI_assert(false); + return {}; + } +}; + +/** + * A generic virtual array span. It's just like a VArraySpan, but the type is only known at + * run-time. + */ +class GVArraySpan : public VArraySpanBase<void> { + private: + const CPPType *m_type; + + GVArraySpan() = default; + + public: + GVArraySpan(const CPPType &type) + { + this->m_type = &type; + this->m_virtual_size = 0; + this->m_category = VArraySpanCategory::StartsAndSizes; + this->m_data.starts_and_sizes.starts = nullptr; + this->m_data.starts_and_sizes.sizes = nullptr; + } + + GVArraySpan(GSpan array, uint virtual_size) + { + this->m_type = &array.type(); + this->m_virtual_size = virtual_size; + this->m_category = VArraySpanCategory::SingleArray; + this->m_data.single_array.start = array.buffer(); + this->m_data.single_array.size = array.size(); + } + + GVArraySpan(const CPPType &type, Span<const void *> starts, Span<uint> sizes) + { + BLI_assert(starts.size() == sizes.size()); + this->m_type = &type; + this->m_virtual_size = starts.size(); + this->m_category = VArraySpanCategory::StartsAndSizes; + this->m_data.starts_and_sizes.starts = (void **)starts.begin(); + this->m_data.starts_and_sizes.sizes = sizes.begin(); + } + + template<typename T> GVArraySpan(VArraySpan<T> other) + { + this->m_type = &CPPType::get<T>(); + memcpy(this, &other, sizeof(VArraySpanBase<void>)); + } + + const CPPType &type() const + { + return *this->m_type; + } + + template<typename T> VArraySpan<T> typed() const + { + BLI_assert(m_type->is<T>()); + return VArraySpan<T>(*this); + } + + GVSpan operator[](uint index) const + { + BLI_assert(index < m_virtual_size); + switch (m_category) { + case VArraySpanCategory::SingleArray: + return GVSpan(GSpan(*m_type, m_data.single_array.start, m_data.single_array.size)); + case VArraySpanCategory::StartsAndSizes: + return GVSpan(GSpan( + *m_type, m_data.starts_and_sizes.starts[index], m_data.starts_and_sizes.sizes[index])); + } + BLI_assert(false); + return GVSpan(*m_type); + } +}; + +} // namespace fn +} // namespace blender + +#endif /* __FN_ARRAY_SPANS_HH__ */ diff --git a/source/blender/functions/FN_attributes_ref.hh b/source/blender/functions/FN_attributes_ref.hh new file mode 100644 index 00000000000..383b26330bf --- /dev/null +++ b/source/blender/functions/FN_attributes_ref.hh @@ -0,0 +1,248 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_ATTRIBUTES_REF_HH__ +#define __FN_ATTRIBUTES_REF_HH__ + +/** \file + * \ingroup fn + * + * An AttributesRef references multiple arrays of equal length. Each array has a corresponding name + * and index. + */ + +#include <optional> + +#include "FN_spans.hh" + +#include "BLI_linear_allocator.hh" +#include "BLI_map.hh" +#include "BLI_utility_mixins.hh" +#include "BLI_vector_set.hh" + +namespace blender { +namespace fn { + +class AttributesInfo; + +class AttributesInfoBuilder : NonCopyable, NonMovable { + private: + LinearAllocator<> m_allocator; + VectorSet<std::string> m_names; + Vector<const CPPType *> m_types; + Vector<void *> m_defaults; + + friend AttributesInfo; + + public: + AttributesInfoBuilder() = default; + ~AttributesInfoBuilder(); + + template<typename T> void add(StringRef name, const T &default_value) + { + this->add(name, CPPType::get<T>(), (const void *)&default_value); + } + + void add(StringRef name, const CPPType &type, const void *default_value = nullptr); +}; + +/** + * Stores which attributes are in an AttributesRef. Every attribute has a unique index, a unique + * name, a type and a default value. + */ +class AttributesInfo : NonCopyable, NonMovable { + private: + LinearAllocator<> m_allocator; + Map<StringRefNull, uint> m_index_by_name; + Vector<StringRefNull> m_name_by_index; + Vector<const CPPType *> m_type_by_index; + Vector<void *> m_defaults; + + public: + AttributesInfo() = default; + AttributesInfo(const AttributesInfoBuilder &builder); + ~AttributesInfo(); + + uint size() const + { + return m_name_by_index.size(); + } + + IndexRange index_range() const + { + return m_name_by_index.index_range(); + } + + StringRefNull name_of(uint index) const + { + return m_name_by_index[index]; + } + + uint index_of(StringRef name) const + { + return m_index_by_name.lookup_as(name); + } + + const void *default_of(uint index) const + { + return m_defaults[index]; + } + + const void *default_of(StringRef name) const + { + return this->default_of(this->index_of(name)); + } + + template<typename T> const T &default_of(uint index) const + { + BLI_assert(m_type_by_index[index]->is<T>()); + return *(T *)m_defaults[index]; + } + + template<typename T> const T &default_of(StringRef name) const + { + return this->default_of<T>(this->index_of(name)); + } + + const CPPType &type_of(uint index) const + { + return *m_type_by_index[index]; + } + + const CPPType &type_of(StringRef name) const + { + return this->type_of(this->index_of(name)); + } + + bool has_attribute(StringRef name, const CPPType &type) const + { + return this->try_index_of(name, type) >= 0; + } + + int try_index_of(StringRef name) const + { + return (int)m_index_by_name.lookup_default_as(name, -1); + } + + int try_index_of(StringRef name, const CPPType &type) const + { + int index = this->try_index_of(name); + if (index == -1) { + return -1; + } + else if (this->type_of((uint)index) == type) { + return index; + } + else { + return -1; + } + } +}; + +/** + * References multiple arrays that match the description of an AttributesInfo instance. This class + * is supposed to be relatively cheap to copy. It does not own any of the arrays itself. + */ +class MutableAttributesRef { + private: + const AttributesInfo *m_info; + Span<void *> m_buffers; + IndexRange m_range; + + public: + MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, uint size) + : MutableAttributesRef(info, buffers, IndexRange(size)) + { + } + + MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, IndexRange range) + : m_info(&info), m_buffers(buffers), m_range(range) + { + } + + uint size() const + { + return m_range.size(); + } + + const AttributesInfo &info() const + { + return *m_info; + } + + GMutableSpan get(uint index) const + { + const CPPType &type = m_info->type_of(index); + void *ptr = POINTER_OFFSET(m_buffers[index], type.size() * m_range.start()); + return GMutableSpan(type, ptr, m_range.size()); + } + + GMutableSpan get(StringRef name) const + { + return this->get(m_info->index_of(name)); + } + + template<typename T> MutableSpan<T> get(uint index) const + { + BLI_assert(m_info->type_of(index).is<T>()); + return MutableSpan<T>((T *)m_buffers[index] + m_range.start(), m_range.size()); + } + + template<typename T> MutableSpan<T> get(StringRef name) const + { + return this->get<T>(m_info->index_of(name)); + } + + std::optional<GMutableSpan> try_get(StringRef name, const CPPType &type) const + { + int index = m_info->try_index_of(name, type); + if (index == -1) { + return {}; + } + else { + return this->get((uint)index); + } + } + + template<typename T> std::optional<MutableSpan<T>> try_get(StringRef name) const + { + int index = m_info->try_index_of(name); + if (index == -1) { + return {}; + } + else if (m_info->type_of((uint)index).is<T>()) { + return this->get<T>((uint)index); + } + else { + return {}; + } + } + + MutableAttributesRef slice(IndexRange range) const + { + return this->slice(range.start(), range.size()); + } + + MutableAttributesRef slice(uint start, uint size) const + { + return MutableAttributesRef(*m_info, m_buffers, m_range.slice(start, size)); + } +}; + +} // namespace fn +} // namespace blender + +#endif /* __FN_ATTRIBUTES_REF_HH__ */ diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh index 1dc72e16e77..706ff85bdf3 100644 --- a/source/blender/functions/FN_cpp_type.hh +++ b/source/blender/functions/FN_cpp_type.hh @@ -21,7 +21,7 @@ * \ingroup functions * * The CPPType class is the core of the runtime-type-system used by the functions system. An - * instance of this class can represent any C++ type, that is default-constructable, destructable, + * instance of this class can represent any C++ type, that is default-constructible, destructible, * movable and copyable. Therefore it also works for all C types. This restrictions might need to * be removed in the future, but for now every required type has these properties. * @@ -71,11 +71,7 @@ #include "BLI_string_ref.hh" namespace blender { -namespace FN { - -using blender::IndexMask; -using blender::StringRef; -using blender::StringRefNull; +namespace fn { class CPPType { public: @@ -241,14 +237,14 @@ class CPPType { void construct_default_n(void *ptr, uint n) const { - BLI_assert(this->pointer_can_point_to_instance(ptr)); + BLI_assert(this->pointer_has_valid_alignment(ptr)); m_construct_default_n(ptr, n); } void construct_default_indices(void *ptr, IndexMask index_mask) const { - BLI_assert(this->pointer_can_point_to_instance(ptr)); + BLI_assert(this->pointer_has_valid_alignment(ptr)); m_construct_default_indices(ptr, index_mask); } @@ -270,14 +266,14 @@ class CPPType { void destruct_n(void *ptr, uint n) const { - BLI_assert(this->pointer_can_point_to_instance(ptr)); + BLI_assert(this->pointer_has_valid_alignment(ptr)); m_destruct_n(ptr, n); } void destruct_indices(void *ptr, IndexMask index_mask) const { - BLI_assert(this->pointer_can_point_to_instance(ptr)); + BLI_assert(this->pointer_has_valid_alignment(ptr)); m_destruct_indices(ptr, index_mask); } @@ -300,8 +296,8 @@ class CPPType { void copy_to_initialized_n(const void *src, void *dst, uint n) const { BLI_assert(src != dst); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); + BLI_assert(this->pointer_has_valid_alignment(src)); + BLI_assert(this->pointer_has_valid_alignment(dst)); m_copy_to_initialized_n(src, dst, n); } @@ -309,8 +305,8 @@ class CPPType { void copy_to_initialized_indices(const void *src, void *dst, IndexMask index_mask) const { BLI_assert(src != dst); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); + BLI_assert(this->pointer_has_valid_alignment(src)); + BLI_assert(this->pointer_has_valid_alignment(dst)); m_copy_to_initialized_indices(src, dst, index_mask); } @@ -335,8 +331,8 @@ class CPPType { void copy_to_uninitialized_n(const void *src, void *dst, uint n) const { BLI_assert(src != dst); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); + BLI_assert(this->pointer_has_valid_alignment(src)); + BLI_assert(this->pointer_has_valid_alignment(dst)); m_copy_to_uninitialized_n(src, dst, n); } @@ -344,8 +340,8 @@ class CPPType { void copy_to_uninitialized_indices(const void *src, void *dst, IndexMask index_mask) const { BLI_assert(src != dst); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); + BLI_assert(this->pointer_has_valid_alignment(src)); + BLI_assert(this->pointer_has_valid_alignment(dst)); m_copy_to_uninitialized_indices(src, dst, index_mask); } @@ -370,8 +366,8 @@ class CPPType { void relocate_to_initialized_n(void *src, void *dst, uint n) const { BLI_assert(src != dst); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); + BLI_assert(this->pointer_has_valid_alignment(src)); + BLI_assert(this->pointer_has_valid_alignment(dst)); m_relocate_to_initialized_n(src, dst, n); } @@ -379,8 +375,8 @@ class CPPType { void relocate_to_initialized_indices(void *src, void *dst, IndexMask index_mask) const { BLI_assert(src != dst); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); + BLI_assert(this->pointer_has_valid_alignment(src)); + BLI_assert(this->pointer_has_valid_alignment(dst)); m_relocate_to_initialized_indices(src, dst, index_mask); } @@ -405,8 +401,8 @@ class CPPType { void relocate_to_uninitialized_n(void *src, void *dst, uint n) const { BLI_assert(src != dst); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); + BLI_assert(this->pointer_has_valid_alignment(src)); + BLI_assert(this->pointer_has_valid_alignment(dst)); m_relocate_to_uninitialized_n(src, dst, n); } @@ -414,8 +410,8 @@ class CPPType { void relocate_to_uninitialized_indices(void *src, void *dst, IndexMask index_mask) const { BLI_assert(src != dst); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); + BLI_assert(this->pointer_has_valid_alignment(src)); + BLI_assert(this->pointer_has_valid_alignment(dst)); m_relocate_to_uninitialized_indices(src, dst, index_mask); } @@ -435,8 +431,8 @@ class CPPType { void fill_initialized_indices(const void *value, void *dst, IndexMask index_mask) const { - BLI_assert(this->pointer_can_point_to_instance(value)); - BLI_assert(this->pointer_can_point_to_instance(dst)); + BLI_assert(this->pointer_has_valid_alignment(value)); + BLI_assert(this->pointer_has_valid_alignment(dst)); m_fill_initialized_indices(value, dst, index_mask); } @@ -456,8 +452,8 @@ class CPPType { void fill_uninitialized_indices(const void *value, void *dst, IndexMask index_mask) const { - BLI_assert(this->pointer_can_point_to_instance(value)); - BLI_assert(this->pointer_can_point_to_instance(dst)); + BLI_assert(this->pointer_has_valid_alignment(value)); + BLI_assert(this->pointer_has_valid_alignment(dst)); m_fill_uninitialized_indices(value, dst, index_mask); } @@ -487,6 +483,11 @@ class CPPType { template<typename T> static const CPPType &get(); + template<typename T> bool is() const + { + return this == &CPPType::get<T>(); + } + private: uint m_size; uint m_alignment; @@ -719,16 +720,18 @@ static std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d return std::unique_ptr<const CPPType>(type); } -} // namespace FN +} // namespace fn } // namespace blender #define MAKE_CPP_TYPE(IDENTIFIER, TYPE_NAME) \ static TYPE_NAME default_value_##IDENTIFIER; \ - static std::unique_ptr<const blender::FN::CPPType> CPPTYPE_##IDENTIFIER##_owner = \ - blender::FN::create_cpp_type<TYPE_NAME>(STRINGIFY(IDENTIFIER), default_value_##IDENTIFIER); \ - const blender::FN::CPPType &CPPType_##IDENTIFIER = *CPPTYPE_##IDENTIFIER##_owner; \ - template<> const blender::FN::CPPType &blender::FN::CPPType::get<TYPE_NAME>() \ + static std::unique_ptr<const blender::fn::CPPType> CPPTYPE_##IDENTIFIER##_owner = \ + blender::fn::create_cpp_type<TYPE_NAME>(STRINGIFY(IDENTIFIER), default_value_##IDENTIFIER); \ + const blender::fn::CPPType &CPPType_##IDENTIFIER = *CPPTYPE_##IDENTIFIER##_owner; \ + template<> const blender::fn::CPPType &blender::fn::CPPType::get<TYPE_NAME>() \ { \ + /* This can happen when trying to access a CPPType during static storage initialization. */ \ + BLI_assert(CPPTYPE_##IDENTIFIER##_owner.get() != nullptr); \ return CPPType_##IDENTIFIER; \ } diff --git a/source/blender/functions/FN_cpp_types.hh b/source/blender/functions/FN_cpp_types.hh index 6ee8788cd52..c39b284d5c4 100644 --- a/source/blender/functions/FN_cpp_types.hh +++ b/source/blender/functions/FN_cpp_types.hh @@ -27,7 +27,7 @@ #include "FN_cpp_type.hh" namespace blender { -namespace FN { +namespace fn { extern const CPPType &CPPType_bool; @@ -44,7 +44,7 @@ extern const CPPType &CPPType_Color4b; extern const CPPType &CPPType_string; -} // namespace FN +} // namespace fn } // namespace blender #endif /* __FN_CPP_TYPES_HH__ */ diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh new file mode 100644 index 00000000000..6be1b68da4d --- /dev/null +++ b/source/blender/functions/FN_generic_vector_array.hh @@ -0,0 +1,208 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_GENERIC_VECTOR_ARRAY_HH__ +#define __FN_GENERIC_VECTOR_ARRAY_HH__ + +/** \file + * \ingroup fn + * + * A `GVectorArray` is a container for a fixed amount of dynamically growing arrays with a generic + * type. Its main use case is to store many small vectors with few separate allocations. Using this + * structure is generally more efficient than allocating each small vector separately. + * + * `GVectorArrayRef<T>` is a typed reference to a GVectorArray and makes it easier and safer to + * work with the class when the type is known at compile time. + */ + +#include "FN_array_spans.hh" +#include "FN_cpp_type.hh" + +#include "BLI_array.hh" +#include "BLI_linear_allocator.hh" +#include "BLI_utility_mixins.hh" + +namespace blender { +namespace fn { + +template<typename T> class GVectorArrayRef; + +class GVectorArray : NonCopyable, NonMovable { + private: + const CPPType &m_type; + uint m_element_size; + Array<void *, 1> m_starts; + Array<uint, 1> m_lengths; + Array<uint, 1> m_capacities; + LinearAllocator<> m_allocator; + + template<typename T> friend class GVectorArrayRef; + + public: + GVectorArray() = delete; + + GVectorArray(const CPPType &type, uint array_size) + : m_type(type), + m_element_size(type.size()), + m_starts(array_size), + m_lengths(array_size), + m_capacities(array_size) + { + m_starts.fill(nullptr); + m_lengths.fill(0); + m_capacities.fill(0); + } + + ~GVectorArray() + { + if (m_type.is_trivially_destructible()) { + return; + } + + for (uint i : m_starts.index_range()) { + m_type.destruct_n(m_starts[i], m_lengths[i]); + } + } + + operator GVArraySpan() const + { + return GVArraySpan(m_type, m_starts.as_span(), m_lengths); + } + + bool is_empty() const + { + return m_starts.size() == 0; + } + + uint size() const + { + return m_starts.size(); + } + + const CPPType &type() const + { + return m_type; + } + + Span<const void *> starts() const + { + return m_starts.as_span(); + } + + Span<uint> lengths() const + { + return m_lengths; + } + + void append(uint index, const void *src) + { + uint old_length = m_lengths[index]; + if (old_length == m_capacities[index]) { + this->grow_at_least_one(index); + } + + void *dst = POINTER_OFFSET(m_starts[index], m_element_size * old_length); + m_type.copy_to_uninitialized(src, dst); + m_lengths[index]++; + } + + void extend(uint index, GVSpan span) + { + BLI_assert(m_type == span.type()); + for (uint i = 0; i < span.size(); i++) { + this->append(index, span[i]); + } + } + + void extend(IndexMask mask, GVArraySpan array_span) + { + BLI_assert(m_type == array_span.type()); + BLI_assert(mask.min_array_size() <= array_span.size()); + for (uint i : mask) { + this->extend(i, array_span[i]); + } + } + + GMutableSpan operator[](uint index) + { + BLI_assert(index < m_starts.size()); + return GMutableSpan(m_type, m_starts[index], m_lengths[index]); + } + template<typename T> GVectorArrayRef<T> typed() + { + return GVectorArrayRef<T>(*this); + } + + private: + void grow_at_least_one(uint index) + { + BLI_assert(m_lengths[index] == m_capacities[index]); + uint new_capacity = m_lengths[index] * 2 + 1; + + void *new_buffer = m_allocator.allocate(m_element_size * new_capacity, m_type.alignment()); + m_type.relocate_to_uninitialized_n(m_starts[index], new_buffer, m_lengths[index]); + + m_starts[index] = new_buffer; + m_capacities[index] = new_capacity; + } +}; + +template<typename T> class GVectorArrayRef { + private: + GVectorArray *m_vector_array; + + public: + GVectorArrayRef(GVectorArray &vector_array) : m_vector_array(&vector_array) + { + BLI_assert(vector_array.m_type.is<T>()); + } + + void append(uint index, const T &value) + { + m_vector_array->append(index, &value); + } + + void extend(uint index, Span<T> values) + { + m_vector_array->extend(index, values); + } + + void extend(uint index, VSpan<T> values) + { + m_vector_array->extend(index, GVSpan(values)); + } + + MutableSpan<T> operator[](uint index) + { + BLI_assert(index < m_vector_array->m_starts.size()); + return MutableSpan<T>((T *)m_vector_array->m_starts[index], m_vector_array->m_lengths[index]); + } + + uint size() const + { + return m_vector_array->size(); + } + + bool is_empty() const + { + return m_vector_array->is_empty(); + } +}; + +} // namespace fn +} // namespace blender + +#endif /* __FN_GENERIC_VECTOR_ARRAY_HH__ */ diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh new file mode 100644 index 00000000000..a7e964b6651 --- /dev/null +++ b/source/blender/functions/FN_multi_function.hh @@ -0,0 +1,108 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_MULTI_FUNCTION_HH__ +#define __FN_MULTI_FUNCTION_HH__ + +/** \file + * \ingroup fn + * + * A `MultiFunction` encapsulates a function that is optimized for throughput (instead of latency). + * The throughput is optimized by always processing many elements at once, instead of each element + * separately. This is ideal for functions that are evaluated often (e.g. for every particle). + * + * By processing a lot of data at once, individual functions become easier to optimize for humans + * and for the compiler. Furthermore, performance profiles become easier to understand and show + * better where bottlenecks are. + * + * Every multi-function has a name and an ordered list of parameters. Parameters are used for input + * and output. In fact, there are three kinds of parameters: inputs, outputs and mutable (which is + * combination of input and output). + * + * To call a multi-function, one has to provide three things: + * - `MFParams`: This references the input and output arrays that the function works with. The + * arrays are not owned by MFParams. + * - `IndexMask`: An array of indices indicating which indices in the provided arrays should be + * touched/processed. + * - `MFContext`: Further information for the called function. + * + * A new multi-function is generally implemented as follows: + * 1. Create a new subclass of MultiFunction. + * 2. Implement a constructor that initialized the signature of the function. + * 3. Override the `call` function. + */ + +#include "FN_multi_function_context.hh" +#include "FN_multi_function_params.hh" + +namespace blender { +namespace fn { + +class MultiFunction { + private: + MFSignature m_signature; + + public: + virtual ~MultiFunction() + { + } + + virtual void call(IndexMask mask, MFParams params, MFContext context) const = 0; + + IndexRange param_indices() const + { + return m_signature.param_types.index_range(); + } + + MFParamType param_type(uint param_index) const + { + return m_signature.param_types[param_index]; + } + + StringRefNull param_name(uint param_index) const + { + return m_signature.param_names[param_index]; + } + + StringRefNull name() const + { + return m_signature.function_name; + } + + const MFSignature &signature() const + { + return m_signature; + } + + protected: + MFSignatureBuilder get_builder(std::string function_name) + { + m_signature.function_name = std::move(function_name); + return MFSignatureBuilder(m_signature); + } +}; + +inline MFParamsBuilder::MFParamsBuilder(const class MultiFunction &fn, uint min_array_size) + : MFParamsBuilder(fn.signature(), min_array_size) +{ +} + +extern const MultiFunction &dummy_multi_function; + +} // namespace fn +} // namespace blender + +#endif /* __FN_MULTI_FUNCTION_HH__ */ diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh new file mode 100644 index 00000000000..9fcf31443b2 --- /dev/null +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -0,0 +1,232 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_MULTI_FUNCTION_BUILDER_HH__ +#define __FN_MULTI_FUNCTION_BUILDER_HH__ + +/** \file + * \ingroup fn + * + * This file contains several utilities to create multi-functions with less redundant code. + */ + +#include <functional> + +#include "FN_multi_function.hh" + +namespace blender { +namespace fn { + +/** + * Generates a multi-function with the following parameters: + * 1. single input (SI) of type In1 + * 2. single output (SO) of type Out1 + * + * This example creates a function that adds 10 to the incoming values: + * CustomMF_SI_SO<int, int> fn("add 10", [](int value) { return value + 10; }); + */ +template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunction { + private: + using FunctionT = std::function<void(IndexMask, VSpan<In1>, MutableSpan<Out1>)>; + FunctionT m_function; + + public: + CustomMF_SI_SO(StringRef name, FunctionT function) : m_function(std::move(function)) + { + MFSignatureBuilder signature = this->get_builder(name); + signature.single_input<In1>("In1"); + signature.single_output<Out1>("Out1"); + } + + template<typename ElementFuncT> + CustomMF_SI_SO(StringRef name, ElementFuncT element_fn) + : CustomMF_SI_SO(name, CustomMF_SI_SO::create_function(element_fn)) + { + } + + template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn) + { + return [=](IndexMask mask, VSpan<In1> in1, MutableSpan<Out1> out1) { + mask.foreach_index([&](uint i) { new ((void *)&out1[i]) Out1(element_fn(in1[i])); }); + }; + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + VSpan<In1> in1 = params.readonly_single_input<In1>(0); + MutableSpan<Out1> out1 = params.uninitialized_single_output<Out1>(1); + m_function(mask, in1, out1); + } +}; + +/** + * Generates a multi-function with the following parameters: + * 1. single input (SI) of type In1 + * 2. single input (SI) of type In2 + * 3. single output (SO) of type Out1 + */ +template<typename In1, typename In2, typename Out1> +class CustomMF_SI_SI_SO : public MultiFunction { + private: + using FunctionT = std::function<void(IndexMask, VSpan<In1>, VSpan<In2>, MutableSpan<Out1>)>; + FunctionT m_function; + + public: + CustomMF_SI_SI_SO(StringRef name, FunctionT function) : m_function(std::move(function)) + { + MFSignatureBuilder signature = this->get_builder(name); + signature.single_input<In1>("In1"); + signature.single_input<In2>("In2"); + signature.single_output<Out1>("Out1"); + } + + template<typename ElementFuncT> + CustomMF_SI_SI_SO(StringRef name, ElementFuncT element_fn) + : CustomMF_SI_SI_SO(name, CustomMF_SI_SI_SO::create_function(element_fn)) + { + } + + template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn) + { + return [=](IndexMask mask, VSpan<In1> in1, VSpan<In2> in2, MutableSpan<Out1> out1) { + mask.foreach_index([&](uint i) { new ((void *)&out1[i]) Out1(element_fn(in1[i], in2[i])); }); + }; + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + VSpan<In1> in1 = params.readonly_single_input<In1>(0); + VSpan<In2> in2 = params.readonly_single_input<In2>(1); + MutableSpan<Out1> out1 = params.uninitialized_single_output<Out1>(2); + m_function(mask, in1, in2, out1); + } +}; + +/** + * Generates a multi-function with the following parameters: + * 1. single input (SI) of type In1 + * 2. single input (SI) of type In2 + * 3. single input (SI) of type In3 + * 4. single output (SO) of type Out1 + */ +template<typename In1, typename In2, typename In3, typename Out1> +class CustomMF_SI_SI_SI_SO : public MultiFunction { + private: + using FunctionT = + std::function<void(IndexMask, VSpan<In1>, VSpan<In2>, VSpan<In3>, MutableSpan<Out1>)>; + FunctionT m_function; + + public: + CustomMF_SI_SI_SI_SO(StringRef name, FunctionT function) : m_function(std::move(function)) + { + MFSignatureBuilder signature = this->get_builder(name); + signature.single_input<In1>("In1"); + signature.single_input<In2>("In2"); + signature.single_input<In3>("In3"); + signature.single_output<Out1>("Out1"); + } + + template<typename ElementFuncT> + CustomMF_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn) + : CustomMF_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SO::create_function(element_fn)) + { + } + + template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn) + { + return [=](IndexMask mask, + VSpan<In1> in1, + VSpan<In2> in2, + VSpan<In3> in3, + MutableSpan<Out1> out1) { + mask.foreach_index( + [&](uint i) { new ((void *)&out1[i]) Out1(element_fn(in1[i], in2[i], in3[i])); }); + }; + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + VSpan<In1> in1 = params.readonly_single_input<In1>(0); + VSpan<In2> in2 = params.readonly_single_input<In2>(1); + VSpan<In3> in3 = params.readonly_single_input<In3>(2); + MutableSpan<Out1> out1 = params.uninitialized_single_output<Out1>(3); + m_function(mask, in1, in2, in3, out1); + } +}; + +/** + * Generates a multi-function with the following parameters: + * 1. single mutable (SM) of type Mut1 + */ +template<typename Mut1> class CustomMF_SM : public MultiFunction { + private: + using FunctionT = std::function<void(IndexMask, MutableSpan<Mut1>)>; + FunctionT m_function; + + public: + CustomMF_SM(StringRef name, FunctionT function) : m_function(std::move(function)) + { + MFSignatureBuilder signature = this->get_builder(name); + signature.single_mutable<Mut1>("Mut1"); + } + + template<typename ElementFuncT> + CustomMF_SM(StringRef name, ElementFuncT element_fn) + : CustomMF_SM(name, CustomMF_SM::create_function(element_fn)) + { + } + + template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn) + { + return [=](IndexMask mask, MutableSpan<Mut1> mut1) { + mask.foreach_index([&](uint i) { element_fn(mut1[i]); }); + }; + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + MutableSpan<Mut1> mut1 = params.single_mutable<Mut1>(0); + m_function(mask, mut1); + } +}; + +/** + * Generates a multi-function that outputs a constant value. + */ +template<typename T> class CustomMF_Constant : public MultiFunction { + private: + T m_value; + + public: + template<typename U> CustomMF_Constant(U &&value) : m_value(std::forward<U>(value)) + { + MFSignatureBuilder signature = this->get_builder("Constant"); + std::stringstream ss; + ss << m_value; + signature.single_output<T>(ss.str()); + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + MutableSpan<T> output = params.uninitialized_single_output<T>(0); + mask.foreach_index([&](uint i) { new (&output[i]) T(m_value); }); + } +}; + +} // namespace fn +} // namespace blender + +#endif /* __FN_MULTI_FUNCTION_BUILDER_HH__ */ diff --git a/source/blender/functions/FN_multi_function_context.hh b/source/blender/functions/FN_multi_function_context.hh new file mode 100644 index 00000000000..2fb1cc94812 --- /dev/null +++ b/source/blender/functions/FN_multi_function_context.hh @@ -0,0 +1,48 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_MULTI_FUNCTION_CONTEXT_HH__ +#define __FN_MULTI_FUNCTION_CONTEXT_HH__ + +/** \file + * \ingroup fn + * + * An #MFContext is passed along with every call to a multi-function. Right now it does nothing, + * but it can be used for the following purposes: + * - Pass debug information up and down the function call stack. + * - Pass reusable memory buffers to sub-functions to increase performance. + * - Pass cached data to called functions. + */ + +#include "BLI_utildefines.h" + +namespace blender { +namespace fn { + +class MFContextBuilder { +}; + +class MFContext { + public: + MFContext(MFContextBuilder &UNUSED(builder)) + { + } +}; + +} // namespace fn +} // namespace blender + +#endif /* __FN_MULTI_FUNCTION_CONTEXT_HH__ */ diff --git a/source/blender/functions/FN_multi_function_data_type.hh b/source/blender/functions/FN_multi_function_data_type.hh new file mode 100644 index 00000000000..1a7b179c6ae --- /dev/null +++ b/source/blender/functions/FN_multi_function_data_type.hh @@ -0,0 +1,127 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_MULTI_FUNCTION_DATA_TYPE_HH__ +#define __FN_MULTI_FUNCTION_DATA_TYPE_HH__ + +/** \file + * \ingroup fn + * + * A MFDataType describes what type of data a multi-function gets as input, outputs or mutates. + * Currently, only individual elements or vectors of elements are supported. Adding more data types + * is possible when necessary. + */ + +#include "FN_cpp_type.hh" + +namespace blender { +namespace fn { + +class MFDataType { + public: + enum Category { + Single, + Vector, + }; + + private: + Category m_category; + const CPPType *m_type; + + MFDataType(Category category, const CPPType &type) : m_category(category), m_type(&type) + { + } + + public: + MFDataType() = default; + + static MFDataType ForSingle(const CPPType &type) + { + return MFDataType(Single, type); + } + + static MFDataType ForVector(const CPPType &type) + { + return MFDataType(Vector, type); + } + + template<typename T> static MFDataType ForSingle() + { + return MFDataType::ForSingle(CPPType::get<T>()); + } + + template<typename T> static MFDataType ForVector() + { + return MFDataType::ForVector(CPPType::get<T>()); + } + + bool is_single() const + { + return m_category == Single; + } + + bool is_vector() const + { + return m_category == Vector; + } + + Category category() const + { + return m_category; + } + + const CPPType &single_type() const + { + BLI_assert(this->is_single()); + return *m_type; + } + + const CPPType &vector_base_type() const + { + BLI_assert(this->is_vector()); + return *m_type; + } + + friend bool operator==(const MFDataType &a, const MFDataType &b); + friend bool operator!=(const MFDataType &a, const MFDataType &b); + + std::string to_string() const + { + switch (m_category) { + case Single: + return m_type->name(); + case Vector: + return m_type->name() + " Vector"; + } + BLI_assert(false); + return ""; + } +}; + +inline bool operator==(const MFDataType &a, const MFDataType &b) +{ + return a.m_category == b.m_category && a.m_type == b.m_type; +} + +inline bool operator!=(const MFDataType &a, const MFDataType &b) +{ + return !(a == b); +} + +} // namespace fn +} // namespace blender + +#endif /* __FN_MULTI_FUNCTION_DATA_TYPE_HH__ */ diff --git a/source/blender/functions/FN_multi_function_network.hh b/source/blender/functions/FN_multi_function_network.hh new file mode 100644 index 00000000000..bb0c870746b --- /dev/null +++ b/source/blender/functions/FN_multi_function_network.hh @@ -0,0 +1,495 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_MULTI_FUNCTION_NETWORK_HH__ +#define __FN_MULTI_FUNCTION_NETWORK_HH__ + +/** \file + * \ingroup fn + * + * A multi-function network (`MFNetwork`) allows you to connect multiple multi-functions. The + * `MFNetworkEvaluator` is a multi-function that wraps an entire network into a new multi-function + * (which can be used in another network and so on). + * + * A MFNetwork is a graph data structure with two kinds of nodes: + * - MFFunctionNode: Represents a multi-function. Its input and output sockets correspond to + * parameters of the referenced multi-function. + * - MFDummyNode: Does not reference a multi-function. Instead it just has sockets that can be + * used to represent node group inputs and outputs. + * + * Links represent data flow. Unlinked input sockets have no value. In order to execute a function + * node, all its inputs have to be connected to something. + * + * Links are only allowed between sockets with the exact same MFDataType. There are no implicit + * conversions. + * + * Every input and output parameter of a multi-function corresponds to exactly one input or output + * socket respectively. A multiple parameter belongs to exactly one input AND one output socket. + * + * There is an .to_dot() method that generates a graph in dot format for debugging purposes. + */ + +#include "FN_multi_function.hh" + +#include "BLI_vector_set.hh" + +namespace blender { +namespace fn { + +class MFNode; +class MFFunctionNode; +class MFDummyNode; +class MFSocket; +class MFInputSocket; +class MFOutputSocket; +class MFNetwork; + +class MFNode : NonCopyable, NonMovable { + protected: + MFNetwork *m_network; + Span<MFInputSocket *> m_inputs; + Span<MFOutputSocket *> m_outputs; + bool m_is_dummy; + uint m_id; + + friend MFNetwork; + + public: + StringRefNull name() const; + + uint id() const; + + MFNetwork &network(); + const MFNetwork &network() const; + + bool is_dummy() const; + bool is_function() const; + + MFDummyNode &as_dummy(); + const MFDummyNode &as_dummy() const; + + MFFunctionNode &as_function(); + const MFFunctionNode &as_function() const; + + MFInputSocket &input(uint index); + const MFInputSocket &input(uint index) const; + + MFOutputSocket &output(uint index); + const MFOutputSocket &output(uint index) const; + + Span<MFInputSocket *> inputs(); + Span<const MFInputSocket *> inputs() const; + + Span<MFOutputSocket *> outputs(); + Span<const MFOutputSocket *> outputs() const; + + template<typename FuncT> void foreach_origin_socket(const FuncT &func) const; + + bool all_inputs_have_origin() const; + + private: + void destruct_sockets(); +}; + +class MFFunctionNode : public MFNode { + private: + const MultiFunction *m_function; + Span<uint> m_input_param_indices; + Span<uint> m_output_param_indices; + + friend MFNetwork; + + public: + StringRefNull name() const; + + const MultiFunction &function() const; + + const MFInputSocket &input_for_param(uint param_index) const; + const MFOutputSocket &output_for_param(uint param_index) const; +}; + +class MFDummyNode : public MFNode { + private: + StringRefNull m_name; + MutableSpan<StringRefNull> m_input_names; + MutableSpan<StringRefNull> m_output_names; + + friend MFNetwork; + + public: + StringRefNull name() const; + + Span<StringRefNull> input_names() const; + Span<StringRefNull> output_names() const; +}; + +class MFSocket : NonCopyable, NonMovable { + protected: + MFNode *m_node; + bool m_is_output; + uint m_index; + MFDataType m_data_type; + uint m_id; + StringRefNull m_name; + + friend MFNetwork; + + public: + StringRefNull name() const; + + uint id() const; + + const MFDataType &data_type() const; + + MFNode &node(); + const MFNode &node() const; + + bool is_input() const; + bool is_output() const; + + MFInputSocket &as_input(); + const MFInputSocket &as_input() const; + + MFOutputSocket &as_output(); + const MFOutputSocket &as_output() const; +}; + +class MFInputSocket : public MFSocket { + private: + MFOutputSocket *m_origin; + + friend MFNetwork; + + public: + MFOutputSocket *origin(); + const MFOutputSocket *origin() const; +}; + +class MFOutputSocket : public MFSocket { + private: + Vector<MFInputSocket *, 1> m_targets; + + friend MFNetwork; + + public: + Span<MFInputSocket *> targets(); + Span<const MFInputSocket *> targets() const; +}; + +class MFNetwork : NonCopyable, NonMovable { + private: + LinearAllocator<> m_allocator; + + VectorSet<MFFunctionNode *> m_function_nodes; + VectorSet<MFDummyNode *> m_dummy_nodes; + + Vector<MFNode *> m_node_or_null_by_id; + Vector<MFSocket *> m_socket_or_null_by_id; + + public: + MFNetwork() = default; + ~MFNetwork(); + + MFFunctionNode &add_function(const MultiFunction &function); + MFDummyNode &add_dummy(StringRef name, + Span<MFDataType> input_types, + Span<MFDataType> output_types, + Span<StringRef> input_names, + Span<StringRef> output_names); + void add_link(MFOutputSocket &from, MFInputSocket &to); + + MFOutputSocket &add_input(StringRef name, MFDataType data_type); + MFInputSocket &add_output(StringRef name, MFDataType data_type); + + void relink(MFOutputSocket &old_output, MFOutputSocket &new_output); + + void remove(MFNode &node); + + uint max_socket_id() const; + + std::string to_dot() const; +}; + +/* -------------------------------------------------------------------- + * MFNode inline methods. + */ + +inline StringRefNull MFNode::name() const +{ + if (m_is_dummy) { + return this->as_dummy().name(); + } + else { + return this->as_function().name(); + } +} + +inline uint MFNode::id() const +{ + return m_id; +} + +inline MFNetwork &MFNode::network() +{ + return *m_network; +} + +inline const MFNetwork &MFNode::network() const +{ + return *m_network; +} + +inline bool MFNode::is_dummy() const +{ + return m_is_dummy; +} + +inline bool MFNode::is_function() const +{ + return !m_is_dummy; +} + +inline MFDummyNode &MFNode::as_dummy() +{ + BLI_assert(m_is_dummy); + return *(MFDummyNode *)this; +} + +inline const MFDummyNode &MFNode::as_dummy() const +{ + BLI_assert(m_is_dummy); + return *(const MFDummyNode *)this; +} + +inline MFFunctionNode &MFNode::as_function() +{ + BLI_assert(!m_is_dummy); + return *(MFFunctionNode *)this; +} + +inline const MFFunctionNode &MFNode::as_function() const +{ + BLI_assert(!m_is_dummy); + return *(const MFFunctionNode *)this; +} + +inline MFInputSocket &MFNode::input(uint index) +{ + return *m_inputs[index]; +} + +inline const MFInputSocket &MFNode::input(uint index) const +{ + return *m_inputs[index]; +} + +inline MFOutputSocket &MFNode::output(uint index) +{ + return *m_outputs[index]; +} + +inline const MFOutputSocket &MFNode::output(uint index) const +{ + return *m_outputs[index]; +} + +inline Span<MFInputSocket *> MFNode::inputs() +{ + return m_inputs; +} + +inline Span<const MFInputSocket *> MFNode::inputs() const +{ + return m_inputs; +} + +inline Span<MFOutputSocket *> MFNode::outputs() +{ + return m_outputs; +} + +inline Span<const MFOutputSocket *> MFNode::outputs() const +{ + return m_outputs; +} + +template<typename FuncT> void MFNode::foreach_origin_socket(const FuncT &func) const +{ + for (const MFInputSocket *socket : m_inputs) { + const MFOutputSocket *origin = socket->origin(); + if (origin != nullptr) { + func(*origin); + } + } +} + +inline bool MFNode::all_inputs_have_origin() const +{ + for (const MFInputSocket *socket : m_inputs) { + if (socket->origin() == nullptr) { + return false; + } + } + return true; +} + +/* -------------------------------------------------------------------- + * MFFunctionNode inline methods. + */ + +inline StringRefNull MFFunctionNode::name() const +{ + return m_function->name(); +} + +inline const MultiFunction &MFFunctionNode::function() const +{ + return *m_function; +} + +inline const MFInputSocket &MFFunctionNode::input_for_param(uint param_index) const +{ + return this->input(m_input_param_indices.first_index(param_index)); +} + +inline const MFOutputSocket &MFFunctionNode::output_for_param(uint param_index) const +{ + return this->output(m_output_param_indices.first_index(param_index)); +} + +/* -------------------------------------------------------------------- + * MFDummyNode inline methods. + */ + +inline StringRefNull MFDummyNode::name() const +{ + return m_name; +} + +inline Span<StringRefNull> MFDummyNode::input_names() const +{ + return m_input_names; +} + +inline Span<StringRefNull> MFDummyNode::output_names() const +{ + return m_output_names; +} + +/* -------------------------------------------------------------------- + * MFSocket inline methods. + */ + +inline StringRefNull MFSocket::name() const +{ + return m_name; +} + +inline uint MFSocket::id() const +{ + return m_id; +} + +inline const MFDataType &MFSocket::data_type() const +{ + return m_data_type; +} + +inline MFNode &MFSocket::node() +{ + return *m_node; +} + +inline const MFNode &MFSocket::node() const +{ + return *m_node; +} + +inline bool MFSocket::is_input() const +{ + return !m_is_output; +} + +inline bool MFSocket::is_output() const +{ + return m_is_output; +} + +inline MFInputSocket &MFSocket::as_input() +{ + BLI_assert(this->is_input()); + return *(MFInputSocket *)this; +} + +inline const MFInputSocket &MFSocket::as_input() const +{ + BLI_assert(this->is_input()); + return *(const MFInputSocket *)this; +} + +inline MFOutputSocket &MFSocket::as_output() +{ + BLI_assert(this->is_output()); + return *(MFOutputSocket *)this; +} + +inline const MFOutputSocket &MFSocket::as_output() const +{ + BLI_assert(this->is_output()); + return *(const MFOutputSocket *)this; +} + +/* -------------------------------------------------------------------- + * MFInputSocket inline methods. + */ + +inline MFOutputSocket *MFInputSocket::origin() +{ + return m_origin; +} + +inline const MFOutputSocket *MFInputSocket::origin() const +{ + return m_origin; +} + +/* -------------------------------------------------------------------- + * MFOutputSocket inline methods. + */ + +inline Span<MFInputSocket *> MFOutputSocket::targets() +{ + return m_targets; +} + +inline Span<const MFInputSocket *> MFOutputSocket::targets() const +{ + return m_targets.as_span(); +} + +/* -------------------------------------------------------------------- + * MFNetwork inline methods. + */ + +inline uint MFNetwork::max_socket_id() const +{ + return m_socket_or_null_by_id.size() - 1; +} + +} // namespace fn +} // namespace blender + +#endif /* __FN_MULTI_FUNCTION_NETWORK_HH__ */ diff --git a/source/blender/functions/FN_multi_function_network_evaluation.hh b/source/blender/functions/FN_multi_function_network_evaluation.hh new file mode 100644 index 00000000000..85ccd1361ef --- /dev/null +++ b/source/blender/functions/FN_multi_function_network_evaluation.hh @@ -0,0 +1,66 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_MULTI_FUNCTION_NETWORK_EVALUATION_HH__ +#define __FN_MULTI_FUNCTION_NETWORK_EVALUATION_HH__ + +/** \file + * \ingroup fn + */ + +#include "FN_multi_function_network.hh" + +namespace blender { +namespace fn { + +class MFNetworkEvaluationStorage; + +class MFNetworkEvaluator : public MultiFunction { + private: + Vector<const MFOutputSocket *> m_inputs; + Vector<const MFInputSocket *> m_outputs; + + public: + MFNetworkEvaluator(Vector<const MFOutputSocket *> inputs, Vector<const MFInputSocket *> outputs); + + void call(IndexMask mask, MFParams params, MFContext context) const override; + + private: + using Storage = MFNetworkEvaluationStorage; + + void copy_inputs_to_storage(MFParams params, Storage &storage) const; + void copy_outputs_to_storage( + MFParams params, + Storage &storage, + Vector<const MFInputSocket *> &outputs_to_initialize_in_the_end) const; + + void evaluate_network_to_compute_outputs(MFContext &global_context, Storage &storage) const; + + void evaluate_function(MFContext &global_context, + const MFFunctionNode &function_node, + Storage &storage) const; + + bool can_do_single_value_evaluation(const MFFunctionNode &function_node, Storage &storage) const; + + void initialize_remaining_outputs(MFParams params, + Storage &storage, + Span<const MFInputSocket *> remaining_outputs) const; +}; + +} // namespace fn +} // namespace blender + +#endif /* __FN_MULTI_FUNCTION_NETWORK_EVALUATION_HH__ */ diff --git a/source/blender/functions/FN_multi_function_param_type.hh b/source/blender/functions/FN_multi_function_param_type.hh new file mode 100644 index 00000000000..d89c13505f9 --- /dev/null +++ b/source/blender/functions/FN_multi_function_param_type.hh @@ -0,0 +1,165 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_MULTI_FUNCTION_PARAM_TYPE_HH__ +#define __FN_MULTI_FUNCTION_PARAM_TYPE_HH__ + +/** \file + * \ingroup fn + * + * A multi-function has an arbitrary amount of parameters. Every parameter belongs to one of three + * interface types: + * - Input: An input parameter is readonly inside the function. The values have to be provided by + * the caller. + * - Output: An output parameter has to be initialized by the function. However, the caller + * provides the memory where the data has to be constructed. + * - Mutable: A mutable parameter can be considered to be an input and output. The caller has to + * initialize the data, but the function is allowed to modify it. + * + * Furthermore, every parameter has a MFDataType that describes what kind of data is being passed + * around. + */ + +#include "FN_multi_function_data_type.hh" + +namespace blender { +namespace fn { + +class MFParamType { + public: + enum InterfaceType { + Input, + Output, + Mutable, + }; + + enum Category { + SingleInput, + VectorInput, + SingleOutput, + VectorOutput, + SingleMutable, + VectorMutable, + }; + + private: + InterfaceType m_interface_type; + MFDataType m_data_type; + + public: + MFParamType(InterfaceType interface_type, MFDataType data_type) + : m_interface_type(interface_type), m_data_type(data_type) + { + } + + static MFParamType ForSingleInput(const CPPType &type) + { + return MFParamType(InterfaceType::Input, MFDataType::ForSingle(type)); + } + + static MFParamType ForVectorInput(const CPPType &base_type) + { + return MFParamType(InterfaceType::Input, MFDataType::ForVector(base_type)); + } + + static MFParamType ForSingleOutput(const CPPType &type) + { + return MFParamType(InterfaceType::Output, MFDataType::ForSingle(type)); + } + + static MFParamType ForVectorOutput(const CPPType &base_type) + { + return MFParamType(InterfaceType::Output, MFDataType::ForVector(base_type)); + } + + static MFParamType ForMutableSingle(const CPPType &type) + { + return MFParamType(InterfaceType::Mutable, MFDataType::ForSingle(type)); + } + + static MFParamType ForMutableVector(const CPPType &base_type) + { + return MFParamType(InterfaceType::Mutable, MFDataType::ForVector(base_type)); + } + + MFDataType data_type() const + { + return m_data_type; + } + + InterfaceType interface_type() const + { + return m_interface_type; + } + + Category category() const + { + switch (m_data_type.category()) { + case MFDataType::Single: { + switch (m_interface_type) { + case Input: + return SingleInput; + case Output: + return SingleOutput; + case Mutable: + return SingleMutable; + } + break; + } + case MFDataType::Vector: { + switch (m_interface_type) { + case Input: + return VectorInput; + case Output: + return VectorOutput; + case Mutable: + return VectorMutable; + } + break; + } + } + BLI_assert(false); + return SingleInput; + } + + bool is_input_or_mutable() const + { + return ELEM(m_interface_type, Input, Mutable); + } + + bool is_output_or_mutable() const + { + return ELEM(m_interface_type, Output, Mutable); + } + + friend bool operator==(const MFParamType &a, const MFParamType &b); + friend bool operator!=(const MFParamType &a, const MFParamType &b); +}; + +inline bool operator==(const MFParamType &a, const MFParamType &b) +{ + return a.m_interface_type == b.m_interface_type && a.m_data_type == b.m_data_type; +} + +inline bool operator!=(const MFParamType &a, const MFParamType &b) +{ + return !(a == b); +} + +} // namespace fn +} // namespace blender + +#endif /* __FN_MULTI_FUNCTION_PARAM_TYPE_HH__ */ diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh new file mode 100644 index 00000000000..6a0eb698250 --- /dev/null +++ b/source/blender/functions/FN_multi_function_params.hh @@ -0,0 +1,240 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_MULTI_FUNCTION_PARAMS_HH__ +#define __FN_MULTI_FUNCTION_PARAMS_HH__ + +/** \file + * \ingroup fn + * + * This file provides an MFParams and MFParamsBuilder structure. + * + * `MFParamsBuilder` is used by a function caller to be prepare all parameters that are passed into + * the function. `MFParams` is then used inside the called function to access the parameters. + */ + +#include "FN_generic_vector_array.hh" +#include "FN_multi_function_signature.hh" + +namespace blender { +namespace fn { + +class MFParamsBuilder { + private: + const MFSignature *m_signature; + uint m_min_array_size; + Vector<GVSpan> m_virtual_spans; + Vector<GMutableSpan> m_mutable_spans; + Vector<GVArraySpan> m_virtual_array_spans; + Vector<GVectorArray *> m_vector_arrays; + + friend class MFParams; + + public: + MFParamsBuilder(const MFSignature &signature, uint min_array_size) + : m_signature(&signature), m_min_array_size(min_array_size) + { + } + + MFParamsBuilder(const class MultiFunction &fn, uint min_array_size); + + template<typename T> void add_readonly_single_input(const T *value) + { + this->add_readonly_single_input( + GVSpan::FromSingle(CPPType::get<T>(), value, m_min_array_size)); + } + void add_readonly_single_input(GVSpan ref) + { + this->assert_current_param_type(MFParamType::ForSingleInput(ref.type())); + BLI_assert(ref.size() >= m_min_array_size); + m_virtual_spans.append(ref); + } + + void add_readonly_vector_input(GVArraySpan ref) + { + this->assert_current_param_type(MFParamType::ForVectorInput(ref.type())); + BLI_assert(ref.size() >= m_min_array_size); + m_virtual_array_spans.append(ref); + } + + void add_uninitialized_single_output(GMutableSpan ref) + { + this->assert_current_param_type(MFParamType::ForSingleOutput(ref.type())); + BLI_assert(ref.size() >= m_min_array_size); + m_mutable_spans.append(ref); + } + + void add_vector_output(GVectorArray &vector_array) + { + this->assert_current_param_type(MFParamType::ForVectorOutput(vector_array.type())); + BLI_assert(vector_array.size() >= m_min_array_size); + m_vector_arrays.append(&vector_array); + } + + void add_single_mutable(GMutableSpan ref) + { + this->assert_current_param_type(MFParamType::ForMutableSingle(ref.type())); + BLI_assert(ref.size() >= m_min_array_size); + m_mutable_spans.append(ref); + } + + void add_vector_mutable(GVectorArray &vector_array) + { + this->assert_current_param_type(MFParamType::ForMutableVector(vector_array.type())); + BLI_assert(vector_array.size() >= m_min_array_size); + m_vector_arrays.append(&vector_array); + } + + GMutableSpan computed_array(uint param_index) + { + BLI_assert(ELEM(m_signature->param_types[param_index].category(), + MFParamType::SingleOutput, + MFParamType::SingleMutable)); + uint data_index = m_signature->data_index(param_index); + return m_mutable_spans[data_index]; + } + + GVectorArray &computed_vector_array(uint param_index) + { + BLI_assert(ELEM(m_signature->param_types[param_index].category(), + MFParamType::VectorOutput, + MFParamType::VectorMutable)); + uint data_index = m_signature->data_index(param_index); + return *m_vector_arrays[data_index]; + } + + private: + void assert_current_param_type(MFParamType param_type) + { + UNUSED_VARS_NDEBUG(param_type); +#ifdef DEBUG + uint param_index = this->current_param_index(); + MFParamType expected_type = m_signature->param_types[param_index]; + BLI_assert(expected_type == param_type); +#endif + } + + uint current_param_index() const + { + return m_virtual_spans.size() + m_mutable_spans.size() + m_virtual_array_spans.size() + + m_vector_arrays.size(); + } +}; + +class MFParams { + private: + MFParamsBuilder *m_builder; + + public: + MFParams(MFParamsBuilder &builder) : m_builder(&builder) + { + } + + template<typename T> VSpan<T> readonly_single_input(uint param_index, StringRef name = "") + { + return this->readonly_single_input(param_index, name).typed<T>(); + } + GVSpan readonly_single_input(uint param_index, StringRef name = "") + { + this->assert_correct_param(param_index, name, MFParamType::SingleInput); + uint data_index = m_builder->m_signature->data_index(param_index); + return m_builder->m_virtual_spans[data_index]; + } + + template<typename T> + MutableSpan<T> uninitialized_single_output(uint param_index, StringRef name = "") + { + return this->uninitialized_single_output(param_index, name).typed<T>(); + } + GMutableSpan uninitialized_single_output(uint param_index, StringRef name = "") + { + this->assert_correct_param(param_index, name, MFParamType::SingleOutput); + uint data_index = m_builder->m_signature->data_index(param_index); + return m_builder->m_mutable_spans[data_index]; + } + + template<typename T> VArraySpan<T> readonly_vector_input(uint param_index, StringRef name = "") + { + return this->readonly_vector_input(param_index, name).typed<T>(); + } + GVArraySpan readonly_vector_input(uint param_index, StringRef name = "") + { + this->assert_correct_param(param_index, name, MFParamType::VectorInput); + uint data_index = m_builder->m_signature->data_index(param_index); + return m_builder->m_virtual_array_spans[data_index]; + } + + template<typename T> GVectorArrayRef<T> vector_output(uint param_index, StringRef name = "") + { + return this->vector_output(param_index, name).typed<T>(); + } + GVectorArray &vector_output(uint param_index, StringRef name = "") + { + this->assert_correct_param(param_index, name, MFParamType::VectorOutput); + uint data_index = m_builder->m_signature->data_index(param_index); + return *m_builder->m_vector_arrays[data_index]; + } + + template<typename T> MutableSpan<T> single_mutable(uint param_index, StringRef name = "") + { + return this->single_mutable(param_index, name).typed<T>(); + } + GMutableSpan single_mutable(uint param_index, StringRef name = "") + { + this->assert_correct_param(param_index, name, MFParamType::SingleMutable); + uint data_index = m_builder->m_signature->data_index(param_index); + return m_builder->m_mutable_spans[data_index]; + } + + template<typename T> GVectorArrayRef<T> vector_mutable(uint param_index, StringRef name = "") + { + return this->vector_mutable(param_index, name).typed<T>(); + } + GVectorArray &vector_mutable(uint param_index, StringRef name = "") + { + this->assert_correct_param(param_index, name, MFParamType::VectorMutable); + uint data_index = m_builder->m_signature->data_index(param_index); + return *m_builder->m_vector_arrays[data_index]; + } + + private: + void assert_correct_param(uint param_index, StringRef name, MFParamType param_type) + { + UNUSED_VARS_NDEBUG(param_index, name, param_type); +#ifdef DEBUG + BLI_assert(m_builder->m_signature->param_types[param_index] == param_type); + if (name.size() > 0) { + BLI_assert(m_builder->m_signature->param_names[param_index] == name); + } +#endif + } + + void assert_correct_param(uint param_index, StringRef name, MFParamType::Category category) + { + UNUSED_VARS_NDEBUG(param_index, name, category); +#ifdef DEBUG + BLI_assert(m_builder->m_signature->param_types[param_index].category() == category); + if (name.size() > 0) { + BLI_assert(m_builder->m_signature->param_names[param_index] == name); + } +#endif + } +}; + +} // namespace fn +} // namespace blender + +#endif /* __FN_MULTI_FUNCTION_PARAMS_HH__ */ diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh new file mode 100644 index 00000000000..77a8ce14c03 --- /dev/null +++ b/source/blender/functions/FN_multi_function_signature.hh @@ -0,0 +1,166 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_MULTI_FUNCTION_SIGNATURE_HH__ +#define __FN_MULTI_FUNCTION_SIGNATURE_HH__ + +/** \file + * \ingroup fn + * + * The signature of a multi-function contains the functions name and expected parameters. New + * signatures should be build using the MFSignatureBuilder class. + */ + +#include "FN_multi_function_param_type.hh" + +#include "BLI_vector.hh" + +namespace blender { +namespace fn { + +struct MFSignature { + std::string function_name; + /* Use RawAllocator so that a MultiFunction can have static storage duration. */ + Vector<std::string, 4, RawAllocator> param_names; + Vector<MFParamType, 4, RawAllocator> param_types; + Vector<uint, 4, RawAllocator> param_data_indices; + + uint data_index(uint param_index) const + { + return param_data_indices[param_index]; + } +}; + +class MFSignatureBuilder { + private: + MFSignature &m_data; + uint m_span_count = 0; + uint m_virtual_span_count = 0; + uint m_virtual_array_span_count = 0; + uint m_vector_array_count = 0; + + public: + MFSignatureBuilder(MFSignature &data) : m_data(data) + { + BLI_assert(data.param_names.is_empty()); + BLI_assert(data.param_types.is_empty()); + BLI_assert(data.param_data_indices.is_empty()); + } + + /* Input Param Types */ + + template<typename T> void single_input(StringRef name) + { + this->single_input(name, CPPType::get<T>()); + } + void single_input(StringRef name, const CPPType &type) + { + this->input(name, MFDataType::ForSingle(type)); + } + template<typename T> void vector_input(StringRef name) + { + this->vector_input(name, CPPType::get<T>()); + } + void vector_input(StringRef name, const CPPType &base_type) + { + this->input(name, MFDataType::ForVector(base_type)); + } + void input(StringRef name, MFDataType data_type) + { + m_data.param_names.append(name); + m_data.param_types.append(MFParamType(MFParamType::Input, data_type)); + + switch (data_type.category()) { + case MFDataType::Single: + m_data.param_data_indices.append(m_virtual_span_count++); + break; + case MFDataType::Vector: + m_data.param_data_indices.append(m_virtual_array_span_count++); + break; + } + } + + /* Output Param Types */ + + template<typename T> void single_output(StringRef name) + { + this->single_output(name, CPPType::get<T>()); + } + void single_output(StringRef name, const CPPType &type) + { + this->output(name, MFDataType::ForSingle(type)); + } + template<typename T> void vector_output(StringRef name) + { + this->vector_output(name, CPPType::get<T>()); + } + void vector_output(StringRef name, const CPPType &base_type) + { + this->output(name, MFDataType::ForVector(base_type)); + } + void output(StringRef name, MFDataType data_type) + { + m_data.param_names.append(name); + m_data.param_types.append(MFParamType(MFParamType::Output, data_type)); + + switch (data_type.category()) { + case MFDataType::Single: + m_data.param_data_indices.append(m_span_count++); + break; + case MFDataType::Vector: + m_data.param_data_indices.append(m_vector_array_count++); + break; + } + } + + /* Mutable Param Types */ + + template<typename T> void single_mutable(StringRef name) + { + this->single_mutable(name, CPPType::get<T>()); + } + void single_mutable(StringRef name, const CPPType &type) + { + this->mutable_(name, MFDataType::ForSingle(type)); + } + template<typename T> void vector_mutable(StringRef name) + { + this->vector_mutable(name, CPPType::get<T>()); + } + void vector_mutable(StringRef name, const CPPType &base_type) + { + this->mutable_(name, MFDataType::ForVector(base_type)); + } + void mutable_(StringRef name, MFDataType data_type) + { + m_data.param_names.append(name); + m_data.param_types.append(MFParamType(MFParamType::Mutable, data_type)); + + switch (data_type.category()) { + case MFDataType::Single: + m_data.param_data_indices.append(m_span_count++); + break; + case MFDataType::Vector: + m_data.param_data_indices.append(m_vector_array_count++); + break; + } + } +}; + +} // namespace fn +} // namespace blender + +#endif /* __FN_MULTI_FUNCTION_SIGNATURE_HH__ */ diff --git a/source/blender/functions/FN_spans.hh b/source/blender/functions/FN_spans.hh new file mode 100644 index 00000000000..b4607527fb5 --- /dev/null +++ b/source/blender/functions/FN_spans.hh @@ -0,0 +1,404 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FN_SPANS_HH__ +#define __FN_SPANS_HH__ + +/** \file + * \ingroup fn + * + * This file implements multiple variants of a span for different use cases. There are two + * requirements of the function system that require span implementations other from + * blender::Span<T>. + * 1. The function system works with a run-time type system (see `CPPType`). Therefore, it has to + * deal with types in a generic way. The type of a Span<T> has to be known at compile time. + * 2. Span<T> expects an underlying memory buffer that is as large as the span. However, sometimes + * we can save some memory and processing when we know that all elements are the same. + * + * The first requirement is solved with generic spans, which use the "G" prefix. Those + * store a CPPType instance to keep track of the type that is currently stored. + * + * The second requirement is solved with virtual spans. A virtual span behaves like a normal span, + * but it might not be backed up by an actual array. Elements in a virtual span are always + * immutable. + * + * Different use cases require different combinations of these properties and therefore use + * different data structures. + */ + +#include "BLI_span.hh" + +#include "FN_cpp_type.hh" + +namespace blender { +namespace fn { + +/** + * A generic span. It behaves just like a blender::Span<T>, but the type is only known at run-time. + */ +class GSpan { + private: + const CPPType *m_type; + const void *m_buffer; + uint m_size; + + public: + GSpan(const CPPType &type, const void *buffer, uint size) + : m_type(&type), m_buffer(buffer), m_size(size) + { + BLI_assert(buffer != nullptr || size == 0); + BLI_assert(type.pointer_has_valid_alignment(buffer)); + } + + GSpan(const CPPType &type) : GSpan(type, nullptr, 0) + { + } + + template<typename T> + GSpan(Span<T> array) : GSpan(CPPType::get<T>(), (const void *)array.data(), array.size()) + { + } + + const CPPType &type() const + { + return *m_type; + } + + bool is_empty() const + { + return m_size == 0; + } + + uint size() const + { + return m_size; + } + + const void *buffer() const + { + return m_buffer; + } + + const void *operator[](uint index) const + { + BLI_assert(index < m_size); + return POINTER_OFFSET(m_buffer, m_type->size() * index); + } + + template<typename T> Span<T> typed() const + { + BLI_assert(m_type->is<T>()); + return Span<T>((const T *)m_buffer, m_size); + } +}; + +/** + * A generic mutable span. It behaves just like a blender::MutableSpan<T>, but the type is only + * known at run-time. + */ +class GMutableSpan { + private: + const CPPType *m_type; + void *m_buffer; + uint m_size; + + public: + GMutableSpan(const CPPType &type, void *buffer, uint size) + : m_type(&type), m_buffer(buffer), m_size(size) + { + BLI_assert(buffer != nullptr || size == 0); + BLI_assert(type.pointer_has_valid_alignment(buffer)); + } + + GMutableSpan(const CPPType &type) : GMutableSpan(type, nullptr, 0) + { + } + + template<typename T> + GMutableSpan(MutableSpan<T> array) + : GMutableSpan(CPPType::get<T>(), (void *)array.begin(), array.size()) + { + } + + operator GSpan() const + { + return GSpan(*m_type, m_buffer, m_size); + } + + const CPPType &type() const + { + return *m_type; + } + + bool is_empty() const + { + return m_size == 0; + } + + uint size() const + { + return m_size; + } + + void *buffer() + { + return m_buffer; + } + + void *operator[](uint index) + { + BLI_assert(index < m_size); + return POINTER_OFFSET(m_buffer, m_type->size() * index); + } + + template<typename T> MutableSpan<T> typed() + { + BLI_assert(m_type->is<T>()); + return MutableSpan<T>((T *)m_buffer, m_size); + } +}; + +enum class VSpanCategory { + Single, + FullArray, + FullPointerArray, +}; + +template<typename T> struct VSpanBase { + protected: + uint m_virtual_size; + VSpanCategory m_category; + union { + struct { + const T *data; + } single; + struct { + const T *data; + } full_array; + struct { + const T *const *data; + } full_pointer_array; + } m_data; + + public: + bool is_single_element() const + { + switch (m_category) { + case VSpanCategory::Single: + return true; + case VSpanCategory::FullArray: + return m_virtual_size == 1; + case VSpanCategory::FullPointerArray: + return m_virtual_size == 1; + } + BLI_assert(false); + return false; + } + + bool is_empty() const + { + return this->m_virtual_size == 0; + } + + uint size() const + { + return this->m_virtual_size; + } +}; + +BLI_STATIC_ASSERT((sizeof(VSpanBase<void>) == sizeof(VSpanBase<AlignedBuffer<64, 64>>)), + "should not depend on the size of the type"); + +/** + * A virtual span. It behaves like a blender::Span<T>, but might not be backed up by an actual + * array. + */ +template<typename T> class VSpan : public VSpanBase<T> { + friend class GVSpan; + + VSpan(const VSpanBase<void> &values) + { + memcpy(this, &values, sizeof(VSpanBase<void>)); + } + + public: + VSpan() + { + this->m_virtual_size = 0; + this->m_category = VSpanCategory::FullArray; + this->m_data.full_array.data = nullptr; + } + + VSpan(Span<T> values) + { + this->m_virtual_size = values.size(); + this->m_category = VSpanCategory::FullArray; + this->m_data.full_array.data = values.begin(); + } + + VSpan(MutableSpan<T> values) : VSpan(Span<T>(values)) + { + } + + VSpan(Span<const T *> values) + { + this->m_virtual_size = values.size(); + this->m_category = VSpanCategory::FullPointerArray; + this->m_data.full_pointer_array.data = values.begin(); + } + + static VSpan FromSingle(const T *value, uint virtual_size) + { + VSpan ref; + ref.m_virtual_size = virtual_size; + ref.m_category = VSpanCategory::Single; + ref.m_data.single.data = value; + return ref; + } + + const T &operator[](uint index) const + { + BLI_assert(index < this->m_virtual_size); + switch (this->m_category) { + case VSpanCategory::Single: + return *this->m_data.single.data; + case VSpanCategory::FullArray: + return this->m_data.full_array.data[index]; + case VSpanCategory::FullPointerArray: + return *this->m_data.full_pointer_array.data[index]; + } + BLI_assert(false); + return *this->m_data.single.data; + } +}; + +/** + * A generic virtual span. It behaves like a blender::Span<T>, but the type is only known at + * run-time and it might not be backed up by an actual array. + */ +class GVSpan : public VSpanBase<void> { + private: + const CPPType *m_type; + + GVSpan() = default; + + public: + GVSpan(const CPPType &type) + { + this->m_type = &type; + this->m_virtual_size = 0; + this->m_category = VSpanCategory::FullArray; + this->m_data.full_array.data = nullptr; + } + + GVSpan(GSpan values) + { + this->m_type = &values.type(); + this->m_virtual_size = values.size(); + this->m_category = VSpanCategory::FullArray; + this->m_data.full_array.data = values.buffer(); + } + + GVSpan(GMutableSpan values) : GVSpan(GSpan(values)) + { + } + + template<typename T> GVSpan(const VSpanBase<T> &values) + { + this->m_type = &CPPType::get<T>(); + memcpy(this, &values, sizeof(VSpanBase<void>)); + } + + template<typename T> GVSpan(Span<T> values) : GVSpan(GSpan(values)) + { + } + + template<typename T> GVSpan(MutableSpan<T> values) : GVSpan(GSpan(values)) + { + } + + static GVSpan FromSingle(const CPPType &type, const void *value, uint virtual_size) + { + GVSpan ref; + ref.m_type = &type; + ref.m_virtual_size = virtual_size; + ref.m_category = VSpanCategory::Single; + ref.m_data.single.data = value; + return ref; + } + + static GVSpan FromFullPointerArray(const CPPType &type, const void *const *values, uint size) + { + GVSpan ref; + ref.m_type = &type; + ref.m_virtual_size = size; + ref.m_category = VSpanCategory::FullPointerArray; + ref.m_data.full_pointer_array.data = values; + return ref; + } + + const CPPType &type() const + { + return *this->m_type; + } + + const void *operator[](uint index) const + { + BLI_assert(index < this->m_virtual_size); + switch (this->m_category) { + case VSpanCategory::Single: + return this->m_data.single.data; + case VSpanCategory::FullArray: + return POINTER_OFFSET(this->m_data.full_array.data, index * m_type->size()); + case VSpanCategory::FullPointerArray: + return this->m_data.full_pointer_array.data[index]; + } + BLI_assert(false); + return this->m_data.single.data; + } + + template<typename T> VSpan<T> typed() const + { + BLI_assert(m_type->is<T>()); + return VSpan<T>(*this); + } + + const void *as_single_element() const + { + BLI_assert(this->is_single_element()); + return (*this)[0]; + } + + void materialize_to_uninitialized(void *dst) const + { + this->materialize_to_uninitialized(IndexRange(m_virtual_size), dst); + } + + void materialize_to_uninitialized(IndexMask mask, void *dst) const + { + BLI_assert(this->size() >= mask.min_array_size()); + + uint element_size = m_type->size(); + for (uint i : mask) { + m_type->copy_to_uninitialized((*this)[i], POINTER_OFFSET(dst, element_size * i)); + } + } +}; + +} // namespace fn +} // namespace blender + +#endif /* __FN_SPANS_HH__ */ diff --git a/source/blender/functions/intern/attributes_ref.cc b/source/blender/functions/intern/attributes_ref.cc new file mode 100644 index 00000000000..dc64f571596 --- /dev/null +++ b/source/blender/functions/intern/attributes_ref.cc @@ -0,0 +1,72 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "FN_attributes_ref.hh" + +namespace blender { +namespace fn { + +AttributesInfoBuilder::~AttributesInfoBuilder() +{ + for (uint i : m_defaults.index_range()) { + m_types[i]->destruct(m_defaults[i]); + } +} + +void AttributesInfoBuilder::add(StringRef name, const CPPType &type, const void *default_value) +{ + if (m_names.add_as(name)) { + m_types.append(&type); + + if (default_value == nullptr) { + default_value = type.default_value(); + } + void *dst = m_allocator.allocate(type.size(), type.alignment()); + type.copy_to_uninitialized(default_value, dst); + m_defaults.append(dst); + } + else { + /* The same name can be added more than once as long as the type is always the same. */ + BLI_assert(m_types[m_names.index_of_as(name)] == &type); + } +} + +AttributesInfo::AttributesInfo(const AttributesInfoBuilder &builder) +{ + for (uint i : builder.m_types.index_range()) { + StringRefNull name = m_allocator.copy_string(builder.m_names[i]); + const CPPType &type = *builder.m_types[i]; + const void *default_value = builder.m_defaults[i]; + + m_index_by_name.add_new(name, i); + m_name_by_index.append(name); + m_type_by_index.append(&type); + + void *dst = m_allocator.allocate(type.size(), type.alignment()); + type.copy_to_uninitialized(default_value, dst); + m_defaults.append(dst); + } +} + +AttributesInfo::~AttributesInfo() +{ + for (uint i : m_defaults.index_range()) { + m_type_by_index[i]->destruct(m_defaults[i]); + } +} + +} // namespace fn +} // namespace blender diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc index 6339250caa5..cb4b065e5bc 100644 --- a/source/blender/functions/intern/cpp_types.cc +++ b/source/blender/functions/intern/cpp_types.cc @@ -22,7 +22,7 @@ #include "BLI_float4x4.hh" namespace blender { -namespace FN { +namespace fn { MAKE_CPP_TYPE(bool, bool) @@ -39,5 +39,5 @@ MAKE_CPP_TYPE(Color4b, blender::Color4b) MAKE_CPP_TYPE(string, std::string) -} // namespace FN +} // namespace fn } // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_nurbs.h b/source/blender/functions/intern/multi_function.cc index c6a3c399b66..8eb5355511d 100644 --- a/source/blender/io/alembic/intern/abc_writer_nurbs.h +++ b/source/blender/functions/intern/multi_function.cc @@ -14,29 +14,27 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_NURBS_H__ -#define __ABC_WRITER_NURBS_H__ - -#include "abc_writer_object.h" +#include "FN_multi_function.hh" -class AbcNurbsWriter : public AbcObjectWriter { - std::vector<Alembic::AbcGeom::ONuPatchSchema> m_nurbs_schema; - bool m_is_animated; +namespace blender { +namespace fn { +class DummyMultiFunction : public MultiFunction { public: - AbcNurbsWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - private: - virtual void do_write(); - - bool isAnimated() const; + DummyMultiFunction() + { + this->get_builder("Dummy"); + } + + void call(IndexMask UNUSED(mask), + MFParams UNUSED(params), + MFContext UNUSED(context)) const override + { + } }; -#endif /* __ABC_WRITER_NURBS_H__ */ +static DummyMultiFunction dummy_multi_function_; +const MultiFunction &dummy_multi_function = dummy_multi_function_; + +} // namespace fn +} // namespace blender diff --git a/source/blender/functions/intern/multi_function_network.cc b/source/blender/functions/intern/multi_function_network.cc new file mode 100644 index 00000000000..93d062f3e5c --- /dev/null +++ b/source/blender/functions/intern/multi_function_network.cc @@ -0,0 +1,278 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_dot_export.hh" +#include "FN_multi_function_network.hh" + +namespace blender { +namespace fn { + +MFNetwork::~MFNetwork() +{ + for (MFFunctionNode *node : m_function_nodes) { + node->destruct_sockets(); + node->~MFFunctionNode(); + } + for (MFDummyNode *node : m_dummy_nodes) { + node->destruct_sockets(); + node->~MFDummyNode(); + } +} + +void MFNode::destruct_sockets() +{ + for (MFInputSocket *socket : m_inputs) { + socket->~MFInputSocket(); + } + for (MFOutputSocket *socket : m_outputs) { + socket->~MFOutputSocket(); + } +} + +/** + * Add a new function node to the network. The caller keeps the ownership of the function. The + * function should not be freed before the network. A reference to the new node is returned. The + * node is owned by the network. + */ +MFFunctionNode &MFNetwork::add_function(const MultiFunction &function) +{ + Vector<uint, 16> input_param_indices, output_param_indices; + + for (uint param_index : function.param_indices()) { + switch (function.param_type(param_index).interface_type()) { + case MFParamType::Input: { + input_param_indices.append(param_index); + break; + } + case MFParamType::Output: { + output_param_indices.append(param_index); + break; + } + case MFParamType::Mutable: { + input_param_indices.append(param_index); + output_param_indices.append(param_index); + break; + } + } + } + + MFFunctionNode &node = *m_allocator.construct<MFFunctionNode>(); + m_function_nodes.add_new(&node); + + node.m_network = this; + node.m_is_dummy = false; + node.m_id = m_node_or_null_by_id.append_and_get_index(&node); + node.m_function = &function; + node.m_input_param_indices = m_allocator.construct_array_copy<uint>(input_param_indices); + node.m_output_param_indices = m_allocator.construct_array_copy<uint>(output_param_indices); + + node.m_inputs = m_allocator.construct_elements_and_pointer_array<MFInputSocket>( + input_param_indices.size()); + node.m_outputs = m_allocator.construct_elements_and_pointer_array<MFOutputSocket>( + output_param_indices.size()); + + for (uint i : input_param_indices.index_range()) { + uint param_index = input_param_indices[i]; + MFParamType param = function.param_type(param_index); + BLI_assert(param.is_input_or_mutable()); + + MFInputSocket &socket = *node.m_inputs[i]; + socket.m_data_type = param.data_type(); + socket.m_node = &node; + socket.m_index = i; + socket.m_is_output = false; + socket.m_name = function.param_name(param_index); + socket.m_origin = nullptr; + socket.m_id = m_socket_or_null_by_id.append_and_get_index(&socket); + } + + for (uint i : output_param_indices.index_range()) { + uint param_index = output_param_indices[i]; + MFParamType param = function.param_type(param_index); + BLI_assert(param.is_output_or_mutable()); + + MFOutputSocket &socket = *node.m_outputs[i]; + socket.m_data_type = param.data_type(); + socket.m_node = &node; + socket.m_index = i; + socket.m_is_output = true; + socket.m_name = function.param_name(param_index); + socket.m_id = m_socket_or_null_by_id.append_and_get_index(&socket); + } + + return node; +} + +/** + * Add a dummy node with the given input and output sockets. + */ +MFDummyNode &MFNetwork::add_dummy(StringRef name, + Span<MFDataType> input_types, + Span<MFDataType> output_types, + Span<StringRef> input_names, + Span<StringRef> output_names) +{ + assert_same_size(input_types, input_names); + assert_same_size(output_types, output_names); + + MFDummyNode &node = *m_allocator.construct<MFDummyNode>(); + m_dummy_nodes.add_new(&node); + + node.m_network = this; + node.m_is_dummy = true; + node.m_name = m_allocator.copy_string(name); + node.m_id = m_node_or_null_by_id.append_and_get_index(&node); + + node.m_inputs = m_allocator.construct_elements_and_pointer_array<MFInputSocket>( + input_types.size()); + node.m_outputs = m_allocator.construct_elements_and_pointer_array<MFOutputSocket>( + output_types.size()); + + node.m_input_names = m_allocator.allocate_array<StringRefNull>(input_types.size()); + node.m_output_names = m_allocator.allocate_array<StringRefNull>(output_types.size()); + + for (uint i : input_types.index_range()) { + MFInputSocket &socket = *node.m_inputs[i]; + socket.m_data_type = input_types[i]; + socket.m_node = &node; + socket.m_index = i; + socket.m_is_output = false; + socket.m_name = m_allocator.copy_string(input_names[i]); + socket.m_id = m_socket_or_null_by_id.append_and_get_index(&socket); + node.m_input_names[i] = socket.m_name; + } + + for (uint i : output_types.index_range()) { + MFOutputSocket &socket = *node.m_outputs[i]; + socket.m_data_type = output_types[i]; + socket.m_node = &node; + socket.m_index = i; + socket.m_is_output = true; + socket.m_name = m_allocator.copy_string(output_names[i]); + socket.m_id = m_socket_or_null_by_id.append_and_get_index(&socket); + node.m_output_names[i] = socket.m_name; + } + + return node; +} + +/** + * Connect two sockets. This invokes undefined behavior if the sockets belong to different + * networks, the sockets have a different data type, or the `to` socket is connected to something + * else already. + */ +void MFNetwork::add_link(MFOutputSocket &from, MFInputSocket &to) +{ + BLI_assert(to.m_origin == nullptr); + BLI_assert(from.m_node->m_network == to.m_node->m_network); + BLI_assert(from.m_data_type == to.m_data_type); + from.m_targets.append(&to); + to.m_origin = &from; +} + +MFOutputSocket &MFNetwork::add_input(StringRef name, MFDataType data_type) +{ + return this->add_dummy(name, {}, {data_type}, {}, {name}).output(0); +} + +MFInputSocket &MFNetwork::add_output(StringRef name, MFDataType data_type) +{ + return this->add_dummy(name, {data_type}, {}, {name}, {}).input(0); +} + +void MFNetwork::relink(MFOutputSocket &old_output, MFOutputSocket &new_output) +{ + BLI_assert(&old_output != &new_output); + for (MFInputSocket *input : old_output.targets()) { + input->m_origin = &new_output; + } + new_output.m_targets.extend(old_output.m_targets); + old_output.m_targets.clear(); +} + +void MFNetwork::remove(MFNode &node) +{ + for (MFInputSocket *socket : node.m_inputs) { + if (socket->m_origin != nullptr) { + socket->m_origin->m_targets.remove_first_occurrence_and_reorder(socket); + } + m_socket_or_null_by_id[socket->m_id] = nullptr; + } + for (MFOutputSocket *socket : node.m_outputs) { + for (MFInputSocket *other : socket->m_targets) { + other->m_origin = nullptr; + } + m_socket_or_null_by_id[socket->m_id] = nullptr; + } + node.destruct_sockets(); + if (node.is_dummy()) { + MFDummyNode &dummy_node = node.as_dummy(); + dummy_node.~MFDummyNode(); + m_dummy_nodes.remove_contained(&dummy_node); + } + else { + MFFunctionNode &function_node = node.as_function(); + function_node.~MFFunctionNode(); + m_function_nodes.remove_contained(&function_node); + } + m_node_or_null_by_id[node.m_id] = nullptr; +} + +std::string MFNetwork::to_dot() const +{ + dot::DirectedGraph digraph; + digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); + + Map<const MFNode *, dot::NodeWithSocketsRef> dot_nodes; + + Vector<const MFNode *> all_nodes; + all_nodes.extend(m_function_nodes.as_span()); + all_nodes.extend(m_dummy_nodes.as_span()); + + for (const MFNode *node : all_nodes) { + dot::Node &dot_node = digraph.new_node(""); + + Vector<std::string> input_names, output_names; + for (const MFInputSocket *socket : node->m_inputs) { + input_names.append(socket->name() + "(" + socket->data_type().to_string() + ")"); + } + for (const MFOutputSocket *socket : node->m_outputs) { + output_names.append(socket->name() + " (" + socket->data_type().to_string() + ")"); + } + + dot::NodeWithSocketsRef dot_node_ref{dot_node, node->name(), input_names, output_names}; + dot_nodes.add_new(node, dot_node_ref); + } + + for (const MFNode *to_node : all_nodes) { + dot::NodeWithSocketsRef to_dot_node = dot_nodes.lookup(to_node); + + for (const MFInputSocket *to_socket : to_node->m_inputs) { + const MFOutputSocket *from_socket = to_socket->m_origin; + if (from_socket != nullptr) { + const MFNode *from_node = from_socket->m_node; + dot::NodeWithSocketsRef from_dot_node = dot_nodes.lookup(from_node); + digraph.new_edge(from_dot_node.output(from_socket->m_index), + to_dot_node.input(to_socket->m_index)); + } + } + } + + return digraph.to_dot_string(); +} + +} // namespace fn +} // namespace blender diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc new file mode 100644 index 00000000000..327a3a66561 --- /dev/null +++ b/source/blender/functions/intern/multi_function_network_evaluation.cc @@ -0,0 +1,1063 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup fn + * + * The `MFNetworkEvaluator` class is a multi-function that consists of potentially many smaller + * multi-functions. When called, it traverses the underlying MFNetwork and executes the required + * function nodes. + * + * There are many possible approaches to evaluate a function network. The approach implemented + * below has the following features: + * - It does not use recursion. Those could become problematic with long node chains. + * - It can handle all existing parameter types (including mutable parameters). + * - Avoids data copies in many cases. + * - Every node is executed at most once. + * - Can compute sub-functions on a single element, when the result is the same for all elements. + * + * Possible improvements: + * - Cache and reuse buffers. + * - Use "deepest depth first" heuristic to decide which order the inputs of a node should be + * computed. This reduces the number of required temporary buffers when they are reused. + */ + +#include "FN_multi_function_network_evaluation.hh" + +#include "BLI_stack.hh" + +namespace blender { +namespace fn { + +struct Value; + +/** + * This keeps track of all the values that flow through the multi-function network. Therefore it + * maintains a mapping between output sockets and their corresponding values. Every `value` + * references some memory, that is owned either by the caller or this storage. + * + * A value can be owned by different sockets over time to avoid unnecessary copies. + */ +class MFNetworkEvaluationStorage { + private: + LinearAllocator<> m_allocator; + IndexMask m_mask; + Array<Value *> m_value_per_output_id; + uint m_min_array_size; + + public: + MFNetworkEvaluationStorage(IndexMask mask, uint max_socket_id); + ~MFNetworkEvaluationStorage(); + + /* Add the values that have been provided by the caller of the multi-function network. */ + void add_single_input_from_caller(const MFOutputSocket &socket, GVSpan virtual_span); + void add_vector_input_from_caller(const MFOutputSocket &socket, GVArraySpan virtual_array_span); + void add_single_output_from_caller(const MFOutputSocket &socket, GMutableSpan span); + void add_vector_output_from_caller(const MFOutputSocket &socket, GVectorArray &vector_array); + + /* Get input buffers for function node evaluations. */ + GVSpan get_single_input__full(const MFInputSocket &socket); + GVSpan get_single_input__single(const MFInputSocket &socket); + GVArraySpan get_vector_input__full(const MFInputSocket &socket); + GVArraySpan get_vector_input__single(const MFInputSocket &socket); + + /* Get output buffers for function node evaluations. */ + GMutableSpan get_single_output__full(const MFOutputSocket &socket); + GMutableSpan get_single_output__single(const MFOutputSocket &socket); + GVectorArray &get_vector_output__full(const MFOutputSocket &socket); + GVectorArray &get_vector_output__single(const MFOutputSocket &socket); + + /* Get mutable buffers for function node evaluations. */ + GMutableSpan get_mutable_single__full(const MFInputSocket &input, const MFOutputSocket &output); + GMutableSpan get_mutable_single__single(const MFInputSocket &input, + const MFOutputSocket &output); + GVectorArray &get_mutable_vector__full(const MFInputSocket &input, const MFOutputSocket &output); + GVectorArray &get_mutable_vector__single(const MFInputSocket &input, + const MFOutputSocket &output); + + /* Mark a node as being done with evaluation. This might free temporary buffers that are no + * longer needed. */ + void finish_node(const MFFunctionNode &node); + void finish_output_socket(const MFOutputSocket &socket); + void finish_input_socket(const MFInputSocket &socket); + + IndexMask mask() const; + bool socket_is_computed(const MFOutputSocket &socket); + bool is_same_value_for_every_index(const MFOutputSocket &socket); + bool socket_has_buffer_for_output(const MFOutputSocket &socket); +}; + +MFNetworkEvaluator::MFNetworkEvaluator(Vector<const MFOutputSocket *> inputs, + Vector<const MFInputSocket *> outputs) + : m_inputs(std::move(inputs)), m_outputs(std::move(outputs)) +{ + BLI_assert(m_outputs.size() > 0); + MFSignatureBuilder signature = this->get_builder("Function Tree"); + + for (auto socket : m_inputs) { + BLI_assert(socket->node().is_dummy()); + + MFDataType type = socket->data_type(); + switch (type.category()) { + case MFDataType::Single: + signature.single_input("Input", type.single_type()); + break; + case MFDataType::Vector: + signature.vector_input("Input", type.vector_base_type()); + break; + } + } + + for (auto socket : m_outputs) { + BLI_assert(socket->node().is_dummy()); + + MFDataType type = socket->data_type(); + switch (type.category()) { + case MFDataType::Single: + signature.single_output("Output", type.single_type()); + break; + case MFDataType::Vector: + signature.vector_output("Output", type.vector_base_type()); + break; + } + } +} + +void MFNetworkEvaluator::call(IndexMask mask, MFParams params, MFContext context) const +{ + if (mask.size() == 0) { + return; + } + + const MFNetwork &network = m_outputs[0]->node().network(); + Storage storage(mask, network.max_socket_id()); + + Vector<const MFInputSocket *> outputs_to_initialize_in_the_end; + + this->copy_inputs_to_storage(params, storage); + this->copy_outputs_to_storage(params, storage, outputs_to_initialize_in_the_end); + this->evaluate_network_to_compute_outputs(context, storage); + this->initialize_remaining_outputs(params, storage, outputs_to_initialize_in_the_end); +} + +BLI_NOINLINE void MFNetworkEvaluator::copy_inputs_to_storage(MFParams params, + Storage &storage) const +{ + for (uint input_index : m_inputs.index_range()) { + uint param_index = input_index + 0; + const MFOutputSocket &socket = *m_inputs[input_index]; + switch (socket.data_type().category()) { + case MFDataType::Single: { + GVSpan input_list = params.readonly_single_input(param_index); + storage.add_single_input_from_caller(socket, input_list); + break; + } + case MFDataType::Vector: { + GVArraySpan input_list_list = params.readonly_vector_input(param_index); + storage.add_vector_input_from_caller(socket, input_list_list); + break; + } + } + } +} + +BLI_NOINLINE void MFNetworkEvaluator::copy_outputs_to_storage( + MFParams params, + Storage &storage, + Vector<const MFInputSocket *> &outputs_to_initialize_in_the_end) const +{ + for (uint output_index : m_outputs.index_range()) { + uint param_index = output_index + m_inputs.size(); + const MFInputSocket &socket = *m_outputs[output_index]; + const MFOutputSocket &origin = *socket.origin(); + + if (origin.node().is_dummy()) { + BLI_assert(m_inputs.contains(&origin)); + /* Don't overwrite input buffers. */ + outputs_to_initialize_in_the_end.append(&socket); + continue; + } + + if (storage.socket_has_buffer_for_output(origin)) { + /* When two outputs will be initialized to the same values. */ + outputs_to_initialize_in_the_end.append(&socket); + continue; + } + + switch (socket.data_type().category()) { + case MFDataType::Single: { + GMutableSpan span = params.uninitialized_single_output(param_index); + storage.add_single_output_from_caller(origin, span); + break; + } + case MFDataType::Vector: { + GVectorArray &vector_array = params.vector_output(param_index); + storage.add_vector_output_from_caller(origin, vector_array); + break; + } + } + } +} + +BLI_NOINLINE void MFNetworkEvaluator::evaluate_network_to_compute_outputs( + MFContext &global_context, Storage &storage) const +{ + Stack<const MFOutputSocket *, 32> sockets_to_compute; + for (const MFInputSocket *socket : m_outputs) { + sockets_to_compute.push(socket->origin()); + } + + Vector<const MFOutputSocket *, 32> missing_sockets; + + /* This is the main loop that traverses the MFNetwork. */ + while (!sockets_to_compute.is_empty()) { + const MFOutputSocket &socket = *sockets_to_compute.peek(); + const MFNode &node = socket.node(); + + if (storage.socket_is_computed(socket)) { + sockets_to_compute.pop(); + continue; + } + + BLI_assert(node.is_function()); + BLI_assert(node.all_inputs_have_origin()); + const MFFunctionNode &function_node = node.as_function(); + + missing_sockets.clear(); + function_node.foreach_origin_socket([&](const MFOutputSocket &origin) { + if (!storage.socket_is_computed(origin)) { + missing_sockets.append(&origin); + } + }); + + sockets_to_compute.push_multiple(missing_sockets); + + bool all_inputs_are_computed = missing_sockets.size() == 0; + if (all_inputs_are_computed) { + this->evaluate_function(global_context, function_node, storage); + sockets_to_compute.pop(); + } + } +} + +BLI_NOINLINE void MFNetworkEvaluator::evaluate_function(MFContext &global_context, + const MFFunctionNode &function_node, + Storage &storage) const +{ + const MultiFunction &function = function_node.function(); + // std::cout << "Function: " << function.name() << "\n"; + + if (this->can_do_single_value_evaluation(function_node, storage)) { + /* The function output would be the same for all elements. Therefore, it is enough to call the + * function only on a single element. This can avoid many duplicate computations. */ + MFParamsBuilder params{function, 1}; + + for (uint param_index : function.param_indices()) { + MFParamType param_type = function.param_type(param_index); + switch (param_type.category()) { + case MFParamType::SingleInput: { + const MFInputSocket &socket = function_node.input_for_param(param_index); + GVSpan values = storage.get_single_input__single(socket); + params.add_readonly_single_input(values); + break; + } + case MFParamType::VectorInput: { + const MFInputSocket &socket = function_node.input_for_param(param_index); + GVArraySpan values = storage.get_vector_input__single(socket); + params.add_readonly_vector_input(values); + break; + } + case MFParamType::SingleOutput: { + const MFOutputSocket &socket = function_node.output_for_param(param_index); + GMutableSpan values = storage.get_single_output__single(socket); + params.add_uninitialized_single_output(values); + break; + } + case MFParamType::VectorOutput: { + const MFOutputSocket &socket = function_node.output_for_param(param_index); + GVectorArray &values = storage.get_vector_output__single(socket); + params.add_vector_output(values); + break; + } + case MFParamType::SingleMutable: { + const MFInputSocket &input = function_node.input_for_param(param_index); + const MFOutputSocket &output = function_node.output_for_param(param_index); + GMutableSpan values = storage.get_mutable_single__single(input, output); + params.add_single_mutable(values); + break; + } + case MFParamType::VectorMutable: { + const MFInputSocket &input = function_node.input_for_param(param_index); + const MFOutputSocket &output = function_node.output_for_param(param_index); + GVectorArray &values = storage.get_mutable_vector__single(input, output); + params.add_vector_mutable(values); + break; + } + } + } + + function.call(IndexRange(1), params, global_context); + } + else { + MFParamsBuilder params{function, storage.mask().min_array_size()}; + + for (uint param_index : function.param_indices()) { + MFParamType param_type = function.param_type(param_index); + switch (param_type.category()) { + case MFParamType::SingleInput: { + const MFInputSocket &socket = function_node.input_for_param(param_index); + GVSpan values = storage.get_single_input__full(socket); + params.add_readonly_single_input(values); + break; + } + case MFParamType::VectorInput: { + const MFInputSocket &socket = function_node.input_for_param(param_index); + GVArraySpan values = storage.get_vector_input__full(socket); + params.add_readonly_vector_input(values); + break; + } + case MFParamType::SingleOutput: { + const MFOutputSocket &socket = function_node.output_for_param(param_index); + GMutableSpan values = storage.get_single_output__full(socket); + params.add_uninitialized_single_output(values); + break; + } + case MFParamType::VectorOutput: { + const MFOutputSocket &socket = function_node.output_for_param(param_index); + GVectorArray &values = storage.get_vector_output__full(socket); + params.add_vector_output(values); + break; + } + case MFParamType::SingleMutable: { + const MFInputSocket &input = function_node.input_for_param(param_index); + const MFOutputSocket &output = function_node.output_for_param(param_index); + GMutableSpan values = storage.get_mutable_single__full(input, output); + params.add_single_mutable(values); + break; + } + case MFParamType::VectorMutable: { + const MFInputSocket &input = function_node.input_for_param(param_index); + const MFOutputSocket &output = function_node.output_for_param(param_index); + GVectorArray &values = storage.get_mutable_vector__full(input, output); + params.add_vector_mutable(values); + break; + } + } + } + + function.call(storage.mask(), params, global_context); + } + + storage.finish_node(function_node); +} + +bool MFNetworkEvaluator::can_do_single_value_evaluation(const MFFunctionNode &function_node, + Storage &storage) const +{ + for (const MFInputSocket *socket : function_node.inputs()) { + if (!storage.is_same_value_for_every_index(*socket->origin())) { + return false; + } + } + if (storage.mask().min_array_size() >= 1) { + for (const MFOutputSocket *socket : function_node.outputs()) { + if (storage.socket_has_buffer_for_output(*socket)) { + return false; + } + } + } + return true; +} + +BLI_NOINLINE void MFNetworkEvaluator::initialize_remaining_outputs( + MFParams params, Storage &storage, Span<const MFInputSocket *> remaining_outputs) const +{ + for (const MFInputSocket *socket : remaining_outputs) { + uint param_index = m_inputs.size() + m_outputs.first_index_of(socket); + + switch (socket->data_type().category()) { + case MFDataType::Single: { + GVSpan values = storage.get_single_input__full(*socket); + GMutableSpan output_values = params.uninitialized_single_output(param_index); + values.materialize_to_uninitialized(storage.mask(), output_values.buffer()); + break; + } + case MFDataType::Vector: { + GVArraySpan values = storage.get_vector_input__full(*socket); + GVectorArray &output_values = params.vector_output(param_index); + output_values.extend(storage.mask(), values); + break; + } + } + } +} + +/* -------------------------------------------------------------------- */ +/** \name Value Types + * \{ */ + +enum class ValueType { + InputSingle, + InputVector, + OutputSingle, + OutputVector, + OwnSingle, + OwnVector, +}; + +struct Value { + ValueType type; + + Value(ValueType type) : type(type) + { + } +}; + +struct InputSingleValue : public Value { + /** This span has been provided by the code that called the multi-function network. */ + GVSpan virtual_span; + + InputSingleValue(GVSpan virtual_span) : Value(ValueType::InputSingle), virtual_span(virtual_span) + { + } +}; + +struct InputVectorValue : public Value { + /** This span has been provided by the code that called the multi-function network. */ + GVArraySpan virtual_array_span; + + InputVectorValue(GVArraySpan virtual_array_span) + : Value(ValueType::InputVector), virtual_array_span(virtual_array_span) + { + } +}; + +struct OutputValue : public Value { + bool is_computed = false; + + OutputValue(ValueType type) : Value(type) + { + } +}; + +struct OutputSingleValue : public OutputValue { + /** This span has been provided by the code that called the multi-function network. */ + GMutableSpan span; + + OutputSingleValue(GMutableSpan span) : OutputValue(ValueType::OutputSingle), span(span) + { + } +}; + +struct OutputVectorValue : public OutputValue { + /** This vector array has been provided by the code that called the multi-function network. */ + GVectorArray *vector_array; + + OutputVectorValue(GVectorArray &vector_array) + : OutputValue(ValueType::OutputVector), vector_array(&vector_array) + { + } +}; + +struct OwnSingleValue : public Value { + /** This span has been allocated during the evaluation of the multi-function network and contains + * intermediate data. It has to be freed once the network evaluation is finished. */ + GMutableSpan span; + int max_remaining_users; + bool is_single_allocated; + + OwnSingleValue(GMutableSpan span, int max_remaining_users, bool is_single_allocated) + : Value(ValueType::OwnSingle), + span(span), + max_remaining_users(max_remaining_users), + is_single_allocated(is_single_allocated) + { + } +}; + +struct OwnVectorValue : public Value { + /** This vector array has been allocated during the evaluation of the multi-function network and + * contains intermediate data. It has to be freed once the network evaluation is finished. */ + GVectorArray *vector_array; + int max_remaining_users; + + OwnVectorValue(GVectorArray &vector_array, int max_remaining_users) + : Value(ValueType::OwnVector), + vector_array(&vector_array), + max_remaining_users(max_remaining_users) + { + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Storage methods + * \{ */ + +MFNetworkEvaluationStorage::MFNetworkEvaluationStorage(IndexMask mask, uint max_socket_id) + : m_mask(mask), + m_value_per_output_id(max_socket_id + 1, nullptr), + m_min_array_size(mask.min_array_size()) +{ +} + +MFNetworkEvaluationStorage::~MFNetworkEvaluationStorage() +{ + for (Value *any_value : m_value_per_output_id) { + if (any_value == nullptr) { + continue; + } + else if (any_value->type == ValueType::OwnSingle) { + OwnSingleValue *value = (OwnSingleValue *)any_value; + GMutableSpan span = value->span; + const CPPType &type = span.type(); + if (value->is_single_allocated) { + type.destruct(span.buffer()); + } + else { + type.destruct_indices(span.buffer(), m_mask); + MEM_freeN(span.buffer()); + } + } + else if (any_value->type == ValueType::OwnVector) { + OwnVectorValue *value = (OwnVectorValue *)any_value; + delete value->vector_array; + } + } +} + +IndexMask MFNetworkEvaluationStorage::mask() const +{ + return m_mask; +} + +bool MFNetworkEvaluationStorage::socket_is_computed(const MFOutputSocket &socket) +{ + Value *any_value = m_value_per_output_id[socket.id()]; + if (any_value == nullptr) { + return false; + } + if (ELEM(any_value->type, ValueType::OutputSingle, ValueType::OutputVector)) { + return ((OutputValue *)any_value)->is_computed; + } + return true; +} + +bool MFNetworkEvaluationStorage::is_same_value_for_every_index(const MFOutputSocket &socket) +{ + Value *any_value = m_value_per_output_id[socket.id()]; + switch (any_value->type) { + case ValueType::OwnSingle: + return ((OwnSingleValue *)any_value)->span.size() == 1; + case ValueType::OwnVector: + return ((OwnVectorValue *)any_value)->vector_array->size() == 1; + case ValueType::InputSingle: + return ((InputSingleValue *)any_value)->virtual_span.is_single_element(); + case ValueType::InputVector: + return ((InputVectorValue *)any_value)->virtual_array_span.is_single_array(); + case ValueType::OutputSingle: + return ((OutputSingleValue *)any_value)->span.size() == 1; + case ValueType::OutputVector: + return ((OutputVectorValue *)any_value)->vector_array->size() == 1; + } + BLI_assert(false); + return false; +} + +bool MFNetworkEvaluationStorage::socket_has_buffer_for_output(const MFOutputSocket &socket) +{ + Value *any_value = m_value_per_output_id[socket.id()]; + if (any_value == nullptr) { + return false; + } + + BLI_assert(ELEM(any_value->type, ValueType::OutputSingle, ValueType::OutputVector)); + return true; +} + +void MFNetworkEvaluationStorage::finish_node(const MFFunctionNode &node) +{ + for (const MFInputSocket *socket : node.inputs()) { + this->finish_input_socket(*socket); + } + for (const MFOutputSocket *socket : node.outputs()) { + this->finish_output_socket(*socket); + } +} + +void MFNetworkEvaluationStorage::finish_output_socket(const MFOutputSocket &socket) +{ + Value *any_value = m_value_per_output_id[socket.id()]; + if (any_value == nullptr) { + return; + } + + if (ELEM(any_value->type, ValueType::OutputSingle, ValueType::OutputVector)) { + ((OutputValue *)any_value)->is_computed = true; + } +} + +void MFNetworkEvaluationStorage::finish_input_socket(const MFInputSocket &socket) +{ + const MFOutputSocket &origin = *socket.origin(); + + Value *any_value = m_value_per_output_id[origin.id()]; + if (any_value == nullptr) { + /* Can happen when a value has been forward to the next node. */ + return; + } + + switch (any_value->type) { + case ValueType::InputSingle: + case ValueType::OutputSingle: + case ValueType::InputVector: + case ValueType::OutputVector: { + break; + } + case ValueType::OwnSingle: { + OwnSingleValue *value = (OwnSingleValue *)any_value; + BLI_assert(value->max_remaining_users >= 1); + value->max_remaining_users--; + if (value->max_remaining_users == 0) { + GMutableSpan span = value->span; + const CPPType &type = span.type(); + if (value->is_single_allocated) { + type.destruct(span.buffer()); + } + else { + type.destruct_indices(span.buffer(), m_mask); + MEM_freeN(span.buffer()); + } + m_value_per_output_id[origin.id()] = nullptr; + } + break; + } + case ValueType::OwnVector: { + OwnVectorValue *value = (OwnVectorValue *)any_value; + BLI_assert(value->max_remaining_users >= 1); + value->max_remaining_users--; + if (value->max_remaining_users == 0) { + delete value->vector_array; + m_value_per_output_id[origin.id()] = nullptr; + } + break; + } + } +} + +void MFNetworkEvaluationStorage::add_single_input_from_caller(const MFOutputSocket &socket, + GVSpan virtual_span) +{ + BLI_assert(m_value_per_output_id[socket.id()] == nullptr); + BLI_assert(virtual_span.size() >= m_min_array_size); + + auto *value = m_allocator.construct<InputSingleValue>(virtual_span); + m_value_per_output_id[socket.id()] = value; +} + +void MFNetworkEvaluationStorage::add_vector_input_from_caller(const MFOutputSocket &socket, + GVArraySpan virtual_array_span) +{ + BLI_assert(m_value_per_output_id[socket.id()] == nullptr); + BLI_assert(virtual_array_span.size() >= m_min_array_size); + + auto *value = m_allocator.construct<InputVectorValue>(virtual_array_span); + m_value_per_output_id[socket.id()] = value; +} + +void MFNetworkEvaluationStorage::add_single_output_from_caller(const MFOutputSocket &socket, + GMutableSpan span) +{ + BLI_assert(m_value_per_output_id[socket.id()] == nullptr); + BLI_assert(span.size() >= m_min_array_size); + + auto *value = m_allocator.construct<OutputSingleValue>(span); + m_value_per_output_id[socket.id()] = value; +} + +void MFNetworkEvaluationStorage::add_vector_output_from_caller(const MFOutputSocket &socket, + GVectorArray &vector_array) +{ + BLI_assert(m_value_per_output_id[socket.id()] == nullptr); + BLI_assert(vector_array.size() >= m_min_array_size); + + auto *value = m_allocator.construct<OutputVectorValue>(vector_array); + m_value_per_output_id[socket.id()] = value; +} + +GMutableSpan MFNetworkEvaluationStorage::get_single_output__full(const MFOutputSocket &socket) +{ + Value *any_value = m_value_per_output_id[socket.id()]; + if (any_value == nullptr) { + const CPPType &type = socket.data_type().single_type(); + void *buffer = MEM_mallocN_aligned(m_min_array_size * type.size(), type.alignment(), AT); + GMutableSpan span(type, buffer, m_min_array_size); + + auto *value = m_allocator.construct<OwnSingleValue>(span, socket.targets().size(), false); + m_value_per_output_id[socket.id()] = value; + + return span; + } + else { + BLI_assert(any_value->type == ValueType::OutputSingle); + return ((OutputSingleValue *)any_value)->span; + } +} + +GMutableSpan MFNetworkEvaluationStorage::get_single_output__single(const MFOutputSocket &socket) +{ + Value *any_value = m_value_per_output_id[socket.id()]; + if (any_value == nullptr) { + const CPPType &type = socket.data_type().single_type(); + void *buffer = m_allocator.allocate(type.size(), type.alignment()); + GMutableSpan span(type, buffer, 1); + + auto *value = m_allocator.construct<OwnSingleValue>(span, socket.targets().size(), true); + m_value_per_output_id[socket.id()] = value; + + return value->span; + } + else { + BLI_assert(any_value->type == ValueType::OutputSingle); + GMutableSpan span = ((OutputSingleValue *)any_value)->span; + BLI_assert(span.size() == 1); + return span; + } +} + +GVectorArray &MFNetworkEvaluationStorage::get_vector_output__full(const MFOutputSocket &socket) +{ + Value *any_value = m_value_per_output_id[socket.id()]; + if (any_value == nullptr) { + const CPPType &type = socket.data_type().vector_base_type(); + GVectorArray *vector_array = new GVectorArray(type, m_min_array_size); + + auto *value = m_allocator.construct<OwnVectorValue>(*vector_array, socket.targets().size()); + m_value_per_output_id[socket.id()] = value; + + return *value->vector_array; + } + else { + BLI_assert(any_value->type == ValueType::OutputVector); + return *((OutputVectorValue *)any_value)->vector_array; + } +} + +GVectorArray &MFNetworkEvaluationStorage::get_vector_output__single(const MFOutputSocket &socket) +{ + Value *any_value = m_value_per_output_id[socket.id()]; + if (any_value == nullptr) { + const CPPType &type = socket.data_type().vector_base_type(); + GVectorArray *vector_array = new GVectorArray(type, 1); + + auto *value = m_allocator.construct<OwnVectorValue>(*vector_array, socket.targets().size()); + m_value_per_output_id[socket.id()] = value; + + return *value->vector_array; + } + else { + BLI_assert(any_value->type == ValueType::OutputVector); + GVectorArray &vector_array = *((OutputVectorValue *)any_value)->vector_array; + BLI_assert(vector_array.size() == 1); + return vector_array; + } +} + +GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputSocket &input, + const MFOutputSocket &output) +{ + const MFOutputSocket &from = *input.origin(); + const MFOutputSocket &to = output; + const CPPType &type = from.data_type().single_type(); + + Value *from_any_value = m_value_per_output_id[from.id()]; + Value *to_any_value = m_value_per_output_id[to.id()]; + BLI_assert(from_any_value != nullptr); + BLI_assert(type == to.data_type().single_type()); + + if (to_any_value != nullptr) { + BLI_assert(to_any_value->type == ValueType::OutputSingle); + GMutableSpan span = ((OutputSingleValue *)to_any_value)->span; + GVSpan virtual_span = this->get_single_input__full(input); + virtual_span.materialize_to_uninitialized(m_mask, span.buffer()); + return span; + } + + if (from_any_value->type == ValueType::OwnSingle) { + OwnSingleValue *value = (OwnSingleValue *)from_any_value; + if (value->max_remaining_users == 1 && !value->is_single_allocated) { + m_value_per_output_id[to.id()] = value; + m_value_per_output_id[from.id()] = nullptr; + value->max_remaining_users = to.targets().size(); + return value->span; + } + } + + GVSpan virtual_span = this->get_single_input__full(input); + void *new_buffer = MEM_mallocN_aligned(m_min_array_size * type.size(), type.alignment(), AT); + GMutableSpan new_array_ref(type, new_buffer, m_min_array_size); + virtual_span.materialize_to_uninitialized(m_mask, new_array_ref.buffer()); + + OwnSingleValue *new_value = m_allocator.construct<OwnSingleValue>( + new_array_ref, to.targets().size(), false); + m_value_per_output_id[to.id()] = new_value; + return new_array_ref; +} + +GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInputSocket &input, + const MFOutputSocket &output) +{ + const MFOutputSocket &from = *input.origin(); + const MFOutputSocket &to = output; + const CPPType &type = from.data_type().single_type(); + + Value *from_any_value = m_value_per_output_id[from.id()]; + Value *to_any_value = m_value_per_output_id[to.id()]; + BLI_assert(from_any_value != nullptr); + BLI_assert(type == to.data_type().single_type()); + + if (to_any_value != nullptr) { + BLI_assert(to_any_value->type == ValueType::OutputSingle); + GMutableSpan span = ((OutputSingleValue *)to_any_value)->span; + BLI_assert(span.size() == 1); + GVSpan virtual_span = this->get_single_input__single(input); + type.copy_to_uninitialized(virtual_span.as_single_element(), span[0]); + return span; + } + + if (from_any_value->type == ValueType::OwnSingle) { + OwnSingleValue *value = (OwnSingleValue *)from_any_value; + if (value->max_remaining_users == 1) { + m_value_per_output_id[to.id()] = value; + m_value_per_output_id[from.id()] = nullptr; + value->max_remaining_users = to.targets().size(); + BLI_assert(value->span.size() == 1); + return value->span; + } + } + + GVSpan virtual_span = this->get_single_input__single(input); + + void *new_buffer = m_allocator.allocate(type.size(), type.alignment()); + type.copy_to_uninitialized(virtual_span.as_single_element(), new_buffer); + GMutableSpan new_array_ref(type, new_buffer, 1); + + OwnSingleValue *new_value = m_allocator.construct<OwnSingleValue>( + new_array_ref, to.targets().size(), true); + m_value_per_output_id[to.id()] = new_value; + return new_array_ref; +} + +GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInputSocket &input, + const MFOutputSocket &output) +{ + const MFOutputSocket &from = *input.origin(); + const MFOutputSocket &to = output; + const CPPType &base_type = from.data_type().vector_base_type(); + + Value *from_any_value = m_value_per_output_id[from.id()]; + Value *to_any_value = m_value_per_output_id[to.id()]; + BLI_assert(from_any_value != nullptr); + BLI_assert(base_type == to.data_type().vector_base_type()); + + if (to_any_value != nullptr) { + BLI_assert(to_any_value->type == ValueType::OutputVector); + GVectorArray &vector_array = *((OutputVectorValue *)to_any_value)->vector_array; + GVArraySpan virtual_array_span = this->get_vector_input__full(input); + vector_array.extend(m_mask, virtual_array_span); + return vector_array; + } + + if (from_any_value->type == ValueType::OwnVector) { + OwnVectorValue *value = (OwnVectorValue *)from_any_value; + if (value->max_remaining_users == 1) { + m_value_per_output_id[to.id()] = value; + m_value_per_output_id[from.id()] = nullptr; + value->max_remaining_users = to.targets().size(); + return *value->vector_array; + } + } + + GVArraySpan virtual_array_span = this->get_vector_input__full(input); + + GVectorArray *new_vector_array = new GVectorArray(base_type, m_min_array_size); + new_vector_array->extend(m_mask, virtual_array_span); + + OwnVectorValue *new_value = m_allocator.construct<OwnVectorValue>(*new_vector_array, + to.targets().size()); + m_value_per_output_id[to.id()] = new_value; + + return *new_vector_array; +} + +GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInputSocket &input, + const MFOutputSocket &output) +{ + const MFOutputSocket &from = *input.origin(); + const MFOutputSocket &to = output; + const CPPType &base_type = from.data_type().vector_base_type(); + + Value *from_any_value = m_value_per_output_id[from.id()]; + Value *to_any_value = m_value_per_output_id[to.id()]; + BLI_assert(from_any_value != nullptr); + BLI_assert(base_type == to.data_type().vector_base_type()); + + if (to_any_value != nullptr) { + BLI_assert(to_any_value->type == ValueType::OutputVector); + GVectorArray &vector_array = *((OutputVectorValue *)to_any_value)->vector_array; + BLI_assert(vector_array.size() == 1); + GVArraySpan virtual_array_span = this->get_vector_input__single(input); + vector_array.extend(0, virtual_array_span[0]); + return vector_array; + } + + if (from_any_value->type == ValueType::OwnVector) { + OwnVectorValue *value = (OwnVectorValue *)from_any_value; + if (value->max_remaining_users == 1) { + m_value_per_output_id[to.id()] = value; + m_value_per_output_id[from.id()] = nullptr; + value->max_remaining_users = to.targets().size(); + return *value->vector_array; + } + } + + GVArraySpan virtual_array_span = this->get_vector_input__single(input); + + GVectorArray *new_vector_array = new GVectorArray(base_type, 1); + new_vector_array->extend(0, virtual_array_span[0]); + + OwnVectorValue *new_value = m_allocator.construct<OwnVectorValue>(*new_vector_array, + to.targets().size()); + m_value_per_output_id[to.id()] = new_value; + return *new_vector_array; +} + +GVSpan MFNetworkEvaluationStorage::get_single_input__full(const MFInputSocket &socket) +{ + const MFOutputSocket &origin = *socket.origin(); + Value *any_value = m_value_per_output_id[origin.id()]; + BLI_assert(any_value != nullptr); + + if (any_value->type == ValueType::OwnSingle) { + OwnSingleValue *value = (OwnSingleValue *)any_value; + if (value->is_single_allocated) { + return GVSpan::FromSingle(value->span.type(), value->span.buffer(), m_min_array_size); + } + else { + return value->span; + } + } + else if (any_value->type == ValueType::InputSingle) { + InputSingleValue *value = (InputSingleValue *)any_value; + return value->virtual_span; + } + else if (any_value->type == ValueType::OutputSingle) { + OutputSingleValue *value = (OutputSingleValue *)any_value; + BLI_assert(value->is_computed); + return value->span; + } + + BLI_assert(false); + return GVSpan(CPPType::get<float>()); +} + +GVSpan MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket &socket) +{ + const MFOutputSocket &origin = *socket.origin(); + Value *any_value = m_value_per_output_id[origin.id()]; + BLI_assert(any_value != nullptr); + + if (any_value->type == ValueType::OwnSingle) { + OwnSingleValue *value = (OwnSingleValue *)any_value; + BLI_assert(value->span.size() == 1); + return value->span; + } + else if (any_value->type == ValueType::InputSingle) { + InputSingleValue *value = (InputSingleValue *)any_value; + BLI_assert(value->virtual_span.is_single_element()); + return value->virtual_span; + } + else if (any_value->type == ValueType::OutputSingle) { + OutputSingleValue *value = (OutputSingleValue *)any_value; + BLI_assert(value->is_computed); + BLI_assert(value->span.size() == 1); + return value->span; + } + + BLI_assert(false); + return GVSpan(CPPType::get<float>()); +} + +GVArraySpan MFNetworkEvaluationStorage::get_vector_input__full(const MFInputSocket &socket) +{ + const MFOutputSocket &origin = *socket.origin(); + Value *any_value = m_value_per_output_id[origin.id()]; + BLI_assert(any_value != nullptr); + + if (any_value->type == ValueType::OwnVector) { + OwnVectorValue *value = (OwnVectorValue *)any_value; + if (value->vector_array->size() == 1) { + GSpan span = (*value->vector_array)[0]; + return GVArraySpan(span, m_min_array_size); + } + else { + return *value->vector_array; + } + } + else if (any_value->type == ValueType::InputVector) { + InputVectorValue *value = (InputVectorValue *)any_value; + return value->virtual_array_span; + } + else if (any_value->type == ValueType::OutputVector) { + OutputVectorValue *value = (OutputVectorValue *)any_value; + return *value->vector_array; + } + + BLI_assert(false); + return GVArraySpan(CPPType::get<float>()); +} + +GVArraySpan MFNetworkEvaluationStorage::get_vector_input__single(const MFInputSocket &socket) +{ + const MFOutputSocket &origin = *socket.origin(); + Value *any_value = m_value_per_output_id[origin.id()]; + BLI_assert(any_value != nullptr); + + if (any_value->type == ValueType::OwnVector) { + OwnVectorValue *value = (OwnVectorValue *)any_value; + BLI_assert(value->vector_array->size() == 1); + return *value->vector_array; + } + else if (any_value->type == ValueType::InputVector) { + InputVectorValue *value = (InputVectorValue *)any_value; + BLI_assert(value->virtual_array_span.is_single_array()); + return value->virtual_array_span; + } + else if (any_value->type == ValueType::OutputVector) { + OutputVectorValue *value = (OutputVectorValue *)any_value; + BLI_assert(value->vector_array->size() == 1); + return *value->vector_array; + } + + BLI_assert(false); + return GVArraySpan(CPPType::get<float>()); +} + +/** \} */ + +} // namespace fn +} // namespace blender diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt index d3c85b891c6..92aacc74190 100644 --- a/source/blender/gpencil_modifiers/CMakeLists.txt +++ b/source/blender/gpencil_modifiers/CMakeLists.txt @@ -25,11 +25,14 @@ set(INC ../blenfont ../blenkernel ../blenlib + ../blentranslation ../bmesh ../depsgraph + ../editors/include ../makesdna ../makesrna ../render/extern/include + ../windowmanager ../../../intern/eigen ../../../intern/guardedalloc ) @@ -40,6 +43,7 @@ set(INC_SYS set(SRC intern/MOD_gpencil_util.h + intern/MOD_gpencil_ui_common.c intern/MOD_gpencil_util.c intern/MOD_gpencilarmature.c @@ -61,6 +65,7 @@ set(SRC intern/MOD_gpenciltime.c intern/MOD_gpenciltint.c + intern/MOD_gpencil_ui_common.h MOD_gpencil_modifiertypes.h ) diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c new file mode 100644 index 00000000000..c15bef1f748 --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c @@ -0,0 +1,458 @@ +/* This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup modifiers + */ + +#include <string.h> + +#include "BLI_listbase.h" + +#include "MEM_guardedalloc.h" + +#include "BKE_context.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_screen.h" + +#include "DNA_object_force_types.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "ED_object.h" + +#include "BLT_translation.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "MOD_gpencil_ui_common.h" /* Self include */ + +static Object *get_gpencilmodifier_object(const bContext *C) +{ + SpaceProperties *sbuts = CTX_wm_space_properties(C); + if (sbuts != NULL && (sbuts->pinid != NULL) && GS(sbuts->pinid->name) == ID_OB) { + return (Object *)sbuts->pinid; + } + else { + return CTX_data_active_object(C); + } +} + +/** + * Poll function so these modifier panels only show for grease pencil objects. + */ +static bool gpencil_modifier_ui_poll(const bContext *C, PanelType *UNUSED(pt)) +{ + Object *ob = get_gpencilmodifier_object(C); + + return (ob != NULL) && (ob->type == OB_GPENCIL); +} + +/* -------------------------------------------------------------------- */ +/** \name Panel Drag and Drop, Expansion Saving + * \{ */ + +/** + * Move a modifier to the index it's moved to after a drag and drop. + */ +static void gpencil_modifier_reorder(bContext *C, Panel *panel, int new_index) +{ + Object *ob = get_gpencilmodifier_object(C); + + GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, panel->runtime.list_index); + PointerRNA props_ptr; + wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_gpencil_modifier_move_to_index", false); + WM_operator_properties_create_ptr(&props_ptr, ot); + RNA_string_set(&props_ptr, "modifier", md->name); + RNA_int_set(&props_ptr, "index", new_index); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr); + WM_operator_properties_free(&props_ptr); +} + +static short get_gpencil_modifier_expand_flag(const bContext *C, Panel *panel) +{ + Object *ob = get_gpencilmodifier_object(C); + GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, panel->runtime.list_index); + return md->ui_expand_flag; + return 0; +} + +static void set_gpencil_modifier_expand_flag(const bContext *C, Panel *panel, short expand_flag) +{ + Object *ob = get_gpencilmodifier_object(C); + GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, panel->runtime.list_index); + md->ui_expand_flag = expand_flag; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Modifier Panel Layouts + * \{ */ + +void gpencil_modifier_masking_panel_draw(const bContext *C, + Panel *panel, + bool use_material, + bool use_vertex) +{ + uiLayout *row, *col, *sub; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + PointerRNA ob_ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); + + PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data"); + bool has_layer = RNA_string_length(&ptr, "layer") != 0; + + uiLayoutSetPropSep(layout, true); + + col = uiLayoutColumn(layout, true); + row = uiLayoutRow(col, true); + uiItemPointerR(row, &ptr, "layer", &obj_data_ptr, "layers", NULL, ICON_GREASEPENCIL); + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, has_layer); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, &ptr, "invert_layers", 0, "", ICON_ARROW_LEFTRIGHT); + + row = uiLayoutRow(col, true); + uiItemR(row, &ptr, "layer_pass", 0, NULL, ICON_NONE); + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, RNA_int_get(&ptr, "layer_pass") != 0); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, &ptr, "invert_layer_pass", 0, "", ICON_ARROW_LEFTRIGHT); + + if (use_material) { + PointerRNA material_ptr = RNA_pointer_get(&ptr, "material"); + bool has_material = !RNA_pointer_is_null(&material_ptr); + + /* Because the Gpencil modifier material property used to be a string in an earlier version of + * Blender, we need to check if the material is valid and display it differently if so. */ + bool valid = false; + { + if (!has_material) { + valid = true; + } + else { + Material *current_material = material_ptr.data; + Object *ob = ob_ptr.data; + for (int i = 0; i <= ob->totcol; i++) { + Material *mat = BKE_object_material_get(ob, i); + if (mat == current_material) { + valid = true; + break; + } + } + } + } + + col = uiLayoutColumn(layout, true); + row = uiLayoutRow(col, true); + uiLayoutSetRedAlert(row, !valid); + uiItemPointerR(row, + &ptr, + "material", + &obj_data_ptr, + "materials", + NULL, + valid ? ICON_SHADING_TEXTURE : ICON_ERROR); + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, has_material); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, &ptr, "invert_materials", 0, "", ICON_ARROW_LEFTRIGHT); + + row = uiLayoutRow(col, true); + uiItemR(row, &ptr, "pass_index", 0, NULL, ICON_NONE); + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, RNA_int_get(&ptr, "pass_index") != 0); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, &ptr, "invert_material_pass", 0, "", ICON_ARROW_LEFTRIGHT); + } + + if (use_vertex) { + bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; + + row = uiLayoutRow(layout, true); + uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, has_vertex_group); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, &ptr, "invert_vertex", 0, "", ICON_ARROW_LEFTRIGHT); + } +} + +void gpencil_modifier_curve_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiItemR(layout, &ptr, "use_custom_curve", 0, NULL, ICON_NONE); +} + +void gpencil_modifier_curve_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiTemplateCurveMapping(layout, &ptr, "curve", 0, false, false, false, false); +} + +/** + * Draw modifier error message. + */ +void gpencil_modifier_panel_end(uiLayout *layout, PointerRNA *ptr) +{ + GpencilModifierData *md = ptr->data; + if (md->error) { + uiLayout *row = uiLayoutRow(layout, false); + uiItemL(row, IFACE_(md->error), ICON_ERROR); + } +} + +/** + * Gets RNA pointers for the active object and the panel's modifier data. + */ +#define ERROR_LIBDATA_MESSAGE TIP_("External library data") +void gpencil_modifier_panel_get_property_pointers(const bContext *C, + Panel *panel, + PointerRNA *r_ob_ptr, + PointerRNA *r_md_ptr) +{ + Object *ob = get_gpencilmodifier_object(C); + GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, panel->runtime.list_index); + + RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, r_md_ptr); + + if (r_ob_ptr != NULL) { + RNA_pointer_create(&ob->id, &RNA_Object, ob, r_ob_ptr); + } + + uiBlock *block = uiLayoutGetBlock(panel->layout); + UI_block_lock_clear(block); + UI_block_lock_set(block, ob && ID_IS_LINKED(ob), ERROR_LIBDATA_MESSAGE); + + uiLayoutSetContextPointer(panel->layout, "modifier", r_md_ptr); +} + +static void gpencil_modifier_ops_extra_draw(bContext *C, uiLayout *layout, void *md_v) +{ + PointerRNA op_ptr; + uiLayout *row; + GpencilModifierData *md = (GpencilModifierData *)md_v; + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); + + PointerRNA ptr; + Object *ob = get_gpencilmodifier_object(C); + RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, &ptr); + uiLayoutSetContextPointer(layout, "modifier", &ptr); + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + + uiLayoutSetUnitsX(layout, 4.0f); + + /* Apply. */ + if (!(mti->flags & eGpencilModifierTypeFlag_NoApply)) { + uiItemO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"), + ICON_CHECKMARK, + "OBJECT_OT_gpencil_modifier_apply"); + } + + /* Duplicate. */ + uiItemO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Duplicate"), + ICON_DUPLICATE, + "OBJECT_OT_gpencil_modifier_copy"); + + uiItemS(layout); + + /* Move to first. */ + row = uiLayoutColumn(layout, false); + uiItemFullO(row, + "OBJECT_OT_gpencil_modifier_move_to_index", + IFACE_("Move to First"), + ICON_TRIA_UP, + NULL, + WM_OP_INVOKE_DEFAULT, + 0, + &op_ptr); + RNA_int_set(&op_ptr, "index", 0); + if (!md->prev) { + uiLayoutSetEnabled(row, false); + } + + /* Move to last. */ + row = uiLayoutColumn(layout, false); + uiItemFullO(row, + "OBJECT_OT_gpencil_modifier_move_to_index", + IFACE_("Move to Last"), + ICON_TRIA_DOWN, + NULL, + WM_OP_INVOKE_DEFAULT, + 0, + &op_ptr); + RNA_int_set(&op_ptr, "index", BLI_listbase_count(&ob->greasepencil_modifiers) - 1); + if (!md->next) { + uiLayoutSetEnabled(row, false); + } +} + +static void gpencil_modifier_panel_header(const bContext *C, Panel *panel) +{ + uiLayout *row, *sub; + uiLayout *layout = panel->layout; + + Object *ob = get_gpencilmodifier_object(C); + GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, panel->runtime.list_index); + PointerRNA ptr; + RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, &ptr); + uiLayoutSetContextPointer(panel->layout, "modifier", &ptr); + + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); + bool narrow_panel = (panel->sizex < UI_UNIT_X * 9 && panel->sizex != 0); + + /* Modifier Icon. */ + row = uiLayoutRow(layout, false); + if (mti->isDisabled && mti->isDisabled(md, 0)) { + uiLayoutSetRedAlert(row, true); + } + uiItemL(row, "", RNA_struct_ui_icon(ptr.type)); + + /* Modifier name. */ + row = uiLayoutRow(layout, true); + if (!narrow_panel) { + uiItemR(row, &ptr, "name", 0, "", ICON_NONE); + } + else { + uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); + } + + /* Display mode buttons. */ + if (mti->flags & eGpencilModifierTypeFlag_SupportsEditmode) { + sub = uiLayoutRow(row, true); + uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE); + } + uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE); + uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE); + + /* Extra operators. */ + // row = uiLayoutRow(layout, true); + uiItemMenuF(row, "", ICON_DOWNARROW_HLT, gpencil_modifier_ops_extra_draw, md); + + /* Remove button. */ + sub = uiLayoutRow(row, true); + uiLayoutSetEmboss(sub, UI_EMBOSS_NONE); + uiItemO(sub, "", ICON_X, "OBJECT_OT_gpencil_modifier_remove"); + + /* Extra padding. */ + uiItemS(layout); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Modifier Registration Helpers + * \{ */ + +/** + * Create a panel in the context's region + */ +PanelType *gpencil_modifier_panel_register(ARegionType *region_type, + GpencilModifierType type, + PanelDrawFn draw) +{ + + /* Get the name for the modifier's panel. */ + char panel_idname[BKE_ST_MAXNAME]; + BKE_gpencil_modifierType_panel_id(type, panel_idname); + + PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + + strcpy(panel_type->idname, panel_idname); + strcpy(panel_type->label, ""); + strcpy(panel_type->context, "modifier"); + strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + + panel_type->draw_header = gpencil_modifier_panel_header; + panel_type->draw = draw; + panel_type->poll = gpencil_modifier_ui_poll; + + /* Give the panel the special flag that says it was built here and corresponds to a + * modifier rather than a #PanelType. */ + panel_type->flag = PNL_LAYOUT_HEADER_EXPAND | PNL_DRAW_BOX | PNL_INSTANCED; + panel_type->reorder = gpencil_modifier_reorder; + panel_type->get_list_data_expand_flag = get_gpencil_modifier_expand_flag; + panel_type->set_list_data_expand_flag = set_gpencil_modifier_expand_flag; + + BLI_addtail(®ion_type->paneltypes, panel_type); + + return panel_type; +} + +/** + * Add a child panel to the parent. + * + * \note To create the panel type's idname, it appends the \a name argument to the \a parent's + * idname. + */ +PanelType *gpencil_modifier_subpanel_register(ARegionType *region_type, + const char *name, + const char *label, + PanelDrawFn draw_header, + PanelDrawFn draw, + PanelType *parent) +{ + /* Create the subpanel's ID name. */ + char panel_idname[BKE_ST_MAXNAME]; + strcpy(panel_idname, parent->idname); + strcat(panel_idname, "_"); + strcat(panel_idname, name); + + PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + + strcpy(panel_type->idname, panel_idname); + strcpy(panel_type->label, label); + strcpy(panel_type->context, "modifier"); + strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + + panel_type->draw_header = draw_header; + panel_type->draw = draw; + panel_type->poll = gpencil_modifier_ui_poll; + panel_type->flag = (PNL_DEFAULT_CLOSED | PNL_DRAW_BOX); + + BLI_assert(parent != NULL); + strcpy(panel_type->parent_id, parent->idname); + panel_type->parent = parent; + BLI_addtail(&parent->children, BLI_genericNodeN(panel_type)); + BLI_addtail(®ion_type->paneltypes, panel_type); + + return panel_type; +} + +/** \} */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h new file mode 100644 index 00000000000..9c6edb51d63 --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h @@ -0,0 +1,66 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup modifiers + */ + +#ifndef __MOD_UI_COMMON__GPENCIL_H__ +#define __MOD_UI_COMMON__GPENCIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "MOD_gpencil_modifiertypes.h" + +struct ARegionType; +struct bContext; +struct PanelType; +struct uiLayout; +typedef void (*PanelDrawFn)(const bContext *, Panel *); + +void gpencil_modifier_masking_panel_draw(const bContext *C, + Panel *panel, + bool use_material, + bool use_vertex); + +void gpencil_modifier_curve_header_draw(const bContext *C, Panel *panel); +void gpencil_modifier_curve_panel_draw(const bContext *C, Panel *panel); + +void gpencil_modifier_panel_end(struct uiLayout *layout, PointerRNA *ptr); + +void gpencil_modifier_panel_get_property_pointers(const bContext *C, + struct Panel *panel, + struct PointerRNA *r_ob_ptr, + struct PointerRNA *r_ptr); + +PanelType *gpencil_modifier_panel_register(struct ARegionType *region_type, + GpencilModifierType type, + PanelDrawFn draw); + +struct PanelType *gpencil_modifier_subpanel_register(struct ARegionType *region_type, + const char *name, + const char *label, + PanelDrawFn draw_header, + PanelDrawFn draw, + struct PanelType *parent); + +#ifdef __cplusplus +} +#endif + +#endif /* __MOD_UI_COMMON__GPENCIL_H__ */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c index 776e5521179..60c3877b89a 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -28,6 +28,8 @@ #include "BLI_math.h" +#include "BLT_translation.h" + #include "DNA_armature_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" @@ -35,8 +37,10 @@ #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_armature.h" +#include "BKE_context.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" @@ -44,10 +48,17 @@ #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "MEM_guardedalloc.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" #include "DEG_depsgraph.h" @@ -181,6 +192,39 @@ static void foreachObjectLink(GpencilModifierData *md, walk(userData, ob, &mmd->object, IDWALK_CB_NOP); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *sub, *row, *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + PointerRNA ob_ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); + + bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "object", 0, NULL, ICON_NONE); + row = uiLayoutRow(layout, true); + uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, has_vertex_group); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, &ptr, "invert_vertex_group", 0, "", ICON_ARROW_LEFTRIGHT); + + col = uiLayoutColumnWithHeading(layout, true, IFACE_("Bind to")); + uiItemR(col, &ptr, "use_vertex_groups", 0, IFACE_("Vertex Groups"), ICON_NONE); + uiItemR(col, &ptr, "use_bone_envelopes", 0, IFACE_("Bone Envelopes"), ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void panelRegister(ARegionType *region_type) +{ + gpencil_modifier_panel_register(region_type, eGpencilModifierType_Armature, panel_draw); +} + GpencilModifierTypeInfo modifierType_Gpencil_Armature = { /* name */ "Armature", /* structName */ "ArmatureGpencilModifierData", @@ -202,4 +246,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Armature = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index da4c1f71f44..d92721f887f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -35,12 +35,16 @@ #include "BLI_math.h" #include "BLI_rand.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_collection.h" +#include "BKE_context.h" #include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" @@ -51,12 +55,19 @@ #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "BKE_screen.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" typedef struct tmpStrokes { @@ -78,6 +89,9 @@ static void initData(GpencilModifierData *md) gpmd->flag |= GP_ARRAY_USE_RELATIVE; gpmd->seed = 1; gpmd->material = NULL; + + /* Open the first subpanel too, because it's activated by default. */ + md->ui_expand_flag = (1 << 0) | (1 << 1); } static void copyData(const GpencilModifierData *md, GpencilModifierData *target) @@ -330,6 +344,143 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "count", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "replace_material", 0, IFACE_("Material Override"), ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void relative_offset_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiItemR(layout, &ptr, "use_relative_offset", 0, IFACE_("Relative Offset"), ICON_NONE); +} + +static void relative_offset_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiLayout *col = uiLayoutColumn(layout, false); + + uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_relative_offset")); + uiItemR(col, &ptr, "relative_offset", 0, IFACE_("Factor"), ICON_NONE); +} + +static void constant_offset_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiItemR(layout, &ptr, "use_constant_offset", 0, IFACE_("Constant Offset"), ICON_NONE); +} + +static void constant_offset_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiLayout *col = uiLayoutColumn(layout, false); + + uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_constant_offset")); + uiItemR(col, &ptr, "constant_offset", 0, IFACE_("Distance"), ICON_NONE); +} + +/** + * Object offset in a subpanel for consistency with the other offset types. + */ +static void object_offset_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiItemR(layout, &ptr, "use_object_offset", 0, NULL, ICON_NONE); +} + +static void object_offset_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiLayout *col = uiLayoutColumn(layout, false); + + uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_object_offset")); + uiItemR(col, &ptr, "offset_object", 0, NULL, ICON_NONE); +} + +static void random_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "random_offset", 0, IFACE_("Offset"), ICON_NONE); + uiItemR(layout, &ptr, "random_rotation", 0, IFACE_("Rotation"), ICON_NONE); + uiItemR(layout, &ptr, "random_scale", 0, IFACE_("Scale"), ICON_NONE); + uiItemR(layout, &ptr, "seed", 0, NULL, ICON_NONE); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Array, panel_draw); + gpencil_modifier_subpanel_register(region_type, + "relative_offset", + "", + relative_offset_header_draw, + relative_offset_draw, + panel_type); + gpencil_modifier_subpanel_register(region_type, + "constant_offset", + "", + constant_offset_header_draw, + constant_offset_draw, + panel_type); + gpencil_modifier_subpanel_register( + region_type, "object_offset", "", object_offset_header_draw, object_offset_draw, panel_type); + gpencil_modifier_subpanel_register( + region_type, "randomize", "Randomize", NULL, random_panel_draw, panel_type); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Array = { /* name */ "Array", /* structName */ "ArrayGpencilModifierData", @@ -352,4 +503,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Array = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index 71a051629d8..54ed2ffafe1 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -30,20 +30,31 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "BKE_context.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" +#include "BKE_screen.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -537,6 +548,88 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec } } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *row, *sub; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + PointerRNA ob_ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); + + int mode = RNA_enum_get(&ptr, "mode"); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "mode", 0, NULL, ICON_NONE); + if (mode == GP_BUILD_MODE_CONCURRENT) { + uiItemR(layout, &ptr, "concurrent_time_alignment", 0, NULL, ICON_NONE); + } + + uiItemS(layout); + + uiItemR(layout, &ptr, "transition", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "start_delay", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "length", 0, IFACE_("Frames"), ICON_NONE); + + uiItemS(layout); + + row = uiLayoutRowWithHeading(layout, true, IFACE_("Use Factor")); + uiItemR(row, &ptr, "use_percentage", 0, "", ICON_NONE); + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_percentage")); + uiItemR(sub, &ptr, "percentage_factor", 0, "", ICON_NONE); + + /* Check for incompatible time modifier. */ + Object *ob = ob_ptr.data; + GpencilModifierData *md = ptr.data; + if (BKE_gpencil_modifiers_findby_type(ob, eGpencilModifierType_Time) != NULL) { + BKE_gpencil_modifier_set_error(md, "Build and Time Offset modifiers are incompatible"); + } + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void frame_range_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiItemR(layout, &ptr, "use_restrict_frame_range", 0, IFACE_("Custom Range"), ICON_NONE); +} + +static void frame_range_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + col = uiLayoutColumn(layout, false); + uiItemR(col, &ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE); + uiItemR(col, &ptr, "frame_end", 0, IFACE_("End"), ICON_NONE); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, false, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Build, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "frame_range", "", frame_range_header_draw, frame_range_panel_draw, panel_type); + gpencil_modifier_subpanel_register( + region_type, "_mask", "Influence", NULL, mask_panel_draw, panel_type); +} + /* ******************************************** */ GpencilModifierTypeInfo modifierType_Gpencil_Build = { @@ -561,4 +654,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Build = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c index 14125d5c8d4..03137a5cf23 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -29,22 +29,33 @@ #include "BLI_math_color.h" #include "BLI_math_vector.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_screen.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "BKE_modifier.h" +#include "RNA_access.h" #include "DEG_depsgraph.h" #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -186,6 +197,42 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "modify_color", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, &ptr, "saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, &ptr, "value", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Color, panel_draw); + PanelType *mask_panel_type = gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); + gpencil_modifier_subpanel_register(region_type, + "curve", + "", + gpencil_modifier_curve_header_draw, + gpencil_modifier_curve_panel_draw, + mask_panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Color = { /* name */ "Hue/Saturation", /* structName */ "ColorGpencilModifierData", @@ -208,4 +255,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Color = { /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index d39c94e06d5..a0987aafcd2 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -28,15 +28,19 @@ #include "BLI_math.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_action.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" @@ -45,10 +49,17 @@ #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "MEM_guardedalloc.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" #include "DEG_depsgraph.h" @@ -345,6 +356,81 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *sub, *row, *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + PointerRNA ob_ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); + + PointerRNA hook_object_ptr = RNA_pointer_get(&ptr, "object"); + bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; + + uiLayoutSetPropSep(layout, true); + + col = uiLayoutColumn(layout, false); + uiItemR(col, &ptr, "object", 0, NULL, ICON_NONE); + if (!RNA_pointer_is_null(&hook_object_ptr) && + RNA_enum_get(&hook_object_ptr, "type") == OB_ARMATURE) { + PointerRNA hook_object_data_ptr = RNA_pointer_get(&hook_object_ptr, "data"); + uiItemPointerR( + col, &ptr, "subtarget", &hook_object_data_ptr, "bones", IFACE_("Bone"), ICON_NONE); + } + + row = uiLayoutRow(layout, true); + uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, has_vertex_group); + uiLayoutSetPropSep(sub, false); + uiItemR(sub, &ptr, "invert_vertex", 0, "", ICON_ARROW_LEFTRIGHT); + + uiItemR(layout, &ptr, "strength", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void falloff_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *row; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + bool use_falloff = RNA_enum_get(&ptr, "falloff_type") != eWarp_Falloff_None; + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "falloff_type", 0, IFACE_("Type"), ICON_NONE); + + row = uiLayoutRow(layout, false); + uiLayoutSetActive(row, use_falloff); + uiItemR(row, &ptr, "falloff_radius", 0, NULL, ICON_NONE); + + uiItemR(layout, &ptr, "use_falloff_uniform", 0, NULL, ICON_NONE); + + if (RNA_enum_get(&ptr, "falloff_type") == eWarp_Falloff_Curve) { + uiTemplateCurveMapping(layout, &ptr, "falloff_curve", 0, false, false, false, false); + } +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Hook, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "falloff", "Falloff", NULL, falloff_panel_draw, panel_type); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Hook = { /* name */ "Hook", /* structName */ "HookGpencilModifierData", @@ -367,4 +453,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Hook = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index 92b35f390f8..0f5fc4d5cf6 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -26,12 +26,16 @@ #include "BLI_listbase.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" @@ -41,10 +45,17 @@ #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "MEM_guardedalloc.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" #include "DEG_depsgraph.h" @@ -208,6 +219,54 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *sub, *row, *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + PointerRNA ob_ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); + + PointerRNA hook_object_ptr = RNA_pointer_get(&ptr, "object"); + bool has_vertex_group = RNA_string_length(&ptr, "vertex_group") != 0; + + uiLayoutSetPropSep(layout, true); + + col = uiLayoutColumn(layout, false); + uiItemR(col, &ptr, "object", 0, NULL, ICON_NONE); + if (!RNA_pointer_is_null(&hook_object_ptr) && + RNA_enum_get(&hook_object_ptr, "type") == OB_ARMATURE) { + PointerRNA hook_object_data_ptr = RNA_pointer_get(&hook_object_ptr, "data"); + uiItemPointerR( + col, &ptr, "subtarget", &hook_object_data_ptr, "bones", IFACE_("Bone"), ICON_NONE); + } + + row = uiLayoutRow(layout, true); + uiItemPointerR(row, &ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE); + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, has_vertex_group); + uiLayoutSetPropSep(sub, false); + uiItemR(sub, &ptr, "invert_vertex", 0, "", ICON_ARROW_LEFTRIGHT); + + uiItemR(layout, &ptr, "strength", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Lattice, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Lattice = { /* name */ "Lattice", /* structName */ "LatticeGpencilModifierData", @@ -230,4 +289,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Lattice = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index 10f0dd763b1..581eaa886d8 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -28,12 +28,16 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" @@ -43,10 +47,17 @@ #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "MEM_guardedalloc.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" #include "DEG_depsgraph.h" @@ -254,6 +265,40 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *row; + uiLayout *layout = panel->layout; + int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + row = uiLayoutRowWithHeading(layout, true, IFACE_("Axis")); + uiItemR(row, &ptr, "x_axis", toggles_flag, NULL, ICON_NONE); + uiItemR(row, &ptr, "y_axis", toggles_flag, NULL, ICON_NONE); + uiItemR(row, &ptr, "z_axis", toggles_flag, NULL, ICON_NONE); + + uiItemR(layout, &ptr, "object", 0, NULL, ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Mirror, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Mirror = { /* name */ "Mirror", /* structName */ "MirrorGpencilModifierData", @@ -276,4 +321,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Mirror = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c index 22e46626a13..619c37015e4 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c @@ -29,6 +29,7 @@ #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BLI_alloca.h" #include "BLI_blenlib.h" @@ -37,6 +38,8 @@ #include "BLI_rand.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "BKE_collection.h" #include "BKE_context.h" #include "BKE_global.h" @@ -51,6 +54,7 @@ #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "bmesh.h" #include "bmesh_tools.h" @@ -59,7 +63,13 @@ #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -305,8 +315,71 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "duplicates", 0, NULL, ICON_NONE); + + col = uiLayoutColumn(layout, false); + uiLayoutSetActive(layout, RNA_int_get(&ptr, "duplicates") > 0); + uiItemR(col, &ptr, "distance", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "offset", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void fade_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiItemR(layout, &ptr, "use_fade", 0, NULL, ICON_NONE); +} + +static void fade_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiLayoutSetActive(layout, RNA_boolean_get(&ptr, "use_fade")); + + col = uiLayoutColumn(layout, false); + uiItemR(col, &ptr, "fading_center", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "fading_thickness", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, &ptr, "fading_opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Multiply, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "fade", "", fade_header_draw, fade_panel_draw, panel_type); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Multiply = { - /* name */ "Multiple Strokes", + /* name */ "MultipleStrokes", /* structName */ "MultiplyGpencilModifierData", /* structSize */ sizeof(MultiplyGpencilModifierData), /* type */ eGpencilModifierTypeType_Gpencil, @@ -327,4 +400,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Multiply = { /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index 73328d7dd31..812bb5628e1 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -31,6 +31,8 @@ #include "BLI_math_vector.h" #include "BLI_rand.h" +#include "BLT_translation.h" + #include "MEM_guardedalloc.h" #include "DNA_gpencil_modifier_types.h" @@ -38,8 +40,10 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" @@ -47,11 +51,18 @@ #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_object.h" +#include "BKE_screen.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -269,6 +280,72 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + col = uiLayoutColumn(layout, false); + uiItemR(col, &ptr, "factor", 0, IFACE_("Position"), ICON_NONE); + uiItemR(col, &ptr, "factor_strength", 0, IFACE_("Strength"), ICON_NONE); + uiItemR(col, &ptr, "factor_thickness", 0, IFACE_("Thickness"), ICON_NONE); + uiItemR(col, &ptr, "factor_uvs", 0, IFACE_("UV"), ICON_NONE); + uiItemR(col, &ptr, "noise_scale", 0, NULL, ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void random_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiItemR(layout, &ptr, "random", 0, IFACE_("Randomize"), ICON_NONE); +} + +static void random_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiLayoutSetActive(layout, RNA_boolean_get(&ptr, "random")); + + uiItemR(layout, &ptr, "step", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "seed", 0, NULL, ICON_NONE); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Noise, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "randomize", "", random_header_draw, random_panel_draw, panel_type); + PanelType *mask_panel_type = gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); + gpencil_modifier_subpanel_register(region_type, + "curve", + "", + gpencil_modifier_curve_header_draw, + gpencil_modifier_curve_panel_draw, + mask_panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Noise = { /* name */ "Noise", /* structName */ "NoiseGpencilModifierData", @@ -291,4 +368,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Noise = { /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c index 686f589ffe9..9cc3712e8f4 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -28,22 +28,33 @@ #include "BLI_math.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "DEG_depsgraph.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -136,6 +147,35 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "location", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "rotation", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "scale", 0, NULL, ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, true); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Offset, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Offset = { /* name */ "Offset", /* structName */ "OffsetGpencilModifierData", @@ -158,4 +198,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Offset = { /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index 92b2621d211..34142709c18 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -28,13 +28,17 @@ #include "BLI_blenlib.h" #include "BLI_math_vector.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" @@ -42,10 +46,17 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "DEG_depsgraph.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -180,6 +191,7 @@ static void bakeModifier(Main *UNUSED(bmain), } } } + static void freeData(GpencilModifierData *md) { OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; @@ -196,6 +208,79 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + int modify_color = RNA_enum_get(&ptr, "modify_color"); + + uiItemR(layout, &ptr, "modify_color", 0, NULL, ICON_NONE); + + if (modify_color == GP_MODIFY_COLOR_HARDNESS) { + uiItemR(layout, &ptr, "hardness", 0, NULL, ICON_NONE); + } + else { + uiItemR(layout, &ptr, "normalize_opacity", 0, NULL, ICON_NONE); + const char *text = (RNA_boolean_get(&ptr, "normalize_opacity")) ? IFACE_("Strength") : + IFACE_("Opacity Factor"); + uiItemR(layout, &ptr, "hardness", 0, text, ICON_NONE); + } + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + int modify_color = RNA_enum_get(&ptr, "modify_color"); + bool show_vertex = (modify_color != GP_MODIFY_COLOR_HARDNESS); + + gpencil_modifier_masking_panel_draw(C, panel, true, show_vertex); +} + +static void curve_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + int modify_color = RNA_enum_get(&ptr, "modify_color"); + uiLayoutSetActive(layout, modify_color != GP_MODIFY_COLOR_HARDNESS); + + gpencil_modifier_curve_header_draw(C, panel); +} + +static void curve_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + int modify_color = RNA_enum_get(&ptr, "modify_color"); + uiLayoutSetActive(layout, modify_color != GP_MODIFY_COLOR_HARDNESS); + + gpencil_modifier_curve_panel_draw(C, panel); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Opacity, panel_draw); + PanelType *mask_panel_type = gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); + gpencil_modifier_subpanel_register( + region_type, "curve", "", curve_header_draw, curve_panel_draw, mask_panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Opacity = { /* name */ "Opacity", /* structName */ "OpacityGpencilModifierData", @@ -218,4 +303,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Opacity = { /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c index 2cda108682e..8d4556421eb 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c @@ -26,20 +26,31 @@ #include "BLI_listbase.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "DNA_vec_types.h" +#include "BKE_context.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "DEG_depsgraph.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -131,6 +142,48 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + int mode = RNA_enum_get(&ptr, "mode"); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "mode", 0, NULL, ICON_NONE); + + if (mode == GP_SIMPLIFY_FIXED) { + uiItemR(layout, &ptr, "step", 0, NULL, ICON_NONE); + } + else if (mode == GP_SIMPLIFY_ADAPTIVE) { + uiItemR(layout, &ptr, "factor", 0, NULL, ICON_NONE); + } + else if (mode == GP_SIMPLIFY_SAMPLE) { + uiItemR(layout, &ptr, "length", 0, NULL, ICON_NONE); + } + else if (mode == GP_SIMPLIFY_MERGE) { + uiItemR(layout, &ptr, "distance", 0, NULL, ICON_NONE); + } + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Simplify, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Simplify = { /* name */ "Simplify", /* structName */ "SimplifyGpencilModifierData", @@ -153,4 +206,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Simplify = { /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c index e2e13b736e4..175a6d81b1b 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c @@ -26,21 +26,32 @@ #include "BLI_listbase.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "DNA_screen_types.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "DEG_depsgraph.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -174,6 +185,47 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *row; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + row = uiLayoutRow(layout, true); + uiItemR(row, &ptr, "use_edit_position", UI_ITEM_R_TOGGLE, IFACE_("Position"), ICON_NONE); + uiItemR(row, &ptr, "use_edit_strength", UI_ITEM_R_TOGGLE, IFACE_("Stength"), ICON_NONE); + uiItemR(row, &ptr, "use_edit_thickness", UI_ITEM_R_TOGGLE, IFACE_("Thickness"), ICON_NONE); + uiItemR(row, &ptr, "use_edit_uv", UI_ITEM_R_TOGGLE, IFACE_("UV"), ICON_NONE); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "factor", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "step", 0, IFACE_("Repeat"), ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, true); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Smooth, panel_draw); + PanelType *mask_panel_type = gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); + gpencil_modifier_subpanel_register(region_type, + "curve", + "", + gpencil_modifier_curve_header_draw, + gpencil_modifier_curve_panel_draw, + mask_panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Smooth = { /* name */ "Smooth", /* structName */ "SmoothGpencilModifierData", @@ -196,4 +248,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Smooth = { /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c index 072159136ce..2797235c002 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c @@ -28,20 +28,31 @@ #include "BLI_listbase.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "BKE_context.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "DEG_depsgraph.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -112,6 +123,34 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "subdivision_type", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "level", 0, IFACE_("Subdivisions"), ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Subdiv, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = { /* name */ "Subdivide", /* structName */ "SubdivGpencilModifierData", @@ -134,4 +173,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = { /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c index a5adf12b617..2d16b6ead5c 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c @@ -27,23 +27,34 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "DEG_depsgraph.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -147,8 +158,56 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + int mode = RNA_enum_get(&ptr, "mode"); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "mode", 0, NULL, ICON_NONE); + + if (ELEM(mode, STROKE, STROKE_AND_FILL)) { + col = uiLayoutColumn(layout, false); + uiItemR(col, &ptr, "fit_method", 0, IFACE_("Stroke Fit Method"), ICON_NONE); + uiItemR(col, &ptr, "uv_offset", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "uv_scale", 0, IFACE_("Scale"), ICON_NONE); + } + + if (mode == STROKE_AND_FILL) { + uiItemS(layout); + } + + if (ELEM(mode, FILL, STROKE_AND_FILL)) { + col = uiLayoutColumn(layout, false); + uiItemR(col, &ptr, "fill_rotation", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "fill_offset", 0, IFACE_("Offset"), ICON_NONE); + uiItemR(col, &ptr, "fill_scale", 0, IFACE_("Scale"), ICON_NONE); + } + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, true); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Texture, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Texture = { - /* name */ "Texture Mapping", + /* name */ "TextureMapping", /* structName */ "TextureGpencilModifierData", /* structSize */ sizeof(TextureGpencilModifierData), /* type */ eGpencilModifierTypeType_Gpencil, @@ -169,4 +228,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Texture = { /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index b9fadea7fd0..4fa47a592ba 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -27,22 +27,33 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "DEG_depsgraph.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -166,6 +177,46 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "normalize_thickness", 0, NULL, ICON_NONE); + + if (RNA_boolean_get(&ptr, "normalize_thickness")) { + uiItemR(layout, &ptr, "thickness", 0, NULL, ICON_NONE); + } + else { + uiItemR(layout, &ptr, "thickness_factor", 0, NULL, ICON_NONE); + } + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, true); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Thick, panel_draw); + PanelType *mask_panel_type = gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); + gpencil_modifier_subpanel_register(region_type, + "curve", + "", + gpencil_modifier_curve_header_draw, + gpencil_modifier_curve_panel_draw, + mask_panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Thick = { /* name */ "Thickness", /* structName */ "ThickGpencilModifierData", @@ -188,4 +239,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Thick = { /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c index 85400b56cad..49396f56d26 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c @@ -26,20 +26,31 @@ #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" +#include "BKE_screen.h" #include "DEG_depsgraph.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" static void initData(GpencilModifierData *md) @@ -165,8 +176,91 @@ static int remapTime(struct GpencilModifierData *md, return cfra + offset; } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *row, *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + int mode = RNA_enum_get(&ptr, "mode"); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "mode", 0, NULL, ICON_NONE); + + col = uiLayoutColumn(layout, false); + + const char *text = (mode == GP_TIME_MODE_FIX) ? IFACE_("Frame") : IFACE_("Frame Offset"); + uiItemR(col, &ptr, "offset", 0, text, ICON_NONE); + + row = uiLayoutRow(col, false); + uiLayoutSetActive(row, mode != GP_TIME_MODE_FIX); + uiItemR(row, &ptr, "frame_scale", 0, IFACE_("Scale"), ICON_NONE); + + row = uiLayoutRow(layout, false); + uiLayoutSetActive(row, mode != GP_TIME_MODE_FIX); + uiItemR(row, &ptr, "use_keep_loop", 0, NULL, ICON_NONE); + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void custom_range_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + int mode = RNA_enum_get(&ptr, "mode"); + + uiLayoutSetActive(layout, mode != GP_TIME_MODE_FIX); + + uiItemR(layout, &ptr, "use_custom_frame_range", 0, NULL, ICON_NONE); +} + +static void custom_range_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + int mode = RNA_enum_get(&ptr, "mode"); + + uiLayoutSetPropSep(layout, true); + + uiLayoutSetActive( + layout, (mode != GP_TIME_MODE_FIX) && (RNA_boolean_get(&ptr, "use_custom_frame_range"))); + + col = uiLayoutColumn(layout, false); + uiItemR(col, &ptr, "frame_start", 0, IFACE_("Frame Start"), ICON_NONE); + uiItemR(col, &ptr, "frame_end", 0, IFACE_("End"), ICON_NONE); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, false, false); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Time, panel_draw); + gpencil_modifier_subpanel_register(region_type, + "custom_range", + "", + custom_range_header_draw, + custom_range_panel_draw, + panel_type); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Time = { - /* name */ "Time Offset", + /* name */ "TimeOffset", /* structName */ "TimeGpencilModifierData", /* structSize */ sizeof(TimeGpencilModifierData), /* type */ eGpencilModifierTypeType_Gpencil, @@ -187,4 +281,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Time = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index c35728bc8b3..da7d33839f1 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -28,16 +28,20 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLT_translation.h" + #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_action.h" #include "BKE_colorband.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" @@ -47,10 +51,17 @@ #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "MEM_guardedalloc.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" #include "MOD_gpencil_util.h" #include "DEG_depsgraph.h" @@ -330,6 +341,56 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + gpencil_modifier_panel_get_property_pointers(C, panel, NULL, &ptr); + + int tint_type = RNA_enum_get(&ptr, "tint_type"); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "vertex_mode", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "factor", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "tint_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + + if (tint_type == GP_TINT_UNIFORM) { + uiItemR(layout, &ptr, "color", 0, NULL, ICON_NONE); + } + else { + col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, false); + uiTemplateColorRamp(col, &ptr, "colors", true); + uiItemS(layout); + uiItemR(layout, &ptr, "object", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "radius", 0, NULL, ICON_NONE); + } + + gpencil_modifier_panel_end(layout, &ptr); +} + +static void mask_panel_draw(const bContext *C, Panel *panel) +{ + gpencil_modifier_masking_panel_draw(C, panel, true, true); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Tint, panel_draw); + PanelType *mask_panel_type = gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); + gpencil_modifier_subpanel_register(region_type, + "curve", + "", + gpencil_modifier_curve_header_draw, + gpencil_modifier_curve_panel_draw, + mask_panel_type); +} + GpencilModifierTypeInfo modifierType_Gpencil_Tint = { /* name */ "Tint", /* structName */ "TintGpencilModifierData", @@ -352,4 +413,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 1d6a5031d7e..0f7e804de9e 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -210,6 +210,7 @@ data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_ data_to_c_simple(shaders/gpu_shader_2D_edituvs_points_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_edituvs_facedots_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_edituvs_edges_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_edituvs_edges_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_edituvs_faces_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_edituvs_stretch_vert.glsl SRC) diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index ab16bfc43c4..41a29a4d45d 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -37,6 +37,7 @@ struct DMFlagMat; struct GSet; struct MLoop; struct MLoopCol; +struct MPropCol; struct MLoopTri; struct MPoly; struct MVert; @@ -82,6 +83,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const int *sculpt_face_sets, const int face_sets_color_seed, const int face_sets_color_default, + const struct MPropCol *vtcol, const int update_flags); void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index ab507d852e8..1cd5c4d519e 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -86,7 +86,7 @@ void GPU_create_smoke_coba_field(struct FluidModifierData *mmd); void GPU_create_smoke_velocity(struct FluidModifierData *mmd); /* Delayed free of OpenGL buffers by main thread */ -void GPU_free_unused_buffers(struct Main *bmain); +void GPU_free_unused_buffers(void); #ifdef __cplusplus } diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h index fe45ec7b78b..f9bdf726930 100644 --- a/source/blender/gpu/GPU_vertex_buffer.h +++ b/source/blender/gpu/GPU_vertex_buffer.h @@ -80,6 +80,8 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *, const GPUVertFormat *, GPUUsa #define GPU_vertbuf_init_with_format(verts, format) \ GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_STATIC) +GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts); + uint GPU_vertbuf_size_get(const GPUVertBuf *); void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len); void GPU_vertbuf_data_resize(GPUVertBuf *, uint v_len); diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h index 61b14a4c5c0..34bfbb27823 100644 --- a/source/blender/gpu/GPU_vertex_format.h +++ b/source/blender/gpu/GPU_vertex_format.h @@ -124,6 +124,10 @@ BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format, return format->names + attr->names[n_idx]; } +/* WARNING: Can only rename using a string with same character count. + * WARNING: This removes all other aliases of this attrib */ +void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr, const char *new_name); + void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len); /* format conversion */ diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index cef90d57ef5..9c21f9040da 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -34,6 +34,7 @@ #include "BLI_hash.h" #include "BLI_math.h" #include "BLI_math_color.h" +#include "BLI_math_color_blend.h" #include "BLI_utildefines.h" #include "DNA_meshdata_types.h" @@ -227,12 +228,13 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const int *sculpt_face_sets, const int face_sets_color_seed, const int face_sets_color_default, + const MPropCol *vtcol, const int update_flags) { const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - const bool show_vcol = vcol && (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; const bool show_face_sets = sculpt_face_sets && (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0; + const bool show_vcol = (vcol || vtcol) && (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; bool empty_mask = true; bool default_face_set = true; @@ -244,8 +246,8 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, GPUVertBufRaw pos_step = {0}; GPUVertBufRaw nor_step = {0}; GPUVertBufRaw msk_step = {0}; - GPUVertBufRaw col_step = {0}; GPUVertBufRaw fset_step = {0}; + GPUVertBufRaw col_step = {0}; GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step); GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step); @@ -312,25 +314,33 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, *(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask; empty_mask = empty_mask && (cmask == 0); - + /* Vertex Colors. */ if (show_vcol) { - const uint loop_index = lt->tri[j]; - const MLoopCol *mcol = &vcol[loop_index]; - ushort scol[4]; - scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); - scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); - scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); - scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); - memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); + ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; + if (vtcol) { + scol[0] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[0]); + scol[1] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[1]); + scol[2] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[2]); + scol[3] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[3]); + memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); + } + else { + const uint loop_index = lt->tri[j]; + const MLoopCol *mcol = &vcol[loop_index]; + scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); + scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); + scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); + scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); + memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); + } } - /* Face Sets. */ memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar) * 3); } } - - gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); } + + gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); } /* Get material index from the first face of this buffer. */ diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index b03b0fc0b1e..f07e3ed70d7 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -60,7 +60,8 @@ #include "PIL_time.h" -static void gpu_free_image_immediate(Image *ima); +static void gpu_free_image(Image *ima, const bool immediate); +static void gpu_free_unused_buffers(void); //* Checking powers of two for images since OpenGL ES requires it */ #ifdef WITH_DDS @@ -859,9 +860,13 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, return NULL; } + /* Free any unused GPU textures, since we know we are in a thread with OpenGL + * context and might as well ensure we have as much space free as possible. */ + gpu_free_unused_buffers(); + /* currently, gpu refresh tagging is used by ima sequences */ if (ima->gpuflag & IMA_GPU_REFRESH) { - gpu_free_image_immediate(ima); + gpu_free_image(ima, true); ima->gpuflag &= ~IMA_GPU_REFRESH; } @@ -1338,63 +1343,65 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i #endif } -static LinkNode *image_free_queue = NULL; -static ThreadMutex img_queue_mutex = BLI_MUTEX_INITIALIZER; +/* Delayed GPU texture free. Image datablocks can be deleted by any thread, + * but there may not be any active OpenGL context. In that case we push them + * into a queue and free the buffers later. */ +static LinkNode *gpu_texture_free_queue = NULL; +static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER; -static void gpu_queue_image_for_free(Image *ima) +static void gpu_free_unused_buffers() { - BLI_mutex_lock(&img_queue_mutex); - BLI_linklist_prepend(&image_free_queue, ima); - BLI_mutex_unlock(&img_queue_mutex); -} - -void GPU_free_unused_buffers(Main *bmain) -{ - if (!BLI_thread_is_main()) { + if (gpu_texture_free_queue == NULL) { return; } - BLI_mutex_lock(&img_queue_mutex); - - /* images */ - for (LinkNode *node = image_free_queue; node; node = node->next) { - Image *ima = node->link; + BLI_mutex_lock(&gpu_texture_queue_mutex); - /* check in case it was freed in the meantime */ - if (bmain && BLI_findindex(&bmain->images, ima) != -1) { - GPU_free_image(ima); + if (gpu_texture_free_queue != NULL) { + for (LinkNode *node = gpu_texture_free_queue; node; node = node->next) { + GPUTexture *tex = node->link; + GPU_texture_free(tex); } - } - BLI_linklist_free(image_free_queue, NULL); - image_free_queue = NULL; + BLI_linklist_free(gpu_texture_free_queue, NULL); + gpu_texture_free_queue = NULL; + } - BLI_mutex_unlock(&img_queue_mutex); + BLI_mutex_unlock(&gpu_texture_queue_mutex); } -static void gpu_free_image_immediate(Image *ima) +static void gpu_free_image(Image *ima, const bool immediate) { for (int eye = 0; eye < 2; eye++) { for (int i = 0; i < TEXTARGET_COUNT; i++) { - /* free glsl image binding */ if (ima->gputexture[i][eye] != NULL) { - GPU_texture_free(ima->gputexture[i][eye]); + if (immediate) { + GPU_texture_free(ima->gputexture[i][eye]); + } + else { + BLI_mutex_lock(&gpu_texture_queue_mutex); + BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]); + BLI_mutex_unlock(&gpu_texture_queue_mutex); + } + ima->gputexture[i][eye] = NULL; } } } - ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE); + ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE; } -void GPU_free_image(Image *ima) +void GPU_free_unused_buffers() { - if (!BLI_thread_is_main()) { - gpu_queue_image_for_free(ima); - return; + if (BLI_thread_is_main()) { + gpu_free_unused_buffers(); } +} - gpu_free_image_immediate(ima); +void GPU_free_image(Image *ima) +{ + gpu_free_image(ima, BLI_thread_is_main()); } void GPU_free_images(Main *bmain) diff --git a/source/blender/gpu/intern/gpu_draw_smoke.c b/source/blender/gpu/intern/gpu_draw_smoke.c index 80c59ed47c9..67947df0ff7 100644 --- a/source/blender/gpu/intern/gpu_draw_smoke.c +++ b/source/blender/gpu/intern/gpu_draw_smoke.c @@ -99,6 +99,7 @@ static void create_color_ramp(const struct ColorBand *coba, float *data) { for (int i = 0; i < TFUNC_WIDTH; i++) { BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); + straight_to_premul_v4(&data[i * 4]); } } @@ -115,7 +116,7 @@ static GPUTexture *create_transfer_function(int type, const struct ColorBand *co break; } - GPUTexture *tex = GPU_texture_create_1d(TFUNC_WIDTH, GPU_RGBA8, data, NULL); + GPUTexture *tex = GPU_texture_create_1d(TFUNC_WIDTH, GPU_SRGB8_A8, data, NULL); MEM_freeN(data); diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index ab55fcfb1e0..fbeb2edc266 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -71,7 +71,7 @@ static struct GPUGlobal { int samples_color_texture_max; float line_width_range[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers - * calculate dfdy in shader differently when drawing to an offscreen buffer. First + * calculate dfdy in shader differently when drawing to an off-screen buffer. First * number is factor on screen and second is off-screen */ float dfdyfactors[2]; float max_anisotropy; @@ -84,9 +84,9 @@ static struct GPUGlobal { * GL_TEXTURE_MAX_LEVEL is higher than the target mip. * We need a workaround in this cases. */ bool mip_render_workaround; - /* There is an issue with the glBlitFramebuffer on MacOS with radeon pro graphics. - * Blitting depth with GL_DEPTH24_STENCIL8 is buggy so the workaround is to use - * GPU_DEPTH32F_STENCIL8. Then Blitting depth will work but blitting stencil will + /* There is an issue with the #glBlitFramebuffer on MacOS with radeon pro graphics. + * Blitting depth with#GL_DEPTH24_STENCIL8 is buggy so the workaround is to use + * #GPU_DEPTH32F_STENCIL8. Then Blitting depth will work but blitting stencil will * still be broken. */ bool depth_blitting_workaround; /* Crappy driver don't know how to map framebuffer slot to output vars... @@ -96,7 +96,7 @@ static struct GPUGlobal { /* Some crappy Intel drivers don't work well with shaders created in different * rendering contexts. */ bool context_local_shaders_workaround; - /* Intel drivers exhibit artifacts when using glCopyImageSubData & workbench antialiasing. + /* Intel drivers exhibit artifacts when using #glCopyImageSubData & workbench anti-aliasing. * (see T76273) */ bool texture_copy_workaround; } GG = {1, 0}; @@ -288,6 +288,19 @@ void gpu_extensions_init(void) } } + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) && + strstr(renderer, "AMD VERDE")) { + /* We have issues with this specific renderer. (see T74024) */ + GG.unused_fb_slot_workaround = true; + GG.broken_amd_driver = true; + } + + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) && + strstr(version, "Mesa 19.3.4")) { + /* Fix slowdown on this particular driver. (see T77641) */ + GG.broken_amd_driver = true; + } + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) { if (strstr(renderer, "AMD Radeon Pro") || strstr(renderer, "AMD Radeon R9") || strstr(renderer, "AMD Radeon RX")) { diff --git a/source/blender/gpu/intern/gpu_platform.c b/source/blender/gpu/intern/gpu_platform.c index a758787466f..5cabde61bc3 100644 --- a/source/blender/gpu/intern/gpu_platform.c +++ b/source/blender/gpu/intern/gpu_platform.c @@ -44,6 +44,8 @@ static struct GPUPlatformGlobal { char *gpu_name; } GPG = {false}; +/* Remove this? */ +#if 0 typedef struct GPUPlatformSupportTest { eGPUSupportLevel support_level; eGPUDeviceType device; @@ -53,6 +55,7 @@ typedef struct GPUPlatformSupportTest { const char *renderer; const char *version; } GPUPlatformSupportTest; +#endif eGPUSupportLevel GPU_platform_support_level(void) { diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 8c03567b95f..711147a61e9 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -117,6 +117,7 @@ extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_ve extern char datatoc_gpu_shader_2D_edituvs_points_vert_glsl[]; extern char datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl[]; extern char datatoc_gpu_shader_2D_edituvs_edges_vert_glsl[]; +extern char datatoc_gpu_shader_2D_edituvs_edges_frag_glsl[]; extern char datatoc_gpu_shader_2D_edituvs_faces_vert_glsl[]; extern char datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl[]; @@ -1171,12 +1172,12 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { [GPU_SHADER_2D_UV_EDGES] = { .vert = datatoc_gpu_shader_2D_edituvs_edges_vert_glsl, - .frag = datatoc_gpu_shader_flat_color_frag_glsl, + .frag = datatoc_gpu_shader_2D_edituvs_edges_frag_glsl, }, [GPU_SHADER_2D_UV_EDGES_SMOOTH] = { .vert = datatoc_gpu_shader_2D_edituvs_edges_vert_glsl, - .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl, + .frag = datatoc_gpu_shader_2D_edituvs_edges_frag_glsl, .defs = "#define SMOOTH_COLOR\n", }, [GPU_SHADER_2D_UV_FACES] = diff --git a/source/blender/gpu/intern/gpu_state.c b/source/blender/gpu/intern/gpu_state.c index 908f5fa5771..30b258a73d1 100644 --- a/source/blender/gpu/intern/gpu_state.c +++ b/source/blender/gpu/intern/gpu_state.c @@ -208,7 +208,7 @@ typedef struct { uint is_cull_face : 1; uint is_depth_test : 1; uint is_dither : 1; - uint is_lighting : 1; + /* uint is_lighting : 1; */ /* UNUSED */ uint is_line_smooth : 1; uint is_color_logic_op : 1; uint is_multisample : 1; diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index a985d45162c..56e82b94fd2 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -677,12 +677,14 @@ static bool gpu_texture_check_capacity( GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum data_format, GLenum data_type) { if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_ANY) || + GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_MAC, GPU_DRIVER_OFFICIAL) || GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OFFICIAL)) { /* Some AMD drivers have a faulty `GL_PROXY_TEXTURE_..` check. * (see T55888, T56185, T59351). * Checking with `GL_PROXY_TEXTURE_..` doesn't prevent `Out Of Memory` issue, * it just states that the OGL implementation can support the texture. - * So manually check the maximum size and maximum number of layers. */ + * So manually check the maximum size and maximum number of layers. + * Same thing happens on Nvidia/macOS 10.15 (T78175). */ switch (proxy) { case GL_PROXY_TEXTURE_2D_ARRAY: if ((tex->d < 0) || (tex->d > GPU_max_texture_layers())) { @@ -1772,8 +1774,13 @@ void GPU_texture_unbind(GPUTexture *tex) void GPU_texture_unbind_all(void) { if (GLEW_ARB_multi_bind) { - glBindTextures(0, GPU_max_textures(), NULL); - glBindSamplers(0, GPU_max_textures(), NULL); + /* Some drivers crash because of the NULL array even if that's explicitly + * allowed by the spec... *sigh* (see T77549). */ + GLuint texs[32] = {0}; + int count = min_ii(32, GPU_max_textures()); + + glBindTextures(0, count, texs); + glBindSamplers(0, count, texs); return; } diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c index 25daabe601d..3b4d469542c 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer.c +++ b/source/blender/gpu/intern/gpu_vertex_buffer.c @@ -85,6 +85,35 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts, } } +GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts) +{ + GPUVertBuf *verts_dst = GPU_vertbuf_create(GPU_USAGE_STATIC); + /* Full copy. */ + *verts_dst = *verts; + GPU_vertformat_copy(&verts_dst->format, &verts->format); + + if (verts->vbo_id) { + uint buffer_sz = GPU_vertbuf_size_get(verts); + + verts_dst->vbo_id = GPU_buf_alloc(); + + glBindBuffer(GL_COPY_READ_BUFFER, verts->vbo_id); + glBindBuffer(GL_COPY_WRITE_BUFFER, verts_dst->vbo_id); + + glBufferData(GL_COPY_WRITE_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); + + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, buffer_sz); +#if VRAM_USAGE + vbo_memory_usage += GPU_vertbuf_size_get(verts); +#endif + } + + if (verts->data) { + verts_dst->data = MEM_dupallocN(verts->data); + } + return verts_dst; +} + /** Same as discard but does not free. */ void GPU_vertbuf_clear(GPUVertBuf *verts) { diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c index b84a7e0f554..585a22277b2 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.c +++ b/source/blender/gpu/intern/gpu_vertex_format.c @@ -262,6 +262,20 @@ int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name) return -1; } +void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr_id, const char *new_name) +{ + BLI_assert(attr_id > -1 && attr_id < format->attr_len); + GPUVertAttr *attr = &format->attrs[attr_id]; + char *attr_name = (char *)GPU_vertformat_attr_name_get(format, attr, 0); + BLI_assert(strlen(attr_name) == strlen(new_name)); + int i = 0; + while (attr_name[i] != '\0') { + attr_name[i] = new_name[i]; + i++; + } + attr->name_len = 1; +} + /* Encode 8 original bytes into 11 safe bytes. */ static void safe_bytes(char out[11], const char data[8]) { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl new file mode 100644 index 00000000000..108fc85c4a5 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl @@ -0,0 +1,30 @@ + + +uniform float dashWidth; + +#ifdef SMOOTH_COLOR +noperspective in vec4 finalColor; +#else +flat in vec4 finalColor; +#endif + +noperspective in vec2 stipple_pos; +flat in vec2 stipple_start; + +out vec4 fragColor; + +void main() +{ + fragColor = finalColor; + + /* Avoid passing viewport size */ + vec2 dd = fwidth(stipple_pos); + + float dist = distance(stipple_start, stipple_pos) / max(dd.x, dd.y); + + if (fract(dist / dashWidth) > 0.5) { + fragColor.rgb = vec3(0.0); + } + + fragColor = blender_srgb_to_framebuffer_space(fragColor); +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl index 02bbe545436..69fe5c93a61 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl @@ -12,6 +12,9 @@ noperspective out vec4 finalColor; flat out vec4 finalColor; #endif +noperspective out vec2 stipple_pos; +flat out vec2 stipple_start; + /* TODO: Port drawing to draw manager and * remove constants duplications. */ #define VERT_UV_SELECT (1 << 3) @@ -28,5 +31,8 @@ void main() gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); gl_Position.z = float(!is_select); + /* Avoid precision loss. */ + stipple_start = stipple_pos = 500.0 + 500.0 * (gl_Position.xy / gl_Position.w); + finalColor = (is_select) ? selectColor : edgeColor; } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl index bdc87baf924..21c7f79a57c 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl @@ -1,11 +1,67 @@ uniform vec3 checkerColorAndSize; -noperspective in vec4 finalColor; +noperspective in vec2 uvInterp; noperspective in float butCo; flat in float discardFac; +flat in float shadeTri; +flat in vec2 outRectSize; +flat in vec4 outRoundCorners; +noperspective in vec4 innerColor; +flat in vec4 borderColor; +flat in vec4 embossColor; +flat in float lineWidth; out vec4 fragColor; +vec3 compute_masks(vec2 uv) +{ + bool upper_half = uv.y > outRectSize.y * 0.5; + bool right_half = uv.x > outRectSize.x * 0.5; + float corner_rad; + + /* Correct aspect ratio for 2D views not using uniform scalling. + * uv is already in pixel space so a uniform scale should give us a ratio of 1. */ + float ratio = (butCo != -2.0) ? (dFdy(uv.y) / dFdx(uv.x)) : 1.0; + vec2 uv_sdf = uv; + uv_sdf.x *= ratio; + + if (right_half) { + uv_sdf.x = outRectSize.x * ratio - uv_sdf.x; + } + if (upper_half) { + uv_sdf.y = outRectSize.y - uv_sdf.y; + corner_rad = right_half ? outRoundCorners.z : outRoundCorners.w; + } + else { + corner_rad = right_half ? outRoundCorners.y : outRoundCorners.x; + } + + /* Signed distance field from the corner (in pixel). + * inner_sdf is sharp and outer_sdf is rounded. */ + uv_sdf -= corner_rad; + float inner_sdf = max(0.0, min(uv_sdf.x, uv_sdf.y)); + float outer_sdf = -length(min(uv_sdf, 0.0)); + float sdf = inner_sdf + outer_sdf + corner_rad; + + /* Fade emboss at the border. */ + float emboss_size = clamp((upper_half) ? 0.0 : (uv.x / corner_rad), 0.0, 1.0); + + /* Clamp line width to be at least 1px wide. This can happen if the projection matrix + * has been scaled (i.e: Node editor)... */ + float line_width = (lineWidth > 0.0) ? max(fwidth(uv.y), lineWidth) : 0.0; + + const float aa_radius = 0.5; + vec3 masks; + masks.x = smoothstep(-aa_radius, aa_radius, sdf); + masks.y = smoothstep(-aa_radius, aa_radius, sdf - line_width); + masks.z = smoothstep(-aa_radius, aa_radius, sdf + line_width * emboss_size); + + /* Compose masks together to avoid having too much alpha. */ + masks.zx = max(vec2(0.0), masks.zx - masks.xy); + + return masks; +} + vec4 do_checkerboard() { float size = checkerColorAndSize.z; @@ -25,16 +81,32 @@ void main() discard; } - fragColor = finalColor; - - if (butCo > 0.5) { - vec4 checker = do_checkerboard(); - fragColor = mix(checker, fragColor, fragColor.a); - } + vec3 masks = compute_masks(uvInterp); if (butCo > 0.0) { + /* Alpha checker widget. */ + if (butCo > 0.5) { + vec4 checker = do_checkerboard(); + fragColor = mix(checker, innerColor, innerColor.a); + } + else { + /* Set alpha to 1.0. */ + fragColor = innerColor; + } fragColor.a = 1.0; } + else { + /* Premultiply here. */ + fragColor = innerColor * vec4(innerColor.aaa, 1.0); + } + fragColor *= masks.y; + fragColor += masks.x * borderColor; + fragColor += masks.z * embossColor; + + /* Un-premult because the blend equation is already doing the mult. */ + if (fragColor.a > 0.0) { + fragColor.rgb /= fragColor.a; + } fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl index d7cc851556b..2fd5effccce 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl @@ -1,127 +1,7 @@ -#define BIT_RANGE(x) uint((1 << x) - 1) - -/* 2 bits for corner */ -/* Attention! Not the same order as in UI_interface.h! - * Ordered by drawing order. */ -#define BOTTOM_LEFT 0u -#define BOTTOM_RIGHT 1u -#define TOP_RIGHT 2u -#define TOP_LEFT 3u -#define CNR_FLAG_RANGE BIT_RANGE(2) - -/* 4bits for corner id */ -#define CORNER_VEC_OFS 2u -#define CORNER_VEC_RANGE BIT_RANGE(4) -const vec2 cornervec[9] = vec2[9](vec2(0.0, 1.0), - vec2(0.02, 0.805), - vec2(0.067, 0.617), - vec2(0.169, 0.45), - vec2(0.293, 0.293), - vec2(0.45, 0.169), - vec2(0.617, 0.076), - vec2(0.805, 0.02), - vec2(1.0, 0.0)); - -/* 4bits for jitter id */ -#define JIT_OFS 6u -#define JIT_RANGE BIT_RANGE(4) -const vec2 jit[9] = vec2[9](vec2(0.468813, -0.481430), - vec2(-0.155755, -0.352820), - vec2(0.219306, -0.238501), - vec2(-0.393286, -0.110949), - vec2(-0.024699, 0.013908), - vec2(0.343805, 0.147431), - vec2(-0.272855, 0.269918), - vec2(0.095909, 0.388710), - vec2(0.0, 0.0)); - -/* 2bits for other flags */ -#define INNER_FLAG uint(1 << 10) /* is inner vert */ -#define EMBOSS_FLAG uint(1 << 11) /* is emboss vert */ - -/* 2bits for color */ -#define COLOR_OFS 12u -#define COLOR_RANGE BIT_RANGE(2) -#define COLOR_INNER 0u -#define COLOR_EDGE 1u -#define COLOR_EMBOSS 2u - -/* 2bits for trias type */ -#define TRIA_FLAG uint(1 << 14) /* is tria vert */ -#define TRIA_FIRST INNER_FLAG /* is first tria (reuse INNER_FLAG) */ - -/* We can reuse the CORNER_* bits for tria */ -#define TRIA_VEC_RANGE BIT_RANGE(6) - -/* Some GPUs have performanse issues with this array being const (Doesn't fit in the registers?). - * To resolve this issue, store the array as a uniform buffer. - * (The array is still stored in the registry, but indexing is done in the uniform buffer.) */ -uniform vec2 triavec[43] = vec2[43]( - - /* ROUNDBOX_TRIA_ARROWS */ - vec2(-0.170000, 0.400000), - vec2(-0.050000, 0.520000), - vec2(0.250000, 0.000000), - vec2(0.470000, -0.000000), - vec2(-0.170000, -0.400000), - vec2(-0.050000, -0.520000), - vec2(0.170000, 0.400000), - vec2(0.050000, 0.520000), - vec2(-0.250000, 0.000000), - vec2(-0.470000, -0.000000), - vec2(0.170000, -0.400000), - vec2(0.050000, -0.520000), - - /* ROUNDBOX_TRIA_SCROLL - circle tria (triangle strip) */ - vec2(0.000000, 1.000000), - vec2(0.382684, 0.923879), - vec2(-0.382683, 0.923880), - vec2(0.707107, 0.707107), - vec2(-0.707107, 0.707107), - vec2(0.923879, 0.382684), - vec2(-0.923879, 0.382684), - vec2(1.000000, 0.000000), - vec2(-1.000000, 0.000000), - vec2(0.923879, -0.382684), - vec2(-0.923879, -0.382684), - vec2(0.707107, -0.707107), - vec2(-0.707107, -0.707107), - vec2(0.382684, -0.923879), - vec2(-0.382683, -0.923880), - vec2(0.000000, -1.000000), - - /* ROUNDBOX_TRIA_MENU - menu arrows */ - vec2(-0.51, 0.07), - vec2(-0.4, 0.18), - vec2(-0.05, -0.39), - vec2(-0.05, -0.17), - vec2(0.41, 0.07), - vec2(0.3, 0.18), - - /* ROUNDBOX_TRIA_CHECK - check mark */ - vec2(-0.67000, 0.020000), - vec2(-0.500000, 0.190000), - vec2(-0.130000, -0.520000), - vec2(-0.130000, -0.170000), - vec2(0.720000, 0.430000), - vec2(0.530000, 0.590000), - -/* ROUNDBOX_TRIA_HOLD_ACTION_ARROW - hold action arrows */ -#define OX (-0.32) -#define OY (0.1) -#define SC (0.35 * 2) - // vec2(-0.5 + SC, 1.0 + OY), vec2( 0.5, 1.0 + OY), vec2( 0.5, 0.0 + OY + SC), - vec2((0.5 - SC) + OX, 1.0 + OY), - vec2(-0.5 + OX, 1.0 + OY), - vec2(-0.5 + OX, SC + OY) -#undef OX -#undef OY -#undef SC -); uniform mat4 ModelViewProjectionMatrix; -#define MAX_PARAM 11 +#define MAX_PARAM 12 #ifdef USE_INSTANCE # define MAX_INSTANCE 6 uniform vec4 parameters[MAX_PARAM * MAX_INSTANCE]; @@ -147,105 +27,152 @@ uniform vec4 parameters[MAX_PARAM]; #define tria2Size parameters[gl_InstanceID * MAX_PARAM + 10].y #define shadeDir parameters[gl_InstanceID * MAX_PARAM + 10].z #define alphaDiscard parameters[gl_InstanceID * MAX_PARAM + 10].w +#define triaType parameters[gl_InstanceID * MAX_PARAM + 11].x /* We encode alpha check and discard factor together. */ #define doAlphaCheck (alphaDiscard < 0.0) #define discardFactor abs(alphaDiscard) -in uint vflag; - -noperspective out vec4 finalColor; +noperspective out vec2 uvInterp; +flat out vec2 outRectSize; +flat out vec4 outRoundCorners; +noperspective out vec4 innerColor; +flat out vec4 borderColor; +flat out vec4 embossColor; +flat out float lineWidth; noperspective out float butCo; flat out float discardFac; vec2 do_widget(void) { - uint cflag = vflag & CNR_FLAG_RANGE; - uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE; - bool is_inner = (vflag & INNER_FLAG) != 0u; - - vec2 v = cornervec[vofs]; - /* Scale by corner radius */ - v *= roundCorners[cflag] * ((is_inner) ? radsi : rads); - /* Flip in the right direction and osition to corner */ - vec4 rct = (is_inner) ? recti : rect; - if (cflag == BOTTOM_LEFT) { - v += rct.xz; - } - else if (cflag == BOTTOM_RIGHT) { - v = vec2(-v.y, v.x); - v += rct.yz; + lineWidth = abs(rect.x - recti.x); + vec2 emboss_ofs = vec2(0.0, -lineWidth); + vec2 v_pos[4] = vec2[4](rect.xz + emboss_ofs, rect.xw, rect.yz + emboss_ofs, rect.yw); + vec2 pos = v_pos[gl_VertexID]; + + uvInterp = pos - rect.xz; + outRectSize = rect.yw - rect.xz; + outRoundCorners = rads * roundCorners; + + vec2 uv = uvInterp / outRectSize; + float fac = clamp((shadeDir > 0.0) ? uv.y : uv.x, 0.0, 1.0); + /* Note innerColor is premultiplied inside the fragment shader. */ + if (doAlphaCheck) { + innerColor = colorInner1; + butCo = uv.x; } - else if (cflag == TOP_RIGHT) { - v = -v; - v += rct.yw; - } - else /* (cflag == TOP_LEFT) */ { - v = vec2(v.y, -v.x); - v += rct.xw; - } - - vec2 uv = faci * (v - recti.xz); - - /* compute uv and color gradient */ - uint color_id = (vflag >> COLOR_OFS) & COLOR_RANGE; - if (color_id == COLOR_INNER) { - float fac = clamp((shadeDir > 0.0) ? uv.y : uv.x, 0.0, 1.0); - - if (doAlphaCheck) { - finalColor = colorInner1; - butCo = uv.x; - } - else { - finalColor = mix(colorInner2, colorInner1, fac); - butCo = -abs(uv.x); - } - } - else if (color_id == COLOR_EDGE) { - finalColor = colorEdge; - butCo = -abs(uv.x); - } - else /* (color_id == COLOR_EMBOSS) */ { - finalColor = colorEmboss; + else { + innerColor = mix(colorInner2, colorInner1, fac); butCo = -abs(uv.x); } - bool is_emboss = (vflag & EMBOSS_FLAG) != 0u; - v.y -= (is_emboss) ? (recti.z - rect.z) : 0.0; + /* We need premultiplied color for transparency. */ + borderColor = colorEdge * vec4(colorEdge.aaa, 1.0); + embossColor = colorEmboss * vec4(colorEmboss.aaa, 1.0); - return v; + return pos; } vec2 do_tria() { - uint vofs = vflag & TRIA_VEC_RANGE; + int vidx = gl_VertexID % 4; + bool tria2 = gl_VertexID > 7; + + vec2 pos; + float size = (tria2) ? -tria2Size : tria1Size; + vec2 center = (tria2) ? tria2Center : tria1Center; + + vec2 arrow_pos[4] = vec2[4](vec2(0.0, 0.6), vec2(0.6, 0.0), vec2(-0.6, 0.0), vec2(0.0, -0.6)); + /* Rotated uv space by 45deg and mirrored. */ + vec2 arrow_uvs[4] = vec2[4](vec2(0.0, 0.85), vec2(0.85, 0.85), vec2(0.0, 0.0), vec2(0.0, 0.85)); + + vec2 point_pos[4] = vec2[4](vec2(-1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, -1.0), vec2(1.0, 1.0)); + vec2 point_uvs[4] = vec2[4](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 0.0), vec2(1.0, 1.0)); + + /* We reuse the SDF roundbox rendering of widget to render the tria shapes. + * This means we do clever tricks to position the rectangle the way we want using + * the 2 triangles uvs. */ + if (triaType == 0.0) { + /* ROUNDBOX_TRIA_NONE */ + outRectSize = uvInterp = pos = vec2(0); + outRoundCorners = vec4(0.01); + } + else if (triaType == 1.0) { + /* ROUNDBOX_TRIA_ARROWS */ + pos = arrow_pos[vidx]; + uvInterp = arrow_uvs[vidx]; + uvInterp -= vec2(0.05, 0.63); /* Translate */ + outRectSize = vec2(0.74, 0.17); + outRoundCorners = vec4(0.08); + } + else if (triaType == 2.0) { + /* ROUNDBOX_TRIA_SCROLL */ + pos = point_pos[vidx]; + uvInterp = point_uvs[vidx]; + outRectSize = vec2(1.0); + outRoundCorners = vec4(0.5); + } + else if (triaType == 3.0) { + /* ROUNDBOX_TRIA_MENU */ + pos = tria2 ? vec2(0.0) : arrow_pos[vidx]; /* Solo tria */ + pos = vec2(pos.y, -pos.x); /* Rotate */ + pos += vec2(-0.05, 0.0); /* Translate */ + size *= 0.8; /* Scale */ + uvInterp = arrow_uvs[vidx]; + uvInterp -= vec2(0.05, 0.63); /* Translate */ + outRectSize = vec2(0.74, 0.17); + outRoundCorners = vec4(0.01); + } + else if (triaType == 4.0) { + /* ROUNDBOX_TRIA_CHECK */ + /* A bit more hacky: We use the two trias joined together to render + * both sides of the checkmark with different length. */ + pos = arrow_pos[min(vidx, 2)]; /* Only keep 1 triangle. */ + pos.y = tria2 ? -pos.y : pos.y; /* Mirror along X */ + pos = pos.x * vec2(0.0872, -0.996) + pos.y * vec2(0.996, 0.0872); /* Rotate (85deg) */ + pos += vec2(-0.1, 0.2); /* Translate */ + center = tria1Center; + size = tria1Size * 1.7; /* Scale */ + uvInterp = arrow_uvs[vidx]; + uvInterp -= tria2 ? vec2(0.4, 0.65) : vec2(0.08, 0.65); /* Translate */ + outRectSize = vec2(0.74, 0.14); + outRoundCorners = vec4(0.01); + } + else { + /* ROUNDBOX_TRIA_HOLD_ACTION_ARROW */ + /* We use a single triangle to cut the round rect in half. The edge will not be Antialiased. */ + pos = tria2 ? vec2(0.0) : arrow_pos[min(vidx, 2)]; /* Only keep 1 triangle. */ + pos = pos.x * vec2(0.707, 0.707) + pos.y * vec2(-0.707, 0.707); /* Rotate (45deg) */ + pos += vec2(-1.7, 2.4); /* Translate (hardcoded, might want to remove) */ + size *= 0.4; /* Scale */ + uvInterp = arrow_uvs[vidx]; + uvInterp -= vec2(0.05, 0.05); /* Translate */ + outRectSize = vec2(0.75); + outRoundCorners = vec4(0.01); + } - vec2 v = triavec[vofs]; + uvInterp *= abs(size); + outRectSize *= abs(size); + outRoundCorners *= abs(size); - finalColor = colorTria; - butCo = -1.0; + pos = pos * size + center; - bool is_tria_first = (vflag & TRIA_FIRST) != 0u; + innerColor = colorTria * vec4(colorTria.aaa, 1.0); - if (is_tria_first) { - v = v * tria1Size + tria1Center; - } - else { - v = v * tria2Size + tria2Center; - } + lineWidth = 0.0; + borderColor = vec4(0.0); + embossColor = vec4(0.0); - return v; + butCo = -2.0; + + return pos; } void main() { discardFac = discardFactor; - bool is_tria = (vflag & TRIA_FLAG) != 0u; - - vec2 v = (is_tria) ? do_tria() : do_widget(); - - /* Antialiasing offset */ - v += jit[(vflag >> JIT_OFS) & JIT_RANGE]; + bool is_tria = (gl_VertexID > 3); + vec2 pos = (is_tria) ? do_tria() : do_widget(); - gl_Position = ModelViewProjectionMatrix * vec4(v, 0.0, 1.0); + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); } diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl index f30e292154e..6d997ec14cc 100644 --- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl @@ -29,4 +29,6 @@ void main() else { fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist)); } + + fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl index 8f8ebebb5f1..d6d6fbab971 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl @@ -9,5 +9,5 @@ void node_ambient_occlusion( } #else /* Stub ambient occlusion because it is not compatible with volumetrics. */ -# define node_ambient_occlusion +# define node_ambient_occlusion(a, b, c, d, e) (e = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl index a8a900b40c6..e1137d9d0e7 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl @@ -11,5 +11,5 @@ void node_bsdf_anisotropic(vec4 color, } #else /* Stub anisotropic because it is not compatible with volumetrics. */ -# define node_bsdf_anisotropic +# define node_bsdf_anisotropic(a, b, c, d, e, f, g) (g = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl index 714792489f6..d7b6143d2a1 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl @@ -9,5 +9,5 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result) } #else /* Stub diffuse because it is not compatible with volumetrics. */ -# define node_bsdf_diffuse +# define node_bsdf_diffuse(a, b, c, d) (d = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl index 747395857ee..443bab7529b 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl @@ -40,4 +40,7 @@ void node_eevee_specular(vec4 diffuse, closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result); } +#else +/* Stub specular because it is not compatible with volumetrics. */ +# define node_eevee_specular(a, b, c, d, e, f, g, h, i, j, k, result) (result = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl index ece770f0e73..6d782ff18de 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl @@ -28,5 +28,5 @@ void node_bsdf_glass( } #else /* Stub glass because it is not compatible with volumetrics. */ -# define node_bsdf_glass +# define node_bsdf_glass(a, b, c, d, e, f) (f = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl index 7513c3a4edb..5ea22f3e0b4 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl @@ -12,5 +12,5 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo } #else /* Stub glossy because it is not compatible with volumetrics. */ -# define node_bsdf_glossy +# define node_bsdf_glossy(a, b, c, d, e) (e = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl index 3c85dc6456c..80ed4e1ef69 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -442,11 +442,13 @@ void node_bsdf_principled_glass(vec4 base_color, result.transmittance = vec3(1.0 - alpha); } #else +/* clang-format off */ /* Stub principled because it is not compatible with volumetrics. */ -# define node_bsdf_principled -# define node_bsdf_principled_dielectric -# define node_bsdf_principled_metallic -# define node_bsdf_principled_clearcoat -# define node_bsdf_principled_subsurface -# define node_bsdf_principled_glass +# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled_dielectric(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled_metallic(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled_clearcoat(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled_subsurface(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled_glass(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, result) (result = CLOSURE_DEFAULT) +/* clang-format on */ #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl index 4088d6db06a..cd043020a7f 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl @@ -12,5 +12,5 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Cl } #else /* Stub refraction because it is not compatible with volumetrics. */ -# define node_bsdf_refraction +# define node_bsdf_refraction(a, b, c, d, e) (e = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl index 9bbbe71b206..c13b55513da 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl @@ -24,5 +24,5 @@ void node_subsurface_scattering(vec4 color, } #else /* Stub subsurface scattering because it is not compatible with volumetrics. */ -# define node_subsurface_scattering +# define node_subsurface_scattering(a, b, c, d, e, f, g, h) (h = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl index 02d288d42bf..bbfc99ccc73 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl @@ -5,5 +5,5 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure r } #else /* Stub toon because it is not compatible with volumetrics. */ -# define node_bsdf_toon +# define node_bsdf_toon(a, b, c, d, e) (e = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl index 5c3ed81410a..79bfd9b24bb 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl @@ -9,5 +9,5 @@ void node_bsdf_translucent(vec4 color, vec3 N, out Closure result) } #else /* Stub translucent because it is not compatible with volumetrics. */ -# define node_bsdf_translucent +# define node_bsdf_translucent(a, b, c) (c = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl index 800d0f81d4a..9040f62bd3f 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl @@ -7,5 +7,5 @@ void node_bsdf_transparent(vec4 color, out Closure result) } #else /* Stub transparent because it is not compatible with volumetrics. */ -# define node_bsdf_transparent +# define node_bsdf_transparent(a, b) (b = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl index 9646ffff8ca..989f18b881a 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl @@ -5,5 +5,5 @@ void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result) } #else /* Stub velvet because it is not compatible with volumetrics. */ -# define node_bsdf_velvet +# define node_bsdf_velvet(a, b, c, d) (d = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl index 2fcf1b8d914..e2789e046e1 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl @@ -26,6 +26,6 @@ void node_wireframe_screenspace(float size, vec2 barycentric, out float fac) } #else /* Stub wireframe because it is not compatible with volumetrics. */ -# define node_wireframe -# define node_wireframe_screenspace +# define node_wireframe(a, b, c, d) (d = 0.0) +# define node_wireframe_screenspace(a, b, c) (c = 0.0) #endif diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt index bc2f8d628e2..360cacc4360 100644 --- a/source/blender/io/CMakeLists.txt +++ b/source/blender/io/CMakeLists.txt @@ -18,6 +18,8 @@ # All rights reserved. # ***** END GPL LICENSE BLOCK ***** +add_subdirectory(common) + if(WITH_ALEMBIC) add_subdirectory(alembic) endif() diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h index ba430752b29..ddf75aa3258 100644 --- a/source/blender/io/alembic/ABC_alembic.h +++ b/source/blender/io/alembic/ABC_alembic.h @@ -13,14 +13,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_ALEMBIC_H__ -#define __ABC_ALEMBIC_H__ - #ifdef __cplusplus extern "C" { #endif @@ -133,5 +131,3 @@ struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *han #ifdef __cplusplus } #endif - -#endif /* __ABC_ALEMBIC_H__ */ diff --git a/source/blender/io/alembic/CMakeLists.txt b/source/blender/io/alembic/CMakeLists.txt index 16f2d944876..da36272b850 100644 --- a/source/blender/io/alembic/CMakeLists.txt +++ b/source/blender/io/alembic/CMakeLists.txt @@ -20,6 +20,7 @@ set(INC . + ../common ../../blenkernel ../../blenlib ../../blenloader @@ -29,6 +30,7 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager + ../../../../intern/clog ../../../../intern/guardedalloc ../../../../intern/utfconv ) @@ -42,7 +44,6 @@ set(INC_SYS set(SRC intern/abc_axis_conversion.cc intern/abc_customdata.cc - intern/abc_exporter.cc intern/abc_reader_archive.cc intern/abc_reader_camera.cc intern/abc_reader_curves.cc @@ -52,22 +53,25 @@ set(SRC intern/abc_reader_points.cc intern/abc_reader_transform.cc intern/abc_util.cc - intern/abc_writer_archive.cc - intern/abc_writer_camera.cc - intern/abc_writer_curves.cc - intern/abc_writer_hair.cc - intern/abc_writer_mball.cc - intern/abc_writer_mesh.cc - intern/abc_writer_nurbs.cc - intern/abc_writer_object.cc - intern/abc_writer_points.cc - intern/abc_writer_transform.cc intern/alembic_capi.cc + exporter/abc_archive.cc + exporter/abc_export_capi.cc + exporter/abc_hierarchy_iterator.cc + exporter/abc_subdiv_disabler.cc + exporter/abc_writer_abstract.cc + exporter/abc_writer_camera.cc + exporter/abc_writer_curves.cc + exporter/abc_writer_hair.cc + exporter/abc_writer_mesh.cc + exporter/abc_writer_mball.cc + exporter/abc_writer_nurbs.cc + exporter/abc_writer_points.cc + exporter/abc_writer_transform.cc + ABC_alembic.h intern/abc_axis_conversion.h intern/abc_customdata.h - intern/abc_exporter.h intern/abc_reader_archive.h intern/abc_reader_camera.h intern/abc_reader_curves.h @@ -77,21 +81,25 @@ set(SRC intern/abc_reader_points.h intern/abc_reader_transform.h intern/abc_util.h - intern/abc_writer_archive.h - intern/abc_writer_camera.h - intern/abc_writer_curves.h - intern/abc_writer_hair.h - intern/abc_writer_mball.h - intern/abc_writer_mesh.h - intern/abc_writer_nurbs.h - intern/abc_writer_object.h - intern/abc_writer_points.h - intern/abc_writer_transform.h + + exporter/abc_archive.h + exporter/abc_hierarchy_iterator.h + exporter/abc_subdiv_disabler.h + exporter/abc_writer_abstract.h + exporter/abc_writer_camera.h + exporter/abc_writer_curves.h + exporter/abc_writer_hair.h + exporter/abc_writer_mesh.h + exporter/abc_writer_mball.h + exporter/abc_writer_nurbs.h + exporter/abc_writer_points.h + exporter/abc_writer_transform.h ) set(LIB bf_blenkernel bf_blenlib + bf_io_common ${ALEMBIC_LIBRARIES} ${OPENEXR_LIBRARIES} diff --git a/source/blender/io/alembic/exporter/abc_archive.cc b/source/blender/io/alembic/exporter/abc_archive.cc new file mode 100644 index 00000000000..5fbf74f0705 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_archive.cc @@ -0,0 +1,265 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +#include "abc_archive.h" + +#include "BKE_blender_version.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "DEG_depsgraph_query.h" + +#include "DNA_scene_types.h" + +#include <Alembic/AbcCoreOgawa/All.h> +#include <Alembic/AbcGeom/All.h> + +#ifdef WIN32 +# include "BLI_path_util.h" +# include "BLI_string.h" + +# include "utfconv.h" +#endif + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::Abc::ErrorHandler; +using Alembic::Abc::kWrapExisting; +using Alembic::Abc::MetaData; +using Alembic::Abc::OArchive; +using Alembic::Abc::TimeSampling; +using Alembic::Abc::TimeSamplingPtr; +using Alembic::Abc::TimeSamplingType; + +static MetaData create_abc_metadata(const Main *bmain, double scene_fps) +{ + MetaData abc_metadata; + + std::string abc_user_description(bmain->name); + if (abc_user_description.empty()) { + abc_user_description = "unknown"; + } + + abc_metadata.set(Alembic::Abc::kApplicationNameKey, "Blender"); + abc_metadata.set(Alembic::Abc::kUserDescriptionKey, abc_user_description); + abc_metadata.set("blender_version", std::string("v") + BKE_blender_version_string()); + abc_metadata.set("FramesPerTimeUnit", std::to_string(scene_fps)); + + time_t raw_time; + time(&raw_time); + char buffer[128]; + +#if defined _WIN32 || defined _WIN64 + ctime_s(buffer, 128, &raw_time); +#else + ctime_r(&raw_time, buffer); +#endif + + const std::size_t buffer_len = strlen(buffer); + if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') { + buffer[buffer_len - 1] = '\0'; + } + + abc_metadata.set(Alembic::Abc::kDateWrittenKey, buffer); + return abc_metadata; +} + +static OArchive *create_archive(std::ofstream *abc_ostream, + const std::string &filename, + MetaData &abc_metadata) +{ + /* Use stream to support unicode character paths on Windows. */ +#ifdef WIN32 + char filename_cstr[FILE_MAX]; + BLI_strncpy(filename_cstr, filename.c_str(), FILE_MAX); + + UTF16_ENCODE(filename_cstr); + std::wstring wstr(filename_cstr_16); + abc_ostream->open(wstr.c_str(), std::ios::out | std::ios::binary); + UTF16_UN_ENCODE(filename_cstr); +#else + abc_ostream->open(filename, std::ios::out | std::ios::binary); +#endif + + ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy; + + Alembic::AbcCoreOgawa::WriteArchive archive_writer; + return new OArchive(archive_writer(abc_ostream, abc_metadata), kWrapExisting, policy); +} + +/* Construct list of shutter samples. + * + * These are taken from the interval [shutter open, shutter close), + * uniformly sampled with 'nr_of_samples' samples. + * + * TODO(Sybren): test that the above interval is indeed half-open. + * + * If 'time_relative' is true, samples are returned as time (in seconds) from params.frame_start. + * If 'time_relative' is false, samples are returned as fractional frames from 0. + * */ +static void get_shutter_samples(double scene_fps, + const AlembicExportParams ¶ms, + int nr_of_samples, + bool time_relative, + std::vector<double> &r_samples) +{ + int frame_offset = time_relative ? params.frame_start : 0; + double time_factor = time_relative ? scene_fps : 1.0; + double shutter_open = params.shutter_open; + double shutter_close = params.shutter_close; + double time_inc = (shutter_close - shutter_open) / nr_of_samples; + + /* sample between shutter open & close */ + for (int sample = 0; sample < nr_of_samples; sample++) { + double sample_time = shutter_open + time_inc * sample; + double time = (frame_offset + sample_time) / time_factor; + + r_samples.push_back(time); + } +} + +static TimeSamplingPtr create_time_sampling(double scene_fps, + const AlembicExportParams ¶ms, + int nr_of_samples) +{ + std::vector<double> samples; + + if (params.frame_start == params.frame_end) { + return TimeSamplingPtr(new TimeSampling()); + } + + get_shutter_samples(scene_fps, params, nr_of_samples, true, samples); + + TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / scene_fps); + return TimeSamplingPtr(new TimeSampling(ts, samples)); +} + +static void get_frames(double scene_fps, + const AlembicExportParams ¶ms, + unsigned int nr_of_samples, + std::set<double> &r_frames) +{ + /* Get one set of shutter samples, then add those around each frame to export. */ + std::vector<double> shutter_samples; + get_shutter_samples(scene_fps, params, nr_of_samples, false, shutter_samples); + + for (double frame = params.frame_start; frame <= params.frame_end; frame += 1.0) { + for (size_t j = 0; j < nr_of_samples; j++) { + r_frames.insert(frame + shutter_samples[j]); + } + } +} + +/* ****************************************************************** */ + +ABCArchive::ABCArchive(const Main *bmain, + const Scene *scene, + AlembicExportParams params, + std::string filename) + : archive(nullptr) +{ + double scene_fps = FPS; + MetaData abc_metadata = create_abc_metadata(bmain, scene_fps); + + // Create the Archive. + archive = create_archive(&abc_ostream_, filename, abc_metadata); + + // Create time samples for transforms and shapes. + TimeSamplingPtr ts_xform; + TimeSamplingPtr ts_shapes; + + ts_xform = create_time_sampling(scene_fps, params, params.frame_samples_xform); + time_sampling_index_transforms_ = archive->addTimeSampling(*ts_xform); + + const bool export_animation = params.frame_start != params.frame_end; + if (!export_animation || params.frame_samples_shape == params.frame_samples_xform) { + ts_shapes = ts_xform; + time_sampling_index_shapes_ = time_sampling_index_transforms_; + } + else { + ts_shapes = create_time_sampling(scene_fps, params, params.frame_samples_shape); + time_sampling_index_shapes_ = archive->addTimeSampling(*ts_shapes); + } + + // Construct the frames to export. + get_frames(scene_fps, params, params.frame_samples_xform, xform_frames_); + get_frames(scene_fps, params, params.frame_samples_shape, shape_frames_); + + // Merge all frames to get the final set of frames to export. + export_frames_.insert(xform_frames_.begin(), xform_frames_.end()); + export_frames_.insert(shape_frames_.begin(), shape_frames_.end()); + + abc_archive_bbox_ = Alembic::AbcGeom::CreateOArchiveBounds(*archive, + time_sampling_index_transforms_); +} + +ABCArchive::~ABCArchive() +{ + delete archive; +} + +uint32_t ABCArchive::time_sampling_index_transforms() const +{ + return time_sampling_index_transforms_; +} + +uint32_t ABCArchive::time_sampling_index_shapes() const +{ + return time_sampling_index_shapes_; +} + +ABCArchive::Frames::const_iterator ABCArchive::frames_begin() const +{ + return export_frames_.begin(); +} +ABCArchive::Frames::const_iterator ABCArchive::frames_end() const +{ + return export_frames_.end(); +} +size_t ABCArchive::total_frame_count() const +{ + return export_frames_.size(); +} + +bool ABCArchive::is_xform_frame(double frame) const +{ + return xform_frames_.find(frame) != xform_frames_.end(); +} +bool ABCArchive::is_shape_frame(double frame) const +{ + return shape_frames_.find(frame) != shape_frames_.end(); +} +ExportSubset ABCArchive::export_subset_for_frame(double frame) const +{ + ExportSubset subset; + subset.transforms = is_xform_frame(frame); + subset.shapes = is_shape_frame(frame); + return subset; +} + +void ABCArchive::update_bounding_box(const Imath::Box3d &bounds) +{ + abc_archive_bbox_.set(bounds); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_archive.h b/source/blender/io/alembic/exporter/abc_archive.h new file mode 100644 index 00000000000..43d0acf2520 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_archive.h @@ -0,0 +1,87 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup Alembic + */ + +#pragma once + +#include "ABC_alembic.h" +#include "IO_abstract_hierarchy_iterator.h" + +#include <Alembic/Abc/OArchive.h> +#include <Alembic/Abc/OTypedScalarProperty.h> + +#include <fstream> +#include <set> +#include <string> + +struct Main; +struct Scene; + +namespace blender { +namespace io { +namespace alembic { + +/* Container for an Alembic archive and time sampling info. + * + * Constructor arguments are used to create the correct output stream and to set the archive's + * metadata. */ +class ABCArchive { + public: + typedef std::set<double> Frames; + + Alembic::Abc::OArchive *archive; + + ABCArchive(const Main *bmain, + const Scene *scene, + AlembicExportParams params, + std::string filename); + ~ABCArchive(); + + uint32_t time_sampling_index_transforms() const; + uint32_t time_sampling_index_shapes() const; + + Frames::const_iterator frames_begin() const; + Frames::const_iterator frames_end() const; + size_t total_frame_count() const; + + bool is_xform_frame(double frame) const; + bool is_shape_frame(double frame) const; + + ExportSubset export_subset_for_frame(double frame) const; + + void update_bounding_box(const Imath::Box3d &bounds); + + private: + std::ofstream abc_ostream_; + uint32_t time_sampling_index_transforms_; + uint32_t time_sampling_index_shapes_; + + Frames xform_frames_; + Frames shape_frames_; + Frames export_frames_; + + Alembic::Abc::OBox3dProperty abc_archive_bbox_; +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_export_capi.cc b/source/blender/io/alembic/exporter/abc_export_capi.cc new file mode 100644 index 00000000000..fbc5b2d5c02 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_export_capi.cc @@ -0,0 +1,220 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +#include "ABC_alembic.h" +#include "abc_archive.h" +#include "abc_hierarchy_iterator.h" +#include "abc_subdiv_disabler.h" + +#include "MEM_guardedalloc.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" + +#include "BKE_blender_version.h" +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +#include <algorithm> + +struct ExportJobData { + Main *bmain; + Depsgraph *depsgraph; + wmWindowManager *wm; + + char filename[FILE_MAX]; + AlembicExportParams params; + + bool was_canceled; + bool export_ok; +}; + +namespace blender { +namespace io { +namespace alembic { + +// Construct the depsgraph for exporting. +static void build_depsgraph(Depsgraph *depsgraph, Main *bmain) +{ + Scene *scene = DEG_get_input_scene(depsgraph); + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer); +} + +static void export_startjob(void *customdata, short *stop, short *do_update, float *progress) +{ + ExportJobData *data = static_cast<ExportJobData *>(customdata); + data->was_canceled = false; + + G.is_rendering = true; + WM_set_locked_interface(data->wm, true); + G.is_break = false; + + *progress = 0.0f; + *do_update = true; + + build_depsgraph(data->depsgraph, data->bmain); + SubdivModifierDisabler subdiv_disabler(data->depsgraph); + if (!data->params.apply_subdiv) { + subdiv_disabler.disable_modifiers(); + } + BKE_scene_graph_update_tagged(data->depsgraph, data->bmain); + + // For restoring the current frame after exporting animation is done. + Scene *scene = DEG_get_input_scene(data->depsgraph); + const int orig_frame = CFRA; + const bool export_animation = (data->params.frame_start != data->params.frame_end); + + // Create the Alembic archive. + ABCArchive abc_archive(data->bmain, scene, data->params, std::string(data->filename)); + + ABCHierarchyIterator iter(data->depsgraph, &abc_archive, data->params); + + if (export_animation) { + CLOG_INFO(&LOG, 2, "Exporting animation"); + + // Writing the animated frames is not 100% of the work, but it's our best guess. + const float progress_per_frame = 1.0f / std::max(size_t(1), abc_archive.total_frame_count()); + ABCArchive::Frames::const_iterator frame_it = abc_archive.frames_begin(); + const ABCArchive::Frames::const_iterator frames_end = abc_archive.frames_end(); + + for (; frame_it != frames_end; frame_it++) { + double frame = *frame_it; + + if (G.is_break || (stop != nullptr && *stop)) { + break; + } + + // Update the scene for the next frame to render. + scene->r.cfra = static_cast<int>(frame); + scene->r.subframe = frame - scene->r.cfra; + BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain); + + CLOG_INFO(&LOG, 2, "Exporting frame %.2f", frame); + ExportSubset export_subset = abc_archive.export_subset_for_frame(frame); + iter.set_export_subset(export_subset); + iter.iterate_and_write(); + + *progress += progress_per_frame; + *do_update = true; + } + } + else { + // If we're not animating, a single iteration over all objects is enough. + iter.iterate_and_write(); + } + + iter.release_writers(); + + // Finish up by going back to the keyframe that was current before we started. + if (CFRA != orig_frame) { + CFRA = orig_frame; + BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain); + } + + data->export_ok = !data->was_canceled; + + *progress = 1.0f; + *do_update = true; +} + +static void export_endjob(void *customdata) +{ + ExportJobData *data = static_cast<ExportJobData *>(customdata); + + DEG_graph_free(data->depsgraph); + + if (data->was_canceled && BLI_exists(data->filename)) { + BLI_delete(data->filename, false, false); + } + + G.is_rendering = false; + WM_set_locked_interface(data->wm, false); +} + +} // namespace alembic +} // namespace io +} // namespace blender + +bool ABC_export(Scene *scene, + bContext *C, + const char *filepath, + const AlembicExportParams *params, + bool as_background_job) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + + ExportJobData *job = static_cast<ExportJobData *>( + MEM_mallocN(sizeof(ExportJobData), "ExportJobData")); + + job->bmain = CTX_data_main(C); + job->wm = CTX_wm_manager(C); + job->export_ok = false; + BLI_strncpy(job->filename, filepath, sizeof(job->filename)); + + job->depsgraph = DEG_graph_new( + job->bmain, scene, view_layer, DAG_EVAL_RENDER /* TODO(Sybren): params->evaluation_mode */); + job->params = *params; + + bool export_ok = false; + if (as_background_job) { + wmJob *wm_job = WM_jobs_get( + job->wm, CTX_wm_window(C), scene, "Alembic Export", WM_JOB_PROGRESS, WM_JOB_TYPE_ALEMBIC); + + /* setup job */ + WM_jobs_customdata_set(wm_job, job, MEM_freeN); + WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); + WM_jobs_callbacks(wm_job, + blender::io::alembic::export_startjob, + NULL, + NULL, + blender::io::alembic::export_endjob); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + } + else { + /* Fake a job context, so that we don't need NULL pointer checks while exporting. */ + short stop = 0, do_update = 0; + float progress = 0.f; + + blender::io::alembic::export_startjob(job, &stop, &do_update, &progress); + blender::io::alembic::export_endjob(job); + export_ok = job->export_ok; + + MEM_freeN(job); + } + + return export_ok; +} diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc new file mode 100644 index 00000000000..90004c0e85b --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc @@ -0,0 +1,261 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +#include "abc_hierarchy_iterator.h" +#include "abc_writer_abstract.h" +#include "abc_writer_camera.h" +#include "abc_writer_curves.h" +#include "abc_writer_hair.h" +#include "abc_writer_mball.h" +#include "abc_writer_mesh.h" +#include "abc_writer_nurbs.h" +#include "abc_writer_points.h" +#include "abc_writer_transform.h" + +#include <memory> +#include <string> + +#include "BLI_assert.h" + +#include "DEG_depsgraph_query.h" + +#include "DNA_ID.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" + +namespace blender { +namespace io { +namespace alembic { + +ABCHierarchyIterator::ABCHierarchyIterator(Depsgraph *depsgraph, + ABCArchive *abc_archive, + const AlembicExportParams ¶ms) + : AbstractHierarchyIterator(depsgraph), abc_archive_(abc_archive), params_(params) +{ +} + +void ABCHierarchyIterator::iterate_and_write() +{ + AbstractHierarchyIterator::iterate_and_write(); + update_archive_bounding_box(); +} + +void ABCHierarchyIterator::update_archive_bounding_box() +{ + Imath::Box3d bounds; + update_bounding_box_recursive(bounds, HierarchyContext::root()); + abc_archive_->update_bounding_box(bounds); +} + +void ABCHierarchyIterator::update_bounding_box_recursive(Imath::Box3d &bounds, + const HierarchyContext *context) +{ + if (context != nullptr) { + AbstractHierarchyWriter *abstract_writer = writers_[context->export_path]; + ABCAbstractWriter *abc_writer = static_cast<ABCAbstractWriter *>(abstract_writer); + + if (abc_writer != nullptr) { + bounds.extendBy(abc_writer->bounding_box()); + } + } + + for (HierarchyContext *child_context : graph_children(context)) { + update_bounding_box_recursive(bounds, child_context); + } +} + +bool ABCHierarchyIterator::mark_as_weak_export(const Object *object) const +{ + if (params_.selected_only && (object->base_flag & BASE_SELECTED) == 0) { + return true; + } + /* TODO(Sybren): handle other flags too? */ + return false; +} + +void ABCHierarchyIterator::delete_object_writer(AbstractHierarchyWriter *writer) +{ + delete writer; +} + +std::string ABCHierarchyIterator::make_valid_name(const std::string &name) const +{ + std::string abc_name(name); + std::replace(abc_name.begin(), abc_name.end(), ' ', '_'); + std::replace(abc_name.begin(), abc_name.end(), '.', '_'); + std::replace(abc_name.begin(), abc_name.end(), ':', '_'); + return abc_name; +} + +AbstractHierarchyIterator::ExportGraph::key_type ABCHierarchyIterator:: + determine_graph_index_object(const HierarchyContext *context) +{ + if (params_.flatten_hierarchy) { + return std::make_pair(nullptr, nullptr); + } + + return AbstractHierarchyIterator::determine_graph_index_object(context); +} + +AbstractHierarchyIterator::ExportGraph::key_type ABCHierarchyIterator::determine_graph_index_dupli( + const HierarchyContext *context, const std::set<Object *> &dupli_set) +{ + if (params_.flatten_hierarchy) { + return std::make_pair(nullptr, nullptr); + } + + return AbstractHierarchyIterator::determine_graph_index_dupli(context, dupli_set); +} + +Alembic::Abc::OObject ABCHierarchyIterator::get_alembic_parent( + const HierarchyContext *context) const +{ + Alembic::Abc::OObject parent; + + if (!context->higher_up_export_path.empty()) { + AbstractHierarchyWriter *writer = get_writer(context->higher_up_export_path); + ABCAbstractWriter *abc_writer = static_cast<ABCAbstractWriter *>(writer); + parent = abc_writer->get_alembic_object(); + } + + if (!parent.valid()) { + /* An invalid parent object means "no parent", which should be translated to Alembic's top + * archive object. */ + return abc_archive_->archive->getTop(); + } + + return parent; +} + +ABCWriterConstructorArgs ABCHierarchyIterator::writer_constructor_args( + const HierarchyContext *context) const +{ + ABCWriterConstructorArgs constructor_args; + constructor_args.depsgraph = depsgraph_; + constructor_args.abc_archive = abc_archive_; + constructor_args.abc_parent = get_alembic_parent(context); + constructor_args.abc_name = context->export_name; + constructor_args.abc_path = context->export_path; + constructor_args.hierarchy_iterator = this; + constructor_args.export_params = ¶ms_; + return constructor_args; +} + +AbstractHierarchyWriter *ABCHierarchyIterator::create_transform_writer( + const HierarchyContext *context) +{ + ABCAbstractWriter *transform_writer = new ABCTransformWriter(writer_constructor_args(context)); + transform_writer->create_alembic_objects(context); + return transform_writer; +} + +AbstractHierarchyWriter *ABCHierarchyIterator::create_data_writer(const HierarchyContext *context) +{ + const ABCWriterConstructorArgs writer_args = writer_constructor_args(context); + ABCAbstractWriter *data_writer = nullptr; + + switch (context->object->type) { + case OB_MESH: + data_writer = new ABCMeshWriter(writer_args); + break; + case OB_CAMERA: + data_writer = new ABCCameraWriter(writer_args); + break; + case OB_CURVE: + if (params_.curves_as_mesh) { + data_writer = new ABCCurveMeshWriter(writer_args); + } + else { + data_writer = new ABCCurveWriter(writer_args); + } + break; + case OB_SURF: + if (params_.curves_as_mesh) { + data_writer = new ABCCurveMeshWriter(writer_args); + } + else { + data_writer = new ABCNurbsWriter(writer_args); + } + break; + case OB_MBALL: + data_writer = new ABCMetaballWriter(writer_args); + break; + + case OB_EMPTY: + case OB_LAMP: + case OB_FONT: + case OB_SPEAKER: + case OB_LIGHTPROBE: + case OB_LATTICE: + case OB_ARMATURE: + case OB_GPENCIL: + return nullptr; + case OB_TYPE_MAX: + BLI_assert(!"OB_TYPE_MAX should not be used"); + return nullptr; + } + + if (!data_writer->is_supported(context)) { + delete data_writer; + return nullptr; + } + + data_writer->create_alembic_objects(context); + return data_writer; +} + +AbstractHierarchyWriter *ABCHierarchyIterator::create_hair_writer(const HierarchyContext *context) +{ + if (!params_.export_hair) { + return nullptr; + } + + const ABCWriterConstructorArgs writer_args = writer_constructor_args(context); + ABCAbstractWriter *hair_writer = new ABCHairWriter(writer_args); + + if (!hair_writer->is_supported(context)) { + delete hair_writer; + return nullptr; + } + + hair_writer->create_alembic_objects(context); + return hair_writer; +} + +AbstractHierarchyWriter *ABCHierarchyIterator::create_particle_writer( + const HierarchyContext *context) +{ + if (!params_.export_particles) { + return nullptr; + } + + const ABCWriterConstructorArgs writer_args = writer_constructor_args(context); + std::unique_ptr<ABCPointsWriter> particle_writer(std::make_unique<ABCPointsWriter>(writer_args)); + + if (!particle_writer->is_supported(context)) { + return nullptr; + } + + particle_writer->create_alembic_objects(context); + return particle_writer.release(); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h new file mode 100644 index 00000000000..edcb31806ba --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h @@ -0,0 +1,90 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ +#pragma once + +#include "ABC_alembic.h" +#include "abc_archive.h" + +#include "IO_abstract_hierarchy_iterator.h" + +#include <string> + +#include <Alembic/Abc/OArchive.h> +#include <Alembic/Abc/OObject.h> + +struct Depsgraph; +struct ID; +struct Object; + +namespace blender { +namespace io { +namespace alembic { + +class ABCHierarchyIterator; + +struct ABCWriterConstructorArgs { + Depsgraph *depsgraph; + ABCArchive *abc_archive; + Alembic::Abc::OObject abc_parent; + std::string abc_name; + std::string abc_path; + const ABCHierarchyIterator *hierarchy_iterator; + const AlembicExportParams *export_params; +}; + +class ABCHierarchyIterator : public AbstractHierarchyIterator { + private: + ABCArchive *abc_archive_; + const AlembicExportParams ¶ms_; + + public: + ABCHierarchyIterator(Depsgraph *depsgraph, + ABCArchive *abc_archive_, + const AlembicExportParams ¶ms); + + virtual void iterate_and_write() override; + virtual std::string make_valid_name(const std::string &name) const override; + + protected: + virtual bool mark_as_weak_export(const Object *object) const override; + + virtual ExportGraph::key_type determine_graph_index_object( + const HierarchyContext *context) override; + virtual AbstractHierarchyIterator::ExportGraph::key_type determine_graph_index_dupli( + const HierarchyContext *context, const std::set<Object *> &dupli_set) override; + + virtual AbstractHierarchyWriter *create_transform_writer( + const HierarchyContext *context) override; + virtual AbstractHierarchyWriter *create_data_writer(const HierarchyContext *context) override; + virtual AbstractHierarchyWriter *create_hair_writer(const HierarchyContext *context) override; + virtual AbstractHierarchyWriter *create_particle_writer( + const HierarchyContext *context) override; + + virtual void delete_object_writer(AbstractHierarchyWriter *writer) override; + + private: + Alembic::Abc::OObject get_alembic_parent(const HierarchyContext *context) const; + ABCWriterConstructorArgs writer_constructor_args(const HierarchyContext *context) const; + void update_archive_bounding_box(); + void update_bounding_box_recursive(Imath::Box3d &bounds, const HierarchyContext *context); +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc new file mode 100644 index 00000000000..7c147076975 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc @@ -0,0 +1,107 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ +#include "abc_subdiv_disabler.h" + +#include <stdio.h> + +#include "BLI_listbase.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "DNA_layer_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" + +#include "BKE_modifier.h" + +namespace blender { +namespace io { +namespace alembic { + +SubdivModifierDisabler::SubdivModifierDisabler(Depsgraph *depsgraph) : depsgraph_(depsgraph) +{ +} + +SubdivModifierDisabler::~SubdivModifierDisabler() +{ + for (ModifierData *modifier : disabled_modifiers_) { + modifier->mode &= ~eModifierMode_DisableTemporary; + } +} + +void SubdivModifierDisabler::disable_modifiers() +{ + Scene *scene = DEG_get_input_scene(depsgraph_); + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph_); + + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { + Object *object = base->object; + + if (object->type != OB_MESH) { + continue; + } + + ModifierData *subdiv = get_subdiv_modifier(scene, object); + if (subdiv == nullptr) { + continue; + } + + /* This disables more modifiers than necessary, as it doesn't take restrictions like + * "export selected objects only" into account. However, with the subsurfs disabled, + * moving to a different frame is also going to be faster, so in the end this is probably + * a good thing to do. */ + subdiv->mode |= eModifierMode_DisableTemporary; + disabled_modifiers_.insert(subdiv); + DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); + } +} + +/* Check if the mesh is a subsurf, ignoring disabled modifiers and + * displace if it's after subsurf. */ +ModifierData *SubdivModifierDisabler::get_subdiv_modifier(Scene *scene, Object *ob) +{ + ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last); + + for (; md; md = md->prev) { + if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Render)) { + continue; + } + + if (md->type == eModifierType_Subsurf) { + SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>(md); + + if (smd->subdivType == ME_CC_SUBSURF) { + return md; + } + } + + /* mesh is not a subsurf. break */ + if ((md->type != eModifierType_Displace) && (md->type != eModifierType_ParticleSystem)) { + return nullptr; + } + } + + return nullptr; +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.h b/source/blender/io/alembic/exporter/abc_subdiv_disabler.h new file mode 100644 index 00000000000..677847f3f63 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.h @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ +#pragma once + +#include <set> + +struct Depsgraph; +struct ModifierData; +struct Object; +struct Scene; + +namespace blender { +namespace io { +namespace alembic { + +/** + * Temporarily all subdivision modifiers on mesh objects. + * The destructor restores all disabled modifiers. + * + * This is used to export unsubdivided meshes to Alembic. It is done in a separate step before the + * exporter starts iterating over all the frames, so that it only has to happen once per export. + */ +class SubdivModifierDisabler final { + private: + Depsgraph *depsgraph_; + std::set<ModifierData *> disabled_modifiers_; + + public: + explicit SubdivModifierDisabler(Depsgraph *depsgraph); + ~SubdivModifierDisabler(); + + void disable_modifiers(); + + static ModifierData *get_subdiv_modifier(Scene *scene, Object *ob); +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_abstract.cc b/source/blender/io/alembic/exporter/abc_writer_abstract.cc new file mode 100644 index 00000000000..e43b394e27f --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_abstract.cc @@ -0,0 +1,101 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ +#include "abc_writer_abstract.h" +#include "abc_hierarchy_iterator.h" + +#include "BKE_animsys.h" +#include "BKE_key.h" +#include "BKE_object.h" + +#include "DNA_modifier_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::Abc::OObject; +using Alembic::Abc::TimeSamplingPtr; + +ABCAbstractWriter::ABCAbstractWriter(const ABCWriterConstructorArgs &args) + : args_(args), + frame_has_been_written_(false), + is_animated_(false), + timesample_index_(args_.abc_archive->time_sampling_index_shapes()) +{ +} + +ABCAbstractWriter::~ABCAbstractWriter() +{ +} + +bool ABCAbstractWriter::is_supported(const HierarchyContext * /*context*/) const +{ + return true; +} + +void ABCAbstractWriter::write(HierarchyContext &context) +{ + if (!frame_has_been_written_) { + is_animated_ = (args_.export_params->frame_start != args_.export_params->frame_end) && + check_is_animated(context); + } + else if (!is_animated_) { + /* A frame has already been written, and without animation one frame is enough. */ + return; + } + + do_write(context); + + frame_has_been_written_ = true; +} + +const Imath::Box3d &ABCAbstractWriter::bounding_box() const +{ + return bounding_box_; +} + +void ABCAbstractWriter::update_bounding_box(Object *object) +{ + BoundBox *bb = BKE_object_boundbox_get(object); + + if (!bb) { + if (object->type != OB_CAMERA) { + CLOG_WARN(&LOG, "Bounding box is null!\n"); + } + bounding_box_.min.x = bounding_box_.min.y = bounding_box_.min.z = 0; + bounding_box_.max.x = bounding_box_.max.y = bounding_box_.max.z = 0; + return; + } + + /* Convert Z-up to Y-up. This also changes which vector goes into which min/max property. */ + bounding_box_.min.x = bb->vec[0][0]; + bounding_box_.min.y = bb->vec[0][2]; + bounding_box_.min.z = -bb->vec[6][1]; + + bounding_box_.max.x = bb->vec[6][0]; + bounding_box_.max.y = bb->vec[6][2]; + bounding_box_.max.z = -bb->vec[0][1]; +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_abstract.h b/source/blender/io/alembic/exporter/abc_writer_abstract.h new file mode 100644 index 00000000000..a83373a567a --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_abstract.h @@ -0,0 +1,77 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ +#pragma once + +#include "IO_abstract_hierarchy_iterator.h" +#include "abc_hierarchy_iterator.h" + +#include <Alembic/Abc/OObject.h> +#include <vector> + +#include "DEG_depsgraph_query.h" +#include "DNA_material_types.h" + +struct Material; +struct Object; + +namespace blender { +namespace io { +namespace alembic { + +class ABCAbstractWriter : public AbstractHierarchyWriter { + protected: + const ABCWriterConstructorArgs args_; + + bool frame_has_been_written_; + bool is_animated_; + uint32_t timesample_index_; + Imath::Box3d bounding_box_; + + public: + explicit ABCAbstractWriter(const ABCWriterConstructorArgs &args); + virtual ~ABCAbstractWriter(); + + virtual void write(HierarchyContext &context) override; + + /* Returns true if the data to be written is actually supported. This would, for example, allow a + * hypothetical camera writer accept a perspective camera but reject an orthogonal one. + * + * Returning false from a transform writer will prevent the object and all its descendants from + * being exported. Returning false from a data writer (object data, hair, or particles) will + * only prevent that data from being written (and thus cause the object to be exported as an + * Empty). */ + virtual bool is_supported(const HierarchyContext *context) const; + + const Imath::Box3d &bounding_box() const; + + /* Called by AlembicHierarchyCreator after checking that the data is supported via + * is_supported(). */ + virtual void create_alembic_objects(const HierarchyContext *context) = 0; + + virtual const Alembic::Abc::OObject get_alembic_object() const = 0; + + protected: + virtual void do_write(HierarchyContext &context) = 0; + + virtual void update_bounding_box(Object *object); +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_camera.cc b/source/blender/io/alembic/exporter/abc_writer_camera.cc new file mode 100644 index 00000000000..7e7277cb4ea --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_camera.cc @@ -0,0 +1,110 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_camera.h" +#include "abc_hierarchy_iterator.h" + +#include "BKE_camera.h" + +#include "BLI_assert.h" + +#include "DNA_camera_types.h" +#include "DNA_scene_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::AbcGeom::CameraSample; +using Alembic::AbcGeom::OCamera; +using Alembic::AbcGeom::OFloatProperty; + +ABCCameraWriter::ABCCameraWriter(const ABCWriterConstructorArgs &args) : ABCAbstractWriter(args) +{ +} + +bool ABCCameraWriter::is_supported(const HierarchyContext *context) const +{ + Camera *camera = static_cast<Camera *>(context->object->data); + return camera->type == CAM_PERSP; +} + +void ABCCameraWriter::create_alembic_objects(const HierarchyContext * /*context*/) +{ + CLOG_INFO(&LOG, 2, "exporting %s", args_.abc_path.c_str()); + abc_camera_ = OCamera(args_.abc_parent, args_.abc_name, timesample_index_); + abc_camera_schema_ = abc_camera_.getSchema(); + + abc_custom_data_container_ = abc_camera_schema_.getUserProperties(); + abc_stereo_distance_ = OFloatProperty( + abc_custom_data_container_, "stereoDistance", timesample_index_); + abc_eye_separation_ = OFloatProperty( + abc_custom_data_container_, "eyeSeparation", timesample_index_); +} + +const Alembic::Abc::OObject ABCCameraWriter::get_alembic_object() const +{ + return abc_camera_; +} + +void ABCCameraWriter::do_write(HierarchyContext &context) +{ + Camera *cam = static_cast<Camera *>(context.object->data); + + abc_stereo_distance_.set(cam->stereo.convergence_distance); + abc_eye_separation_.set(cam->stereo.interocular_distance); + + const double apperture_x = cam->sensor_x / 10.0; + const double apperture_y = cam->sensor_y / 10.0; + const double film_aspect = apperture_x / apperture_y; + + CameraSample camera_sample; + camera_sample.setFocalLength(cam->lens); + camera_sample.setHorizontalAperture(apperture_x); + camera_sample.setVerticalAperture(apperture_y); + camera_sample.setHorizontalFilmOffset(apperture_x * cam->shiftx); + camera_sample.setVerticalFilmOffset(apperture_y * cam->shifty * film_aspect); + camera_sample.setNearClippingPlane(cam->clip_start); + camera_sample.setFarClippingPlane(cam->clip_end); + + if (cam->dof.focus_object) { + Imath::V3f v(context.object->loc[0] - cam->dof.focus_object->loc[0], + context.object->loc[1] - cam->dof.focus_object->loc[1], + context.object->loc[2] - cam->dof.focus_object->loc[2]); + camera_sample.setFocusDistance(v.length()); + } + else { + camera_sample.setFocusDistance(cam->dof.focus_distance); + } + + /* Blender camera does not have an fstop param, so try to find a custom prop + * instead. */ + camera_sample.setFStop(cam->dof.aperture_fstop); + + camera_sample.setLensSqueezeRatio(1.0); + abc_camera_schema_.set(camera_sample); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_camera.h b/source/blender/io/alembic/exporter/abc_writer_camera.h new file mode 100644 index 00000000000..a72cfa2f357 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_camera.h @@ -0,0 +1,52 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#pragma once + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_abstract.h" + +#include <Alembic/AbcGeom/OCamera.h> + +namespace blender { +namespace io { +namespace alembic { + +class ABCCameraWriter : public ABCAbstractWriter { + private: + Alembic::AbcGeom::OCamera abc_camera_; + Alembic::AbcGeom::OCameraSchema abc_camera_schema_; + + Alembic::AbcGeom::OCompoundProperty abc_custom_data_container_; + Alembic::AbcGeom::OFloatProperty abc_stereo_distance_; + Alembic::AbcGeom::OFloatProperty abc_eye_separation_; + + public: + explicit ABCCameraWriter(const ABCWriterConstructorArgs &args); + + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; + + protected: + virtual bool is_supported(const HierarchyContext *context) const override; + virtual void do_write(HierarchyContext &context) override; +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_curves.cc b/source/blender/io/alembic/exporter/abc_writer_curves.cc index db93ac1920e..f2a46c5e4fe 100644 --- a/source/blender/io/alembic/intern/abc_writer_curves.cc +++ b/source/blender/io/alembic/exporter/abc_writer_curves.cc @@ -22,9 +22,7 @@ */ #include "abc_writer_curves.h" -#include "abc_axis_conversion.h" -#include "abc_reader_curves.h" -#include "abc_writer_transform.h" +#include "intern/abc_axis_conversion.h" #include "DNA_curve_types.h" #include "DNA_object_types.h" @@ -33,6 +31,9 @@ #include "BKE_mesh.h" #include "BKE_object.h" +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + using Alembic::AbcGeom::OCompoundProperty; using Alembic::AbcGeom::OCurves; using Alembic::AbcGeom::OCurvesSchema; @@ -40,24 +41,36 @@ using Alembic::AbcGeom::OInt16Property; using Alembic::AbcGeom::ON3fGeomParam; using Alembic::AbcGeom::OV2fGeomParam; -AbcCurveWriter::AbcCurveWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent) +namespace blender { +namespace io { +namespace alembic { + +const std::string ABC_CURVE_RESOLUTION_U_PROPNAME("blender:resolution"); + +ABCCurveWriter::ABCCurveWriter(const ABCWriterConstructorArgs &args) : ABCAbstractWriter(args) +{ +} + +void ABCCurveWriter::create_alembic_objects(const HierarchyContext *context) { - OCurves curves(parent->alembicXform(), m_name, m_time_sampling); - m_schema = curves.getSchema(); + CLOG_INFO(&LOG, 2, "exporting %s", args_.abc_path.c_str()); + abc_curve_ = OCurves(args_.abc_parent, args_.abc_name, timesample_index_); + abc_curve_schema_ = abc_curve_.getSchema(); - Curve *cu = static_cast<Curve *>(m_object->data); - OCompoundProperty user_props = m_schema.getUserProperties(); + Curve *cu = static_cast<Curve *>(context->object->data); + OCompoundProperty user_props = abc_curve_schema_.getUserProperties(); OInt16Property user_prop_resolu(user_props, ABC_CURVE_RESOLUTION_U_PROPNAME); user_prop_resolu.set(cu->resolu); } -void AbcCurveWriter::do_write() +const Alembic::Abc::OObject ABCCurveWriter::get_alembic_object() const { - Curve *curve = static_cast<Curve *>(m_object->data); + return abc_curve_; +} + +void ABCCurveWriter::do_write(HierarchyContext &context) +{ + Curve *curve = static_cast<Curve *>(context.object->data); std::vector<Imath::V3f> verts; std::vector<int32_t> vert_counts; @@ -148,35 +161,31 @@ void AbcCurveWriter::do_write() Alembic::AbcGeom::OFloatGeomParam::Sample width_sample; width_sample.setVals(widths); - m_sample = OCurvesSchema::Sample(verts, - vert_counts, - curve_type, - periodicity, - width_sample, - OV2fGeomParam::Sample(), /* UVs */ - ON3fGeomParam::Sample(), /* normals */ - curve_basis, - weights, - orders, - knots); - - m_sample.setSelfBounds(bounds()); - m_schema.set(m_sample); + OCurvesSchema::Sample sample(verts, + vert_counts, + curve_type, + periodicity, + width_sample, + OV2fGeomParam::Sample(), /* UVs */ + ON3fGeomParam::Sample(), /* normals */ + curve_basis, + weights, + orders, + knots); + + update_bounding_box(context.object); + sample.setSelfBounds(bounding_box_); + abc_curve_schema_.set(sample); } -AbcCurveMeshWriter::AbcCurveMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcGenericMeshWriter(ob, parent, time_sampling, settings) +ABCCurveMeshWriter::ABCCurveMeshWriter(const ABCWriterConstructorArgs &args) + : ABCGenericMeshWriter(args) { } -Mesh *AbcCurveMeshWriter::getEvaluatedMesh(Scene * /*scene_eval*/, - Object *ob_eval, - bool &r_needsfree) +Mesh *ABCCurveMeshWriter::get_export_mesh(Object *object_eval, bool &r_needsfree) { - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); + Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object_eval); if (mesh_eval != NULL) { /* Mesh_eval only exists when generative modifiers are in use. */ r_needsfree = false; @@ -184,5 +193,9 @@ Mesh *AbcCurveMeshWriter::getEvaluatedMesh(Scene * /*scene_eval*/, } r_needsfree = true; - return BKE_mesh_new_nomain_from_curve(ob_eval); + return BKE_mesh_new_nomain_from_curve(object_eval); } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_curves.h b/source/blender/io/alembic/exporter/abc_writer_curves.h index 83f0289dd2d..12a909761f5 100644 --- a/source/blender/io/alembic/intern/abc_writer_curves.h +++ b/source/blender/io/alembic/exporter/abc_writer_curves.h @@ -16,40 +16,46 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_WRITER_CURVES_H__ -#define __ABC_WRITER_CURVES_H__ - +#include "abc_writer_abstract.h" #include "abc_writer_mesh.h" -#include "abc_writer_object.h" -class AbcCurveWriter : public AbcObjectWriter { - Alembic::AbcGeom::OCurvesSchema m_schema; - Alembic::AbcGeom::OCurvesSchema::Sample m_sample; +#include <Alembic/AbcGeom/OCurves.h> + +namespace blender { +namespace io { +namespace alembic { + +extern const std::string ABC_CURVE_RESOLUTION_U_PROPNAME; + +class ABCCurveWriter : public ABCAbstractWriter { + private: + Alembic::AbcGeom::OCurves abc_curve_; + Alembic::AbcGeom::OCurvesSchema abc_curve_schema_; public: - AbcCurveWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); + explicit ABCCurveWriter(const ABCWriterConstructorArgs &args); + + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; protected: - void do_write(); + virtual void do_write(HierarchyContext &context) override; }; -class AbcCurveMeshWriter : public AbcGenericMeshWriter { +class ABCCurveMeshWriter : public ABCGenericMeshWriter { public: - AbcCurveMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); + ABCCurveMeshWriter(const ABCWriterConstructorArgs &args); protected: - Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree); + virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override; }; -#endif /* __ABC_WRITER_CURVES_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc index ed62889b03d..ac4deddd9b4 100644 --- a/source/blender/io/alembic/intern/abc_writer_hair.cc +++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc @@ -19,8 +19,7 @@ */ #include "abc_writer_hair.h" -#include "abc_axis_conversion.h" -#include "abc_writer_transform.h" +#include "intern/abc_axis_conversion.h" #include <cstdio> @@ -35,35 +34,46 @@ #include "BKE_mesh_runtime.h" #include "BKE_particle.h" -using Alembic::Abc::P3fArraySamplePtr; +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; +using Alembic::Abc::P3fArraySamplePtr; using Alembic::AbcGeom::OCurves; using Alembic::AbcGeom::OCurvesSchema; using Alembic::AbcGeom::ON3fGeomParam; using Alembic::AbcGeom::OV2fGeomParam; -/* ************************************************************************** */ +namespace blender { +namespace io { +namespace alembic { -AbcHairWriter::AbcHairWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys) - : AbcObjectWriter(ob, time_sampling, settings, parent), m_uv_warning_shown(false) +ABCHairWriter::ABCHairWriter(const ABCWriterConstructorArgs &args) + : ABCAbstractWriter(args), uv_warning_shown_(false) { - m_psys = psys; +} - OCurves curves(parent->alembicXform(), psys->name, m_time_sampling); - m_schema = curves.getSchema(); +void ABCHairWriter::create_alembic_objects(const HierarchyContext * /*context*/) +{ + CLOG_INFO(&LOG, 2, "exporting %s", args_.abc_path.c_str()); + abc_curves_ = OCurves(args_.abc_parent, args_.abc_name, timesample_index_); + abc_curves_schema_ = abc_curves_.getSchema(); } -void AbcHairWriter::do_write() +const Alembic::Abc::OObject ABCHairWriter::get_alembic_object() const { - if (!m_psys) { - return; - } - Mesh *mesh = mesh_get_eval_final( - m_settings.depsgraph, m_settings.scene, m_object, &CD_MASK_MESH); + return abc_curves_; +} + +bool ABCHairWriter::check_is_animated(const HierarchyContext & /*context*/) const +{ + /* We assume that hair particles are always animated. */ + return true; +} + +void ABCHairWriter::do_write(HierarchyContext &context) +{ + Scene *scene_eval = DEG_get_evaluated_scene(args_.depsgraph); + Mesh *mesh = mesh_get_eval_final(args_.depsgraph, scene_eval, context.object, &CD_MASK_MESH); BKE_mesh_tessface_ensure(mesh); std::vector<Imath::V3f> verts; @@ -71,44 +81,45 @@ void AbcHairWriter::do_write() std::vector<Imath::V2f> uv_values; std::vector<Imath::V3f> norm_values; - if (m_psys->pathcache) { - ParticleSettings *part = m_psys->part; - bool export_children = m_settings.export_child_hairs && m_psys->childcache && - part->childtype != 0; + ParticleSystem *psys = context.particle_system; + if (psys->pathcache) { + ParticleSettings *part = psys->part; + bool export_children = psys->childcache && part->childtype != 0; if (!export_children || part->draw & PART_DRAW_PARENT) { - write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices); + write_hair_sample(context, mesh, verts, norm_values, uv_values, hvertices); } if (export_children) { - write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices); + write_hair_child_sample(context, mesh, verts, norm_values, uv_values, hvertices); } } Alembic::Abc::P3fArraySample iPos(verts); - m_sample = OCurvesSchema::Sample(iPos, hvertices); - m_sample.setBasis(Alembic::AbcGeom::kNoBasis); - m_sample.setType(Alembic::AbcGeom::kLinear); - m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic); + OCurvesSchema::Sample sample(iPos, hvertices); + sample.setBasis(Alembic::AbcGeom::kNoBasis); + sample.setType(Alembic::AbcGeom::kLinear); + sample.setWrap(Alembic::AbcGeom::kNonPeriodic); if (!uv_values.empty()) { OV2fGeomParam::Sample uv_smp; uv_smp.setVals(uv_values); - m_sample.setUVs(uv_smp); + sample.setUVs(uv_smp); } if (!norm_values.empty()) { ON3fGeomParam::Sample norm_smp; norm_smp.setVals(norm_values); - m_sample.setNormals(norm_smp); + sample.setNormals(norm_smp); } - m_sample.setSelfBounds(bounds()); - m_schema.set(m_sample); + update_bounding_box(context.object); + sample.setSelfBounds(bounding_box_); + abc_curves_schema_.set(sample); } -void AbcHairWriter::write_hair_sample(Mesh *mesh, - ParticleSettings *part, +void ABCHairWriter::write_hair_sample(const HierarchyContext &context, + Mesh *mesh, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, std::vector<Imath::V2f> &uv_values, @@ -116,28 +127,30 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh, { /* Get untransformed vertices, there's a xform under the hair. */ float inv_mat[4][4]; - invert_m4_m4_safe(inv_mat, m_object->obmat); + invert_m4_m4_safe(inv_mat, context.object->obmat); MTFace *mtface = mesh->mtface; MFace *mface = mesh->mface; MVert *mverts = mesh->mvert; - if ((!mtface || !mface) && !m_uv_warning_shown) { + if ((!mtface || !mface) && !uv_warning_shown_) { std::fprintf(stderr, "Warning, no UV set found for underlying geometry of %s.\n", - m_object->id.name + 2); - m_uv_warning_shown = true; + context.object->id.name + 2); + uv_warning_shown_ = true; } - ParticleData *pa = m_psys->particles; + ParticleSystem *psys = context.particle_system; + ParticleSettings *part = psys->part; + ParticleData *pa = psys->particles; int k; - ParticleCacheKey **cache = m_psys->pathcache; + ParticleCacheKey **cache = psys->pathcache; ParticleCacheKey *path; float normal[3]; Imath::V3f tmp_nor; - for (int p = 0; p < m_psys->totpart; p++, pa++) { + for (int p = 0; p < psys->totpart; p++, pa++) { /* underlying info for faces-only emission */ path = cache[p]; @@ -219,8 +232,8 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh, } } -void AbcHairWriter::write_hair_child_sample(Mesh *mesh, - ParticleSettings *part, +void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context, + Mesh *mesh, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, std::vector<Imath::V2f> &uv_values, @@ -228,26 +241,30 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh, { /* Get untransformed vertices, there's a xform under the hair. */ float inv_mat[4][4]; - invert_m4_m4_safe(inv_mat, m_object->obmat); + invert_m4_m4_safe(inv_mat, context.object->obmat); MTFace *mtface = mesh->mtface; MVert *mverts = mesh->mvert; - ParticleCacheKey **cache = m_psys->childcache; + ParticleSystem *psys = context.particle_system; + ParticleSettings *part = psys->part; + ParticleCacheKey **cache = psys->childcache; ParticleCacheKey *path; - ChildParticle *pc = m_psys->child; + ChildParticle *pc = psys->child; - for (int p = 0; p < m_psys->totchild; p++, pc++) { + for (int p = 0; p < psys->totchild; p++, pc++) { path = cache[p]; if (part->from == PART_FROM_FACE && part->childtype != PART_CHILD_PARTICLES && mtface) { const int num = pc->num; if (num < 0) { - ABC_LOG(m_settings.logger) - << "Warning, child particle of hair system " << m_psys->name - << " has unknown face index of geometry of " << (m_object->id.name + 2) - << ", skipping child hair." << std::endl; + CLOG_WARN( + &LOG, + "Child particle of hair system %s has unknown face index of geometry of %s, skipping " + "child hair.", + psys->name, + context.object->id.name + 2); continue; } @@ -288,3 +305,7 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh, } } } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_hair.h b/source/blender/io/alembic/exporter/abc_writer_hair.h index 67d1b7b3d23..af1372a08f3 100644 --- a/source/blender/io/alembic/intern/abc_writer_hair.h +++ b/source/blender/io/alembic/exporter/abc_writer_hair.h @@ -13,50 +13,56 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_WRITER_HAIR_H__ -#define __ABC_WRITER_HAIR_H__ - -#include "abc_writer_object.h" +#include "abc_writer_abstract.h" +#include <Alembic/AbcGeom/OCurves.h> +#include <vector> struct ParticleSettings; struct ParticleSystem; -class AbcHairWriter : public AbcObjectWriter { - ParticleSystem *m_psys; +namespace blender { +namespace io { +namespace alembic { - Alembic::AbcGeom::OCurvesSchema m_schema; - Alembic::AbcGeom::OCurvesSchema::Sample m_sample; +class ABCHairWriter : public ABCAbstractWriter { + private: + Alembic::AbcGeom::OCurves abc_curves_; + Alembic::AbcGeom::OCurvesSchema abc_curves_schema_; - bool m_uv_warning_shown; + bool uv_warning_shown_; public: - AbcHairWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys); + explicit ABCHairWriter(const ABCWriterConstructorArgs &args); - private: - virtual void do_write(); + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; - void write_hair_sample(struct Mesh *mesh, - ParticleSettings *part, + protected: + virtual void do_write(HierarchyContext &context) override; + virtual bool check_is_animated(const HierarchyContext &context) const override; + + private: + void write_hair_sample(const HierarchyContext &context, + struct Mesh *mesh, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, std::vector<Imath::V2f> &uv_values, std::vector<int32_t> &hvertices); - void write_hair_child_sample(struct Mesh *mesh, - ParticleSettings *part, + void write_hair_child_sample(const HierarchyContext &context, + struct Mesh *mesh, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, std::vector<Imath::V2f> &uv_values, std::vector<int32_t> &hvertices); }; -#endif /* __ABC_WRITER_HAIR_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_mball.cc b/source/blender/io/alembic/exporter/abc_writer_mball.cc new file mode 100644 index 00000000000..167e392eb96 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_mball.cc @@ -0,0 +1,90 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_mball.h" +#include "abc_hierarchy_iterator.h" + +#include "BLI_assert.h" + +#include "BKE_displist.h" +#include "BKE_lib_id.h" +#include "BKE_mball.h" +#include "BKE_mesh.h" +#include "BKE_object.h" + +#include "DNA_mesh_types.h" +#include "DNA_meta_types.h" + +namespace blender { +namespace io { +namespace alembic { + +ABCMetaballWriter::ABCMetaballWriter(const ABCWriterConstructorArgs &args) + : ABCGenericMeshWriter(args) +{ +} + +bool ABCMetaballWriter::is_supported(const HierarchyContext *context) const +{ + Scene *scene = DEG_get_input_scene(args_.depsgraph); + bool supported = is_basis_ball(scene, context->object) && + ABCGenericMeshWriter::is_supported(context); + return supported; +} + +bool ABCMetaballWriter::check_is_animated(const HierarchyContext & /*context*/) const +{ + /* We assume that metaballs are always animated, as the current object may + * not be animated but another ball in the same group may be. */ + return true; +} + +bool ABCMetaballWriter::export_as_subdivision_surface(Object * /*ob_eval*/) const +{ + /* Metaballs should be exported to subdivision surfaces, if the export options allow. */ + return true; +} + +Mesh *ABCMetaballWriter::get_export_mesh(Object *object_eval, bool &r_needsfree) +{ + Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object_eval); + if (mesh_eval != nullptr) { + /* Mesh_eval only exists when generative modifiers are in use. */ + r_needsfree = false; + return mesh_eval; + } + r_needsfree = true; + return BKE_mesh_new_from_object(args_.depsgraph, object_eval, false); +} + +void ABCMetaballWriter::free_export_mesh(Mesh *mesh) +{ + BKE_id_free(nullptr, mesh); +} + +bool ABCMetaballWriter::is_basis_ball(Scene *scene, Object *ob) const +{ + Object *basis_ob = BKE_mball_basis_find(scene, ob); + return ob == basis_ob; +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_camera.h b/source/blender/io/alembic/exporter/abc_writer_mball.h index 3b515911a48..90d8c4d4b15 100644 --- a/source/blender/io/alembic/intern/abc_writer_camera.h +++ b/source/blender/io/alembic/exporter/abc_writer_mball.h @@ -13,33 +13,33 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_WRITER_CAMERA_H__ -#define __ABC_WRITER_CAMERA_H__ +#include "abc_writer_mesh.h" -#include "abc_writer_object.h" - -/* ************************************************************************** */ - -class AbcCameraWriter : public AbcObjectWriter { - Alembic::AbcGeom::OCameraSchema m_camera_schema; - Alembic::AbcGeom::CameraSample m_camera_sample; - Alembic::AbcGeom::OCompoundProperty m_custom_data_container; - Alembic::AbcGeom::OFloatProperty m_stereo_distance; - Alembic::AbcGeom::OFloatProperty m_eye_separation; +namespace blender { +namespace io { +namespace alembic { +class ABCMetaballWriter : public ABCGenericMeshWriter { public: - AbcCameraWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); + explicit ABCMetaballWriter(const ABCWriterConstructorArgs &args); + + protected: + virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override; + virtual void free_export_mesh(Mesh *mesh) override; + virtual bool is_supported(const HierarchyContext *context) const override; + virtual bool check_is_animated(const HierarchyContext &context) const override; + virtual bool export_as_subdivision_surface(Object *ob_eval) const override; private: - virtual void do_write(); + bool is_basis_ball(Scene *scene, Object *ob) const; }; -#endif /* __ABC_WRITER_CAMERA_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index df1734c9de1..07196f2b81f 100644 --- a/source/blender/io/alembic/intern/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -19,29 +19,37 @@ */ #include "abc_writer_mesh.h" -#include "abc_axis_conversion.h" -#include "abc_writer_transform.h" +#include "abc_hierarchy_iterator.h" +#include "intern/abc_axis_conversion.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_fluidsim_types.h" +#include "BLI_assert.h" +#include "BLI_math_vector.h" -#include "BKE_anim_data.h" -#include "BKE_key.h" +#include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_material.h" #include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" +#include "BKE_object.h" #include "bmesh.h" #include "bmesh_tools.h" -#include "DEG_depsgraph_query.h" +#include "DEG_depsgraph.h" + +#include "DNA_layer_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_fluidsim_types.h" +#include "DNA_particle_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; using Alembic::Abc::FloatArraySample; using Alembic::Abc::Int32ArraySample; +using Alembic::Abc::OObject; using Alembic::Abc::V2fArraySample; using Alembic::Abc::V3fArraySample; @@ -58,138 +66,83 @@ using Alembic::AbcGeom::OSubDSchema; using Alembic::AbcGeom::OV2fGeomParam; using Alembic::AbcGeom::UInt32ArraySample; -/* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ - -static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points) -{ - points.clear(); - points.resize(mesh->totvert); +namespace blender { +namespace io { +namespace alembic { - MVert *verts = mesh->mvert; - - for (int i = 0, e = mesh->totvert; i < e; i++) { - copy_yup_from_zup(points[i].getValue(), verts[i].co); - } -} +/* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ +static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points); static void get_topology(struct Mesh *mesh, std::vector<int32_t> &poly_verts, std::vector<int32_t> &loop_counts, - bool &r_has_flat_shaded_poly) -{ - const int num_poly = mesh->totpoly; - const int num_loops = mesh->totloop; - MLoop *mloop = mesh->mloop; - MPoly *mpoly = mesh->mpoly; - r_has_flat_shaded_poly = false; - - poly_verts.clear(); - loop_counts.clear(); - poly_verts.reserve(num_loops); - loop_counts.reserve(num_poly); - - /* NOTE: data needs to be written in the reverse order. */ - for (int i = 0; i < num_poly; i++) { - MPoly &poly = mpoly[i]; - loop_counts.push_back(poly.totloop); - - r_has_flat_shaded_poly |= (poly.flag & ME_SMOOTH) == 0; - - MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1); - - for (int j = 0; j < poly.totloop; j++, loop--) { - poly_verts.push_back(loop->v); - } - } -} - + bool &r_has_flat_shaded_poly); static void get_creases(struct Mesh *mesh, std::vector<int32_t> &indices, std::vector<int32_t> &lengths, - std::vector<float> &sharpnesses) -{ - const float factor = 1.0f / 255.0f; + std::vector<float> &sharpnesses); +static void get_loop_normals(struct Mesh *mesh, + std::vector<Imath::V3f> &normals, + bool has_flat_shaded_poly); - indices.clear(); - lengths.clear(); - sharpnesses.clear(); +ABCGenericMeshWriter::ABCGenericMeshWriter(const ABCWriterConstructorArgs &args) + : ABCAbstractWriter(args), is_subd_(false) +{ +} - MEdge *edge = mesh->medge; +void ABCGenericMeshWriter::create_alembic_objects(const HierarchyContext *context) +{ + if (!args_.export_params->apply_subdiv && export_as_subdivision_surface(context->object)) { + is_subd_ = args_.export_params->use_subdiv_schema; + } - for (int i = 0, e = mesh->totedge; i < e; i++) { - const float sharpness = static_cast<float>(edge[i].crease) * factor; + if (is_subd_) { + CLOG_INFO(&LOG, 2, "exporting OSubD %s", args_.abc_path.c_str()); + abc_subdiv_ = OSubD(args_.abc_parent, args_.abc_name, timesample_index_); + abc_subdiv_schema_ = abc_subdiv_.getSchema(); + } + else { + CLOG_INFO(&LOG, 2, "exporting OPolyMesh %s", args_.abc_path.c_str()); + abc_poly_mesh_ = OPolyMesh(args_.abc_parent, args_.abc_name, timesample_index_); + abc_poly_mesh_schema_ = abc_poly_mesh_.getSchema(); - if (sharpness != 0.0f) { - indices.push_back(edge[i].v1); - indices.push_back(edge[i].v2); - sharpnesses.push_back(sharpness); - } + OCompoundProperty typeContainer = abc_poly_mesh_.getSchema().getUserProperties(); + OBoolProperty type(typeContainer, "meshtype"); + type.set(subsurf_modifier_ == nullptr); } - lengths.resize(sharpnesses.size(), 2); + Scene *scene_eval = DEG_get_evaluated_scene(args_.depsgraph); + liquid_sim_modifier_ = get_liquid_sim_modifier(scene_eval, context->object); } -static void get_loop_normals(struct Mesh *mesh, - std::vector<Imath::V3f> &normals, - bool has_flat_shaded_poly) +ABCGenericMeshWriter::~ABCGenericMeshWriter() { - normals.clear(); - - /* If all polygons are smooth shaded, and there are no custom normals, we don't need to export - * normals at all. This is also done by other software, see T71246. */ - if (!has_flat_shaded_poly && !CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL) && - (mesh->flag & ME_AUTOSMOOTH) == 0) { - return; - } - - BKE_mesh_calc_normals_split(mesh); - const float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL)); - BLI_assert(lnors != NULL || !"BKE_mesh_calc_normals_split() should have computed CD_NORMAL"); - - normals.resize(mesh->totloop); +} - /* NOTE: data needs to be written in the reverse order. */ - int abc_index = 0; - MPoly *mp = mesh->mpoly; - for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) { - for (int j = mp->totloop - 1; j >= 0; j--, abc_index++) { - int blender_index = mp->loopstart + j; - copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]); - } +const Alembic::Abc::OObject ABCGenericMeshWriter::get_alembic_object() const +{ + if (is_subd_) { + return abc_subdiv_; } + return abc_poly_mesh_; } -/* *************** Modifiers *************** */ - -/* check if the mesh is a subsurf, ignoring disabled modifiers and - * displace if it's after subsurf. */ -static ModifierData *get_subsurf_modifier(Scene *scene, Object *ob) +bool ABCGenericMeshWriter::export_as_subdivision_surface(Object *ob_eval) const { - ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last); + ModifierData *md = static_cast<ModifierData *>(ob_eval->modifiers.last); for (; md; md = md->prev) { - if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Render)) { - continue; - } - - if (md->type == eModifierType_Subsurf) { - SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>(md); - - if (smd->subdivType == ME_CC_SUBSURF) { - return md; - } - } - - /* mesh is not a subsurf. break */ - if ((md->type != eModifierType_Displace) && (md->type != eModifierType_ParticleSystem)) { - return NULL; + /* This modifier has been temporarily disabled by SubdivModifierDisabler, + * so this indicates this is to be exported as subdivision surface. */ + if (md->type == eModifierType_Subsurf && (md->mode & eModifierMode_DisableTemporary)) { + return true; } } - return NULL; + return false; } -static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob) +ModifierData *ABCGenericMeshWriter::get_liquid_sim_modifier(Scene *scene, Object *ob) { ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluidsim); @@ -201,122 +154,99 @@ static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob) } } - return NULL; + return nullptr; } -/* ************************************************************************** */ - -AbcGenericMeshWriter::AbcGenericMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent) +bool ABCGenericMeshWriter::is_supported(const HierarchyContext *context) const { - m_is_animated = isAnimated(); - m_subsurf_mod = NULL; - m_is_subd = false; - - /* If the object is static, use the default static time sampling. */ - if (!m_is_animated) { - time_sampling = 0; - } + Object *object = context->object; + bool is_dupli = context->duplicator != nullptr; + int base_flag; - if (!m_settings.apply_subdiv) { - m_subsurf_mod = get_subsurf_modifier(m_settings.scene, m_object); - m_is_subd = (m_subsurf_mod != NULL); + if (is_dupli) { + /* Construct the object's base flags from its dupli-parent, just like is done in + * deg_objects_dupli_iterator_next(). Without this, the visibility check below will fail. Doing + * this here, instead of a more suitable location in AbstractHierarchyIterator, prevents + * copying the Object for every dupli. */ + base_flag = object->base_flag; + object->base_flag = context->duplicator->base_flag | BASE_FROM_DUPLI; } - m_is_liquid = (get_liquid_sim_modifier(m_settings.scene, m_object) != NULL); + int visibility = BKE_object_visibility( + object, DAG_EVAL_RENDER /* TODO(Sybren): add evaluation mode to export options? */); - while (parent->alembicXform().getChildHeader(m_name)) { - m_name.append("_"); + if (is_dupli) { + object->base_flag = base_flag; } - if (m_settings.use_subdiv_schema && m_is_subd) { - OSubD subd(parent->alembicXform(), m_name, m_time_sampling); - m_subdiv_schema = subd.getSchema(); - } - else { - OPolyMesh mesh(parent->alembicXform(), m_name, m_time_sampling); - m_mesh_schema = mesh.getSchema(); - - OCompoundProperty typeContainer = m_mesh_schema.getUserProperties(); - OBoolProperty type(typeContainer, "meshtype"); - type.set(m_is_subd); - } + return (visibility & OB_VISIBLE_SELF) != 0; } -AbcGenericMeshWriter::~AbcGenericMeshWriter() +void ABCGenericMeshWriter::do_write(HierarchyContext &context) { - if (m_subsurf_mod) { - m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; - } -} + Object *object = context.object; + bool needsfree = false; -bool AbcGenericMeshWriter::isAnimated() const -{ - if (BKE_animdata_id_is_animated(static_cast<ID *>(m_object->data))) { - return true; - } - if (BKE_key_from_object(m_object) != NULL) { - return true; - } + Mesh *mesh = get_export_mesh(object, needsfree); - /* Test modifiers. */ - ModifierData *md = static_cast<ModifierData *>(m_object->modifiers.first); - while (md) { + if (mesh == nullptr) { + return; + } - if (md->type != eModifierType_Subsurf) { - return true; - } + if (args_.export_params->triangulate) { + const bool tag_only = false; + const int quad_method = args_.export_params->quad_method; + const int ngon_method = args_.export_params->ngon_method; - md = md->next; - } + struct BMeshCreateParams bmcp = {false}; + struct BMeshFromMeshParams bmfmp = {true, false, false, 0}; + BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp); - return false; -} + BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr); -void AbcGenericMeshWriter::setIsAnimated(bool is_animated) -{ - m_is_animated = is_animated; -} + Mesh *triangulated_mesh = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); + BM_mesh_free(bm); -void AbcGenericMeshWriter::do_write() -{ - /* We have already stored a sample for this object. */ - if (!m_first_frame && !m_is_animated) { - return; + if (needsfree) { + free_export_mesh(mesh); + } + mesh = triangulated_mesh; + needsfree = true; } - bool needsfree; - struct Mesh *mesh = getFinalMesh(needsfree); + m_custom_data_config.pack_uvs = args_.export_params->packuv; + m_custom_data_config.mpoly = mesh->mpoly; + m_custom_data_config.mloop = mesh->mloop; + m_custom_data_config.totpoly = mesh->totpoly; + m_custom_data_config.totloop = mesh->totloop; + m_custom_data_config.totvert = mesh->totvert; try { - if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) { - writeSubD(mesh); + if (is_subd_) { + write_subd(context, mesh); } else { - writeMesh(mesh); + write_mesh(context, mesh); } if (needsfree) { - freeEvaluatedMesh(mesh); + free_export_mesh(mesh); } } catch (...) { if (needsfree) { - freeEvaluatedMesh(mesh); + free_export_mesh(mesh); } throw; } } -void AbcGenericMeshWriter::freeEvaluatedMesh(struct Mesh *mesh) +void ABCGenericMeshWriter::free_export_mesh(Mesh *mesh) { - BKE_id_free(NULL, mesh); + BKE_id_free(nullptr, mesh); } -void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) +void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh) { std::vector<Imath::V3f> points, normals; std::vector<int32_t> poly_verts, loop_counts; @@ -326,32 +256,33 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) get_vertices(mesh, points); get_topology(mesh, poly_verts, loop_counts, has_flat_shaded_poly); - if (m_first_frame && m_settings.export_face_sets) { - writeFaceSets(mesh, m_mesh_schema); + if (!frame_has_been_written_ && args_.export_params->face_sets) { + write_face_sets(context.object, mesh, abc_poly_mesh_schema_); } - m_mesh_sample = OPolyMeshSchema::Sample( + OPolyMeshSchema::Sample mesh_sample = OPolyMeshSchema::Sample( V3fArraySample(points), Int32ArraySample(poly_verts), Int32ArraySample(loop_counts)); - UVSample sample; - if (m_settings.export_uvs) { - const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); + UVSample uvs_and_indices; - if (!sample.indices.empty() && !sample.uvs.empty()) { + if (!frame_has_been_written_ && args_.export_params->uvs) { + const char *name = get_uv_sample(uvs_and_indices, m_custom_data_config, &mesh->ldata); + + if (!uvs_and_indices.indices.empty() && !uvs_and_indices.uvs.empty()) { OV2fGeomParam::Sample uv_sample; - uv_sample.setVals(V2fArraySample(sample.uvs)); - uv_sample.setIndices(UInt32ArraySample(sample.indices)); + uv_sample.setVals(V2fArraySample(uvs_and_indices.uvs)); + uv_sample.setIndices(UInt32ArraySample(uvs_and_indices.indices)); uv_sample.setScope(kFacevaryingScope); - m_mesh_schema.setUVSourceName(name); - m_mesh_sample.setUVs(uv_sample); + abc_poly_mesh_schema_.setUVSourceName(name); + mesh_sample.setUVs(uv_sample); } write_custom_data( - m_mesh_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); + abc_poly_mesh_schema_.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); } - if (m_settings.export_normals) { + if (args_.export_params->normals) { get_loop_normals(mesh, normals, has_flat_shaded_poly); ON3fGeomParam::Sample normals_sample; @@ -360,22 +291,23 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) normals_sample.setVals(V3fArraySample(normals)); } - m_mesh_sample.setNormals(normals_sample); + mesh_sample.setNormals(normals_sample); } - if (m_is_liquid) { - getVelocities(mesh, velocities); - m_mesh_sample.setVelocities(V3fArraySample(velocities)); + if (liquid_sim_modifier_ != nullptr) { + get_velocities(mesh, velocities); + mesh_sample.setVelocities(V3fArraySample(velocities)); } - m_mesh_sample.setSelfBounds(bounds()); + update_bounding_box(context.object); + mesh_sample.setSelfBounds(bounding_box_); - m_mesh_schema.set(m_mesh_sample); + abc_poly_mesh_schema_.set(mesh_sample); - writeArbGeoParams(mesh); + write_arb_geo_params(mesh); } -void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh) +void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *mesh) { std::vector<float> crease_sharpness; std::vector<Imath::V3f> points; @@ -387,15 +319,15 @@ void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh) get_topology(mesh, poly_verts, loop_counts, has_flat_poly); get_creases(mesh, crease_indices, crease_lengths, crease_sharpness); - if (m_first_frame && m_settings.export_face_sets) { - writeFaceSets(mesh, m_subdiv_schema); + if (!frame_has_been_written_ && args_.export_params->face_sets) { + write_face_sets(context.object, mesh, abc_subdiv_schema_); } - m_subdiv_sample = OSubDSchema::Sample( + OSubDSchema::Sample subdiv_sample = OSubDSchema::Sample( V3fArraySample(points), Int32ArraySample(poly_verts), Int32ArraySample(loop_counts)); UVSample sample; - if (m_first_frame && m_settings.export_uvs) { + if (!frame_has_been_written_ && args_.export_params->uvs) { const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); if (!sample.indices.empty() && !sample.uvs.empty()) { @@ -404,30 +336,32 @@ void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh) uv_sample.setIndices(UInt32ArraySample(sample.indices)); uv_sample.setScope(kFacevaryingScope); - m_subdiv_schema.setUVSourceName(name); - m_subdiv_sample.setUVs(uv_sample); + abc_subdiv_schema_.setUVSourceName(name); + subdiv_sample.setUVs(uv_sample); } write_custom_data( - m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); + abc_subdiv_schema_.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); } if (!crease_indices.empty()) { - m_subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices)); - m_subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths)); - m_subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness)); + subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices)); + subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths)); + subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness)); } - m_subdiv_sample.setSelfBounds(bounds()); - m_subdiv_schema.set(m_subdiv_sample); + update_bounding_box(context.object); + subdiv_sample.setSelfBounds(bounding_box_); + abc_subdiv_schema_.set(subdiv_sample); - writeArbGeoParams(mesh); + write_arb_geo_params(mesh); } -template<typename Schema> void AbcGenericMeshWriter::writeFaceSets(struct Mesh *me, Schema &schema) +template<typename Schema> +void ABCGenericMeshWriter::write_face_sets(Object *object, struct Mesh *mesh, Schema &schema) { std::map<std::string, std::vector<int32_t>> geo_groups; - getGeoGroups(me, geo_groups); + get_geo_groups(object, mesh, geo_groups); std::map<std::string, std::vector<int32_t>>::iterator it; for (it = geo_groups.begin(); it != geo_groups.end(); ++it) { @@ -438,83 +372,35 @@ template<typename Schema> void AbcGenericMeshWriter::writeFaceSets(struct Mesh * } } -Mesh *AbcGenericMeshWriter::getFinalMesh(bool &r_needsfree) +void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me) { - /* We don't want subdivided mesh data */ - if (m_subsurf_mod) { - m_subsurf_mod->mode |= eModifierMode_DisableTemporary; - } - - r_needsfree = false; - - Scene *scene = DEG_get_evaluated_scene(m_settings.depsgraph); - Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object); - struct Mesh *mesh = getEvaluatedMesh(scene, ob_eval, r_needsfree); - - if (m_subsurf_mod) { - m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; - } - - if (m_settings.triangulate) { - const bool tag_only = false; - const int quad_method = m_settings.quad_method; - const int ngon_method = m_settings.ngon_method; - - struct BMeshCreateParams bmcp = {false}; - struct BMeshFromMeshParams bmfmp = {true, false, false, 0}; - BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp); - - BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, NULL, NULL, NULL); - - Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); - BM_mesh_free(bm); - - if (r_needsfree) { - BKE_id_free(NULL, mesh); - } - - mesh = result; - r_needsfree = true; + if (liquid_sim_modifier_ != nullptr) { + /* We don't need anything more for liquid meshes. */ + return; } - m_custom_data_config.pack_uvs = m_settings.pack_uv; - m_custom_data_config.mpoly = mesh->mpoly; - m_custom_data_config.mloop = mesh->mloop; - m_custom_data_config.totpoly = mesh->totpoly; - m_custom_data_config.totloop = mesh->totloop; - m_custom_data_config.totvert = mesh->totvert; - - return mesh; -} - -void AbcGenericMeshWriter::writeArbGeoParams(struct Mesh *me) -{ - if (m_is_liquid) { - /* We don't need anything more for liquid meshes. */ + if (frame_has_been_written_ || !args_.export_params->vcolors) { return; } - if (m_first_frame && m_settings.export_vcols) { - if (m_subdiv_schema.valid()) { - write_custom_data( - m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &me->ldata, CD_MLOOPCOL); - } - else { - write_custom_data( - m_mesh_schema.getArbGeomParams(), m_custom_data_config, &me->ldata, CD_MLOOPCOL); - } + OCompoundProperty arb_geom_params; + if (is_subd_) { + arb_geom_params = abc_subdiv_.getSchema().getArbGeomParams(); } + else { + arb_geom_params = abc_poly_mesh_.getSchema().getArbGeomParams(); + } + write_custom_data(arb_geom_params, m_custom_data_config, &me->ldata, CD_MLOOPCOL); } -void AbcGenericMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels) +void ABCGenericMeshWriter::get_velocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels) { const int totverts = mesh->totvert; vels.clear(); vels.resize(totverts); - ModifierData *md = get_liquid_sim_modifier(m_settings.scene, m_object); - FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(md); + FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(liquid_sim_modifier_); FluidsimSettings *fss = fmd->fss; if (fss->meshVelocities) { @@ -530,8 +416,9 @@ void AbcGenericMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V } } -void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, - std::map<std::string, std::vector<int32_t>> &geo_groups) +void ABCGenericMeshWriter::get_geo_groups(Object *object, + struct Mesh *mesh, + std::map<std::string, std::vector<int32_t>> &geo_groups) { const int num_poly = mesh->totpoly; MPoly *polygons = mesh->mpoly; @@ -540,13 +427,13 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, MPoly ¤t_poly = polygons[i]; short mnr = current_poly.mat_nr; - Material *mat = BKE_object_material_get(m_object, mnr + 1); + Material *mat = BKE_object_material_get(object, mnr + 1); if (!mat) { continue; } - std::string name = get_id_name(&mat->id); + std::string name = args_.hierarchy_iterator->get_id_name(&mat->id); if (geo_groups.find(name) == geo_groups.end()) { std::vector<int32_t> faceArray; @@ -557,9 +444,9 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, } if (geo_groups.size() == 0) { - Material *mat = BKE_object_material_get(m_object, 1); + Material *mat = BKE_object_material_get(object, 1); - std::string name = (mat) ? get_id_name(&mat->id) : "default"; + std::string name = (mat) ? args_.hierarchy_iterator->get_id_name(&mat->id) : "default"; std::vector<int32_t> faceArray; @@ -571,21 +458,116 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, } } -AbcMeshWriter::AbcMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcGenericMeshWriter(ob, parent, time_sampling, settings) +/* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ + +static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points) { + points.clear(); + points.resize(mesh->totvert); + + MVert *verts = mesh->mvert; + + for (int i = 0, e = mesh->totvert; i < e; i++) { + copy_yup_from_zup(points[i].getValue(), verts[i].co); + } } -AbcMeshWriter::~AbcMeshWriter() +static void get_topology(struct Mesh *mesh, + std::vector<int32_t> &poly_verts, + std::vector<int32_t> &loop_counts, + bool &r_has_flat_shaded_poly) { + const int num_poly = mesh->totpoly; + const int num_loops = mesh->totloop; + MLoop *mloop = mesh->mloop; + MPoly *mpoly = mesh->mpoly; + r_has_flat_shaded_poly = false; + + poly_verts.clear(); + loop_counts.clear(); + poly_verts.reserve(num_loops); + loop_counts.reserve(num_poly); + + /* NOTE: data needs to be written in the reverse order. */ + for (int i = 0; i < num_poly; i++) { + MPoly &poly = mpoly[i]; + loop_counts.push_back(poly.totloop); + + r_has_flat_shaded_poly |= (poly.flag & ME_SMOOTH) == 0; + + MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1); + + for (int j = 0; j < poly.totloop; j++, loop--) { + poly_verts.push_back(loop->v); + } + } +} + +static void get_creases(struct Mesh *mesh, + std::vector<int32_t> &indices, + std::vector<int32_t> &lengths, + std::vector<float> &sharpnesses) +{ + const float factor = 1.0f / 255.0f; + + indices.clear(); + lengths.clear(); + sharpnesses.clear(); + + MEdge *edge = mesh->medge; + + for (int i = 0, e = mesh->totedge; i < e; i++) { + const float sharpness = static_cast<float>(edge[i].crease) * factor; + + if (sharpness != 0.0f) { + indices.push_back(edge[i].v1); + indices.push_back(edge[i].v2); + sharpnesses.push_back(sharpness); + } + } + + lengths.resize(sharpnesses.size(), 2); } -Mesh *AbcMeshWriter::getEvaluatedMesh(Scene *scene_eval, - Object *ob_eval, - bool &UNUSED(r_needsfree)) +static void get_loop_normals(struct Mesh *mesh, + std::vector<Imath::V3f> &normals, + bool has_flat_shaded_poly) +{ + normals.clear(); + + /* If all polygons are smooth shaded, and there are no custom normals, we don't need to export + * normals at all. This is also done by other software, see T71246. */ + if (!has_flat_shaded_poly && !CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL) && + (mesh->flag & ME_AUTOSMOOTH) == 0) { + return; + } + + BKE_mesh_calc_normals_split(mesh); + const float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL)); + BLI_assert(lnors != nullptr || !"BKE_mesh_calc_normals_split() should have computed CD_NORMAL"); + + normals.resize(mesh->totloop); + + /* NOTE: data needs to be written in the reverse order. */ + int abc_index = 0; + MPoly *mp = mesh->mpoly; + for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) { + for (int j = mp->totloop - 1; j >= 0; j--, abc_index++) { + int blender_index = mp->loopstart + j; + copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]); + } + } +} + +ABCMeshWriter::ABCMeshWriter(const ABCWriterConstructorArgs &args) : ABCGenericMeshWriter(args) { - return mesh_get_eval_final(m_settings.depsgraph, scene_eval, ob_eval, &CD_MASK_MESH); } + +Mesh *ABCMeshWriter::get_export_mesh(Object *object_eval, bool & /*r_needsfree*/) +{ + return BKE_object_get_evaluated_mesh(object_eval); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.h b/source/blender/io/alembic/exporter/abc_writer_mesh.h new file mode 100644 index 00000000000..bf4d4e9b9d8 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.h @@ -0,0 +1,95 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#pragma once + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_abstract.h" +#include "intern/abc_customdata.h" + +#include <Alembic/AbcGeom/OPolyMesh.h> +#include <Alembic/AbcGeom/OSubD.h> + +struct ModifierData; + +namespace blender { +namespace io { +namespace alembic { + +/* Writer for Alembic geometry. Does not assume the object is a mesh object. */ +class ABCGenericMeshWriter : public ABCAbstractWriter { + private: + /* Either polymesh or subd is used, depending on is_subd_. + * References to the schema must be kept, or Alembic will not properly write. */ + Alembic::AbcGeom::OPolyMesh abc_poly_mesh_; + Alembic::AbcGeom::OPolyMeshSchema abc_poly_mesh_schema_; + + Alembic::AbcGeom::OSubD abc_subdiv_; + Alembic::AbcGeom::OSubDSchema abc_subdiv_schema_; + + /* Determines whether a poly mesh or a subdivision surface is exported. + * The value is set by an export option but only true if there is a subdivision modifier on the + * exported object. */ + bool is_subd_; + ModifierData *subsurf_modifier_; + ModifierData *liquid_sim_modifier_; + + CDStreamConfig m_custom_data_config; + + public: + explicit ABCGenericMeshWriter(const ABCWriterConstructorArgs &args); + virtual ~ABCGenericMeshWriter(); + + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const; + + protected: + virtual bool is_supported(const HierarchyContext *context) const override; + virtual void do_write(HierarchyContext &context) override; + + virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) = 0; + virtual void free_export_mesh(Mesh *mesh); + + virtual bool export_as_subdivision_surface(Object *ob_eval) const; + + private: + void write_mesh(HierarchyContext &context, Mesh *mesh); + void write_subd(HierarchyContext &context, Mesh *mesh); + template<typename Schema> void write_face_sets(Object *object, Mesh *mesh, Schema &schema); + + ModifierData *get_liquid_sim_modifier(Scene *scene_eval, Object *ob_eval); + + void write_arb_geo_params(Mesh *me); + void get_velocities(Mesh *mesh, std::vector<Imath::V3f> &vels); + void get_geo_groups(Object *object, + Mesh *mesh, + std::map<std::string, std::vector<int32_t>> &geo_groups); +}; + +/* Writer for Alembic geometry of Blender Mesh objects. */ +class ABCMeshWriter : public ABCGenericMeshWriter { + public: + ABCMeshWriter(const ABCWriterConstructorArgs &args); + + protected: + virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override; +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_nurbs.cc b/source/blender/io/alembic/exporter/abc_writer_nurbs.cc index 8b4a1050d33..1fd382214a6 100644 --- a/source/blender/io/alembic/intern/abc_writer_nurbs.cc +++ b/source/blender/io/alembic/exporter/abc_writer_nurbs.cc @@ -19,8 +19,7 @@ */ #include "abc_writer_nurbs.h" -#include "abc_axis_conversion.h" -#include "abc_writer_transform.h" +#include "intern/abc_axis_conversion.h" #include "DNA_curve_types.h" #include "DNA_object_types.h" @@ -29,48 +28,70 @@ #include "BKE_curve.h" +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::Abc::OObject; using Alembic::AbcGeom::FloatArraySample; using Alembic::AbcGeom::OBoolProperty; using Alembic::AbcGeom::OCompoundProperty; using Alembic::AbcGeom::ONuPatch; using Alembic::AbcGeom::ONuPatchSchema; -AbcNurbsWriter::AbcNurbsWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent) +ABCNurbsWriter::ABCNurbsWriter(const ABCWriterConstructorArgs &args) : ABCAbstractWriter(args) { - m_is_animated = isAnimated(); - - /* if the object is static, use the default static time sampling */ - if (!m_is_animated) { - m_time_sampling = 0; - } +} - Curve *curve = static_cast<Curve *>(m_object->data); - size_t numNurbs = BLI_listbase_count(&curve->nurb); +void ABCNurbsWriter::create_alembic_objects(const HierarchyContext *context) +{ + Curve *curve = static_cast<Curve *>(context->object->data); + size_t num_nurbs = BLI_listbase_count(&curve->nurb); + OObject abc_parent = args_.abc_parent; + const char *abc_parent_path = abc_parent.getFullName().c_str(); - for (size_t i = 0; i < numNurbs; i++) { - std::stringstream str; - str << m_name << '_' << i; + for (size_t i = 0; i < num_nurbs; i++) { + std::stringstream patch_name_stream; + patch_name_stream << args_.abc_name << '_' << i; - while (parent->alembicXform().getChildHeader(str.str())) { - str << "_"; + while (abc_parent.getChildHeader(patch_name_stream.str())) { + patch_name_stream << "_"; } - ONuPatch nurbs(parent->alembicXform(), str.str().c_str(), m_time_sampling); - m_nurbs_schema.push_back(nurbs.getSchema()); + std::string patch_name = patch_name_stream.str(); + CLOG_INFO(&LOG, 2, "exporting %s/%s", abc_parent_path, patch_name.c_str()); + + ONuPatch nurbs(abc_parent, patch_name.c_str(), timesample_index_); + abc_nurbs_.push_back(nurbs); + abc_nurbs_schemas_.push_back(nurbs.getSchema()); + } +} + +const OObject ABCNurbsWriter::get_alembic_object() const +{ + if (abc_nurbs_.empty()) { + return OObject(); } + /* For parenting purposes within the Alembic file, all NURBS patches are equal, so just use the + * first one. */ + return abc_nurbs_[0]; } -bool AbcNurbsWriter::isAnimated() const +bool ABCNurbsWriter::check_is_animated(const HierarchyContext &context) const { - /* check if object has shape keys */ - Curve *cu = static_cast<Curve *>(m_object->data); + /* Check if object has shape keys. */ + Curve *cu = static_cast<Curve *>(context.object->data); return (cu->key != NULL); } +bool ABCNurbsWriter::is_supported(const HierarchyContext *context) const +{ + return ELEM(context->object->type, OB_SURF, OB_CURVE); +} + static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_knots) { if (num_knots <= 1) { @@ -91,22 +112,13 @@ static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_ knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]); } -void AbcNurbsWriter::do_write() +void ABCNurbsWriter::do_write(HierarchyContext &context) { - /* we have already stored a sample for this object. */ - if (!m_first_frame && !m_is_animated) { - return; - } - - if (!ELEM(m_object->type, OB_SURF, OB_CURVE)) { - return; - } - - Curve *curve = static_cast<Curve *>(m_object->data); + Curve *curve = static_cast<Curve *>(context.object->data); ListBase *nulb; - if (m_object->runtime.curve_cache->deformed_nurbs.first != NULL) { - nulb = &m_object->runtime.curve_cache->deformed_nurbs; + if (context.object->runtime.curve_cache->deformed_nurbs.first != NULL) { + nulb = &context.object->runtime.curve_cache->deformed_nurbs; } else { nulb = BKE_curve_nurbs_get(curve); @@ -143,7 +155,7 @@ void AbcNurbsWriter::do_write() /* TODO(kevin): to accommodate other software we should duplicate control * points to indicate that a NURBS is cyclic. */ - OCompoundProperty user_props = m_nurbs_schema[count].getUserProperties(); + OCompoundProperty user_props = abc_nurbs_schemas_[count].getUserProperties(); if ((nu->flagu & CU_NURB_ENDPOINT) != 0) { OBoolProperty prop(user_props, "endpoint_u"); @@ -165,6 +177,10 @@ void AbcNurbsWriter::do_write() prop.set(true); } - m_nurbs_schema[count].set(sample); + abc_nurbs_schemas_[count].set(sample); } } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_nurbs.h b/source/blender/io/alembic/exporter/abc_writer_nurbs.h new file mode 100644 index 00000000000..23af4c40556 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_nurbs.h @@ -0,0 +1,57 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#pragma once + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_abstract.h" +#include "abc_writer_mesh.h" +#include <vector> + +namespace blender { +namespace io { +namespace alembic { + +class ABCNurbsWriter : public ABCAbstractWriter { + private: + std::vector<Alembic::AbcGeom::ONuPatch> abc_nurbs_; + std::vector<Alembic::AbcGeom::ONuPatchSchema> abc_nurbs_schemas_; + + public: + explicit ABCNurbsWriter(const ABCWriterConstructorArgs &args); + + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; + + protected: + virtual bool is_supported(const HierarchyContext *context) const override; + virtual void do_write(HierarchyContext &context) override; + virtual bool check_is_animated(const HierarchyContext &context) const override; +}; + +class ABCNurbsMeshWriter : public ABCGenericMeshWriter { + public: + explicit ABCNurbsMeshWriter(const ABCWriterConstructorArgs &args); + + protected: + virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override; +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_points.cc b/source/blender/io/alembic/exporter/abc_writer_points.cc new file mode 100644 index 00000000000..19870e39a90 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_points.cc @@ -0,0 +1,148 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Kévin Dietrich. + * All rights reserved. + */ + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_points.h" + +#include "DNA_object_types.h" +#include "DNA_particle_types.h" + +#include "BKE_lattice.h" +#include "BKE_particle.h" + +#include "BLI_math.h" + +#include "DEG_depsgraph_query.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::AbcGeom::kVertexScope; +using Alembic::AbcGeom::OPoints; +using Alembic::AbcGeom::OPointsSchema; + +ABCPointsWriter::ABCPointsWriter(const ABCWriterConstructorArgs &args) : ABCAbstractWriter(args) +{ +} + +void ABCPointsWriter::create_alembic_objects(const HierarchyContext * /*context*/) +{ + CLOG_INFO(&LOG, 2, "exporting OPoints %s", args_.abc_path.c_str()); + abc_points_ = OPoints(args_.abc_parent, args_.abc_name, timesample_index_); + abc_points_schema_ = abc_points_.getSchema(); +} + +const Alembic::Abc::OObject ABCPointsWriter::get_alembic_object() const +{ + return abc_points_; +} + +bool ABCPointsWriter::is_supported(const HierarchyContext *context) const +{ + return ELEM(context->particle_system->part->type, + PART_EMITTER, + PART_FLUID_FLIP, + PART_FLUID_SPRAY, + PART_FLUID_BUBBLE, + PART_FLUID_FOAM, + PART_FLUID_TRACER, + PART_FLUID_SPRAYFOAM, + PART_FLUID_SPRAYBUBBLE, + PART_FLUID_FOAMBUBBLE, + PART_FLUID_SPRAYFOAMBUBBLE); +} + +bool ABCPointsWriter::check_is_animated(const HierarchyContext & /*context*/) const +{ + /* We assume that particles are always animated. */ + return true; +} + +void ABCPointsWriter::do_write(HierarchyContext &context) +{ + BLI_assert(context.particle_system != nullptr); + + std::vector<Imath::V3f> points; + std::vector<Imath::V3f> velocities; + std::vector<float> widths; + std::vector<uint64_t> ids; + + ParticleSystem *psys = context.particle_system; + ParticleKey state; + ParticleSimulationData sim; + sim.depsgraph = args_.depsgraph; + sim.scene = DEG_get_evaluated_scene(args_.depsgraph); + sim.ob = context.object; + sim.psys = psys; + + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + uint64_t index = 0; + for (int p = 0; p < psys->totpart; p++) { + float pos[3], vel[3]; + + if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) { + continue; + } + + state.time = DEG_get_ctime(args_.depsgraph); + if (psys_get_particle_state(&sim, p, &state, 0) == 0) { + continue; + } + + /* location */ + mul_v3_m4v3(pos, context.object->imat, state.co); + + /* velocity */ + sub_v3_v3v3(vel, state.co, psys->particles[p].prev_state.co); + + /* Convert Z-up to Y-up. */ + points.push_back(Imath::V3f(pos[0], pos[2], -pos[1])); + velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1])); + widths.push_back(psys->particles[p].size); + ids.push_back(index++); + } + + if (psys->lattice_deform_data) { + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; + } + + Alembic::Abc::P3fArraySample psample(points); + Alembic::Abc::UInt64ArraySample idsample(ids); + Alembic::Abc::V3fArraySample vsample(velocities); + Alembic::Abc::FloatArraySample wsample_array(widths); + Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope); + + OPointsSchema::Sample sample(psample, idsample, vsample, wsample); + update_bounding_box(context.object); + sample.setSelfBounds(bounding_box_); + abc_points_schema_.set(sample); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_archive.h b/source/blender/io/alembic/exporter/abc_writer_points.h index 737717c1710..03800b80acf 100644 --- a/source/blender/io/alembic/intern/abc_writer_archive.h +++ b/source/blender/io/alembic/exporter/abc_writer_points.h @@ -16,35 +16,37 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_WRITER_ARCHIVE_H__ -#define __ABC_WRITER_ARCHIVE_H__ +#include "abc_writer_abstract.h" -#include <Alembic/Abc/All.h> -#include <Alembic/AbcCoreOgawa/All.h> +#include <Alembic/AbcGeom/OPoints.h> -#include <fstream> +namespace blender { +namespace io { +namespace alembic { -struct Main; -struct Scene; +class ABCPointsWriter : public ABCAbstractWriter { + Alembic::AbcGeom::OPoints abc_points_; + Alembic::AbcGeom::OPointsSchema abc_points_schema_; -/* Wrappers around input and output archives. The goal is to be able to use - * streams so that unicode paths work on Windows (T49112), and to make sure that - * the stream objects remain valid as long as the archives are open. - */ + public: + explicit ABCPointsWriter(const ABCWriterConstructorArgs &args); -class ArchiveWriter { - std::ofstream m_outfile; - Alembic::Abc::OArchive m_archive; + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; - public: - ArchiveWriter(const char *filename, const std::string &abc_scene_name, const Scene *scene); + virtual bool is_supported(const HierarchyContext *context) const override; - Alembic::Abc::OArchive &archive(); + protected: + virtual bool check_is_animated(const HierarchyContext &context) const override; + virtual void do_write(HierarchyContext &context) override; }; -#endif /* __ABC_WRITER_ARCHIVE_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_transform.cc b/source/blender/io/alembic/exporter/abc_writer_transform.cc new file mode 100644 index 00000000000..65d6b7c5b41 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_transform.cc @@ -0,0 +1,115 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_transform.h" +#include "abc_hierarchy_iterator.h" +#include "intern/abc_axis_conversion.h" +#include "intern/abc_util.h" + +#include "BKE_object.h" + +#include "BLI_math_matrix.h" +#include "BLI_math_rotation.h" + +#include "DNA_layer_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::Abc::OObject; +using Alembic::AbcGeom::OXform; +using Alembic::AbcGeom::OXformSchema; +using Alembic::AbcGeom::XformSample; + +ABCTransformWriter::ABCTransformWriter(const ABCWriterConstructorArgs &args) + : ABCAbstractWriter(args) +{ + timesample_index_ = args_.abc_archive->time_sampling_index_transforms(); +} + +void ABCTransformWriter::create_alembic_objects(const HierarchyContext * /*context*/) +{ + CLOG_INFO(&LOG, 2, "exporting %s", args_.abc_path.c_str()); + abc_xform_ = OXform(args_.abc_parent, args_.abc_name, timesample_index_); + abc_xform_schema_ = abc_xform_.getSchema(); +} + +void ABCTransformWriter::do_write(HierarchyContext &context) +{ + float parent_relative_matrix[4][4]; // The object matrix relative to the parent. + mul_m4_m4m4(parent_relative_matrix, context.parent_matrix_inv_world, context.matrix_world); + + // After this, parent_relative_matrix uses Y=up. + copy_m44_axis_swap(parent_relative_matrix, parent_relative_matrix, ABC_YUP_FROM_ZUP); + + /* If the parent is a camera, undo its to-Maya rotation (see below). */ + bool is_root_object = context.export_parent == nullptr; + if (!is_root_object && context.export_parent->type == OB_CAMERA) { + float rot_mat[4][4]; + axis_angle_to_mat4_single(rot_mat, 'X', M_PI_2); + mul_m4_m4m4(parent_relative_matrix, rot_mat, parent_relative_matrix); + } + + /* If the object is a camera, apply an extra rotation to Maya camera orientation. */ + if (context.object->type == OB_CAMERA) { + float rot_mat[4][4]; + axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2); + mul_m4_m4m4(parent_relative_matrix, parent_relative_matrix, rot_mat); + } + + if (is_root_object) { + /* Only apply scaling to root objects, parenting will propagate it. */ + float scale_mat[4][4]; + scale_m4_fl(scale_mat, args_.export_params->global_scale); + scale_mat[3][3] = args_.export_params->global_scale; /* also scale translation */ + mul_m4_m4m4(parent_relative_matrix, parent_relative_matrix, scale_mat); + parent_relative_matrix[3][3] /= + args_.export_params->global_scale; /* normalise the homogeneous component */ + } + + XformSample xform_sample; + xform_sample.setMatrix(convert_matrix_datatype(parent_relative_matrix)); + xform_sample.setInheritsXforms(true); + abc_xform_schema_.set(xform_sample); +} + +const OObject ABCTransformWriter::get_alembic_object() const +{ + return abc_xform_; +} + +bool ABCTransformWriter::check_is_animated(const HierarchyContext &context) const +{ + if (context.duplicator != NULL) { + /* This object is being duplicated, so could be emitted by a particle system and thus + * influenced by forces. TODO(Sybren): Make this more strict. Probably better to get from the + * depsgraph whether this object instance has a time source. */ + return true; + } + return BKE_object_moves_in_time(context.object, context.animation_check_include_parent); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_points.h b/source/blender/io/alembic/exporter/abc_writer_transform.h index 184a363ae6b..950bff39c29 100644 --- a/source/blender/io/alembic/intern/abc_writer_points.h +++ b/source/blender/io/alembic/exporter/abc_writer_transform.h @@ -12,38 +12,36 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_WRITER_POINTS_H__ -#define __ABC_WRITER_POINTS_H__ - -#include "abc_customdata.h" -#include "abc_writer_object.h" +#include "abc_writer_abstract.h" -struct ParticleSystem; +#include <Alembic/AbcGeom/OXform.h> -/* ************************************************************************** */ +namespace blender { +namespace io { +namespace alembic { -class AbcPointsWriter : public AbcObjectWriter { - Alembic::AbcGeom::OPointsSchema m_schema; - Alembic::AbcGeom::OPointsSchema::Sample m_sample; - ParticleSystem *m_psys; +class ABCTransformWriter : public ABCAbstractWriter { + private: + Alembic::AbcGeom::OXform abc_xform_; + Alembic::AbcGeom::OXformSchema abc_xform_schema_; public: - AbcPointsWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys); + explicit ABCTransformWriter(const ABCWriterConstructorArgs &args); + virtual void create_alembic_objects(const HierarchyContext *context) override; - void do_write(); + protected: + virtual void do_write(HierarchyContext &context) override; + virtual bool check_is_animated(const HierarchyContext &context) const override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; }; -#endif /* __ABC_WRITER_POINTS_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.cc b/source/blender/io/alembic/intern/abc_axis_conversion.cc index 17db5e9c99f..cebab1f2e41 100644 --- a/source/blender/io/alembic/intern/abc_axis_conversion.cc +++ b/source/blender/io/alembic/intern/abc_axis_conversion.cc @@ -20,12 +20,14 @@ #include "abc_axis_conversion.h" -extern "C" { #include "BLI_assert.h" +#include "BLI_math_geom.h" + #include "DNA_object_types.h" -#include "BLI_math_geom.h" -} +namespace blender { +namespace io { +namespace alembic { void create_swapped_rotation_matrix(float rot_x_mat[3][3], float rot_y_mat[3][3], @@ -72,7 +74,8 @@ void create_swapped_rotation_matrix(float rot_x_mat[3][3], rot_z_mat[1][0] = -sin(rz); rot_z_mat[0][1] = sin(rz); rot_z_mat[1][1] = cos(rz); -} +} // namespace + // alembicvoidcreate_swapped_rotation_matrix(floatrot_x_mat[3][3],floatrot_y_mat[3][3],floatrot_z_mat[3][3],constfloateuler[3],AbcAxisSwapModemode) /* Convert matrix from Z=up to Y=up or vice versa. * Use yup_mat = zup_mat for in-place conversion. */ @@ -164,3 +167,7 @@ void create_transform_matrix(Object *obj, copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP); } + +} // namespace alembic +} // namespace io +} // namespace blender
\ No newline at end of file diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.h b/source/blender/io/alembic/intern/abc_axis_conversion.h index 7fde0e92ea4..9a19e9116be 100644 --- a/source/blender/io/alembic/intern/abc_axis_conversion.h +++ b/source/blender/io/alembic/intern/abc_axis_conversion.h @@ -22,13 +22,13 @@ * \ingroup Alembic */ +#include "BLI_compiler_compat.h" + struct Object; -#ifdef _MSC_VER -# define ABC_INLINE static __forceinline -#else -# define ABC_INLINE static inline -#endif +namespace blender { +namespace io { +namespace alembic { /* TODO(kevin): for now keeping these transformations hardcoded to make sure * everything works properly, and also because Alembic is almost exclusively @@ -37,7 +37,7 @@ struct Object; /* Copy from Y-up to Z-up. */ -ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3]) +BLI_INLINE void copy_zup_from_yup(float zup[3], const float yup[3]) { const float old_yup1 = yup[1]; /* in case zup == yup */ zup[0] = yup[0]; @@ -45,7 +45,7 @@ ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3]) zup[2] = old_yup1; } -ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3]) +BLI_INLINE void copy_zup_from_yup(short zup[3], const short yup[3]) { const short old_yup1 = yup[1]; /* in case zup == yup */ zup[0] = yup[0]; @@ -55,7 +55,7 @@ ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3]) /* Copy from Z-up to Y-up. */ -ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3]) +BLI_INLINE void copy_yup_from_zup(float yup[3], const float zup[3]) { const float old_zup1 = zup[1]; /* in case yup == zup */ yup[0] = zup[0]; @@ -63,7 +63,7 @@ ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3]) yup[2] = -old_zup1; } -ABC_INLINE void copy_yup_from_zup(short yup[3], const short zup[3]) +BLI_INLINE void copy_yup_from_zup(short yup[3], const short zup[3]) { const short old_zup1 = zup[1]; /* in case yup == zup */ yup[0] = zup[0]; @@ -97,3 +97,7 @@ void create_transform_matrix(Object *obj, float r_transform_mat[4][4], AbcMatrixMode mode, Object *proxy_from); + +} // namespace alembic +} // namespace io +} // namespace blender
\ No newline at end of file diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 62f6a52f7cf..f3e2342e844 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -50,6 +50,9 @@ using Alembic::Abc::V2fArraySample; using Alembic::AbcGeom::OC4fGeomParam; using Alembic::AbcGeom::OV2fGeomParam; +namespace blender { +namespace io { +namespace alembic { static void get_uvs(const CDStreamConfig &config, std::vector<Imath::V2f> &uvs, @@ -485,3 +488,7 @@ void read_custom_data(const std::string &iobject_full_name, } } } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h index 96b57b08681..8f4accb70dc 100644 --- a/source/blender/io/alembic/intern/abc_customdata.h +++ b/source/blender/io/alembic/intern/abc_customdata.h @@ -16,14 +16,12 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_CUSTOMDATA_H__ -#define __ABC_CUSTOMDATA_H__ - #include <Alembic/Abc/All.h> #include <Alembic/AbcGeom/All.h> @@ -38,6 +36,9 @@ struct Mesh; using Alembic::Abc::ICompoundProperty; using Alembic::Abc::OCompoundProperty; +namespace blender { +namespace io { +namespace alembic { struct UVSample { std::vector<Imath::V2f> uvs; @@ -112,4 +113,6 @@ void read_custom_data(const std::string &iobject_full_name, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss); -#endif /* __ABC_CUSTOMDATA_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_exporter.cc b/source/blender/io/alembic/intern/abc_exporter.cc deleted file mode 100644 index 8dad8dff199..00000000000 --- a/source/blender/io/alembic/intern/abc_exporter.cc +++ /dev/null @@ -1,673 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_exporter.h" - -#include <cmath> - -#include "abc_util.h" -#include "abc_writer_archive.h" -#include "abc_writer_camera.h" -#include "abc_writer_curves.h" -#include "abc_writer_hair.h" -#include "abc_writer_mball.h" -#include "abc_writer_mesh.h" -#include "abc_writer_nurbs.h" -#include "abc_writer_points.h" -#include "abc_writer_transform.h" - -#include "DNA_camera_types.h" -#include "DNA_curve_types.h" -#include "DNA_fluid_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meta_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_space_types.h" /* for FILE_MAX */ - -#include "BLI_string.h" - -#ifdef WIN32 -/* needed for MSCV because of snprintf from BLI_string */ -# include "BLI_winstuff.h" -#endif - -#include "BKE_duplilist.h" -#include "BKE_global.h" -#include "BKE_idprop.h" -#include "BKE_layer.h" -#include "BKE_main.h" -#include "BKE_mball.h" -#include "BKE_modifier.h" -#include "BKE_particle.h" -#include "BKE_scene.h" - -#include "DEG_depsgraph_query.h" - -using Alembic::Abc::OBox3dProperty; -using Alembic::Abc::TimeSamplingPtr; - -/* ************************************************************************** */ - -ExportSettings::ExportSettings() - : scene(NULL), - view_layer(NULL), - depsgraph(NULL), - logger(), - selected_only(false), - visible_objects_only(false), - renderable_only(false), - frame_start(1), - frame_end(1), - frame_samples_xform(1), - frame_samples_shape(1), - shutter_open(0.0), - shutter_close(1.0), - global_scale(1.0f), - flatten_hierarchy(false), - export_normals(false), - export_uvs(false), - export_vcols(false), - export_face_sets(false), - export_vweigths(false), - export_hair(true), - export_particles(true), - apply_subdiv(false), - use_subdiv_schema(false), - export_child_hairs(true), - pack_uv(false), - triangulate(false), - quad_method(0), - ngon_method(0) -{ -} - -static bool object_is_smoke_sim(Object *ob) -{ - ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluid); - - if (md) { - FluidModifierData *smd = reinterpret_cast<FluidModifierData *>(md); - return (smd->type == MOD_FLUID_TYPE_DOMAIN && smd->domain && - smd->domain->type == FLUID_DOMAIN_TYPE_GAS); - } - - return false; -} - -static bool object_type_is_exportable(Scene *scene, Object *ob) -{ - switch (ob->type) { - case OB_MESH: - if (object_is_smoke_sim(ob)) { - return false; - } - - return true; - case OB_EMPTY: - case OB_CURVE: - case OB_SURF: - case OB_CAMERA: - return true; - case OB_MBALL: - return AbcMBallWriter::isBasisBall(scene, ob); - default: - return false; - } -} - -/** - * Returns whether this object should be exported into the Alembic file. - * - * \param settings: export settings, used for options like 'selected only'. - * \param ob: the object's base in question. - * \param is_duplicated: Normally false; true when the object is instanced - * into the scene by a dupli-object (e.g. part of a dupligroup). - * This ignores selection and layer visibility, - * and assumes that the dupli-object itself (e.g. the group-instantiating empty) is exported. - */ -static bool export_object(const ExportSettings *const settings, - const Base *const base, - bool is_duplicated) -{ - if (!is_duplicated) { - View3D *v3d = NULL; - - /* These two tests only make sense when the object isn't being instanced - * into the scene. When it is, its exportability is determined by - * its dupli-object and the DupliObject::no_draw property. */ - if (settings->selected_only && !BASE_SELECTED(v3d, base)) { - return false; - } - // FIXME Sybren: handle these cleanly (maybe just remove code), - // now using active scene layer instead. - if (settings->visible_objects_only && !BASE_VISIBLE(v3d, base)) { - return false; - } - } - - Object *ob_eval = DEG_get_evaluated_object(settings->depsgraph, base->object); - if ((ob_eval->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) { - /* XXX fix after 2.80: the object was not part of the depsgraph, and thus we cannot get the - * evaluated copy to export. This will be handled more elegantly in the new - * AbstractHierarchyIterator that Sybren is working on. This condition is temporary, and avoids - * a BLI_assert() failure getting the evaluated mesh of this object. */ - return false; - } - - // if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) { - // return false; - // } - - return true; -} - -/* ************************************************************************** */ - -AbcExporter::AbcExporter(Main *bmain, const char *filename, ExportSettings &settings) - : m_bmain(bmain), - m_settings(settings), - m_filename(filename), - m_trans_sampling_index(0), - m_shape_sampling_index(0), - m_writer(NULL) -{ -} - -AbcExporter::~AbcExporter() -{ - /* Free xforms map */ - m_xforms_type::iterator it_x, e_x; - for (it_x = m_xforms.begin(), e_x = m_xforms.end(); it_x != e_x; ++it_x) { - delete it_x->second; - } - - /* Free shapes vector */ - for (int i = 0, e = m_shapes.size(); i != e; i++) { - delete m_shapes[i]; - } - - delete m_writer; -} - -void AbcExporter::getShutterSamples(unsigned int nr_of_samples, - bool time_relative, - std::vector<double> &samples) -{ - Scene *scene = m_settings.scene; /* for use in the FPS macro */ - samples.clear(); - - unsigned int frame_offset = time_relative ? m_settings.frame_start : 0; - double time_factor = time_relative ? FPS : 1.0; - double shutter_open = m_settings.shutter_open; - double shutter_close = m_settings.shutter_close; - double time_inc = (shutter_close - shutter_open) / nr_of_samples; - - /* sample between shutter open & close */ - for (int sample = 0; sample < nr_of_samples; sample++) { - double sample_time = shutter_open + time_inc * sample; - double time = (frame_offset + sample_time) / time_factor; - - samples.push_back(time); - } -} - -Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step) -{ - std::vector<double> samples; - - if (m_settings.frame_start == m_settings.frame_end) { - return TimeSamplingPtr(new Alembic::Abc::TimeSampling()); - } - - getShutterSamples(step, true, samples); - - /* TODO(Sybren): shouldn't we use the FPS macro here? */ - Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()), - 1.0 / m_settings.scene->r.frs_sec); - - return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples)); -} - -void AbcExporter::getFrameSet(unsigned int nr_of_samples, std::set<double> &frames) -{ - frames.clear(); - - std::vector<double> shutter_samples; - - getShutterSamples(nr_of_samples, false, shutter_samples); - - for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) { - for (size_t j = 0; j < nr_of_samples; j++) { - frames.insert(frame + shutter_samples[j]); - } - } -} - -void AbcExporter::operator()(short *do_update, float *progress, bool *was_canceled) -{ - std::string abc_scene_name; - - if (m_bmain->name[0] != '\0') { - char scene_file_name[FILE_MAX]; - BLI_strncpy(scene_file_name, m_bmain->name, FILE_MAX); - abc_scene_name = scene_file_name; - } - else { - abc_scene_name = "untitled"; - } - - m_writer = new ArchiveWriter(m_filename, abc_scene_name, m_settings.scene); - - /* Create time samplings for transforms and shapes. */ - - TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_samples_xform); - - m_trans_sampling_index = m_writer->archive().addTimeSampling(*trans_time); - - TimeSamplingPtr shape_time; - - if ((m_settings.frame_samples_shape == m_settings.frame_samples_xform) || - (m_settings.frame_start == m_settings.frame_end)) { - shape_time = trans_time; - m_shape_sampling_index = m_trans_sampling_index; - } - else { - shape_time = createTimeSampling(m_settings.frame_samples_shape); - m_shape_sampling_index = m_writer->archive().addTimeSampling(*shape_time); - } - - OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds( - m_writer->archive(), m_trans_sampling_index); - - createTransformWritersHierarchy(); - createShapeWriters(); - - /* Make a list of frames to export. */ - - std::set<double> xform_frames; - getFrameSet(m_settings.frame_samples_xform, xform_frames); - - std::set<double> shape_frames; - getFrameSet(m_settings.frame_samples_shape, shape_frames); - - /* Merge all frames needed. */ - std::set<double> frames(xform_frames); - frames.insert(shape_frames.begin(), shape_frames.end()); - - /* Export all frames. */ - - std::set<double>::const_iterator begin = frames.begin(); - std::set<double>::const_iterator end = frames.end(); - - const float size = static_cast<float>(frames.size()); - size_t i = 0; - - for (; begin != end; ++begin) { - *progress = (++i / size); - *do_update = 1; - - if (G.is_break) { - *was_canceled = true; - break; - } - - const double frame = *begin; - - /* 'frame' is offset by start frame, so need to cancel the offset. */ - setCurrentFrame(m_bmain, frame); - - if (shape_frames.count(frame) != 0) { - for (int i = 0, e = m_shapes.size(); i != e; i++) { - m_shapes[i]->write(); - } - } - - if (xform_frames.count(frame) == 0) { - continue; - } - - m_xforms_type::iterator xit, xe; - for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) { - xit->second->write(); - } - - /* Save the archive 's bounding box. */ - Imath::Box3d bounds; - - for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) { - Imath::Box3d box = xit->second->bounds(); - bounds.extendBy(box); - } - - archive_bounds_prop.set(bounds); - } -} - -void AbcExporter::createTransformWritersHierarchy() -{ - for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; - base = base->next) { - Object *ob = base->object; - - if (export_object(&m_settings, base, false)) { - switch (ob->type) { - case OB_LAMP: - case OB_LATTICE: - case OB_SPEAKER: - /* We do not export transforms for objects of these classes. */ - break; - default: - exploreTransform(base, ob, ob->parent, NULL); - } - } - } -} - -void AbcExporter::exploreTransform(Base *base, - Object *object, - Object *parent, - Object *dupliObParent) -{ - /* If an object isn't exported itself, its duplilist shouldn't be - * exported either. */ - if (!export_object(&m_settings, base, dupliObParent != NULL)) { - return; - } - - Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, object); - if (object_type_is_exportable(m_settings.scene, ob)) { - createTransformWriter(ob, parent, dupliObParent); - } - - ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob); - - if (lb) { - DupliObject *link = static_cast<DupliObject *>(lb->first); - Object *dupli_ob = NULL; - Object *dupli_parent = NULL; - - for (; link; link = link->next) { - /* This skips things like custom bone shapes. */ - if (m_settings.renderable_only && link->no_draw) { - continue; - } - - if (link->type == OB_DUPLICOLLECTION) { - dupli_ob = link->ob; - dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob; - - exploreTransform(base, dupli_ob, dupli_parent, ob); - } - } - - free_object_duplilist(lb); - } -} - -AbcTransformWriter *AbcExporter::createTransformWriter(Object *ob, - Object *parent, - Object *dupliObParent) -{ - /* An object should not be its own parent, or we'll get infinite loops. */ - BLI_assert(ob != parent); - BLI_assert(ob != dupliObParent); - - std::string name; - if (m_settings.flatten_hierarchy) { - name = get_id_name(ob); - } - else { - name = get_object_dag_path_name(ob, dupliObParent); - } - - /* check if we have already created a transform writer for this object */ - AbcTransformWriter *my_writer = getXForm(name); - if (my_writer != NULL) { - return my_writer; - } - - AbcTransformWriter *parent_writer = NULL; - Alembic::Abc::OObject alembic_parent; - - if (m_settings.flatten_hierarchy || parent == NULL) { - /* Parentless objects still have the "top object" as parent - * in Alembic. */ - alembic_parent = m_writer->archive().getTop(); - } - else { - /* Since there are so many different ways to find parents (as evident - * in the number of conditions below), we can't really look up the - * parent by name. We'll just call createTransformWriter(), which will - * return the parent's AbcTransformWriter pointer. */ - if (parent->parent) { - if (parent == dupliObParent) { - parent_writer = createTransformWriter(parent, parent->parent, NULL); - } - else { - parent_writer = createTransformWriter(parent, parent->parent, dupliObParent); - } - } - else if (parent == dupliObParent) { - if (dupliObParent->parent == NULL) { - parent_writer = createTransformWriter(parent, NULL, NULL); - } - else { - parent_writer = createTransformWriter( - parent, dupliObParent->parent, dupliObParent->parent); - } - } - else { - parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent); - } - - BLI_assert(parent_writer); - alembic_parent = parent_writer->alembicXform(); - } - - my_writer = new AbcTransformWriter( - ob, alembic_parent, parent_writer, m_trans_sampling_index, m_settings); - - /* When flattening, the matrix of the dupliobject has to be added. */ - if (m_settings.flatten_hierarchy && dupliObParent) { - my_writer->m_proxy_from = dupliObParent; - } - - m_xforms[name] = my_writer; - return my_writer; -} - -void AbcExporter::createShapeWriters() -{ - for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; - base = base->next) { - exploreObject(base, base->object, NULL); - } -} - -void AbcExporter::exploreObject(Base *base, Object *object, Object *dupliObParent) -{ - /* If an object isn't exported itself, its duplilist shouldn't be - * exported either. */ - if (!export_object(&m_settings, base, dupliObParent != NULL)) { - return; - } - - Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, object); - createShapeWriter(ob, dupliObParent); - - ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob); - - if (lb) { - DupliObject *link = static_cast<DupliObject *>(lb->first); - - for (; link; link = link->next) { - /* This skips things like custom bone shapes. */ - if (m_settings.renderable_only && link->no_draw) { - continue; - } - if (link->type == OB_DUPLICOLLECTION) { - exploreObject(base, link->ob, ob); - } - } - - free_object_duplilist(lb); - } -} - -void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform) -{ - if (!m_settings.export_hair && !m_settings.export_particles) { - return; - } - - ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first); - - for (; psys; psys = psys->next) { - if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) { - continue; - } - - if (m_settings.export_hair && psys->part->type == PART_HAIR) { - m_settings.export_child_hairs = true; - m_shapes.push_back(new AbcHairWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); - } - else if (m_settings.export_particles && - (psys->part->type == PART_EMITTER || psys->part->type == PART_FLUID_FLIP || - psys->part->type == PART_FLUID_SPRAY || psys->part->type == PART_FLUID_BUBBLE || - psys->part->type == PART_FLUID_FOAM || psys->part->type == PART_FLUID_TRACER || - psys->part->type == PART_FLUID_SPRAYFOAM || - psys->part->type == PART_FLUID_SPRAYBUBBLE || - psys->part->type == PART_FLUID_FOAMBUBBLE || - psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE)) { - m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); - } - } -} - -void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) -{ - if (!object_type_is_exportable(m_settings.scene, ob)) { - return; - } - - std::string name; - - if (m_settings.flatten_hierarchy) { - name = get_id_name(ob); - } - else { - name = get_object_dag_path_name(ob, dupliObParent); - } - - AbcTransformWriter *xform = getXForm(name); - - if (!xform) { - ABC_LOG(m_settings.logger) << __func__ << ": xform " << name << " is NULL\n"; - return; - } - - createParticleSystemsWriters(ob, xform); - - switch (ob->type) { - case OB_MESH: { - Mesh *me = static_cast<Mesh *>(ob->data); - - if (!me) { - return; - } - - m_shapes.push_back(new AbcMeshWriter(ob, xform, m_shape_sampling_index, m_settings)); - break; - } - case OB_SURF: { - Curve *cu = static_cast<Curve *>(ob->data); - - if (!cu) { - return; - } - - AbcObjectWriter *writer; - if (m_settings.curves_as_mesh) { - writer = new AbcCurveMeshWriter(ob, xform, m_shape_sampling_index, m_settings); - } - else { - writer = new AbcNurbsWriter(ob, xform, m_shape_sampling_index, m_settings); - } - m_shapes.push_back(writer); - break; - } - case OB_CURVE: { - Curve *cu = static_cast<Curve *>(ob->data); - - if (!cu) { - return; - } - - AbcObjectWriter *writer; - if (m_settings.curves_as_mesh) { - writer = new AbcCurveMeshWriter(ob, xform, m_shape_sampling_index, m_settings); - } - else { - writer = new AbcCurveWriter(ob, xform, m_shape_sampling_index, m_settings); - } - m_shapes.push_back(writer); - break; - } - case OB_CAMERA: { - Camera *cam = static_cast<Camera *>(ob->data); - - if (cam->type == CAM_PERSP) { - m_shapes.push_back(new AbcCameraWriter(ob, xform, m_shape_sampling_index, m_settings)); - } - - break; - } - case OB_MBALL: { - MetaBall *mball = static_cast<MetaBall *>(ob->data); - if (!mball) { - return; - } - - m_shapes.push_back( - new AbcMBallWriter(m_bmain, ob, xform, m_shape_sampling_index, m_settings)); - break; - } - } -} - -AbcTransformWriter *AbcExporter::getXForm(const std::string &name) -{ - std::map<std::string, AbcTransformWriter *>::iterator it = m_xforms.find(name); - - if (it == m_xforms.end()) { - return NULL; - } - - return it->second; -} - -void AbcExporter::setCurrentFrame(Main *bmain, double t) -{ - m_settings.scene->r.cfra = static_cast<int>(t); - m_settings.scene->r.subframe = static_cast<float>(t) - m_settings.scene->r.cfra; - BKE_scene_graph_update_for_newframe(m_settings.depsgraph, bmain); -} diff --git a/source/blender/io/alembic/intern/abc_exporter.h b/source/blender/io/alembic/intern/abc_exporter.h deleted file mode 100644 index 049ccb291bd..00000000000 --- a/source/blender/io/alembic/intern/abc_exporter.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_EXPORTER_H__ -#define __ABC_EXPORTER_H__ - -#include <Alembic/Abc/All.h> -#include <map> -#include <set> -#include <vector> - -#include "abc_util.h" - -class AbcObjectWriter; -class AbcTransformWriter; -class ArchiveWriter; - -struct Base; -struct Depsgraph; -struct Main; -struct Object; -struct Scene; -struct ViewLayer; - -struct ExportSettings { - ExportSettings(); - - Scene *scene; - /** Scene layer to export; all its objects will be exported, unless selected_only=true. */ - ViewLayer *view_layer; - Depsgraph *depsgraph; - SimpleLogger logger; - - bool selected_only; - bool visible_objects_only; - bool renderable_only; - - double frame_start, frame_end; - double frame_samples_xform; - double frame_samples_shape; - double shutter_open; - double shutter_close; - float global_scale; - - bool flatten_hierarchy; - - bool export_normals; - bool export_uvs; - bool export_vcols; - bool export_face_sets; - bool export_vweigths; - bool export_hair; - bool export_particles; - - bool apply_subdiv; - bool curves_as_mesh; - bool use_subdiv_schema; - bool export_child_hairs; - bool pack_uv; - bool triangulate; - - int quad_method; - int ngon_method; -}; - -class AbcExporter { - Main *m_bmain; - ExportSettings &m_settings; - - const char *m_filename; - - unsigned int m_trans_sampling_index, m_shape_sampling_index; - - ArchiveWriter *m_writer; - - /* mapping from name to transform writer */ - typedef std::map<std::string, AbcTransformWriter *> m_xforms_type; - m_xforms_type m_xforms; - - std::vector<AbcObjectWriter *> m_shapes; - - public: - AbcExporter(Main *bmain, const char *filename, ExportSettings &settings); - ~AbcExporter(); - - void operator()(short *do_update, float *progress, bool *was_canceled); - - protected: - void getShutterSamples(unsigned int nr_of_samples, - bool time_relative, - std::vector<double> &samples); - void getFrameSet(unsigned int nr_of_samples, std::set<double> &frames); - - private: - Alembic::Abc::TimeSamplingPtr createTimeSampling(double step); - - void createTransformWritersHierarchy(); - AbcTransformWriter *createTransformWriter(Object *ob, Object *parent, Object *dupliObParent); - void exploreTransform(Base *base, Object *object, Object *parent, Object *dupliObParent); - void exploreObject(Base *base, Object *object, Object *dupliObParent); - void createShapeWriters(); - void createShapeWriter(Object *ob, Object *dupliObParent); - void createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform); - - AbcTransformWriter *getXForm(const std::string &name); - - void setCurrentFrame(Main *bmain, double t); -}; - -#endif /* __ABC_EXPORTER_H__ */ diff --git a/source/blender/io/alembic/intern/abc_reader_archive.cc b/source/blender/io/alembic/intern/abc_reader_archive.cc index d55736f732a..d7f1095f0fd 100644 --- a/source/blender/io/alembic/intern/abc_reader_archive.cc +++ b/source/blender/io/alembic/intern/abc_reader_archive.cc @@ -39,6 +39,10 @@ using Alembic::Abc::Exception; using Alembic::Abc::IArchive; using Alembic::Abc::kWrapExisting; +namespace blender { +namespace io { +namespace alembic { + static IArchive open_archive(const std::string &filename, const std::vector<std::istream *> &input_streams) { @@ -103,3 +107,7 @@ Alembic::Abc::IObject ArchiveReader::getTop() { return m_archive.getTop(); } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_archive.h b/source/blender/io/alembic/intern/abc_reader_archive.h index 304c876adce..aea62b46cce 100644 --- a/source/blender/io/alembic/intern/abc_reader_archive.h +++ b/source/blender/io/alembic/intern/abc_reader_archive.h @@ -16,14 +16,12 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_ARCHIVE_H__ -#define __ABC_READER_ARCHIVE_H__ - #include <Alembic/Abc/All.h> #include <Alembic/AbcCoreOgawa/All.h> @@ -32,6 +30,10 @@ struct Main; struct Scene; +namespace blender { +namespace io { +namespace alembic { + /* Wrappers around input and output archives. The goal is to be able to use * streams so that unicode paths work on Windows (T49112), and to make sure that * the stream objects remain valid as long as the archives are open. @@ -50,4 +52,6 @@ class ArchiveReader { Alembic::Abc::IObject getTop(); }; -#endif /* __ABC_READER_ARCHIVE_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_camera.cc b/source/blender/io/alembic/intern/abc_reader_camera.cc index 0752534f8c2..3affb35908d 100644 --- a/source/blender/io/alembic/intern/abc_reader_camera.cc +++ b/source/blender/io/alembic/intern/abc_reader_camera.cc @@ -37,6 +37,10 @@ using Alembic::AbcGeom::IFloatProperty; using Alembic::AbcGeom::ISampleSelector; using Alembic::AbcGeom::kWrapExisting; +namespace blender { +namespace io { +namespace alembic { + AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -109,3 +113,7 @@ void AbcCameraReader::readObjectData(Main *bmain, const ISampleSelector &sample_ m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str()); m_object->data = bcam; } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_camera.h b/source/blender/io/alembic/intern/abc_reader_camera.h index 1d9763b0454..b733269407b 100644 --- a/source/blender/io/alembic/intern/abc_reader_camera.h +++ b/source/blender/io/alembic/intern/abc_reader_camera.h @@ -13,16 +13,18 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_CAMERA_H__ -#define __ABC_READER_CAMERA_H__ - #include "abc_reader_object.h" +namespace blender { +namespace io { +namespace alembic { + class AbcCameraReader : public AbcObjectReader { Alembic::AbcGeom::ICameraSchema m_schema; @@ -37,4 +39,6 @@ class AbcCameraReader : public AbcObjectReader { void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); }; -#endif /* __ABC_READER_CAMERA_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_curves.cc b/source/blender/io/alembic/intern/abc_reader_curves.cc index d5e0b694294..a505dfd654b 100644 --- a/source/blender/io/alembic/intern/abc_reader_curves.cc +++ b/source/blender/io/alembic/intern/abc_reader_curves.cc @@ -54,6 +54,10 @@ using Alembic::AbcGeom::IInt16Property; using Alembic::AbcGeom::ISampleSelector; using Alembic::AbcGeom::kWrapExisting; +namespace blender { +namespace io { +namespace alembic { + AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -351,3 +355,7 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh, return BKE_mesh_new_nomain_from_curve(m_object); } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_curves.h b/source/blender/io/alembic/intern/abc_reader_curves.h index eb0538308f8..7488adb9b24 100644 --- a/source/blender/io/alembic/intern/abc_reader_curves.h +++ b/source/blender/io/alembic/intern/abc_reader_curves.h @@ -16,14 +16,12 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_CURVES_H__ -#define __ABC_READER_CURVES_H__ - #include "abc_reader_mesh.h" #include "abc_reader_object.h" @@ -31,6 +29,10 @@ struct Curve; #define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution" +namespace blender { +namespace io { +namespace alembic { + class AbcCurveReader : public AbcObjectReader { Alembic::AbcGeom::ICurvesSchema m_curves_schema; @@ -53,4 +55,6 @@ class AbcCurveReader : public AbcObjectReader { const Alembic::Abc::ISampleSelector &sample_selector); }; -#endif /* __ABC_READER_CURVES_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index 8b79a3a0aa0..756dde3783c 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -32,6 +32,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "BLI_compiler_compat.h" #include "BLI_math_geom.h" #include "BKE_main.h" @@ -59,6 +60,10 @@ using Alembic::AbcGeom::N3fArraySamplePtr; using Alembic::AbcGeom::UInt32ArraySamplePtr; using Alembic::AbcGeom::V2fArraySamplePtr; +namespace blender { +namespace io { +namespace alembic { + /* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ /* Some helpers for mesh generation */ @@ -339,7 +344,7 @@ static void process_normals(CDStreamConfig &config, } } -ABC_INLINE void read_uvs_params(CDStreamConfig &config, +BLI_INLINE void read_uvs_params(CDStreamConfig &config, AbcMeshData &abc_data, const IV2fGeomParam &uv, const ISampleSelector &selector) @@ -714,7 +719,7 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSel /* ************************************************************************** */ -ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) +BLI_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) { for (int i = 0, e = totedge; i < e; i++) { MEdge &edge = edges[i]; @@ -930,3 +935,7 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, return config.mesh; } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.h b/source/blender/io/alembic/intern/abc_reader_mesh.h index bc95c7ec134..363a74b8b5f 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.h +++ b/source/blender/io/alembic/intern/abc_reader_mesh.h @@ -13,19 +13,21 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_MESH_H__ -#define __ABC_READER_MESH_H__ - #include "abc_customdata.h" #include "abc_reader_object.h" struct Mesh; +namespace blender { +namespace io { +namespace alembic { + class AbcMeshReader : public AbcObjectReader { Alembic::AbcGeom::IPolyMeshSchema m_schema; @@ -83,4 +85,6 @@ void read_mverts(MVert *mverts, CDStreamConfig get_config(struct Mesh *mesh); -#endif /* __ABC_READER_MESH_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_nurbs.cc b/source/blender/io/alembic/intern/abc_reader_nurbs.cc index 5b9954b3ff6..3ca3f6229ab 100644 --- a/source/blender/io/alembic/intern/abc_reader_nurbs.cc +++ b/source/blender/io/alembic/intern/abc_reader_nurbs.cc @@ -44,6 +44,10 @@ using Alembic::AbcGeom::INuPatch; using Alembic::AbcGeom::INuPatchSchema; using Alembic::AbcGeom::IObject; +namespace blender { +namespace io { +namespace alembic { + AbcNurbsReader::AbcNurbsReader(const IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -222,3 +226,7 @@ void AbcNurbsReader::getNurbsPatches(const IObject &obj) getNurbsPatches(child); } } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_nurbs.h b/source/blender/io/alembic/intern/abc_reader_nurbs.h index f4284c136fb..738da82885d 100644 --- a/source/blender/io/alembic/intern/abc_reader_nurbs.h +++ b/source/blender/io/alembic/intern/abc_reader_nurbs.h @@ -13,16 +13,18 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_NURBS_H__ -#define __ABC_READER_NURBS_H__ - #include "abc_reader_object.h" +namespace blender { +namespace io { +namespace alembic { + class AbcNurbsReader : public AbcObjectReader { std::vector<std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject>> m_schemas; @@ -37,4 +39,6 @@ class AbcNurbsReader : public AbcObjectReader { void getNurbsPatches(const Alembic::Abc::IObject &obj); }; -#endif /* __ABC_READER_NURBS_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc index e5bd0771a42..39b9cd4c161 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.cc +++ b/source/blender/io/alembic/intern/abc_reader_object.cc @@ -41,6 +41,10 @@ using Alembic::AbcGeom::IObject; using Alembic::AbcGeom::IXform; using Alembic::AbcGeom::IXformSchema; +namespace blender { +namespace io { +namespace alembic { + AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings) : m_name(""), m_object_name(""), @@ -330,3 +334,7 @@ void AbcObjectReader::decref() m_refcount--; BLI_assert(m_refcount >= 0); } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h index dcc2697e0b5..0bde60b06b5 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.h +++ b/source/blender/io/alembic/intern/abc_reader_object.h @@ -13,14 +13,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_OBJECT_H__ -#define __ABC_READER_OBJECT_H__ - #include <Alembic/Abc/All.h> #include <Alembic/AbcGeom/All.h> @@ -33,6 +31,10 @@ struct Object; using Alembic::AbcCoreAbstract::chrono_t; +namespace blender { +namespace io { +namespace alembic { + struct ImportSettings { bool do_convert_mat; float conversion_mat[4][4]; @@ -166,4 +168,6 @@ class AbcObjectReader { Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time); -#endif /* __ABC_READER_OBJECT_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_points.cc b/source/blender/io/alembic/intern/abc_reader_points.cc index c5d08693176..b805da4daa3 100644 --- a/source/blender/io/alembic/intern/abc_reader_points.cc +++ b/source/blender/io/alembic/intern/abc_reader_points.cc @@ -43,6 +43,10 @@ using Alembic::AbcGeom::IPoints; using Alembic::AbcGeom::IPointsSchema; using Alembic::AbcGeom::ISampleSelector; +namespace blender { +namespace io { +namespace alembic { + AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -153,3 +157,7 @@ struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh, return new_mesh ? new_mesh : existing_mesh; } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_points.h b/source/blender/io/alembic/intern/abc_reader_points.h index 99881e091f9..8a970ac35b3 100644 --- a/source/blender/io/alembic/intern/abc_reader_points.h +++ b/source/blender/io/alembic/intern/abc_reader_points.h @@ -16,17 +16,19 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_POINTS_H__ -#define __ABC_READER_POINTS_H__ - #include "abc_customdata.h" #include "abc_reader_object.h" +namespace blender { +namespace io { +namespace alembic { + class AbcPointsReader : public AbcObjectReader { Alembic::AbcGeom::IPointsSchema m_schema; Alembic::AbcGeom::IPointsSchema::Sample m_sample; @@ -51,4 +53,6 @@ void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, const Alembic::AbcGeom::ISampleSelector &selector, CDStreamConfig &config); -#endif /* __ABC_READER_POINTS_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_transform.cc b/source/blender/io/alembic/intern/abc_reader_transform.cc index 3df391f8432..456d1da2c68 100644 --- a/source/blender/io/alembic/intern/abc_reader_transform.cc +++ b/source/blender/io/alembic/intern/abc_reader_transform.cc @@ -29,6 +29,10 @@ using Alembic::Abc::ISampleSelector; +namespace blender { +namespace io { +namespace alembic { + AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -72,3 +76,7 @@ void AbcEmptyReader::readObjectData(Main *bmain, const ISampleSelector &UNUSED(s m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str()); m_object->data = NULL; } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_transform.h b/source/blender/io/alembic/intern/abc_reader_transform.h index 6b4d23c1884..812d3bdfc92 100644 --- a/source/blender/io/alembic/intern/abc_reader_transform.h +++ b/source/blender/io/alembic/intern/abc_reader_transform.h @@ -13,18 +13,20 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_TRANSFORM_H__ -#define __ABC_READER_TRANSFORM_H__ - #include "abc_reader_object.h" #include <Alembic/AbcGeom/All.h> +namespace blender { +namespace io { +namespace alembic { + class AbcEmptyReader : public AbcObjectReader { Alembic::AbcGeom::IXformSchema m_schema; @@ -39,4 +41,6 @@ class AbcEmptyReader : public AbcObjectReader { void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); }; -#endif /* __ABC_READER_TRANSFORM_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_util.cc b/source/blender/io/alembic/intern/abc_util.cc index 1f3bd2a1aaa..04febd7bfcb 100644 --- a/source/blender/io/alembic/intern/abc_util.cc +++ b/source/blender/io/alembic/intern/abc_util.cc @@ -38,6 +38,10 @@ #include "PIL_time.h" +namespace blender { +namespace io { +namespace alembic { + std::string get_id_name(const Object *const ob) { if (!ob) { @@ -49,12 +53,16 @@ std::string get_id_name(const Object *const ob) std::string get_id_name(const ID *const id) { - std::string name(id->name + 2); - std::replace(name.begin(), name.end(), ' ', '_'); - std::replace(name.begin(), name.end(), '.', '_'); - std::replace(name.begin(), name.end(), ':', '_'); + return get_valid_abc_name(id->name + 2); +} - return name; +std::string get_valid_abc_name(const char *name) +{ + std::string name_string(name); + std::replace(name_string.begin(), name_string.end(), ' ', '_'); + std::replace(name_string.begin(), name_string.end(), '.', '_'); + std::replace(name_string.begin(), name_string.end(), ':', '_'); + return name_string; } /** @@ -252,3 +260,7 @@ std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger) os << logger.str(); return os; } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_util.h b/source/blender/io/alembic/intern/abc_util.h index 57b4d9800a5..4689173ab5f 100644 --- a/source/blender/io/alembic/intern/abc_util.h +++ b/source/blender/io/alembic/intern/abc_util.h @@ -13,23 +13,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_UTIL_H__ -#define __ABC_UTIL_H__ - #include <Alembic/Abc/All.h> #include <Alembic/AbcGeom/All.h> -#ifdef _MSC_VER -# define ABC_INLINE static __forceinline -#else -# define ABC_INLINE static inline -#endif - /** * \brief The CacheReader struct is only used for anonymous pointers, * to interface between C and C++ code. This library only creates @@ -41,14 +33,19 @@ struct CacheReader { using Alembic::Abc::chrono_t; -class AbcObjectReader; -struct ImportSettings; - struct ID; struct Object; +namespace blender { +namespace io { +namespace alembic { + +class AbcObjectReader; +struct ImportSettings; + std::string get_id_name(const ID *const id); std::string get_id_name(const Object *const ob); +std::string get_valid_abc_name(const char *name); std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent); /* Convert from float to Alembic matrix representations. Does NOT convert from Z-up to Y-up. */ @@ -164,4 +161,6 @@ class SimpleLogger { */ std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger); -#endif /* __ABC_UTIL_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_archive.cc b/source/blender/io/alembic/intern/abc_writer_archive.cc deleted file mode 100644 index 40926532f85..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_archive.cc +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_archive.h" - -#include "BKE_blender_version.h" - -#include "BLI_path_util.h" -#include "BLI_string.h" - -#include "DNA_scene_types.h" - -#ifdef WIN32 -# include "utfconv.h" -#endif - -#include <fstream> - -using Alembic::Abc::ErrorHandler; -using Alembic::Abc::kWrapExisting; -using Alembic::Abc::OArchive; - -/* This kinda duplicates CreateArchiveWithInfo, but Alembic does not seem to - * have a version supporting streams. */ -static OArchive create_archive(std::ostream *ostream, - const std::string &scene_name, - double scene_fps) -{ - Alembic::Abc::MetaData abc_metadata; - - abc_metadata.set(Alembic::Abc::kApplicationNameKey, "Blender"); - abc_metadata.set(Alembic::Abc::kUserDescriptionKey, scene_name); - abc_metadata.set("blender_version", std::string("v") + BKE_blender_version_string()); - abc_metadata.set("FramesPerTimeUnit", std::to_string(scene_fps)); - - time_t raw_time; - time(&raw_time); - char buffer[128]; - -#if defined _WIN32 || defined _WIN64 - ctime_s(buffer, 128, &raw_time); -#else - ctime_r(&raw_time, buffer); -#endif - - const std::size_t buffer_len = strlen(buffer); - if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') { - buffer[buffer_len - 1] = '\0'; - } - - abc_metadata.set(Alembic::Abc::kDateWrittenKey, buffer); - - ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy; - Alembic::AbcCoreOgawa::WriteArchive archive_writer; - return OArchive(archive_writer(ostream, abc_metadata), kWrapExisting, policy); -} - -ArchiveWriter::ArchiveWriter(const char *filename, - const std::string &abc_scene_name, - const Scene *scene) -{ - /* Use stream to support unicode character paths on Windows. */ -#ifdef WIN32 - UTF16_ENCODE(filename); - std::wstring wstr(filename_16); - m_outfile.open(wstr.c_str(), std::ios::out | std::ios::binary); - UTF16_UN_ENCODE(filename); -#else - m_outfile.open(filename, std::ios::out | std::ios::binary); -#endif - - m_archive = create_archive(&m_outfile, abc_scene_name, FPS); -} - -OArchive &ArchiveWriter::archive() -{ - return m_archive; -} diff --git a/source/blender/io/alembic/intern/abc_writer_camera.cc b/source/blender/io/alembic/intern/abc_writer_camera.cc deleted file mode 100644 index 07ae81e584f..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_camera.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_camera.h" -#include "abc_writer_transform.h" - -#include "DNA_camera_types.h" -#include "DNA_object_types.h" - -using Alembic::AbcGeom::OCamera; -using Alembic::AbcGeom::OFloatProperty; - -AbcCameraWriter::AbcCameraWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent) -{ - OCamera camera(parent->alembicXform(), m_name, m_time_sampling); - m_camera_schema = camera.getSchema(); - - m_custom_data_container = m_camera_schema.getUserProperties(); - m_stereo_distance = OFloatProperty(m_custom_data_container, "stereoDistance", m_time_sampling); - m_eye_separation = OFloatProperty(m_custom_data_container, "eyeSeparation", m_time_sampling); -} - -void AbcCameraWriter::do_write() -{ - Camera *cam = static_cast<Camera *>(m_object->data); - - m_stereo_distance.set(cam->stereo.convergence_distance); - m_eye_separation.set(cam->stereo.interocular_distance); - - const double apperture_x = cam->sensor_x / 10.0; - const double apperture_y = cam->sensor_y / 10.0; - const double film_aspect = apperture_x / apperture_y; - - m_camera_sample.setFocalLength(cam->lens); - m_camera_sample.setHorizontalAperture(apperture_x); - m_camera_sample.setVerticalAperture(apperture_y); - m_camera_sample.setHorizontalFilmOffset(apperture_x * cam->shiftx); - m_camera_sample.setVerticalFilmOffset(apperture_y * cam->shifty * film_aspect); - m_camera_sample.setNearClippingPlane(cam->clip_start); - m_camera_sample.setFarClippingPlane(cam->clip_end); - - if (cam->dof.focus_object) { - Imath::V3f v(m_object->loc[0] - cam->dof.focus_object->loc[0], - m_object->loc[1] - cam->dof.focus_object->loc[1], - m_object->loc[2] - cam->dof.focus_object->loc[2]); - m_camera_sample.setFocusDistance(v.length()); - } - else { - m_camera_sample.setFocusDistance(cam->dof.focus_distance); - } - - /* Blender camera does not have an fstop param, so try to find a custom prop - * instead. */ - m_camera_sample.setFStop(cam->dof.aperture_fstop); - - m_camera_sample.setLensSqueezeRatio(1.0); - m_camera_schema.set(m_camera_sample); -} diff --git a/source/blender/io/alembic/intern/abc_writer_mball.cc b/source/blender/io/alembic/intern/abc_writer_mball.cc deleted file mode 100644 index 3593acf18b0..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_mball.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_mball.h" -#include "abc_writer_mesh.h" - -#include "DNA_mesh_types.h" -#include "DNA_meta_types.h" -#include "DNA_object_types.h" - -#include "BKE_displist.h" -#include "BKE_lib_id.h" -#include "BKE_mball.h" -#include "BKE_mesh.h" -#include "BKE_object.h" - -#include "BLI_utildefines.h" - -AbcMBallWriter::AbcMBallWriter(Main *bmain, - Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcGenericMeshWriter(ob, parent, time_sampling, settings), m_bmain(bmain) -{ - m_is_animated = isAnimated(); -} - -AbcMBallWriter::~AbcMBallWriter() -{ -} - -bool AbcMBallWriter::isAnimated() const -{ - return true; -} - -Mesh *AbcMBallWriter::getEvaluatedMesh(Scene * /*scene_eval*/, Object *ob_eval, bool &r_needsfree) -{ - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); - if (mesh_eval != NULL) { - /* Mesh_eval only exists when generative modifiers are in use. */ - r_needsfree = false; - return mesh_eval; - } - r_needsfree = true; - - /* The approach below is copied from BKE_mesh_new_from_object() */ - Mesh *tmpmesh = BKE_mesh_add(m_bmain, ((ID *)m_object->data)->name + 2); - BLI_assert(tmpmesh != NULL); - - /* BKE_mesh_add gives us a user count we don't need */ - id_us_min(&tmpmesh->id); - - ListBase disp = {NULL, NULL}; - /* TODO(sergey): This is gonna to work for until Depsgraph - * only contains for_render flag. As soon as CoW is - * implemented, this is to be rethought. - */ - BKE_displist_make_mball_forRender(m_settings.depsgraph, m_settings.scene, m_object, &disp); - BKE_mesh_from_metaball(&disp, tmpmesh); - BKE_displist_free(&disp); - - BKE_mesh_texspace_copy_from_object(tmpmesh, m_object); - - return tmpmesh; -} - -void AbcMBallWriter::freeEvaluatedMesh(struct Mesh *mesh) -{ - BKE_id_free(m_bmain, mesh); -} - -bool AbcMBallWriter::isBasisBall(Scene *scene, Object *ob) -{ - Object *basis_ob = BKE_mball_basis_find(scene, ob); - return ob == basis_ob; -} diff --git a/source/blender/io/alembic/intern/abc_writer_mball.h b/source/blender/io/alembic/intern/abc_writer_mball.h deleted file mode 100644 index e3ac1e69cae..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_mball.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_MBALL_H__ -#define __ABC_WRITER_MBALL_H__ - -#include "abc_writer_mesh.h" -#include "abc_writer_object.h" - -struct Main; -struct Object; - -/* AbcMBallWriter converts the metaballs to meshes at every frame, - * and defers to AbcGenericMeshWriter to perform the writing - * to the Alembic file. Only the basis balls are exported, as this - * results in the entire shape as one mesh. */ -class AbcMBallWriter : public AbcGenericMeshWriter { - Main *m_bmain; - - public: - explicit AbcMBallWriter(Main *bmain, - Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - ~AbcMBallWriter(); - - static bool isBasisBall(Scene *scene, Object *ob); - - protected: - Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) override; - void freeEvaluatedMesh(struct Mesh *mesh) override; - - private: - bool isAnimated() const override; -}; - -#endif /* __ABC_WRITER_MBALL_H__ */ diff --git a/source/blender/io/alembic/intern/abc_writer_mesh.h b/source/blender/io/alembic/intern/abc_writer_mesh.h deleted file mode 100644 index 9152a370e4f..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_mesh.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_MESH_H__ -#define __ABC_WRITER_MESH_H__ - -#include "abc_customdata.h" -#include "abc_writer_object.h" - -struct Mesh; -struct ModifierData; - -/* Writer for Alembic meshes. Does not assume the object is a mesh object. */ -class AbcGenericMeshWriter : public AbcObjectWriter { - protected: - Alembic::AbcGeom::OPolyMeshSchema m_mesh_schema; - Alembic::AbcGeom::OPolyMeshSchema::Sample m_mesh_sample; - - Alembic::AbcGeom::OSubDSchema m_subdiv_schema; - Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample; - - Alembic::Abc::OArrayProperty m_mat_indices; - - bool m_is_animated; - ModifierData *m_subsurf_mod; - - CDStreamConfig m_custom_data_config; - - bool m_is_liquid; - bool m_is_subd; - - public: - AbcGenericMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - ~AbcGenericMeshWriter(); - void setIsAnimated(bool is_animated); - - protected: - virtual void do_write(); - virtual bool isAnimated() const; - virtual Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) = 0; - virtual void freeEvaluatedMesh(struct Mesh *mesh); - - Mesh *getFinalMesh(bool &r_needsfree); - - void writeMesh(struct Mesh *mesh); - void writeSubD(struct Mesh *mesh); - - void writeArbGeoParams(struct Mesh *mesh); - void getGeoGroups(struct Mesh *mesh, std::map<std::string, std::vector<int32_t>> &geoGroups); - - /* fluid surfaces support */ - void getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels); - - template<typename Schema> void writeFaceSets(struct Mesh *mesh, Schema &schema); -}; - -class AbcMeshWriter : public AbcGenericMeshWriter { - public: - AbcMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - ~AbcMeshWriter(); - - protected: - virtual Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) override; -}; - -#endif /* __ABC_WRITER_MESH_H__ */ diff --git a/source/blender/io/alembic/intern/abc_writer_object.cc b/source/blender/io/alembic/intern/abc_writer_object.cc deleted file mode 100644 index f4a3587f54d..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_object.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_object.h" - -#include "DNA_object_types.h" - -#include "BKE_object.h" - -AbcObjectWriter::AbcObjectWriter(Object *ob, - uint32_t time_sampling, - ExportSettings &settings, - AbcObjectWriter *parent) - : m_object(ob), m_settings(settings), m_time_sampling(time_sampling), m_first_frame(true) -{ - m_name = get_id_name(m_object) + "Shape"; - - if (parent) { - parent->addChild(this); - } -} - -AbcObjectWriter::~AbcObjectWriter() -{ -} - -void AbcObjectWriter::addChild(AbcObjectWriter *child) -{ - m_children.push_back(child); -} - -Imath::Box3d AbcObjectWriter::bounds() -{ - BoundBox *bb = BKE_object_boundbox_get(this->m_object); - - if (!bb) { - if (this->m_object->type != OB_CAMERA) { - ABC_LOG(m_settings.logger) << "Bounding box is null!\n"; - } - - return Imath::Box3d(); - } - - /* Convert Z-up to Y-up. This also changes which vector goes into which min/max property. */ - this->m_bounds.min.x = bb->vec[0][0]; - this->m_bounds.min.y = bb->vec[0][2]; - this->m_bounds.min.z = -bb->vec[6][1]; - - this->m_bounds.max.x = bb->vec[6][0]; - this->m_bounds.max.y = bb->vec[6][2]; - this->m_bounds.max.z = -bb->vec[0][1]; - - return this->m_bounds; -} - -void AbcObjectWriter::write() -{ - do_write(); - m_first_frame = false; -} diff --git a/source/blender/io/alembic/intern/abc_writer_object.h b/source/blender/io/alembic/intern/abc_writer_object.h deleted file mode 100644 index 830c4aee903..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_object.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_OBJECT_H__ -#define __ABC_WRITER_OBJECT_H__ - -#include <Alembic/Abc/All.h> -#include <Alembic/AbcGeom/All.h> - -#include "abc_exporter.h" - -#include "DNA_ID.h" - -class AbcTransformWriter; - -struct Main; -struct Object; - -class AbcObjectWriter { - protected: - Object *m_object; - ExportSettings &m_settings; - - uint32_t m_time_sampling; - - Imath::Box3d m_bounds; - std::vector<AbcObjectWriter *> m_children; - - std::vector<std::pair<std::string, IDProperty *>> m_props; - - bool m_first_frame; - std::string m_name; - - public: - AbcObjectWriter(Object *ob, - uint32_t time_sampling, - ExportSettings &settings, - AbcObjectWriter *parent = NULL); - - virtual ~AbcObjectWriter(); - - void addChild(AbcObjectWriter *child); - - virtual Imath::Box3d bounds(); - - void write(); - - private: - virtual void do_write() = 0; -}; - -#endif /* __ABC_WRITER_OBJECT_H__ */ diff --git a/source/blender/io/alembic/intern/abc_writer_points.cc b/source/blender/io/alembic/intern/abc_writer_points.cc deleted file mode 100644 index ac663b62693..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_points.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_points.h" -#include "abc_util.h" -#include "abc_writer_mesh.h" -#include "abc_writer_transform.h" - -#include "DNA_object_types.h" -#include "DNA_particle_types.h" - -#include "BKE_lattice.h" -#include "BKE_particle.h" - -#include "BLI_math.h" - -#include "DEG_depsgraph_query.h" - -using Alembic::AbcGeom::kVertexScope; -using Alembic::AbcGeom::OPoints; -using Alembic::AbcGeom::OPointsSchema; - -/* ************************************************************************** */ - -AbcPointsWriter::AbcPointsWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys) - : AbcObjectWriter(ob, time_sampling, settings, parent) -{ - m_psys = psys; - - OPoints points(parent->alembicXform(), psys->name, m_time_sampling); - m_schema = points.getSchema(); -} - -void AbcPointsWriter::do_write() -{ - if (!m_psys) { - return; - } - - std::vector<Imath::V3f> points; - std::vector<Imath::V3f> velocities; - std::vector<float> widths; - std::vector<uint64_t> ids; - - ParticleKey state; - - ParticleSimulationData sim; - sim.depsgraph = m_settings.depsgraph; - sim.scene = m_settings.scene; - sim.ob = m_object; - sim.psys = m_psys; - - m_psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - - uint64_t index = 0; - for (int p = 0; p < m_psys->totpart; p++) { - float pos[3], vel[3]; - - if (m_psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) { - continue; - } - - state.time = DEG_get_ctime(m_settings.depsgraph); - - if (psys_get_particle_state(&sim, p, &state, 0) == 0) { - continue; - } - - /* location */ - mul_v3_m4v3(pos, m_object->imat, state.co); - - /* velocity */ - sub_v3_v3v3(vel, state.co, m_psys->particles[p].prev_state.co); - - /* Convert Z-up to Y-up. */ - points.push_back(Imath::V3f(pos[0], pos[2], -pos[1])); - velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1])); - widths.push_back(m_psys->particles[p].size); - ids.push_back(index++); - } - - if (m_psys->lattice_deform_data) { - BKE_lattice_deform_data_destroy(m_psys->lattice_deform_data); - m_psys->lattice_deform_data = NULL; - } - - Alembic::Abc::P3fArraySample psample(points); - Alembic::Abc::UInt64ArraySample idsample(ids); - Alembic::Abc::V3fArraySample vsample(velocities); - Alembic::Abc::FloatArraySample wsample_array(widths); - Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope); - - m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample); - m_sample.setSelfBounds(bounds()); - - m_schema.set(m_sample); -} diff --git a/source/blender/io/alembic/intern/abc_writer_transform.cc b/source/blender/io/alembic/intern/abc_writer_transform.cc deleted file mode 100644 index 1ec7db0a1c6..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_transform.cc +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_transform.h" -#include "abc_axis_conversion.h" - -#include <OpenEXR/ImathBoxAlgo.h> - -#include "DNA_object_types.h" - -#include "BLI_math.h" - -#include "DEG_depsgraph_query.h" - -using Alembic::AbcGeom::OObject; -using Alembic::AbcGeom::OXform; - -AbcTransformWriter::AbcTransformWriter(Object *ob, - const OObject &abc_parent, - AbcTransformWriter *parent, - unsigned int time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent), m_proxy_from(NULL) -{ - m_is_animated = hasAnimation(m_object); - - if (!m_is_animated) { - time_sampling = 0; - } - - m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling); - m_schema = m_xform.getSchema(); - - /* Blender objects can't have a parent without inheriting the transform. */ - m_inherits_xform = parent != NULL; -} - -void AbcTransformWriter::do_write() -{ - Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object); - - if (m_first_frame) { - m_visibility = Alembic::AbcGeom::CreateVisibilityProperty( - m_xform, m_xform.getSchema().getTimeSampling()); - } - - m_visibility.set(!(ob_eval->restrictflag & OB_RESTRICT_VIEWPORT)); - - if (!m_first_frame && !m_is_animated) { - return; - } - - float yup_mat[4][4]; - create_transform_matrix( - ob_eval, yup_mat, m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD, m_proxy_from); - - /* If the parent is a camera, undo its to-Maya rotation (see below). */ - bool is_root_object = !m_inherits_xform || ob_eval->parent == nullptr; - if (!is_root_object && ob_eval->parent->type == OB_CAMERA) { - float rot_mat[4][4]; - axis_angle_to_mat4_single(rot_mat, 'X', M_PI_2); - mul_m4_m4m4(yup_mat, rot_mat, yup_mat); - } - - /* If the object is a camera, apply an extra rotation to Maya camera orientation. */ - if (ob_eval->type == OB_CAMERA) { - float rot_mat[4][4]; - axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2); - mul_m4_m4m4(yup_mat, yup_mat, rot_mat); - } - - if (is_root_object) { - /* Only apply scaling to root objects, parenting will propagate it. */ - float scale_mat[4][4]; - scale_m4_fl(scale_mat, m_settings.global_scale); - scale_mat[3][3] = m_settings.global_scale; /* also scale translation */ - mul_m4_m4m4(yup_mat, yup_mat, scale_mat); - yup_mat[3][3] /= m_settings.global_scale; /* normalise the homogeneous component */ - } - - m_matrix = convert_matrix_datatype(yup_mat); - m_sample.setMatrix(m_matrix); - m_sample.setInheritsXforms(m_inherits_xform); - m_schema.set(m_sample); -} - -Imath::Box3d AbcTransformWriter::bounds() -{ - Imath::Box3d bounds; - - for (int i = 0; i < m_children.size(); i++) { - Imath::Box3d box(m_children[i]->bounds()); - bounds.extendBy(box); - } - - return Imath::transform(bounds, m_matrix); -} - -bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const -{ - return true; -} diff --git a/source/blender/io/alembic/intern/abc_writer_transform.h b/source/blender/io/alembic/intern/abc_writer_transform.h deleted file mode 100644 index 4397b220761..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_transform.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_TRANSFORM_H__ -#define __ABC_WRITER_TRANSFORM_H__ - -#include "abc_writer_object.h" - -#include <Alembic/AbcGeom/All.h> - -class AbcTransformWriter : public AbcObjectWriter { - Alembic::AbcGeom::OXform m_xform; - Alembic::AbcGeom::OXformSchema m_schema; - Alembic::AbcGeom::XformSample m_sample; - Alembic::AbcGeom::OVisibilityProperty m_visibility; - Alembic::Abc::M44d m_matrix; - - bool m_is_animated; - bool m_inherits_xform; - - public: - Object *m_proxy_from; - - public: - AbcTransformWriter(Object *ob, - const Alembic::AbcGeom::OObject &abc_parent, - AbcTransformWriter *parent, - unsigned int time_sampling, - ExportSettings &settings); - - Alembic::AbcGeom::OXform &alembicXform() - { - return m_xform; - } - virtual Imath::Box3d bounds(); - - private: - virtual void do_write(); - - bool hasAnimation(Object *ob) const; -}; - -#endif /* __ABC_WRITER_TRANSFORM_H__ */ diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index a30b15fee5f..5932791ecf4 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -30,13 +30,6 @@ #include "abc_reader_points.h" #include "abc_reader_transform.h" #include "abc_util.h" -#include "abc_writer_camera.h" -#include "abc_writer_curves.h" -#include "abc_writer_hair.h" -#include "abc_writer_mesh.h" -#include "abc_writer_nurbs.h" -#include "abc_writer_points.h" -#include "abc_writer_transform.h" #include "MEM_guardedalloc.h" @@ -58,12 +51,15 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "ED_undo.h" + /* SpaceType struct has a member called 'new' which obviously conflicts with C++ * so temporarily redefining the new keyword to make it compile. */ #define new extern_new #include "BKE_screen.h" #undef new +#include "BLI_compiler_compat.h" #include "BLI_fileops.h" #include "BLI_ghash.h" #include "BLI_listbase.h" @@ -74,48 +70,33 @@ #include "WM_api.h" #include "WM_types.h" -using Alembic::Abc::Int32ArraySamplePtr; using Alembic::Abc::ObjectHeader; - -using Alembic::AbcGeom::kWrapExisting; -using Alembic::AbcGeom::MetaData; -using Alembic::AbcGeom::P3fArraySamplePtr; - using Alembic::AbcGeom::ICamera; -using Alembic::AbcGeom::ICompoundProperty; using Alembic::AbcGeom::ICurves; -using Alembic::AbcGeom::ICurvesSchema; using Alembic::AbcGeom::IFaceSet; using Alembic::AbcGeom::ILight; -using Alembic::AbcGeom::IN3fArrayProperty; -using Alembic::AbcGeom::IN3fGeomParam; using Alembic::AbcGeom::INuPatch; using Alembic::AbcGeom::IObject; using Alembic::AbcGeom::IPoints; -using Alembic::AbcGeom::IPointsSchema; using Alembic::AbcGeom::IPolyMesh; -using Alembic::AbcGeom::IPolyMeshSchema; using Alembic::AbcGeom::ISampleSelector; using Alembic::AbcGeom::ISubD; -using Alembic::AbcGeom::IV2fGeomParam; using Alembic::AbcGeom::IXform; -using Alembic::AbcGeom::IXformSchema; -using Alembic::AbcGeom::N3fArraySamplePtr; -using Alembic::AbcGeom::V3fArraySamplePtr; -using Alembic::AbcGeom::XformSample; - +using Alembic::AbcGeom::MetaData; using Alembic::AbcMaterial::IMaterial; +using namespace blender::io::alembic; + struct AbcArchiveHandle { int unused; }; -ABC_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle) +BLI_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle) { return reinterpret_cast<ArchiveReader *>(handle); } -ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive) +BLI_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive) { return reinterpret_cast<AbcArchiveHandle *>(archive); } @@ -225,195 +206,6 @@ static void find_iobject(const IObject &object, IObject &ret, const std::string ret = tmp; } -struct ExportJobData { - ViewLayer *view_layer; - Main *bmain; - wmWindowManager *wm; - - char filename[1024]; - ExportSettings settings; - - short *stop; - short *do_update; - float *progress; - - bool was_canceled; - bool export_ok; -}; - -static void export_startjob(void *customdata, short *stop, short *do_update, float *progress) -{ - ExportJobData *data = static_cast<ExportJobData *>(customdata); - - data->stop = stop; - data->do_update = do_update; - data->progress = progress; - - /* XXX annoying hack: needed to prevent data corruption when changing - * scene frame in separate threads - */ - G.is_rendering = true; - WM_set_locked_interface(data->wm, true); - G.is_break = false; - - DEG_graph_build_from_view_layer( - data->settings.depsgraph, data->bmain, data->settings.scene, data->view_layer); - BKE_scene_graph_update_tagged(data->settings.depsgraph, data->bmain); - - try { - AbcExporter exporter(data->bmain, data->filename, data->settings); - - Scene *scene = data->settings.scene; /* for the CFRA macro */ - const int orig_frame = CFRA; - - data->was_canceled = false; - exporter(do_update, progress, &data->was_canceled); - - if (CFRA != orig_frame) { - CFRA = orig_frame; - - BKE_scene_graph_update_for_newframe(data->settings.depsgraph, data->bmain); - } - - data->export_ok = !data->was_canceled; - } - catch (const std::exception &e) { - ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n'; - } - catch (...) { - ABC_LOG(data->settings.logger) << "Abc Export: unknown error...\n"; - } -} - -static void export_endjob(void *customdata) -{ - ExportJobData *data = static_cast<ExportJobData *>(customdata); - - DEG_graph_free(data->settings.depsgraph); - - if (data->was_canceled && BLI_exists(data->filename)) { - BLI_delete(data->filename, false, false); - } - - std::string log = data->settings.logger.str(); - if (!log.empty()) { - std::cerr << log; - WM_report(RPT_ERROR, "Errors occurred during the export, look in the console to know more..."); - } - - G.is_rendering = false; - WM_set_locked_interface(data->wm, false); -} - -bool ABC_export(Scene *scene, - bContext *C, - const char *filepath, - const struct AlembicExportParams *params, - bool as_background_job) -{ - ExportJobData *job = static_cast<ExportJobData *>( - MEM_mallocN(sizeof(ExportJobData), "ExportJobData")); - - job->view_layer = CTX_data_view_layer(C); - job->bmain = CTX_data_main(C); - job->wm = CTX_wm_manager(C); - job->export_ok = false; - BLI_strncpy(job->filename, filepath, 1024); - - /* Alright, alright, alright.... - * - * ExportJobData contains an ExportSettings containing a SimpleLogger. - * - * Since ExportJobData is a C-style struct dynamically allocated with - * MEM_mallocN (see above), its constructor is never called, therefore the - * ExportSettings constructor is not called which implies that the - * SimpleLogger one is not called either. SimpleLogger in turn does not call - * the constructor of its data members which ultimately means that its - * std::ostringstream member has a NULL pointer. To be able to properly use - * the stream's operator<<, the pointer needs to be set, therefore we have - * to properly construct everything. And this is done using the placement - * new operator as here below. It seems hackish, but I'm too lazy to - * do bigger refactor and maybe there is a better way which does not involve - * hardcore refactoring. */ - new (&job->settings) ExportSettings(); - job->settings.scene = scene; - job->settings.depsgraph = DEG_graph_new(job->bmain, scene, job->view_layer, DAG_EVAL_RENDER); - - /* TODO(Sybren): for now we only export the active scene layer. - * Later in the 2.8 development process this may be replaced by using - * a specific collection for Alembic I/O, which can then be toggled - * between "real" objects and cached Alembic files. */ - job->settings.view_layer = job->view_layer; - - job->settings.frame_start = params->frame_start; - job->settings.frame_end = params->frame_end; - job->settings.frame_samples_xform = params->frame_samples_xform; - job->settings.frame_samples_shape = params->frame_samples_shape; - job->settings.shutter_open = params->shutter_open; - job->settings.shutter_close = params->shutter_close; - - /* TODO(Sybren): For now this is ignored, until we can get selection - * detection working through Base pointers (instead of ob->flags). */ - job->settings.selected_only = params->selected_only; - - job->settings.export_face_sets = params->face_sets; - job->settings.export_normals = params->normals; - job->settings.export_uvs = params->uvs; - job->settings.export_vcols = params->vcolors; - job->settings.export_hair = params->export_hair; - job->settings.export_particles = params->export_particles; - job->settings.apply_subdiv = params->apply_subdiv; - job->settings.curves_as_mesh = params->curves_as_mesh; - job->settings.flatten_hierarchy = params->flatten_hierarchy; - - /* TODO(Sybren): visible_layer & renderable only is ignored for now, - * to be replaced with collections later in the 2.8 dev process - * (also see note above). */ - job->settings.visible_objects_only = params->visible_objects_only; - job->settings.renderable_only = params->renderable_only; - - job->settings.use_subdiv_schema = params->use_subdiv_schema; - job->settings.pack_uv = params->packuv; - job->settings.global_scale = params->global_scale; - job->settings.triangulate = params->triangulate; - job->settings.quad_method = params->quad_method; - job->settings.ngon_method = params->ngon_method; - - if (job->settings.frame_start > job->settings.frame_end) { - std::swap(job->settings.frame_start, job->settings.frame_end); - } - - bool export_ok = false; - if (as_background_job) { - wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), - CTX_wm_window(C), - job->settings.scene, - "Alembic Export", - WM_JOB_PROGRESS, - WM_JOB_TYPE_ALEMBIC); - - /* setup job */ - WM_jobs_customdata_set(wm_job, job, MEM_freeN); - WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob); - - WM_jobs_start(CTX_wm_manager(C), wm_job); - } - else { - /* Fake a job context, so that we don't need NULL pointer checks while exporting. */ - short stop = 0, do_update = 0; - float progress = 0.f; - - export_startjob(job, &stop, &do_update, &progress); - export_endjob(job); - export_ok = job->export_ok; - - MEM_freeN(job); - } - - return export_ok; -} - /* ********************** Import file ********************** */ /** @@ -622,6 +414,7 @@ enum { }; struct ImportJobData { + bContext *C; Main *bmain; Scene *scene; ViewLayer *view_layer; @@ -640,6 +433,7 @@ struct ImportJobData { char error_code; bool was_cancelled; bool import_ok; + bool is_background_job; }; static void import_startjob(void *user_data, short *stop, short *do_update, float *progress) @@ -823,6 +617,12 @@ static void import_endjob(void *user_data) DEG_id_tag_update(&data->scene->id, ID_RECALC_BASE_FLAGS); DEG_relations_tag_update(data->bmain); + + if (data->is_background_job) { + /* Blender already returned from the import operator, so we need to store our own extra undo + * step. */ + ED_undo_push(data->C, "Alembic Import Finished"); + } } for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { @@ -868,6 +668,7 @@ bool ABC_import(bContext *C, { /* Using new here since MEM_* functions do not call constructor to properly initialize data. */ ImportJobData *job = new ImportJobData(); + job->C = C; job->bmain = CTX_data_main(C); job->scene = CTX_data_scene(C); job->view_layer = CTX_data_view_layer(C); @@ -884,6 +685,7 @@ bool ABC_import(bContext *C, job->error_code = ABC_NO_ERROR; job->was_cancelled = false; job->archive = NULL; + job->is_background_job = as_background_job; G.is_break = false; diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index edac84e2aaa..1de86425521 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -344,9 +344,11 @@ bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *ani return true; } -/* \todo refactor read_node_transform to not automatically apply anything, +/** + * \todo refactor read_node_transform to not automatically apply anything, * but rather return the transform matrix, so caller can do with it what is - * necessary. Same for \ref get_node_mat */ + * necessary. Same for \ref get_node_mat + */ void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob) { float mat[4][4]; diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp index ec9977c1469..e8765fa2bcd 100644 --- a/source/blender/io/collada/BCMath.cpp +++ b/source/blender/io/collada/BCMath.cpp @@ -17,6 +17,8 @@ * All rights reserved. */ +#include "BLI_utildefines.h" + #include "BCMath.h" #include "BlenderContext.h" diff --git a/source/blender/io/collada/ImageExporter.cpp b/source/blender/io/collada/ImageExporter.cpp index 1c897e37a4a..51d753db03f 100644 --- a/source/blender/io/collada/ImageExporter.cpp +++ b/source/blender/io/collada/ImageExporter.cpp @@ -55,7 +55,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) ImBuf *imbuf = BKE_image_acquire_ibuf(image, NULL, NULL); if (!imbuf) { - fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name); + fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->filepath); return; } @@ -104,7 +104,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) else { /* make absolute source path */ - BLI_strncpy(source_path, image->name, sizeof(source_path)); + BLI_strncpy(source_path, image->filepath, sizeof(source_path)); BLI_path_abs(source_path, ID_BLEND_PATH_FROM_GLOBAL(&image->id)); BLI_path_normalize(NULL, source_path); diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt new file mode 100644 index 00000000000..4ed6f12762e --- /dev/null +++ b/source/blender/io/common/CMakeLists.txt @@ -0,0 +1,45 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2020, Blender Foundation +# All rights reserved. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../../blenkernel + ../../blenlib + ../../depsgraph + ../../makesdna +) + +set(INC_SYS +) + +set(SRC + intern/abstract_hierarchy_iterator.cc + + IO_abstract_hierarchy_iterator.h +) + +set(LIB + bf_blenkernel + bf_blenlib +) + +blender_add_lib(bf_io_common "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +target_link_libraries(bf_io_common INTERFACE) diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h index e31d5c91252..5f84fd48b71 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h +++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h @@ -48,7 +48,8 @@ struct Object; struct ParticleSystem; struct ViewLayer; -namespace USD { +namespace blender { +namespace io { class AbstractHierarchyWriter; @@ -90,6 +91,14 @@ struct HierarchyContext { * exported objects, in which case this string is empty even though 'duplicator' is set. */ std::string original_export_path; + /* Export path of the higher-up exported data. For transforms, this is the export path of the + * parent object. For object data, this is the export path of that object's transform. + * + * From the exported file's point of view, this is the path to the parent in that file. The term + * "parent" is not used here to avoid confusion with Blender's meaning of the word (which always + * refers to a different object). */ + std::string higher_up_export_path; + bool operator<(const HierarchyContext &other) const; /* Return a HierarchyContext representing the root of the export hierarchy. */ @@ -119,6 +128,39 @@ class AbstractHierarchyWriter { virtual bool check_is_animated(const HierarchyContext &context) const; }; +/* Determines which subset of the writers actually gets to write. */ +struct ExportSubset { + bool transforms : 1; + bool shapes : 1; +}; + +/* EnsuredWriter represents an AbstractHierarchyWriter* combined with information whether it was + * newly created or not. It's returned by AbstractHierarchyIterator::ensure_writer(). */ +class EnsuredWriter { + private: + AbstractHierarchyWriter *writer_; + + /* Is set to truth when ensure_writer() did not find existing writer and created a new one. + * Is set to false when writer has been re-used or when allocation of the new one has failed + * (`writer` will be `nullptr` in that case and bool(ensured_writer) will be false). */ + bool newly_created_; + + EnsuredWriter(AbstractHierarchyWriter *writer, bool newly_created); + + public: + EnsuredWriter(); + + static EnsuredWriter empty(); + static EnsuredWriter existing(AbstractHierarchyWriter *writer); + static EnsuredWriter newly_created(AbstractHierarchyWriter *writer); + + bool is_newly_created() const; + + /* These operators make an EnsuredWriter* act as an AbstractHierarchyWriter* */ + operator bool() const; + AbstractHierarchyWriter *operator->(); +}; + /* AbstractHierarchyIterator iterates over objects in a dependency graph, and constructs export * writers. These writers are then called to perform the actual writing to a USD or Alembic file. * @@ -147,6 +189,7 @@ class AbstractHierarchyIterator { ExportPathMap duplisource_export_path_; Depsgraph *depsgraph_; WriterMap writers_; + ExportSubset export_subset_; public: explicit AbstractHierarchyIterator(Depsgraph *depsgraph); @@ -154,12 +197,21 @@ class AbstractHierarchyIterator { /* Iterate over the depsgraph, create writers, and tell the writers to write. * Main entry point for the AbstractHierarchyIterator, must be called for every to-be-exported - * frame. */ - void iterate_and_write(); + * (sub)frame. */ + virtual void iterate_and_write(); /* Release all writers. Call after all frames have been exported. */ void release_writers(); + /* Determine which subset of writers is used for exporting. + * Set this before calling iterate_and_write(). + * + * Note that writers are created for each iterated object, regardless of this option. When a + * writer is created it will also write the current iteration, to ensure the hierarchy is + * complete. The `export_subset` option is only in effect when the writer already existed from a + * previous iteration. */ + void set_export_subset(ExportSubset export_subset_); + /* Convert the given name to something that is valid for the exported file format. * This base implementation is a no-op; override in a concrete subclass. */ virtual std::string make_valid_name(const std::string &name) const; @@ -187,7 +239,6 @@ class AbstractHierarchyIterator { Object *duplicator, const std::set<Object *> &dupli_set); - ExportChildren &graph_children(const HierarchyContext *parent_context); void context_update_for_graph_index(HierarchyContext *context, const ExportGraph::key_type &graph_index) const; @@ -200,18 +251,21 @@ class AbstractHierarchyIterator { void make_writer_object_data(const HierarchyContext *context); void make_writers_particle_systems(const HierarchyContext *context); + /* Return the appropriate HierarchyContext for the data of the object represented by + * object_context. */ + HierarchyContext context_for_object_data(const HierarchyContext *object_context) const; + /* Convenience wrappers around get_id_name(). */ std::string get_object_name(const Object *object) const; std::string get_object_data_name(const Object *object) const; - AbstractHierarchyWriter *get_writer(const std::string &export_path) const; - typedef AbstractHierarchyWriter *(AbstractHierarchyIterator::*create_writer_func)( const HierarchyContext *); - /* Ensure that a writer exists; if it doesn't, call create_func(context). The create_func - * function should be one of the create_XXXX_writer(context) functions declared below. */ - AbstractHierarchyWriter *ensure_writer(HierarchyContext *context, - create_writer_func create_func); + /* Ensure that a writer exists; if it doesn't, call create_func(context). + * + * The create_func function should be one of the create_XXXX_writer(context) functions declared + * below. */ + EnsuredWriter ensure_writer(HierarchyContext *context, create_writer_func create_func); protected: /* Construct a valid path for the export file format. This class concatenates by using '/' as a @@ -256,8 +310,12 @@ class AbstractHierarchyIterator { /* Called by release_writers() to free what the create_XXX_writer() functions allocated. */ virtual void delete_object_writer(AbstractHierarchyWriter *writer) = 0; + + AbstractHierarchyWriter *get_writer(const std::string &export_path) const; + ExportChildren &graph_children(const HierarchyContext *parent_context); }; -} // namespace USD +} // namespace io +} // namespace blender #endif /* __ABSTRACT_HIERARCHY_ITERATOR_H__ */ diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc index ab83ea2c3c4..9a456bfaf69 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc @@ -16,7 +16,7 @@ * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. */ -#include "abstract_hierarchy_iterator.h" +#include "IO_abstract_hierarchy_iterator.h" #include <iostream> #include <limits.h> @@ -41,7 +41,8 @@ #include "DEG_depsgraph_query.h" -namespace USD { +namespace blender { +namespace io { const HierarchyContext *HierarchyContext::root() { @@ -74,6 +75,43 @@ void HierarchyContext::mark_as_not_instanced() original_export_path.clear(); } +EnsuredWriter::EnsuredWriter() : writer_(nullptr), newly_created_(false) +{ +} + +EnsuredWriter::EnsuredWriter(AbstractHierarchyWriter *writer, bool newly_created) + : writer_(writer), newly_created_(newly_created) +{ +} + +EnsuredWriter EnsuredWriter::empty() +{ + return EnsuredWriter(nullptr, false); +} +EnsuredWriter EnsuredWriter::existing(AbstractHierarchyWriter *writer) +{ + return EnsuredWriter(writer, false); +} +EnsuredWriter EnsuredWriter::newly_created(AbstractHierarchyWriter *writer) +{ + return EnsuredWriter(writer, true); +} + +bool EnsuredWriter::is_newly_created() const +{ + return newly_created_; +} + +EnsuredWriter::operator bool() const +{ + return writer_ != nullptr; +} + +AbstractHierarchyWriter *EnsuredWriter::operator->() +{ + return writer_; +} + AbstractHierarchyWriter::~AbstractHierarchyWriter() { } @@ -104,7 +142,7 @@ bool AbstractHierarchyWriter::check_is_animated(const HierarchyContext &context) } AbstractHierarchyIterator::AbstractHierarchyIterator(Depsgraph *depsgraph) - : depsgraph_(depsgraph), writers_() + : depsgraph_(depsgraph), writers_(), export_subset_({true, true}) { } @@ -131,6 +169,11 @@ void AbstractHierarchyIterator::release_writers() writers_.clear(); } +void AbstractHierarchyIterator::set_export_subset(ExportSubset export_subset) +{ + export_subset_ = export_subset; +} + std::string AbstractHierarchyIterator::make_valid_name(const std::string &name) const { return name; @@ -341,6 +384,8 @@ void AbstractHierarchyIterator::visit_object(Object *object, context->animation_check_include_parent = false; context->export_path = ""; context->original_export_path = ""; + context->higher_up_export_path = ""; + copy_m4_m4(context->matrix_world, object->obmat); ExportGraph::key_type graph_index = determine_graph_index_object(context); @@ -494,7 +539,6 @@ void AbstractHierarchyIterator::determine_duplication_references( void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_context) { - AbstractHierarchyWriter *transform_writer = nullptr; float parent_matrix_inv_world[4][4]; if (parent_context) { @@ -507,20 +551,27 @@ void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_cont for (HierarchyContext *context : graph_children(parent_context)) { // Update the context so that it is correct for this parent-child relation. copy_m4_m4(context->parent_matrix_inv_world, parent_matrix_inv_world); + if (parent_context != nullptr) { + context->higher_up_export_path = parent_context->export_path; + } // Get or create the transform writer. - transform_writer = ensure_writer(context, &AbstractHierarchyIterator::create_transform_writer); - if (transform_writer == nullptr) { + EnsuredWriter transform_writer = ensure_writer( + context, &AbstractHierarchyIterator::create_transform_writer); + + if (!transform_writer) { // Unable to export, so there is nothing to attach any children to; just abort this entire // branch of the export hierarchy. return; } BLI_assert(DEG_is_evaluated_object(context->object)); - /* XXX This can lead to too many XForms being written. For example, a camera writer can refuse - * to write an orthographic camera. By the time that this is known, the XForm has already been - * written. */ - transform_writer->write(*context); + if (transform_writer.is_newly_created() || export_subset_.transforms) { + /* XXX This can lead to too many XForms being written. For example, a camera writer can + * refuse to write an orthographic camera. By the time that this is known, the XForm has + * already been written. */ + transform_writer->write(*context); + } if (!context->weak_export) { make_writers_particle_systems(context); @@ -534,17 +585,24 @@ void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_cont // TODO(Sybren): iterate over all unused writers and call unused_during_iteration() or something. } +HierarchyContext AbstractHierarchyIterator::context_for_object_data( + const HierarchyContext *object_context) const +{ + HierarchyContext data_context = *object_context; + data_context.higher_up_export_path = object_context->export_path; + data_context.export_name = get_object_data_name(data_context.object); + data_context.export_path = path_concatenate(data_context.higher_up_export_path, + data_context.export_name); + return data_context; +} + void AbstractHierarchyIterator::make_writer_object_data(const HierarchyContext *context) { if (context->object->data == nullptr) { return; } - HierarchyContext data_context = *context; - data_context.export_path = get_object_data_path(context); - - /* data_context.original_export_path is just a copy from the context. It points to the object, - * but needs to point to the object data. */ + HierarchyContext data_context = context_for_object_data(context); if (data_context.is_instance()) { ID *object_data = static_cast<ID *>(context->object->data); data_context.original_export_path = duplisource_export_path_[object_data]; @@ -553,13 +611,16 @@ void AbstractHierarchyIterator::make_writer_object_data(const HierarchyContext * BLI_assert(data_context.is_instance()); } - AbstractHierarchyWriter *data_writer; - data_writer = ensure_writer(&data_context, &AbstractHierarchyIterator::create_data_writer); - if (data_writer == nullptr) { + /* Always write upon creation, otherwise depend on which subset is active. */ + EnsuredWriter data_writer = ensure_writer(&data_context, + &AbstractHierarchyIterator::create_data_writer); + if (!data_writer) { return; } - data_writer->write(data_context); + if (data_writer.is_newly_created() || export_subset_.shapes) { + data_writer->write(data_context); + } } void AbstractHierarchyIterator::make_writers_particle_systems( @@ -573,11 +634,13 @@ void AbstractHierarchyIterator::make_writers_particle_systems( } HierarchyContext hair_context = *transform_context; + hair_context.export_name = make_valid_name(psys->name); hair_context.export_path = path_concatenate(transform_context->export_path, - make_valid_name(psys->name)); + hair_context.export_name); + hair_context.higher_up_export_path = transform_context->export_path; hair_context.particle_system = psys; - AbstractHierarchyWriter *writer = nullptr; + EnsuredWriter writer; switch (psys->part->type) { case PART_HAIR: writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_hair_writer); @@ -586,8 +649,12 @@ void AbstractHierarchyIterator::make_writers_particle_systems( writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_particle_writer); break; } + if (!writer) { + continue; + } - if (writer != nullptr) { + /* Always write upon creation, otherwise depend on which subset is active. */ + if (writer.is_newly_created() || export_subset_.shapes) { writer->write(hair_context); } } @@ -615,22 +682,21 @@ AbstractHierarchyWriter *AbstractHierarchyIterator::get_writer( return it->second; } -AbstractHierarchyWriter *AbstractHierarchyIterator::ensure_writer( +EnsuredWriter AbstractHierarchyIterator::ensure_writer( HierarchyContext *context, AbstractHierarchyIterator::create_writer_func create_func) { AbstractHierarchyWriter *writer = get_writer(context->export_path); if (writer != nullptr) { - return writer; + return EnsuredWriter::existing(writer); } writer = (this->*create_func)(context); if (writer == nullptr) { - return nullptr; + return EnsuredWriter::empty(); } writers_[context->export_path] = writer; - - return writer; + return EnsuredWriter::newly_created(writer); } std::string AbstractHierarchyIterator::path_concatenate(const std::string &parent_path, @@ -649,4 +715,5 @@ bool AbstractHierarchyIterator::should_visit_dupli_object(const DupliObject *dup return !dupli_object->no_draw; } -} // namespace USD +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index 732a638a255..19e16a5b328 100644 --- a/source/blender/io/usd/CMakeLists.txt +++ b/source/blender/io/usd/CMakeLists.txt @@ -32,6 +32,7 @@ add_definitions(-DPXR_STATIC) set(INC . + ../common ../../blenkernel ../../blenlib ../../blenloader @@ -52,7 +53,6 @@ set(INC_SYS ) set(SRC - intern/abstract_hierarchy_iterator.cc intern/usd_capi.cc intern/usd_hierarchy_iterator.cc intern/usd_writer_abstract.cc @@ -64,7 +64,6 @@ set(SRC intern/usd_writer_transform.cc usd.h - intern/abstract_hierarchy_iterator.h intern/usd_exporter_context.h intern/usd_hierarchy_iterator.h intern/usd_writer_abstract.h @@ -79,6 +78,7 @@ set(SRC set(LIB bf_blenkernel bf_blenlib + bf_io_common ) list(APPEND LIB @@ -100,10 +100,10 @@ endif() # Source: https://github.com/PixarAnimationStudios/USD/blob/master/BUILDING.md#linking-whole-archives if(WIN32) target_link_libraries(bf_usd INTERFACE ${USD_LIBRARIES}) -elseif(CMAKE_COMPILER_IS_GNUCXX) - target_link_libraries(bf_usd INTERFACE "-Wl,--whole-archive ${USD_LIBRARIES} -Wl,--no-whole-archive ${TBB_LIBRARIES}") -elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") +elseif(APPLE) target_link_libraries(bf_usd INTERFACE -Wl,-force_load ${USD_LIBRARIES}) +elseif(UNIX) + target_link_libraries(bf_usd INTERFACE "-Wl,--whole-archive ${USD_LIBRARIES} -Wl,--no-whole-archive ${TBB_LIBRARIES}") else() message(FATAL_ERROR "Unknown how to link USD with your compiler ${CMAKE_CXX_COMPILER_ID}") endif() diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc index cf962446d04..2d3972410a4 100644 --- a/source/blender/io/usd/intern/usd_capi.cc +++ b/source/blender/io/usd/intern/usd_capi.cc @@ -44,7 +44,9 @@ #include "WM_api.h" #include "WM_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { struct ExportJobData { Main *bmain; @@ -157,7 +159,9 @@ static void export_endjob(void *customdata) WM_set_locked_interface(data->wm, false); } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender bool USD_export(bContext *C, const char *filepath, @@ -167,8 +171,8 @@ bool USD_export(bContext *C, ViewLayer *view_layer = CTX_data_view_layer(C); Scene *scene = CTX_data_scene(C); - USD::ExportJobData *job = static_cast<USD::ExportJobData *>( - MEM_mallocN(sizeof(USD::ExportJobData), "ExportJobData")); + blender::io::usd::ExportJobData *job = static_cast<blender::io::usd::ExportJobData *>( + MEM_mallocN(sizeof(blender::io::usd::ExportJobData), "ExportJobData")); job->bmain = CTX_data_main(C); job->wm = CTX_wm_manager(C); @@ -186,7 +190,11 @@ bool USD_export(bContext *C, /* setup job */ WM_jobs_customdata_set(wm_job, job, MEM_freeN); WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, USD::export_startjob, nullptr, nullptr, USD::export_endjob); + WM_jobs_callbacks(wm_job, + blender::io::usd::export_startjob, + nullptr, + nullptr, + blender::io::usd::export_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); } @@ -195,8 +203,8 @@ bool USD_export(bContext *C, short stop = 0, do_update = 0; float progress = 0.f; - USD::export_startjob(job, &stop, &do_update, &progress); - USD::export_endjob(job); + blender::io::usd::export_startjob(job, &stop, &do_update, &progress); + blender::io::usd::export_endjob(job); export_ok = job->export_ok; MEM_freeN(job); diff --git a/source/blender/io/usd/intern/usd_exporter_context.h b/source/blender/io/usd/intern/usd_exporter_context.h index 4ae415b3d34..07a9d0fc0c5 100644 --- a/source/blender/io/usd/intern/usd_exporter_context.h +++ b/source/blender/io/usd/intern/usd_exporter_context.h @@ -27,7 +27,9 @@ struct Depsgraph; struct Object; -namespace USD { +namespace blender { +namespace io { +namespace usd { class USDHierarchyIterator; @@ -39,6 +41,8 @@ struct USDExporterContext { const USDExportParams &export_params; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_EXPORTER_CONTEXT_H__ */ diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc index 56e367dd877..388b588b331 100644 --- a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc +++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc @@ -41,7 +41,9 @@ #include "DNA_layer_types.h" #include "DNA_object_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDHierarchyIterator::USDHierarchyIterator(Depsgraph *depsgraph, pxr::UsdStageRefPtr stage, @@ -145,4 +147,6 @@ AbstractHierarchyWriter *USDHierarchyIterator::create_particle_writer(const Hier return nullptr; } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.h b/source/blender/io/usd/intern/usd_hierarchy_iterator.h index a608012a390..7d750bff0cb 100644 --- a/source/blender/io/usd/intern/usd_hierarchy_iterator.h +++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.h @@ -19,7 +19,7 @@ #ifndef __USD_HIERARCHY_ITERATOR_H__ #define __USD_HIERARCHY_ITERATOR_H__ -#include "abstract_hierarchy_iterator.h" +#include "IO_abstract_hierarchy_iterator.h" #include "usd.h" #include "usd_exporter_context.h" @@ -32,7 +32,13 @@ struct Depsgraph; struct ID; struct Object; -namespace USD { +namespace blender { +namespace io { +namespace usd { + +using blender::io::AbstractHierarchyIterator; +using blender::io::AbstractHierarchyWriter; +using blender::io::HierarchyContext; class USDHierarchyIterator : public AbstractHierarchyIterator { private: @@ -66,6 +72,8 @@ class USDHierarchyIterator : public AbstractHierarchyIterator { USDExporterContext create_usd_export_context(const HierarchyContext *context); }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_HIERARCHY_ITERATOR_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_abstract.cc b/source/blender/io/usd/intern/usd_writer_abstract.cc index 76a2436ee92..a416941fb4d 100644 --- a/source/blender/io/usd/intern/usd_writer_abstract.cc +++ b/source/blender/io/usd/intern/usd_writer_abstract.cc @@ -32,7 +32,9 @@ static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal); static const pxr::TfToken surface("surface", pxr::TfToken::Immortal); } // namespace usdtokens -namespace USD { +namespace blender { +namespace io { +namespace usd { USDAbstractWriter::USDAbstractWriter(const USDExporterContext &usd_export_context) : usd_export_context_(usd_export_context), @@ -112,4 +114,6 @@ pxr::UsdShadeMaterial USDAbstractWriter::ensure_usd_material(Material *material) return usd_material; } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h index 01b53f4c916..f81cf5197af 100644 --- a/source/blender/io/usd/intern/usd_writer_abstract.h +++ b/source/blender/io/usd/intern/usd_writer_abstract.h @@ -19,7 +19,7 @@ #ifndef __USD_WRITER_ABSTRACT_H__ #define __USD_WRITER_ABSTRACT_H__ -#include "abstract_hierarchy_iterator.h" +#include "IO_abstract_hierarchy_iterator.h" #include "usd_exporter_context.h" #include <pxr/usd/sdf/path.h> @@ -36,7 +36,12 @@ struct Material; struct Object; -namespace USD { +namespace blender { +namespace io { +namespace usd { + +using blender::io::AbstractHierarchyWriter; +using blender::io::HierarchyContext; class USDAbstractWriter : public AbstractHierarchyWriter { protected: @@ -70,6 +75,8 @@ class USDAbstractWriter : public AbstractHierarchyWriter { pxr::UsdShadeMaterial ensure_usd_material(Material *material); }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_ABSTRACT_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_camera.cc b/source/blender/io/usd/intern/usd_writer_camera.cc index ea551a43c9f..d51eb32d3fd 100644 --- a/source/blender/io/usd/intern/usd_writer_camera.cc +++ b/source/blender/io/usd/intern/usd_writer_camera.cc @@ -28,7 +28,9 @@ #include "DNA_camera_types.h" #include "DNA_scene_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDCameraWriter::USDCameraWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) { @@ -106,4 +108,6 @@ void USDCameraWriter::do_write(HierarchyContext &context) } } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_camera.h b/source/blender/io/usd/intern/usd_writer_camera.h index 971264ef11e..8b5795d7d9f 100644 --- a/source/blender/io/usd/intern/usd_writer_camera.h +++ b/source/blender/io/usd/intern/usd_writer_camera.h @@ -21,7 +21,9 @@ #include "usd_writer_abstract.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { /* Writer for writing camera data to UsdGeomCamera. */ class USDCameraWriter : public USDAbstractWriter { @@ -33,6 +35,8 @@ class USDCameraWriter : public USDAbstractWriter { virtual void do_write(HierarchyContext &context) override; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_CAMERA_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_hair.cc b/source/blender/io/usd/intern/usd_writer_hair.cc index d38c1032969..0e0256bdb69 100644 --- a/source/blender/io/usd/intern/usd_writer_hair.cc +++ b/source/blender/io/usd/intern/usd_writer_hair.cc @@ -26,7 +26,9 @@ #include "DNA_particle_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDHairWriter::USDHairWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) { @@ -85,4 +87,6 @@ bool USDHairWriter::check_is_animated(const HierarchyContext &) const return true; } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_hair.h b/source/blender/io/usd/intern/usd_writer_hair.h index 1e882fa1654..cecacd0a355 100644 --- a/source/blender/io/usd/intern/usd_writer_hair.h +++ b/source/blender/io/usd/intern/usd_writer_hair.h @@ -21,7 +21,9 @@ #include "usd_writer_abstract.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { /* Writer for writing hair particle data as USD curves. */ class USDHairWriter : public USDAbstractWriter { @@ -33,6 +35,8 @@ class USDHairWriter : public USDAbstractWriter { virtual bool check_is_animated(const HierarchyContext &context) const override; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_HAIR_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_light.cc b/source/blender/io/usd/intern/usd_writer_light.cc index 0ce3ee5f8ce..19115dd1a4e 100644 --- a/source/blender/io/usd/intern/usd_writer_light.cc +++ b/source/blender/io/usd/intern/usd_writer_light.cc @@ -30,7 +30,9 @@ #include "DNA_light_types.h" #include "DNA_object_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDLightWriter::USDLightWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) { @@ -107,4 +109,6 @@ void USDLightWriter::do_write(HierarchyContext &context) usd_light.CreateSpecularAttr().Set(light->spec_fac, timecode); } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_light.h b/source/blender/io/usd/intern/usd_writer_light.h index 349c034b6bc..73666622af1 100644 --- a/source/blender/io/usd/intern/usd_writer_light.h +++ b/source/blender/io/usd/intern/usd_writer_light.h @@ -21,7 +21,9 @@ #include "usd_writer_abstract.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { class USDLightWriter : public USDAbstractWriter { public: @@ -32,6 +34,8 @@ class USDLightWriter : public USDAbstractWriter { virtual void do_write(HierarchyContext &context) override; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_LIGHT_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index 61337beff20..29a9734f876 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -42,7 +42,9 @@ #include "DNA_object_fluidsim_types.h" #include "DNA_particle_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDGenericMeshWriter::USDGenericMeshWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) { @@ -484,4 +486,6 @@ Mesh *USDMeshWriter::get_export_mesh(Object *object_eval, bool & /*r_needsfree*/ return BKE_object_get_evaluated_mesh(object_eval); } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_mesh.h b/source/blender/io/usd/intern/usd_writer_mesh.h index 4175e2b7e27..a14ceecfa53 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.h +++ b/source/blender/io/usd/intern/usd_writer_mesh.h @@ -23,7 +23,9 @@ #include <pxr/usd/usdGeom/mesh.h> -namespace USD { +namespace blender { +namespace io { +namespace usd { struct USDMeshData; @@ -61,6 +63,8 @@ class USDMeshWriter : public USDGenericMeshWriter { virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_MESH_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_metaball.cc b/source/blender/io/usd/intern/usd_writer_metaball.cc index 96bf854d327..f003fba18a4 100644 --- a/source/blender/io/usd/intern/usd_writer_metaball.cc +++ b/source/blender/io/usd/intern/usd_writer_metaball.cc @@ -34,7 +34,9 @@ #include "DNA_mesh_types.h" #include "DNA_meta_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDMetaballWriter::USDMetaballWriter(const USDExporterContext &ctx) : USDGenericMeshWriter(ctx) { @@ -76,4 +78,6 @@ bool USDMetaballWriter::is_basis_ball(Scene *scene, Object *ob) const return ob == basis_ob; } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_metaball.h b/source/blender/io/usd/intern/usd_writer_metaball.h index 1a86daae2ae..9f51a3314a5 100644 --- a/source/blender/io/usd/intern/usd_writer_metaball.h +++ b/source/blender/io/usd/intern/usd_writer_metaball.h @@ -21,7 +21,9 @@ #include "usd_writer_mesh.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { class USDMetaballWriter : public USDGenericMeshWriter { public: @@ -37,6 +39,8 @@ class USDMetaballWriter : public USDGenericMeshWriter { bool is_basis_ball(Scene *scene, Object *ob) const; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_METABALL_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_transform.cc b/source/blender/io/usd/intern/usd_writer_transform.cc index 0694d873002..643f1a8f4b1 100644 --- a/source/blender/io/usd/intern/usd_writer_transform.cc +++ b/source/blender/io/usd/intern/usd_writer_transform.cc @@ -28,7 +28,9 @@ #include "DNA_layer_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDTransformWriter::USDTransformWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) { @@ -59,4 +61,6 @@ bool USDTransformWriter::check_is_animated(const HierarchyContext &context) cons return BKE_object_moves_in_time(context.object, context.animation_check_include_parent); } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_transform.h b/source/blender/io/usd/intern/usd_writer_transform.h index 52c4a657f33..8b4741f1177 100644 --- a/source/blender/io/usd/intern/usd_writer_transform.h +++ b/source/blender/io/usd/intern/usd_writer_transform.h @@ -23,7 +23,9 @@ #include <pxr/usd/usdGeom/xform.h> -namespace USD { +namespace blender { +namespace io { +namespace usd { class USDTransformWriter : public USDAbstractWriter { private: @@ -37,6 +39,8 @@ class USDTransformWriter : public USDAbstractWriter { bool check_is_animated(const HierarchyContext &context) const override; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_TRANSFORM_H__ */ diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index f40fba27958..660f0121699 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -360,16 +360,17 @@ typedef struct Library { ID id; struct FileData *filedata; /** Path name used for reading, can be relative and edited in the outliner. */ - char name[1024]; + char filepath[1024]; /** - * Absolute filepath, this is only for convenience, - * 'name' is the real path used on file read but in - * some cases its useful to access the absolute one. - * This is set on file read. - * Use BKE_library_filepath_set() rather than setting 'name' - * directly and it will be kept in sync - campbell */ - char filepath[1024]; + * Run-time only, absolute file-path (set on read). + * This is only for convenience, `filepath` is the real path + * used on file read but in some cases its useful to access the absolute one. + * + * Use #BKE_library_filepath_set() rather than setting `filepath` + * directly and it will be kept in sync - campbell + */ + char filepath_abs[1024]; /** Set for indirectly linked libs, used in the outliner and while reading. */ struct Library *parent; @@ -506,29 +507,36 @@ typedef enum ID_Type { /* fluidsim Ipo */ #define ID_FLUIDSIM MAKE_ID2('F', 'S') -#define ID_FAKE_USERS(id) ((((ID *)id)->flag & LIB_FAKEUSER) ? 1 : 0) -#define ID_REAL_USERS(id) (((ID *)id)->us - ID_FAKE_USERS(id)) -#define ID_EXTRA_USERS(id) (((ID *)id)->tag & LIB_TAG_EXTRAUSER ? 1 : 0) +#define ID_FAKE_USERS(id) ((((const ID *)id)->flag & LIB_FAKEUSER) ? 1 : 0) +#define ID_REAL_USERS(id) (((const ID *)id)->us - ID_FAKE_USERS(id)) +#define ID_EXTRA_USERS(id) (((const ID *)id)->tag & LIB_TAG_EXTRAUSER ? 1 : 0) #define ID_CHECK_UNDO(id) \ ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM) && (GS((id)->name) != ID_WS)) #define ID_BLEND_PATH(_bmain, _id) \ - ((_id)->lib ? (_id)->lib->filepath : BKE_main_blendfile_path((_bmain))) + ((_id)->lib ? (_id)->lib->filepath_abs : BKE_main_blendfile_path((_bmain))) #define ID_BLEND_PATH_FROM_GLOBAL(_id) \ - ((_id)->lib ? (_id)->lib->filepath : BKE_main_blendfile_path_from_global()) + ((_id)->lib ? (_id)->lib->filepath_abs : BKE_main_blendfile_path_from_global()) -#define ID_MISSING(_id) ((((ID *)(_id))->tag & LIB_TAG_MISSING) != 0) +#define ID_MISSING(_id) ((((const ID *)(_id))->tag & LIB_TAG_MISSING) != 0) -#define ID_IS_LINKED(_id) (((ID *)(_id))->lib != NULL) +#define ID_IS_LINKED(_id) (((const ID *)(_id))->lib != NULL) /* Note that this is a fairly high-level check, should be used at user interaction level, not in * BKE_library_override typically (especially due to the check on LIB_TAG_EXTERN). */ #define ID_IS_OVERRIDABLE_LIBRARY(_id) \ - (ID_IS_LINKED(_id) && !ID_MISSING(_id) && (((ID *)(_id))->tag & LIB_TAG_EXTERN) != 0) + (ID_IS_LINKED(_id) && !ID_MISSING(_id) && (((const ID *)(_id))->tag & LIB_TAG_EXTERN) != 0) + +#define ID_IS_OVERRIDE_LIBRARY_REAL(_id) \ + (((const ID *)(_id))->override_library != NULL && \ + ((const ID *)(_id))->override_library->reference != NULL) + +#define ID_IS_OVERRIDE_LIBRARY_VIRTUAL(_id) \ + ((((const ID *)(_id))->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) != 0) #define ID_IS_OVERRIDE_LIBRARY(_id) \ - (((ID *)(_id))->override_library != NULL && ((ID *)(_id))->override_library->reference != NULL) + (ID_IS_OVERRIDE_LIBRARY_REAL(_id) || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(_id)) #define ID_IS_OVERRIDE_LIBRARY_TEMPLATE(_id) \ (((ID *)(_id))->override_library != NULL && ((ID *)(_id))->override_library->reference == NULL) @@ -566,6 +574,11 @@ enum { * we want to restore if possible, and silently drop if it's missing. */ LIB_INDIRECT_WEAK_LINK = 1 << 11, + /** + * The data-block is a sub-data of another one, which is an override. + * Note that this also applies to shapekeys, even though they are not 100% embedded data... + */ + LIB_EMBEDDED_DATA_LIB_OVERRIDE = 1 << 12, }; /** diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index c95a701a78a..98e858dbf41 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -703,8 +703,9 @@ typedef struct bDopeSheet { /** String to search for in displayed names of F-Curves, or NlaTracks/GP Layers/etc. */ char searchstr[64]; - /** Flags to use for filtering data. */ + /** Flags to use for filtering data #eAnimFilter_Flags. */ int filterflag; + /** #eDopeSheet_FilterFlag2 */ int filterflag2; /** Standard flags. */ int flag; diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h index f315cc4b8a0..2ec4f4ee991 100644 --- a/source/blender/makesdna/DNA_brush_defaults.h +++ b/source/blender/makesdna/DNA_brush_defaults.h @@ -47,6 +47,7 @@ .crease_pinch_factor = 0.5f, \ .normal_radius_factor = 0.5f, \ .area_radius_factor = 0.5f, \ + .disconnected_distance_max = 0.1f, \ .sculpt_plane = SCULPT_DISP_DIR_AREA, \ .cloth_damping = 0.01, \ .cloth_mass = 1, \ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 7490dbe5cdc..4056faf359f 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -439,6 +439,21 @@ typedef struct Brush { float rgb[3]; /** Opacity. */ float alpha; + /** Hardness */ + float hardness; + /** Flow */ + float flow; + /** Wet Mix */ + float wet_mix; + float wet_persistence; + /** Density */ + float density; + + /** Tip Shape */ + /* Factor that controls the shape of the brush tip by rounding the corners of a square. */ + /* 0.0 value produces a square, 1.0 produces a circle. */ + float tip_roundness; + float tip_scale_x; /** Background color. */ float secondary_rgb[3]; @@ -503,16 +518,14 @@ typedef struct Brush { float texture_sample_bias; int curve_preset; - float hardness; + + /* Maximun distance to search fake neighbors from a vertex. */ + float disconnected_distance_max; /* automasking */ int automasking_flags; int automasking_boundary_edges_propagation_steps; - /* Factor that controls the shape of the brush tip by rounding the corners of a square. */ - /* 0.0 value produces a square, 1.0 produces a circle. */ - float tip_roundness; - int elastic_deform_type; float elastic_deform_volume_preservation; @@ -670,6 +683,7 @@ typedef enum eBrushFlags2 { BRUSH_MULTIPLANE_SCRAPE_DYNAMIC = (1 << 0), BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW = (1 << 1), BRUSH_POSE_IK_ANCHORED = (1 << 2), + BRUSH_USE_CONNECTED_ONLY = (1 << 3), } eBrushFlags2; typedef enum { @@ -720,6 +734,8 @@ typedef enum eBrushSculptTool { SCULPT_TOOL_CLAY_THUMB = 25, SCULPT_TOOL_CLOTH = 26, SCULPT_TOOL_DRAW_FACE_SETS = 27, + SCULPT_TOOL_PAINT = 28, + SCULPT_TOOL_SMEAR = 29, } eBrushSculptTool; /* Brush.uv_sculpt_tool */ @@ -762,6 +778,8 @@ typedef enum eBrushUVSculptTool { SCULPT_TOOL_ELASTIC_DEFORM, \ SCULPT_TOOL_POSE, \ SCULPT_TOOL_DRAW_FACE_SETS, \ + SCULPT_TOOL_PAINT, \ + SCULPT_TOOL_SMEAR, \ \ /* These brushes could handle dynamic topology, \ \ * but user feedback indicates it's better not to */ \ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 65087a6d459..85d9a04a902 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -61,7 +61,8 @@ typedef struct bConstraint { /** Constraint name, MAX_NAME. */ char name[64]; - char _pad[2]; + /* Flag for panel and subpanel closed / open state in the UI. */ + short ui_expand_flag; /** Amount of influence exherted by constraint (0.0-1.0). */ float enforce; @@ -689,8 +690,8 @@ typedef enum eBConstraint_Types { /* flag 0x20 (1 << 5) was used to indicate that a constraint was evaluated * using a 'local' hack for posebones only. */ typedef enum eBConstraint_Flags { - /* expand for UI */ - CONSTRAINT_EXPAND = (1 << 0), + /* Expansion for old box constraint layouts. Just for versioning. */ + CONSTRAINT_EXPAND_DEPRECATED = (1 << 0), /* pre-check for illegal object name or bone name */ CONSTRAINT_DISABLE = (1 << 2), /* to indicate which Ipo should be shown, maybe for 3d access later too */ diff --git a/source/blender/makesdna/DNA_curveprofile_types.h b/source/blender/makesdna/DNA_curveprofile_types.h index 63e1049b636..ca00f783905 100644 --- a/source/blender/makesdna/DNA_curveprofile_types.h +++ b/source/blender/makesdna/DNA_curveprofile_types.h @@ -43,13 +43,22 @@ typedef struct CurveProfilePoint { float x, y; /** Flag selection state and others. */ short flag; - /** Flags for both handle's type (eBezTriple_Handle). */ + /** Flags for both handle's type (eBezTriple_Handle auto, vect, free, and aligned supported). */ char h1, h2; + /** Handle locations, keep together. + * \note For now the two handle types are set to the same type in RNA. */ + float h1_loc[2]; + float h2_loc[2]; + char _pad[4]; + /** Runtime pointer to the point's profile for updating the curve with no direct reference. */ + struct CurveProfile *profile; } CurveProfilePoint; /** #CurveProfilePoint.flag */ enum { PROF_SELECT = (1 << 0), + PROF_H1_SELECT = (1 << 1), + PROF_H2_SELECT = (1 << 2), }; /** Defines a profile. */ @@ -76,10 +85,11 @@ typedef struct CurveProfile { /** #CurveProfile.flag */ enum { - PROF_USE_CLIP = (1 << 0), /* Keep control points inside bounding rectangle. */ - /* PROF_SYMMETRY_MODE = (1 << 1), */ /* Unused for now. */ - PROF_SAMPLE_STRAIGHT_EDGES = (1 << 2), /* Sample extra points on straight edges. */ - PROF_SAMPLE_EVEN_LENGTHS = (1 << 3), /* Put segments evenly spaced along the path. */ + PROF_USE_CLIP = (1 << 0), /* Keep control points inside bounding rectangle. */ + /* PROF_SYMMETRY_MODE = (1 << 1), Unused for now. */ + PROF_SAMPLE_STRAIGHT_EDGES = (1 << 2), /* Sample extra points on straight edges. */ + PROF_SAMPLE_EVEN_LENGTHS = (1 << 3), /* Put segments evenly spaced along the path. */ + PROF_DIRTY_PRESET = (1 << 4), /* Marks when the dynamic preset has been changed. */ }; typedef enum eCurveProfilePresets { diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index e4999fd4464..c24bbccae1e 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -148,10 +148,9 @@ typedef enum CustomDataType { CD_CUSTOMLOOPNORMAL = 41, CD_SCULPT_FACE_SETS = 42, - /* Hair and PointCloud */ CD_LOCATION = 43, - CD_RADIUS = 44, CD_HAIRCURVE = 45, + CD_RADIUS = 44, CD_HAIRMAPPING = 46, CD_PROP_COLOR = 47, @@ -205,7 +204,7 @@ typedef enum CustomDataType { #define CD_MASK_TESSLOOPNORMAL (1LL << CD_TESSLOOPNORMAL) #define CD_MASK_CUSTOMLOOPNORMAL (1LL << CD_CUSTOMLOOPNORMAL) #define CD_MASK_SCULPT_FACE_SETS (1LL << CD_SCULPT_FACE_SETS) -#define CD_MASK_PROP_COLOR (1LL << CD_PROP_COLOR) +#define CD_MASK_PROP_COLOR (1ULL << CD_PROP_COLOR) /** Data types that may be defined for all mesh elements types. */ #define CD_MASK_GENERIC_DATA (CD_MASK_PROP_FLOAT | CD_MASK_PROP_INT32 | CD_MASK_PROP_STRING) diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h index e8a22d8c821..e3f4865e894 100644 --- a/source/blender/makesdna/DNA_fluid_types.h +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -45,6 +45,7 @@ enum { FLUID_DOMAIN_USE_FRACTIONS = (1 << 13), /* Use second order obstacles. */ FLUID_DOMAIN_DELETE_IN_OBSTACLE = (1 << 14), /* Delete fluid inside obstacles. */ FLUID_DOMAIN_USE_DIFFUSION = (1 << 15), /* Use diffusion (e.g. viscosity, surface tension). */ + FLUID_DOMAIN_USE_RESUMABLE_CACHE = (1 << 16), /* Determine if cache should be resumable. */ }; /* Border collisions. */ @@ -214,6 +215,7 @@ enum { #define FLUID_DOMAIN_DIR_SCRIPT "script" #define FLUID_DOMAIN_SMOKE_SCRIPT "smoke_script.py" #define FLUID_DOMAIN_LIQUID_SCRIPT "liquid_script.py" +#define FLUID_CACHE_VERSION "C01" /* Cache file names. */ #define FLUID_NAME_CONFIG "config" @@ -224,24 +226,24 @@ enum { #define FLUID_NAME_GUIDING "fluid_guiding" /* Fluid object names.*/ -#define FLUID_NAME_FLAGS "flags" -#define FLUID_NAME_VELOCITY "vel" -#define FLUID_NAME_VELOCITYTMP "velocityTmp" +#define FLUID_NAME_FLAGS "flags" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_VELOCITY "velocity" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_VELOCITYTMP "velocity_previous" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_VELOCITYX "x_vel" #define FLUID_NAME_VELOCITYY "y_vel" #define FLUID_NAME_VELOCITYZ "z_vel" #define FLUID_NAME_PRESSURE "pressure" -#define FLUID_NAME_PHIOBS "phiObs" +#define FLUID_NAME_PHIOBS "phi_obstacle" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_PHISIN "phiSIn" -#define FLUID_NAME_PHIIN "phiIn" -#define FLUID_NAME_PHIOUT "phiOut" +#define FLUID_NAME_PHIIN "phi_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PHIOUT "phi_out" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_FORCES "forces" #define FLUID_NAME_FORCE_X "x_force" #define FLUID_NAME_FORCE_Y "y_force" #define FLUID_NAME_FORCE_Z "z_force" #define FLUID_NAME_NUMOBS "numObs" #define FLUID_NAME_PHIOBSSIN "phiObsSIn" -#define FLUID_NAME_PHIOBSIN "phiObsIn" +#define FLUID_NAME_PHIOBSIN "phi_obstacle_inflow" #define FLUID_NAME_OBVEL "obvel" #define FLUID_NAME_OBVELC "obvelC" #define FLUID_NAME_OBVEL_X "x_obvel" @@ -254,44 +256,48 @@ enum { #define FLUID_NAME_INVEL_Y "y_invel" #define FLUID_NAME_INVEL_Z "z_invel" #define FLUID_NAME_PHIOUTSIN "phiOutSIn" -#define FLUID_NAME_PHIOUTIN "phiOutIn" +#define FLUID_NAME_PHIOUTIN "phi_out_inflow" /* Smoke object names. */ -#define FLUID_NAME_SHADOW "shadow" -#define FLUID_NAME_EMISSION "emission" +#define FLUID_NAME_SHADOW "shadow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_EMISSION "emission" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_EMISSIONIN "emissionIn" -#define FLUID_NAME_DENSITY "density" -#define FLUID_NAME_DENSITYIN "densityIn" +#define FLUID_NAME_DENSITY "density" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_DENSITYIN "density_inflow" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_HEAT "heat" #define FLUID_NAME_HEATIN "heatIn" -#define FLUID_NAME_COLORR "color_r" -#define FLUID_NAME_COLORG "color_g" -#define FLUID_NAME_COLORB "color_b" -#define FLUID_NAME_COLORRIN "color_r_in" -#define FLUID_NAME_COLORGIN "color_g_in" -#define FLUID_NAME_COLORBIN "color_b_in" -#define FLUID_NAME_FLAME "flame" -#define FLUID_NAME_FUEL "fuel" -#define FLUID_NAME_REACT "react" -#define FLUID_NAME_FUELIN "fuelIn" -#define FLUID_NAME_REACTIN "reactIn" +#define FLUID_NAME_TEMPERATURE "temperature" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_TEMPERATUREIN "temperature_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORR "color_r" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORG "color_g" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORB "color_b" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORRIN "color_r_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORGIN "color_g_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORBIN "color_b_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FLAME "flame" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FUEL "fuel" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_REACT "react" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FUELIN "fuel_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_REACTIN "react_inflow" /* == OpenVDB grid attribute name. */ /* Liquid object names. */ -#define FLUID_NAME_PHIPARTS "phiParts" -#define FLUID_NAME_PHI "phi" -#define FLUID_NAME_PHITMP "phiTmp" +#define FLUID_NAME_PHIPARTS "phi_particles" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PHI "phi" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PHITMP "phi_previous" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_VELOCITYOLD "velOld" #define FLUID_NAME_VELOCITYPARTS "velParts" #define FLUID_NAME_MAPWEIGHTS "mapWeights" #define FLUID_NAME_PP "pp" #define FLUID_NAME_PVEL "pVel" +#define FLUID_NAME_PARTS "particles" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PARTSVELOCITY "particles_velocity" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_PINDEX "pindex" #define FLUID_NAME_GPI "gpi" #define FLUID_NAME_CURVATURE "gpi" /* Noise object names. */ #define FLUID_NAME_VELOCITY_NOISE "velocity_noise" -#define FLUID_NAME_DENSITY_NOISE "density_noise" +#define FLUID_NAME_DENSITY_NOISE "density_noise" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_PHIIN_NOISE "phiIn_noise" #define FLUID_NAME_PHIOUT_NOISE "phiOut_noise" #define FLUID_NAME_PHIOBS_NOISE "phiObs_noise" @@ -306,11 +312,11 @@ enum { #define FLUID_NAME_TEXTURE_U2 "textureU2" #define FLUID_NAME_TEXTURE_V2 "textureV2" #define FLUID_NAME_TEXTURE_W2 "textureW2" -#define FLUID_NAME_UV0 "uvGrid0" -#define FLUID_NAME_UV1 "uvGrid1" -#define FLUID_NAME_COLORR_NOISE "color_r_noise" -#define FLUID_NAME_COLORG_NOISE "color_g_noise" -#define FLUID_NAME_COLORB_NOISE "color_b_noise" +#define FLUID_NAME_UV0 "uv_grid_0" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_UV1 "uv_grid_1" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORR_NOISE "color_r_noise" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORG_NOISE "color_g_noise" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORB_NOISE "color_b_noise" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_FLAME_NOISE "flame_noise" #define FLUID_NAME_FUEL_NOISE "fuel_noise" #define FLUID_NAME_REACT_NOISE "react_noise" @@ -321,7 +327,8 @@ enum { #define FLUID_NAME_PP_MESH "pp_mesh" #define FLUID_NAME_FLAGS_MESH "flags_mesh" #define FLUID_NAME_LMESH "lMesh" -#define FLUID_NAME_VELOCITYVEC_MESH "lVelMesh" +/* == OpenVDB grid attribute name. */ +#define FLUID_NAME_VELOCITYVEC_MESH "vertex_velocities_mesh" #define FLUID_NAME_VELOCITY_MESH "velocity_mesh" #define FLUID_NAME_PINDEX_MESH "pindex_mesh" #define FLUID_NAME_GPI_MESH "gpi_mesh" @@ -329,18 +336,28 @@ enum { /* Particles object names. */ #define FLUID_NAME_PP_PARTICLES "ppSnd" #define FLUID_NAME_PVEL_PARTICLES "pVelSnd" -#define FLUID_NAME_PFORCE_PARTICLES "pForceSnd" #define FLUID_NAME_PLIFE_PARTICLES "pLifeSnd" -#define FLUID_NAME_VELOCITY_PARTICLES "velocity_particles" -#define FLUID_NAME_FLAGS_PARTICLES "flags_particles" -#define FLUID_NAME_PHI_PARTICLES "phi_particles" -#define FLUID_NAME_PHIOBS_PARTICLES "phiObs_particles" -#define FLUID_NAME_PHIOUT_PARTICLES "phiOut_particles" -#define FLUID_NAME_NORMAL_PARTICLES "normal_particles" -#define FLUID_NAME_NEIGHBORRATIO_PARTICLES "neighborRatio_particles" -#define FLUID_NAME_TRAPPEDAIR_PARTICLES "trappedAir_particles" -#define FLUID_NAME_WAVECREST_PARTICLES "waveCrest_particles" -#define FLUID_NAME_KINETICENERGY_PARTICLES "kineticEnergy_particles" +#define FLUID_NAME_PFORCE_PARTICLES "pForceSnd" +/* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PARTS_PARTICLES "particles_secondary" +/* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PARTSVEL_PARTICLES "particles_velocity_secondary" +/* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PARTSLIFE_PARTICLES "particles_life_secondary" +#define FLUID_NAME_PARTSFORCE_PARTICLES "particles_force_secondary" +#define FLUID_NAME_VELOCITY_PARTICLES "velocity_secondary" +#define FLUID_NAME_FLAGS_PARTICLES "flags_secondary" +#define FLUID_NAME_PHI_PARTICLES "phi_secondary" +#define FLUID_NAME_PHIOBS_PARTICLES "phiObs_secondary" +#define FLUID_NAME_PHIOUT_PARTICLES "phiOut_secondary" +#define FLUID_NAME_NORMAL_PARTICLES "normal_secondary" +#define FLUID_NAME_NEIGHBORRATIO_PARTICLES "neighbor_ratio_secondary" +/* == OpenVDB grid attribute name. */ +#define FLUID_NAME_TRAPPEDAIR_PARTICLES "trapped_air_secondary" +/* == OpenVDB grid attribute name. */ +#define FLUID_NAME_WAVECREST_PARTICLES "wave_crest_secondary" +/* == OpenVDB grid attribute name. */ +#define FLUID_NAME_KINETICENERGY_PARTICLES "kinetic_energy_secondary" /* Guiding object names. */ #define FLUID_NAME_VELT "velT" @@ -349,9 +366,9 @@ enum { #define FLUID_NAME_PHIGUIDEIN "phiGuideIn" #define FLUID_NAME_GUIDEVELC "guidevelC" #define FLUID_NAME_GUIDEVEL_X "x_guidevel" -#define FLUID_NAME_GUIDEVEL_Y "Y_guidevel" +#define FLUID_NAME_GUIDEVEL_Y "y_guidevel" #define FLUID_NAME_GUIDEVEL_Z "z_guidevel" -#define FLUID_NAME_GUIDEVEL "guidevel" +#define FLUID_NAME_GUIDEVEL "velocity_guide" /* Cache file extensions. */ #define FLUID_DOMAIN_EXTENSION_UNI ".uni" @@ -374,7 +391,18 @@ enum { enum { FLUID_DOMAIN_CACHE_REPLAY = 0, FLUID_DOMAIN_CACHE_MODULAR = 1, - FLUID_DOMAIN_CACHE_FINAL = 2, + FLUID_DOMAIN_CACHE_ALL = 2, +}; + +enum { + VDB_COMPRESSION_BLOSC = 0, + VDB_COMPRESSION_ZIP = 1, + VDB_COMPRESSION_NONE = 2, +}; + +enum { + VDB_PRECISION_HALF_FLOAT = 0, + VDB_PRECISION_FULL_FLOAT = 1, }; /* Deprecated values (i.e. all defines and enums below this line up until typedefs). */ @@ -391,12 +419,6 @@ enum { SM_HRES_FULLSAMPLE = 2, }; -enum { - VDB_COMPRESSION_BLOSC = 0, - VDB_COMPRESSION_ZIP = 1, - VDB_COMPRESSION_NONE = 2, -}; - typedef struct FluidDomainVertexVelocity { float vel[3]; } FluidDomainVertexVelocity; @@ -566,7 +588,8 @@ typedef struct FluidDomainSettings { char cache_directory[1024]; char error[64]; /* Bake error description. */ short cache_type; - char _pad8[2]; /* Unused. */ + char cache_id[4]; /* Run-time only */ + char _pad8[6]; /* Time options. */ float dt; @@ -591,17 +614,17 @@ typedef struct FluidDomainSettings { char coba_field; /* Simulation field used for the color mapping. */ char interp_method; + /* OpenVDB cache options. */ + int openvdb_compression; + float clipping; + char openvdb_data_depth; + char _pad9[7]; /* Unused. */ + /* -- Deprecated / unsed options (below). -- */ /* View options. */ int viewsettings; - char _pad9[4]; /* Unused. */ - - /* OpenVDB cache options. */ - int openvdb_comp; - float clipping; - char data_depth; - char _pad10[7]; /* Unused. */ + char _pad10[4]; /* Unused. */ /* Pointcache options. */ /* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index 674999ab465..5d35db1a960 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -58,7 +58,7 @@ typedef enum GpencilModifierMode { eGpencilModifierMode_Realtime = (1 << 0), eGpencilModifierMode_Render = (1 << 1), eGpencilModifierMode_Editmode = (1 << 2), - eGpencilModifierMode_Expanded = (1 << 3), + eGpencilModifierMode_Expanded_DEPRECATED = (1 << 3), } GpencilModifierMode; typedef enum { @@ -72,7 +72,7 @@ typedef struct GpencilModifierData { int type, mode; int stackindex; short flag; - short _pad; + short ui_expand_flag; /** MAX_NAME. */ char name[64]; diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index c3180ae79db..b6e2910a1b0 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -735,10 +735,10 @@ typedef enum eGP_DrawMode { #define GPENCIL_ANY_EDIT_MODE(gpd) \ ((gpd) && ((gpd)->flag & \ (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE))) -#define GPENCIL_PAINT_MODE(gpd) ((gpd) && (gpd->flag & (GP_DATA_STROKE_PAINTMODE))) +#define GPENCIL_PAINT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_PAINTMODE)) #define GPENCIL_SCULPT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_SCULPTMODE)) #define GPENCIL_WEIGHT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE)) -#define GPENCIL_VERTEX_MODE(gpd) ((gpd) && (gpd->flag & (GP_DATA_STROKE_VERTEXMODE))) +#define GPENCIL_VERTEX_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_VERTEXMODE)) #define GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd) \ ((gpd) && ((gpd)->flag & (GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE))) #define GPENCIL_NONE_EDIT_MODE(gpd) \ diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index 11a6a937e92..0ffb6c8a76a 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -129,7 +129,7 @@ typedef struct Image { ID id; /** File path, 1024 = FILE_MAX. */ - char name[1024]; + char filepath[1024]; /** Not written in file. */ struct MovieCache *cache; diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h index 3685290e571..a1cc6f89314 100644 --- a/source/blender/makesdna/DNA_key_types.h +++ b/source/blender/makesdna/DNA_key_types.h @@ -113,7 +113,7 @@ typedef struct Key { /** * Can never be 0, this is used for detecting old data. - * current free uid for keyblocks + * current free UID for key-blocks. */ int uidgen; } Key; diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 357c3260121..6a4ec65318b 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -112,7 +112,7 @@ typedef enum eMaterialGPencilStyle_Flag { /* protected from further editing */ GP_MATERIAL_LOCKED = (1 << 2), /* do onion skinning */ - GP_MATERIAL_ONIONSKIN = (1 << 3), + GP_MATERIAL_HIDE_ONIONSKIN = (1 << 3), /* clamp texture */ GP_MATERIAL_TEX_CLAMP = (1 << 4), /* mix fill texture */ diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index acc020ec710..9435cb3bd78 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -46,6 +46,7 @@ struct MLoopTri; struct MLoopUV; struct MPoly; struct MVert; +struct MPropCol; struct Material; struct Mesh; struct Multires; @@ -244,9 +245,9 @@ typedef struct TFace { /** #Mesh_Runtime.wrapper_type */ typedef enum eMeshWrapperType { - /** Use mesh data (#Mesh.mvert,#Mesh.medge, #Mesh.mloop, #Mesh.mpoly). */ + /** Use mesh data (#Mesh.mvert, #Mesh.medge, #Mesh.mloop, #Mesh.mpoly). */ ME_WRAPPER_TYPE_MDATA = 0, - /** Use edit-mesh data (#Mesh.#edit_mesh, #Mesh_Runtime.edit_data). */ + /** Use edit-mesh data (#Mesh.edit_mesh, #Mesh_Runtime.edit_data). */ ME_WRAPPER_TYPE_BMESH = 1, /* ME_WRAPPER_TYPE_SUBD = 2, */ /* TODO */ } eMeshWrapperType; @@ -285,7 +286,7 @@ enum { ME_AUTOSMOOTH = 1 << 5, ME_FLAG_UNUSED_6 = 1 << 6, /* cleared */ ME_FLAG_UNUSED_7 = 1 << 7, /* cleared */ - ME_FLAG_UNUSED_8 = 1 << 8, /* cleared */ + ME_REMESH_REPROJECT_VERTEX_COLORS = 1 << 8, ME_DS_EXPAND = 1 << 9, ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10, ME_REMESH_SMOOTH_NORMALS = 1 << 11, diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 04deecde43e..cc2ba3fb999 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -345,7 +345,7 @@ typedef struct MLoopCol { } MLoopCol; typedef struct MPropCol { - float col[4]; + float color[4]; } MPropCol; /** Multi-Resolution loop data. */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 1413db4baea..05daf6caa47 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -394,6 +394,8 @@ typedef struct BevelModifierData { short flags; /** Used to interpret the bevel value. */ short val_flags; + /** For the type and how we build the bevel's profile. */ + short profile_type; /** Flags to tell the tool how to limit the bevel. */ short lim_flags; /** Flags to direct how edge weights are applied to verts. */ @@ -407,6 +409,7 @@ typedef struct BevelModifierData { short miter_outer; /** The method to use for creating >2-way intersections */ short vmesh_method; + char _pad0[2]; /** Controls profile shape (0->1, .5 is round). */ float profile; /** if the MOD_BEVEL_ANGLE is set, @@ -417,6 +420,7 @@ typedef struct BevelModifierData { * this will be the name of the vert group, MAX_VGROUP_NAME */ char defgrp_name[64]; + char _pad1[4]; /** Curve info for the custom profile */ struct CurveProfile *custom_profile; @@ -429,12 +433,15 @@ enum { MOD_BEVEL_ANGLE = (1 << 3), MOD_BEVEL_WEIGHT = (1 << 4), MOD_BEVEL_VGROUP = (1 << 5), - MOD_BEVEL_CUSTOM_PROFILE = (1 << 7), - /* MOD_BEVEL_SAMPLE_STRAIGHT = (1 << 8), */ /* UNUSED */ - /* unused = (1 << 9), */ - /* unused = (1 << 10), */ - /* unused = (1 << 11), */ - /* unused = (1 << 12), */ +/* unused = (1 << 6), */ +#ifdef DNA_DEPRECATED_ALLOW + MOD_BEVEL_CUSTOM_PROFILE_DEPRECATED = (1 << 7), +#endif + /* unused = (1 << 8), */ + /* unused = (1 << 9), */ + /* unused = (1 << 10), */ + /* unused = (1 << 11), */ + /* unused = (1 << 12), */ MOD_BEVEL_OVERLAP_OK = (1 << 13), MOD_BEVEL_EVEN_WIDTHS = (1 << 14), MOD_BEVEL_HARDEN_NORMALS = (1 << 15), @@ -446,6 +453,13 @@ enum { MOD_BEVEL_AMT_WIDTH = 1, MOD_BEVEL_AMT_DEPTH = 2, MOD_BEVEL_AMT_PERCENT = 3, + MOD_BEVEL_AMT_ABSOLUTE = 4, +}; + +/* BevelModifierData->profile_type */ +enum { + MOD_BEVEL_PROFILE_SUPERELLIPSE = 0, + MOD_BEVEL_PROFILE_CUSTOM = 1, }; /* BevelModifierData->edge_flags */ diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h index 94d11095108..d750a7f3148 100644 --- a/source/blender/makesdna/DNA_movieclip_types.h +++ b/source/blender/makesdna/DNA_movieclip_types.h @@ -78,7 +78,7 @@ typedef struct MovieClip { struct AnimData *adt; /** File path, 1024 = FILE_MAX. */ - char name[1024]; + char filepath[1024]; /** Sequence or movie. */ int source; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 4ff0e531168..993aad92564 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -844,6 +844,15 @@ typedef struct NodeTexSky { float sun_direction[3]; float turbidity; float ground_albedo; + float sun_size; + float sun_elevation; + float sun_rotation; + int altitude; + float air_density; + float dust_density; + float ozone_density; + char sun_disc; + char _pad[3]; } NodeTexSky; typedef struct NodeTexImage { @@ -1171,8 +1180,9 @@ enum { }; /* sky texture */ -#define SHD_SKY_OLD 0 -#define SHD_SKY_NEW 1 +#define SHD_SKY_PREETHAM 0 +#define SHD_SKY_HOSEK 1 +#define SHD_SKY_NISHITA 2 /* environment texture */ #define SHD_PROJ_EQUIRECTANGULAR 0 diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h index 7f022f104e6..78f645deaa2 100644 --- a/source/blender/makesdna/DNA_object_force_types.h +++ b/source/blender/makesdna/DNA_object_force_types.h @@ -92,6 +92,10 @@ typedef struct PartDeflect { * How much force is converted into "air flow", i.e. * force used as the velocity of surrounding medium. */ float f_flow; + /** How much force is reduced when acting parallel to a surface, e.g. cloth. */ + float f_wind_factor; + + char _pad0[4]; /** Noise size for noise effector, restlength for harmonic effector. */ float f_size; diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 9776063f220..d8a7599e4cb 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -62,8 +62,7 @@ enum { TSE_DRAG_AFTER = (1 << 8), /* Needed because outliner-only elements can be active */ TSE_ACTIVE = (1 << 9), - /* Needed because walk selection should not activate */ - TSE_ACTIVE_WALK = (1 << 10), + /* TSE_ACTIVE_WALK = (1 << 10), */ /* Unused */ TSE_DRAG_ANY = (TSE_DRAG_INTO | TSE_DRAG_BEFORE | TSE_DRAG_AFTER), }; diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index 4b6f079aa28..7f01e58f2af 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -218,8 +218,10 @@ .bloom_radius = 6.5f, \ .bloom_clamp = 0.0f, \ \ - .motion_blur_samples = 8, \ .motion_blur_shutter = 0.5f, \ + .motion_blur_depth_scale = 100.0f, \ + .motion_blur_max = 32, \ + .motion_blur_steps = 1, \ \ .shadow_cube_size = 512, \ .shadow_cascade_size = 1024, \ @@ -325,7 +327,7 @@ .doublimit = 0.001, \ .vgroup_weight = 1.0f, \ .uvcalc_margin = 0.001f, \ - .uvcalc_flag = UVCALC_TRANSFORM_CORRECT, \ + .uvcalc_flag = UVCALC_TRANSFORM_CORRECT_SLIDE, \ .unwrapper = 1, \ .select_thresh = 0.01f, \ \ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index c50e48982b3..dd62ddb640f 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1590,7 +1590,6 @@ typedef struct SceneEEVEE { float gi_irradiance_smoothing; float gi_glossy_clamp; float gi_filter_quality; - char _pad[4]; float gi_cubemap_draw_size; float gi_irradiance_draw_size; @@ -1628,8 +1627,11 @@ typedef struct SceneEEVEE { float bloom_radius; float bloom_clamp; - int motion_blur_samples; + int motion_blur_samples DNA_DEPRECATED; + int motion_blur_max; + int motion_blur_steps; float motion_blur_shutter; + float motion_blur_depth_scale; int shadow_method DNA_DEPRECATED; int shadow_cube_size; @@ -2172,7 +2174,7 @@ typedef enum eSculptFlags { SCULPT_FLAG_UNUSED_6 = (1 << 6), /* cleared */ - SCULPT_USE_OPENMP = (1 << 7), + SCULPT_FLAG_UNUSED_7 = (1 << 7), /* cleared */ SCULPT_ONLY_DEFORM = (1 << 8), // SCULPT_SHOW_DIFFUSE = (1 << 9), // deprecated @@ -2233,10 +2235,12 @@ enum { #define UVCALC_FILLHOLES (1 << 0) /** would call this UVCALC_ASPECT_CORRECT, except it should be default with old file */ #define UVCALC_NO_ASPECT_CORRECT (1 << 1) -/** adjust UV's while transforming to avoid distortion */ -#define UVCALC_TRANSFORM_CORRECT (1 << 2) +/** Adjust UV's while transforming with Vert or Edge Slide. */ +#define UVCALC_TRANSFORM_CORRECT_SLIDE (1 << 2) /** Use mesh data after subsurf to compute UVs*/ #define UVCALC_USESUBSURF (1 << 3) +/** adjust UV's while transforming to avoid distortion */ +#define UVCALC_TRANSFORM_CORRECT (1 << 4) /* ToolSettings.uv_flag */ #define UV_SYNC_SELECTION 1 diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 07cba2bad1c..f9fcbdab55d 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -41,6 +41,7 @@ struct uiLayout; struct wmDrawBuffer; struct wmTimer; struct wmTooltipState; +struct PointerRNA; /* TODO Doing this is quite ugly :) * Once the top-bar is merged bScreen should be refactored to use ScrAreaMap. */ @@ -135,6 +136,15 @@ typedef struct Panel_Runtime { /* For instanced panels: Index of the list item the panel corresponds to. */ int list_index; + + /** + * Pointer for storing which data the panel corresponds to. + * Useful when there can be multiple instances of the same panel type. + * + * \note A panel and its sub-panels share the same custom data pointer. + * This avoids freeing the same pointer twice when panels are removed. + */ + struct PointerRNA *custom_data_ptr; } Panel_Runtime; /** The part from uiBlock that needs saved in file. */ @@ -427,7 +437,7 @@ typedef struct ARegion { /** Private, cached notifier events. */ short do_draw; /** Private, cached notifier events. */ - short do_draw_overlay; + short do_draw_paintcursor; /** Private, set for indicate drawing overlapped. */ short overlap; /** Temporary copy of flag settings for clean fullscreen. */ @@ -609,7 +619,7 @@ enum { /* regiontype, first two are the default set */ /* Do NOT change order, append on end. Types are hardcoded needed */ -enum { +typedef enum eRegionType { RGN_TYPE_WINDOW = 0, RGN_TYPE_HEADER = 1, RGN_TYPE_CHANNELS = 2, @@ -625,7 +635,7 @@ enum { RGN_TYPE_EXECUTE = 10, RGN_TYPE_FOOTER = 11, RGN_TYPE_TOOL_HEADER = 12, -}; +} eRegionType; /* use for function args */ #define RGN_TYPE_ANY -1 diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h index 18a4e8655a3..f19181bf07d 100644 --- a/source/blender/makesdna/DNA_shader_fx_types.h +++ b/source/blender/makesdna/DNA_shader_fx_types.h @@ -50,7 +50,7 @@ typedef enum ShaderFxMode { eShaderFxMode_Realtime = (1 << 0), eShaderFxMode_Render = (1 << 1), eShaderFxMode_Editmode = (1 << 2), - eShaderFxMode_Expanded = (1 << 3), + eShaderFxMode_Expanded_DEPRECATED = (1 << 3), } ShaderFxMode; typedef enum { @@ -64,7 +64,8 @@ typedef struct ShaderFxData { int type, mode; int stackindex; short flag; - char _pad[2]; + /* Expansion for shader effect panels and sub-panels. */ + short ui_expand_flag; /** MAX_NAME. */ char name[64]; @@ -171,6 +172,10 @@ typedef struct PixelShaderFxData { ShaderFxData_Runtime runtime; } PixelShaderFxData; +typedef enum ePixelShaderFx_Flag { + FX_PIXEL_FILTER_NEAREST = (1 << 0), +} ePixelShaderFx_Flag; + typedef struct RimShaderFxData { ShaderFxData shaderfx; int offset[2]; diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h index 04ac9d4e5be..35ff3a658ba 100644 --- a/source/blender/makesdna/DNA_sound_types.h +++ b/source/blender/makesdna/DNA_sound_types.h @@ -36,7 +36,7 @@ typedef struct bSound { * The path to the sound file. */ /** 1024 = FILE_MAX. */ - char name[1024]; + char filepath[1024]; /** * The packed file. diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index f559065ea28..83489477a8f 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1199,7 +1199,11 @@ typedef struct SpaceText { struct Text *text; - int top, left; + /** Determines at what line the top of the text is displayed. */ + int top; + + /** Determines the horizontal scroll (in columns). */ + int left; char _pad1[4]; short flags; diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h index dbd5def74d4..27663ffcbdd 100644 --- a/source/blender/makesdna/DNA_text_types.h +++ b/source/blender/makesdna/DNA_text_types.h @@ -43,10 +43,21 @@ typedef struct TextLine { typedef struct Text { ID id; - char *name; + /** + * Optional file path, when NULL text is considered internal. + * Otherwise this path will be used when saving/reloading. + * + * When set this is where the file will or has been saved. + */ + char *filepath; + + /** + * Python code object for this text (cached result of #Py_CompileStringObject). + */ void *compiled; - int flags, nlines; + int flags; + char _pad0[4]; ListBase lines; TextLine *curl, *sell; @@ -57,12 +68,15 @@ typedef struct Text { #define TXT_TABSIZE 4 -/* text flags */ +/** #Text.flags */ enum { + /** Set if the file in run-time differs from the file on disk, or if there is no file on disk. */ TXT_ISDIRTY = 1 << 0, + /** When the text hasn't been written to a file. #Text.filepath may be NULL or invalid. */ TXT_ISMEM = 1 << 2, + /** Should always be set if the Text is not to be written into the `.blend`. */ TXT_ISEXT = 1 << 3, - /** Used by space handler scriptlinks. */ + /** Load the script as a Python module when loading the `.blend` file. */ TXT_ISSCRIPT = 1 << 4, TXT_FLAG_UNUSED_8 = 1 << 8, /* cleared */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 63e7a90547e..d751ad9ac47 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -619,8 +619,11 @@ typedef struct UserDef_FileSpaceData { typedef struct UserDef_Experimental { char use_undo_legacy; + char use_new_particle_system; + char use_new_hair_type; + char use_cycles_debug; /** `makesdna` does not allow empty structs. */ - char _pad0[7]; + char _pad0[4]; } UserDef_Experimental; #define USER_EXPERIMENTAL_TEST(userdef, member) \ @@ -633,12 +636,12 @@ typedef struct UserDef { /** #eUserPref_Flag. */ int flag; /** #eDupli_ID_Flags. */ - short dupflag; + unsigned int dupflag; /** #eUserPref_PrefFlag preferences for the preferences. */ char pref_flag; char savetime; char mouse_emulate_3_button_modifier; - char _pad4[3]; + char _pad4[1]; /** FILE_MAXDIR length. */ char tempdir[768]; char fontdir[768]; @@ -1150,6 +1153,13 @@ typedef enum eDupli_ID_Flags { USER_DUP_HAIR = (1 << 14), USER_DUP_POINTCLOUD = (1 << 15), USER_DUP_VOLUME = (1 << 16), + + USER_DUP_OBDATA = (~0) & ((1 << 24) - 1), + + /* Those are not exposed as user preferences, only used internaly. */ + USER_DUP_OBJECT = (1 << 24), + /* USER_DUP_COLLECTION = (1 << 25), */ /* UNUSED, keep because we may implement. */ + } eDupli_ID_Flags; /** diff --git a/source/blender/makesdna/DNA_vfont_types.h b/source/blender/makesdna/DNA_vfont_types.h index 295552635fe..086fb2bc905 100644 --- a/source/blender/makesdna/DNA_vfont_types.h +++ b/source/blender/makesdna/DNA_vfont_types.h @@ -36,7 +36,7 @@ typedef struct VFont { ID id; /** 1024 = FILE_MAX. */ - char name[1024]; + char filepath[1024]; struct VFontData *data; struct PackedFile *packedfile; diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 01e3971a216..0f2761e311e 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -96,6 +96,7 @@ set(SRC ${CMAKE_CURRENT_BINARY_DIR}/dna_verify.c ${SRC_DNA_INC} + ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h dna_rename_defs.h dna_utils.h ) diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index cf7c201795e..3d95eba4aed 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -963,11 +963,10 @@ static int elem_strcmp(const char *name, const char *oname) * Returns whether the specified field exists according to the struct format * pointed to by old. * - * \param sdna: Old SDNA - * \param type: Current field type name - * \param name: Current field name - * \param old: Pointer to struct information in sdna - * \return true when existing, false otherwise. + * \param type: Current field type name. + * \param name: Current field name. + * \param old: Pointer to struct information in sdna. + * \return true when existing, false otherwise.. */ static bool elem_exists_impl( /* Expand SDNA. */ @@ -995,6 +994,9 @@ static bool elem_exists_impl( return false; } +/** + * \param sdna: Old SDNA. + */ static bool elem_exists(const SDNA *sdna, const char *type, const char *name, const short *old) { return elem_exists_impl( @@ -1079,7 +1081,7 @@ static const char *find_elem(const SDNA *sdna, /** * Converts the contents of a single field of a struct, of a non-struct type, - * from oldsdna to newsdna format. + * from \a oldsdna to \a newsdna format. * * \param newsdna: SDNA of current Blender * \param oldsdna: SDNA of Blender that saved file diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index aabc16c4111..f2cf72843bd 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -77,6 +77,9 @@ DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_parent, guide_parent) DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_source, guide_source) DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_vel_factor, guide_vel_factor) DNA_STRUCT_RENAME_ELEM(FluidEffectorSettings, guiding_mode, guide_mode) +DNA_STRUCT_RENAME_ELEM(Image, name, filepath) +DNA_STRUCT_RENAME_ELEM(Library, name, filepath) +DNA_STRUCT_RENAME_ELEM(MovieClip, name, filepath) DNA_STRUCT_RENAME_ELEM(Object, col, color) DNA_STRUCT_RENAME_ELEM(Object, dup_group, instance_collection) DNA_STRUCT_RENAME_ELEM(Object, dupfacesca, instance_faces_scale) @@ -84,8 +87,10 @@ DNA_STRUCT_RENAME_ELEM(Object, size, scale) DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_group, instance_collection) DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_ob, instance_object) DNA_STRUCT_RENAME_ELEM(ParticleSettings, dupliweights, instance_weights) +DNA_STRUCT_RENAME_ELEM(Text, name, filepath) DNA_STRUCT_RENAME_ELEM(ThemeSpace, scrubbing_background, time_scrub_background) DNA_STRUCT_RENAME_ELEM(ThemeSpace, show_back_grad, background_type) +DNA_STRUCT_RENAME_ELEM(VFont, name, filepath) DNA_STRUCT_RENAME_ELEM(View3D, far, clip_end) DNA_STRUCT_RENAME_ELEM(View3D, near, clip_start) DNA_STRUCT_RENAME_ELEM(View3D, ob_centre, ob_center) @@ -100,6 +105,7 @@ DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutY, curve_out_y) DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleIn, scale_in_x) DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleOut, scale_out_x) DNA_STRUCT_RENAME_ELEM(bSameVolumeConstraint, flag, free_axis) +DNA_STRUCT_RENAME_ELEM(bSound, name, filepath) DNA_STRUCT_RENAME_ELEM(bTheme, tact, space_action) DNA_STRUCT_RENAME_ELEM(bTheme, tbuts, space_properties) DNA_STRUCT_RENAME_ELEM(bTheme, tclip, space_clip) diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 083806350e7..6d220454364 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -217,7 +217,7 @@ void BLI_system_backtrace(FILE *fp) /** * Ensure type \c str to is in the #types array. * \param str: Struct name without any qualifiers. - * \param len: The struct size in bytes. + * \param size: The struct size in bytes. * \return Index in the #types array. */ static int add_type(const char *str, int size); diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 4a3cd50a89a..ce53454319a 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -388,6 +388,8 @@ extern StructRNA RNA_MeshIntProperty; extern StructRNA RNA_MeshLoop; extern StructRNA RNA_MeshLoopColor; extern StructRNA RNA_MeshLoopColorLayer; +extern StructRNA RNA_MeshVertColor; +extern StructRNA RNA_MeshVertColorLayer; extern StructRNA RNA_MeshLoopTriangle; extern StructRNA RNA_MeshPolygon; extern StructRNA RNA_MeshSequenceCacheModifier; @@ -820,12 +822,12 @@ int RNA_property_array_item_index(PropertyRNA *prop, char name); int RNA_property_string_maxlength(PropertyRNA *prop); -const char *RNA_property_ui_name(PropertyRNA *prop); -const char *RNA_property_ui_name_raw(PropertyRNA *prop); -const char *RNA_property_ui_description(PropertyRNA *prop); -const char *RNA_property_ui_description_raw(PropertyRNA *prop); -const char *RNA_property_translation_context(PropertyRNA *prop); -int RNA_property_ui_icon(PropertyRNA *prop); +const char *RNA_property_ui_name(const PropertyRNA *prop); +const char *RNA_property_ui_name_raw(const PropertyRNA *prop); +const char *RNA_property_ui_description(const PropertyRNA *prop); +const char *RNA_property_ui_description_raw(const PropertyRNA *prop); +const char *RNA_property_translation_context(const PropertyRNA *prop); +int RNA_property_ui_icon(const PropertyRNA *prop); /* Dynamic Property Information */ @@ -1466,6 +1468,7 @@ bool RNA_struct_override_matches(struct Main *bmain, struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, const char *root_path, + const size_t root_path_len, struct IDOverrideLibrary *override, const eRNAOverrideMatch flags, eRNAOverrideMatchResult *r_report_flags); @@ -1483,7 +1486,8 @@ void RNA_struct_override_apply(struct Main *bmain, struct IDOverrideLibrary *override); struct IDOverrideLibraryProperty *RNA_property_override_property_find(PointerRNA *ptr, - PropertyRNA *prop); + PropertyRNA *prop, + struct ID **r_owner_id); struct IDOverrideLibraryProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created); diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 64a8e5cbdfb..eaea895746e 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -48,6 +48,7 @@ set(DEFSRC rna_fluid.c rna_gpencil.c rna_gpencil_modifier.c + rna_hair.c rna_image.c rna_key.c rna_lattice.c @@ -78,9 +79,11 @@ set(DEFSRC rna_sculpt_paint.c rna_sequencer.c rna_shader_fx.c + rna_simulation.c rna_sound.c rna_space.c rna_speaker.c + rna_pointcloud.c rna_test.c rna_text.c rna_texture.c @@ -97,20 +100,6 @@ set(DEFSRC rna_xr.c ) -if(WITH_NEW_OBJECT_TYPES) - list(APPEND DEFSRC - rna_hair.c - rna_pointcloud.c - ) -endif() - -if (WITH_NEW_SIMULATION_TYPE) - list(APPEND DEFSRC - rna_simulation.c - ) -endif() - - set(APISRC rna_action_api.c rna_animation_api.c @@ -346,15 +335,6 @@ if(WITH_XR_OPENXR) add_definitions(-DWITH_XR_OPENXR) endif() -if(WITH_NEW_OBJECT_TYPES) - add_definitions(-DWITH_NEW_OBJECT_TYPES) -endif() - -if (WITH_NEW_SIMULATION_TYPE) - add_definitions(-DWITH_NEW_SIMULATION_TYPE) -endif() - - # Build makesrna executable blender_include_dirs( . @@ -444,3 +424,6 @@ set(LIB add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_rna "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +# Needed so we can use dna_type_offsets.h for defaults initialization. +add_dependencies(bf_blenkernel bf_dna) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index ff435710561..8d61b21759f 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3770,7 +3770,8 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr /* XXX This systematically enforces that flag on ID pointers... * we'll probably have to revisit. :/ */ StructRNA *type = rna_find_struct((const char *)pprop->type); - if (type && (type->flag & STRUCT_ID)) { + if (type && (type->flag & STRUCT_ID) && + !(prop->flag_internal & PROP_INTERN_PTR_OWNERSHIP_FORCED)) { prop->flag |= PROP_PTR_NO_OWNERSHIP; } break; @@ -3781,7 +3782,8 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr /* XXX This systematically enforces that flag on ID pointers... * we'll probably have to revisit. :/ */ StructRNA *type = rna_find_struct((const char *)cprop->item_type); - if (type && (type->flag & STRUCT_ID)) { + if (type && (type->flag & STRUCT_ID) && + !(prop->flag_internal & PROP_INTERN_PTR_OWNERSHIP_FORCED)) { prop->flag |= PROP_PTR_NO_OWNERSHIP; } break; @@ -4270,9 +4272,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint}, {"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve}, {"rna_gpencil.c", NULL, RNA_def_gpencil}, -#ifdef WITH_NEW_OBJECT_TYPES {"rna_hair.c", NULL, RNA_def_hair}, -#endif {"rna_image.c", "rna_image_api.c", RNA_def_image}, {"rna_key.c", NULL, RNA_def_key}, {"rna_light.c", NULL, RNA_def_light}, @@ -4295,9 +4295,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_packedfile.c", NULL, RNA_def_packedfile}, {"rna_palette.c", NULL, RNA_def_palette}, {"rna_particle.c", NULL, RNA_def_particle}, -#ifdef WITH_NEW_OBJECT_TYPES {"rna_pointcloud.c", NULL, RNA_def_pointcloud}, -#endif {"rna_pose.c", "rna_pose_api.c", RNA_def_pose}, {"rna_curveprofile.c", NULL, RNA_def_profile}, {"rna_lightprobe.c", NULL, RNA_def_lightprobe}, @@ -4307,9 +4305,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_screen.c", NULL, RNA_def_screen}, {"rna_sculpt_paint.c", NULL, RNA_def_sculpt_paint}, {"rna_sequencer.c", "rna_sequencer_api.c", RNA_def_sequencer}, -#ifdef WITH_NEW_SIMULATION_TYPE {"rna_simulation.c", NULL, RNA_def_simulation}, -#endif {"rna_space.c", "rna_space_api.c", RNA_def_space}, {"rna_speaker.c", NULL, RNA_def_speaker}, {"rna_test.c", NULL, RNA_def_test}, diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 50658ef412b..bb67783622b 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -71,17 +71,13 @@ const EnumPropertyItem rna_enum_id_type_items[] = { {ID_PA, "PARTICLE", ICON_PARTICLE_DATA, "Particle", ""}, {ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""}, {ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""}, -#ifdef WITH_NEW_SIMULATION_TYPE {ID_SIM, "SIMULATION", ICON_PHYSICS, "Simulation", ""}, /* TODO: Use correct icon. */ -#endif {ID_SO, "SOUND", ICON_SOUND, "Sound", ""}, {ID_SPK, "SPEAKER", ICON_SPEAKER, "Speaker", ""}, {ID_TXT, "TEXT", ICON_TEXT, "Text", ""}, {ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Texture", ""}, -#ifdef WITH_NEW_OBJECT_TYPES {ID_HA, "HAIR", ICON_HAIR_DATA, "Hair", ""}, {ID_PT, "POINTCLOUD", ICON_POINTCLOUD_DATA, "PointCloud", ""}, -#endif {ID_VO, "VOLUME", ICON_VOLUME_DATA, "Volume", ""}, {ID_WM, "WINDOWMANAGER", ICON_WINDOW, "Window Manager", ""}, {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""}, @@ -256,11 +252,9 @@ short RNA_type_to_ID_code(const StructRNA *type) if (base_type == &RNA_FreestyleLineStyle) { return ID_LS; } -# ifdef WITH_NEW_OBJECT_TYPES if (base_type == &RNA_Hair) { return ID_HA; } -# endif if (base_type == &RNA_Lattice) { return ID_LT; } @@ -294,11 +288,9 @@ short RNA_type_to_ID_code(const StructRNA *type) if (base_type == &RNA_PaintCurve) { return ID_PC; } -# ifdef WITH_NEW_OBJECT_TYPES if (base_type == &RNA_PointCloud) { return ID_PT; } -# endif if (base_type == &RNA_LightProbe) { return ID_LP; } @@ -308,11 +300,9 @@ short RNA_type_to_ID_code(const StructRNA *type) if (base_type == &RNA_Screen) { return ID_SCR; } -# ifdef WITH_NEW_SIMULATION_TYPE if (base_type == &RNA_Simulation) { return ID_SIM; } -# endif if (base_type == &RNA_Sound) { return ID_SO; } @@ -366,11 +356,7 @@ StructRNA *ID_code_to_RNA_type(short idcode) case ID_GR: return &RNA_Collection; case ID_HA: -# ifdef WITH_NEW_OBJECT_TYPES return &RNA_Hair; -# else - return &RNA_ID; -# endif case ID_IM: return &RNA_Image; case ID_KE: @@ -404,11 +390,7 @@ StructRNA *ID_code_to_RNA_type(short idcode) case ID_PC: return &RNA_PaintCurve; case ID_PT: -# ifdef WITH_NEW_OBJECT_TYPES return &RNA_PointCloud; -# else - return &RNA_ID; -# endif case ID_LP: return &RNA_LightProbe; case ID_SCE: @@ -416,11 +398,7 @@ StructRNA *ID_code_to_RNA_type(short idcode) case ID_SCR: return &RNA_Screen; case ID_SIM: -# ifdef WITH_NEW_SIMULATION_TYPE return &RNA_Simulation; -# else - return &RNA_ID; -# endif case ID_SO: return &RNA_Sound; case ID_SPK: @@ -1565,6 +1543,7 @@ static void rna_def_ID(BlenderRNA *brna) "Preview", "Preview image and icon of this data-block (None if not supported for this type of data)"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_pointer_funcs(prop, "rna_IDPreview_get", NULL, NULL, NULL); prop = RNA_def_pointer( @@ -1691,7 +1670,7 @@ static void rna_def_library(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_LIBRARY_DATA_DIRECT); prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); - RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_string_sdna(prop, NULL, "filepath"); RNA_def_property_ui_text(prop, "File Path", "Path to the library .blend file"); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Library_filepath_set"); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 2197764794b..79cf993e0cc 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -273,9 +273,9 @@ static IDProperty *rna_idproperty_ui_container(PropertyRNA *prop) } /* return a UI local ID prop definition for this prop */ -static IDProperty *rna_idproperty_ui(PropertyRNA *prop) +static const IDProperty *rna_idproperty_ui(const PropertyRNA *prop) { - IDProperty *idprop = rna_idproperty_ui_container(prop); + IDProperty *idprop = rna_idproperty_ui_container((PropertyRNA *)prop); if (idprop) { return IDP_GetPropertyTypeFromGroup(idprop, ((IDProperty *)prop)->name, IDP_GROUP); @@ -645,7 +645,7 @@ static const char *rna_ensure_property_identifier(const PropertyRNA *prop) } } -static const char *rna_ensure_property_description(PropertyRNA *prop) +static const char *rna_ensure_property_description(const PropertyRNA *prop) { const char *description = NULL; @@ -654,7 +654,7 @@ static const char *rna_ensure_property_description(PropertyRNA *prop) } else { /* attempt to get the local ID values */ - IDProperty *idp_ui = rna_idproperty_ui(prop); + const IDProperty *idp_ui = rna_idproperty_ui(prop); if (idp_ui) { IDProperty *item = IDP_GetPropertyTypeFromGroup(idp_ui, "description", IDP_STRING); @@ -1140,7 +1140,7 @@ PropertySubType RNA_property_subtype(PropertyRNA *prop) /* Restrict to arrays only for now for performance reasons. */ if (idprop->type == IDP_ARRAY && ELEM(idprop->subtype, IDP_INT, IDP_FLOAT, IDP_DOUBLE)) { - IDProperty *idp_ui = rna_idproperty_ui(prop); + const IDProperty *idp_ui = rna_idproperty_ui(prop); if (idp_ui) { IDProperty *item = IDP_GetPropertyTypeFromGroup(idp_ui, "subtype", IDP_STRING); @@ -1312,7 +1312,7 @@ void RNA_property_int_range(PointerRNA *ptr, PropertyRNA *prop, int *hardmin, in if (prop->magic != RNA_MAGIC) { /* attempt to get the local ID values */ - IDProperty *idp_ui = rna_idproperty_ui(prop); + const IDProperty *idp_ui = rna_idproperty_ui(prop); if (idp_ui) { IDProperty *item; @@ -1353,7 +1353,7 @@ void RNA_property_int_ui_range( if (prop->magic != RNA_MAGIC) { /* attempt to get the local ID values */ - IDProperty *idp_ui = rna_idproperty_ui(prop); + const IDProperty *idp_ui = rna_idproperty_ui(prop); if (idp_ui) { IDProperty *item; @@ -1403,7 +1403,7 @@ void RNA_property_float_range(PointerRNA *ptr, PropertyRNA *prop, float *hardmin if (prop->magic != RNA_MAGIC) { /* attempt to get the local ID values */ - IDProperty *idp_ui = rna_idproperty_ui(prop); + const IDProperty *idp_ui = rna_idproperty_ui(prop); if (idp_ui) { IDProperty *item; @@ -1448,7 +1448,7 @@ void RNA_property_float_ui_range(PointerRNA *ptr, if (prop->magic != RNA_MAGIC) { /* attempt to get the local ID values */ - IDProperty *idp_ui = rna_idproperty_ui(prop); + const IDProperty *idp_ui = rna_idproperty_ui(prop); if (idp_ui) { IDProperty *item; @@ -2025,35 +2025,34 @@ int RNA_property_enum_bitflag_identifiers( return 0; } -const char *RNA_property_ui_name(PropertyRNA *prop) +const char *RNA_property_ui_name(const PropertyRNA *prop) { return CTX_IFACE_(prop->translation_context, rna_ensure_property_name(prop)); } -const char *RNA_property_ui_name_raw(PropertyRNA *prop) +const char *RNA_property_ui_name_raw(const PropertyRNA *prop) { return rna_ensure_property_name(prop); } -const char *RNA_property_ui_description(PropertyRNA *prop) +const char *RNA_property_ui_description(const PropertyRNA *prop) { return TIP_(rna_ensure_property_description(prop)); } -const char *RNA_property_ui_description_raw(PropertyRNA *prop) +const char *RNA_property_ui_description_raw(const PropertyRNA *prop) { return rna_ensure_property_description(prop); } -const char *RNA_property_translation_context(PropertyRNA *_prop) +const char *RNA_property_translation_context(const PropertyRNA *prop) { - PropertyRNA *prop = rna_ensure_property(_prop); - return prop->translation_context; + return rna_ensure_property((PropertyRNA *)prop)->translation_context; } -int RNA_property_ui_icon(PropertyRNA *prop) +int RNA_property_ui_icon(const PropertyRNA *prop) { - return rna_ensure_property(prop)->icon; + return rna_ensure_property((PropertyRNA *)prop)->icon; } bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop_orig) @@ -2065,9 +2064,10 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop_orig) PropertyRNA *prop = rna_ensure_property(prop_orig); flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag; - return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0 && - (!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) && - (!id->override_library || RNA_property_overridable_get(ptr, prop_orig))))); + return ( + (flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0 && + (!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) && + (!ID_IS_OVERRIDE_LIBRARY(id) || RNA_property_overridable_get(ptr, prop_orig))))); } /** @@ -2101,7 +2101,7 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char * } return false; } - if (id->override_library != NULL) { + if (ID_IS_OVERRIDE_LIBRARY(id)) { /* We need the real data property in case of IDProperty here... */ PropertyRNA *real_prop = rna_ensure_property_realdata(&prop, ptr); if (real_prop == NULL || !RNA_property_overridable_get(ptr, real_prop)) { @@ -2847,7 +2847,7 @@ int RNA_property_int_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop) if (prop->magic != RNA_MAGIC) { /* attempt to get the local ID values */ - IDProperty *idp_ui = rna_idproperty_ui(prop); + const IDProperty *idp_ui = rna_idproperty_ui(prop); if (idp_ui) { IDProperty *item; @@ -2883,7 +2883,7 @@ void RNA_property_int_get_default_array(PointerRNA *ptr, PropertyRNA *prop, int if (prop->magic != RNA_MAGIC) { int length = rna_ensure_property_array_length(ptr, prop); - IDProperty *idp_ui = rna_idproperty_ui(prop); + const IDProperty *idp_ui = rna_idproperty_ui(prop); IDProperty *item = idp_ui ? IDP_GetPropertyFromGroup(idp_ui, "default") : NULL; int defval = (item && item->type == IDP_INT) ? IDP_Int(item) : iprop->defaultvalue; @@ -3220,7 +3220,7 @@ float RNA_property_float_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop) if (prop->magic != RNA_MAGIC) { /* attempt to get the local ID values */ - IDProperty *idp_ui = rna_idproperty_ui(prop); + const IDProperty *idp_ui = rna_idproperty_ui(prop); if (idp_ui) { IDProperty *item; @@ -3256,7 +3256,7 @@ void RNA_property_float_get_default_array(PointerRNA *ptr, PropertyRNA *prop, fl if (prop->magic != RNA_MAGIC) { int length = rna_ensure_property_array_length(ptr, prop); - IDProperty *idp_ui = rna_idproperty_ui(prop); + const IDProperty *idp_ui = rna_idproperty_ui(prop); IDProperty *item = idp_ui ? IDP_GetPropertyFromGroup(idp_ui, "default") : NULL; float defval = (item && item->type == IDP_DOUBLE) ? IDP_Double(item) : fprop->defaultvalue; @@ -3473,6 +3473,24 @@ void RNA_property_string_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop, { StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop); + if (prop->magic != RNA_MAGIC) { + /* attempt to get the local ID values */ + const IDProperty *idp_ui = rna_idproperty_ui(prop); + + if (idp_ui) { + IDProperty *item; + + item = IDP_GetPropertyTypeFromGroup(idp_ui, "default", IDP_STRING); + if (item) { + strcpy(value, IDP_String(item)); + return; + } + } + + strcpy(value, ""); + return; + } + BLI_assert(RNA_property_type(prop) == PROP_STRING); strcpy(value, sprop->defaultvalue); @@ -3507,6 +3525,22 @@ int RNA_property_string_default_length(PointerRNA *UNUSED(ptr), PropertyRNA *pro { StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop); + if (prop->magic != RNA_MAGIC) { + /* attempt to get the local ID values */ + const IDProperty *idp_ui = rna_idproperty_ui(prop); + + if (idp_ui) { + IDProperty *item; + + item = IDP_GetPropertyTypeFromGroup(idp_ui, "default", IDP_STRING); + if (item) { + return strlen(IDP_String(item)); + } + } + + return 0; + } + BLI_assert(RNA_property_type(prop) == PROP_STRING); return strlen(sprop->defaultvalue); @@ -5380,7 +5414,7 @@ bool RNA_path_resolve_property_full( * This is a convenience method to avoid logic errors and ugly syntax, * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call. * \note Assumes all pointers provided are valid. - * \param r_item_pointer: The final Pointer or Collection item value. + * \param r_item_ptr: The final Pointer or Collection item value. * You must check for its validity before use! * \return True only if both a valid pointer and property are found after resolving the path */ @@ -5406,7 +5440,7 @@ bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr, * it combines both \a RNA_path_resolve_full and * \a RNA_path_resolve_property_full in a single call. * \note Assumes all pointers provided are valid. - * \param r_item_pointer: The final Pointer or Collection item value. + * \param r_item_ptr: The final Pointer or Collection item value. * You must check for its validity before use! * \return True only if both a valid pointer and property are found after resolving the path */ diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 265e83ddcba..8cd8f80b7c8 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -18,17 +18,20 @@ * \ingroup RNA */ +#include <string.h> + #include "MEM_guardedalloc.h" #include "DNA_ID.h" #include "DNA_constraint_types.h" +#include "DNA_key_types.h" #include "DNA_modifier_types.h" #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_utildefines.h" -// #define DEBUG_OVERRIDE_TIMEIT +//#define DEBUG_OVERRIDE_TIMEIT #ifdef DEBUG_OVERRIDE_TIMEIT # include "PIL_time_utildefines.h" @@ -106,7 +109,7 @@ bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop) char *rna_path = RNA_path_from_ID_to_property(ptr, prop); ID *id = ptr->owner_id; - if (rna_path == NULL || id == NULL || id->override_library == NULL) { + if (rna_path == NULL || id == NULL || !ID_IS_OVERRIDE_LIBRARY(id)) { return false; } @@ -180,6 +183,7 @@ static int rna_property_override_diff(Main *bmain, PropertyRNA *prop_a, PropertyRNA *prop_b, const char *rna_path, + const size_t rna_path_len, eRNACompareMode mode, IDOverrideLibrary *override, const int flags, @@ -191,7 +195,7 @@ bool RNA_property_equals( BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE)); return (rna_property_override_diff( - bmain, ptr_a, ptr_b, prop, NULL, NULL, NULL, mode, NULL, 0, NULL) == 0); + bmain, ptr_a, ptr_b, prop, NULL, NULL, NULL, 0, mode, NULL, 0, NULL) == 0); } bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode) @@ -249,6 +253,7 @@ static int rna_property_override_diff(Main *bmain, PropertyRNA *prop_a, PropertyRNA *prop_b, const char *rna_path, + const size_t rna_path_len, eRNACompareMode mode, IDOverrideLibrary *override, const int flags, @@ -363,6 +368,7 @@ static int rna_property_override_diff(Main *bmain, mode, override, rna_path, + rna_path_len, diff_flags, &override_changed); if (override_changed && r_report_flags) { @@ -568,6 +574,7 @@ bool RNA_struct_override_matches(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, const char *root_path, + const size_t root_path_len, IDOverrideLibrary *override, const eRNAOverrideMatch flags, eRNAOverrideMatchResult *r_report_flags) @@ -649,31 +656,51 @@ bool RNA_struct_override_matches(Main *bmain, #endif #define RNA_PATH_BUFFSIZE 8192 -#define RNA_PATH_PRINTF(_str, ...) \ - if (BLI_snprintf(rna_path, RNA_PATH_BUFFSIZE, (_str), __VA_ARGS__) >= RNA_PATH_BUFFSIZE) { \ - rna_path = BLI_sprintfN((_str), __VA_ARGS__); \ - } \ - (void)0 -#define RNA_PATH_FREE \ - if (rna_path != rna_path_buffer) \ - MEM_freeN(rna_path) char rna_path_buffer[RNA_PATH_BUFFSIZE]; char *rna_path = rna_path_buffer; + size_t rna_path_len = 0; /* XXX TODO this will have to be refined to handle collections insertions, and array items */ if (root_path) { + BLI_assert(strlen(root_path) == root_path_len); + + const char *prop_name = RNA_property_identifier(prop_local); + const size_t prop_name_len = strlen(prop_name); + /* Inlined building, much much more efficient. */ if (prop_local->magic == RNA_MAGIC) { - RNA_PATH_PRINTF("%s.%s", root_path, RNA_property_identifier(prop_local)); + rna_path_len = root_path_len + 1 + prop_name_len; + if (rna_path_len >= RNA_PATH_BUFFSIZE) { + rna_path = MEM_mallocN(rna_path_len + 1, __func__); + } + + memcpy(rna_path, root_path, root_path_len); + rna_path[root_path_len] = '.'; + memcpy(rna_path + root_path_len + 1, prop_name, prop_name_len); + rna_path[rna_path_len] = '\0'; } else { - RNA_PATH_PRINTF("%s[\"%s\"]", root_path, RNA_property_identifier(prop_local)); + rna_path_len = root_path_len + 2 + prop_name_len + 2; + if (rna_path_len >= RNA_PATH_BUFFSIZE) { + rna_path = MEM_mallocN(rna_path_len + 1, __func__); + } + + memcpy(rna_path, root_path, root_path_len); + rna_path[root_path_len] = '['; + rna_path[root_path_len + 1] = '"'; + memcpy(rna_path + root_path_len + 2, prop_name, prop_name_len); + rna_path[root_path_len + 2 + prop_name_len] = '"'; + rna_path[root_path_len + 2 + prop_name_len + 1] = ']'; + rna_path[rna_path_len] = '\0'; } } else { /* This is rather slow, but is not much called, so not really worth optimizing. */ rna_path = RNA_path_from_ID_to_property(ptr_local, prop_local); + if (rna_path != NULL) { + rna_path_len = strlen(rna_path); + } } if (rna_path == NULL) { continue; @@ -684,7 +711,10 @@ bool RNA_struct_override_matches(Main *bmain, IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path); if (ignore_overridden && op != NULL) { BKE_lib_override_library_operations_tag(op, IDOVERRIDE_LIBRARY_TAG_UNUSED, false); - RNA_PATH_FREE; + + if (rna_path != rna_path_buffer) { + MEM_freeN(rna_path); + } continue; } @@ -702,6 +732,7 @@ bool RNA_struct_override_matches(Main *bmain, prop_local, prop_reference, rna_path, + rna_path_len, RNA_EQ_STRICT, override, flags, @@ -769,17 +800,18 @@ bool RNA_struct_override_matches(Main *bmain, matching = false; if (!(do_create || do_restore)) { /* Since we have no 'changing' action allowed, we can break here. */ - MEM_SAFE_FREE(rna_path); + if (rna_path != rna_path_buffer) { + MEM_freeN(rna_path); + } break; } } } - RNA_PATH_FREE; - + if (rna_path != rna_path_buffer) { + MEM_freeN(rna_path); + } #undef RNA_PATH_BUFFSIZE -#undef RNA_PATH_PRINTF -#undef RNA_PATH_FREE } RNA_property_collection_end(&iter); @@ -1045,18 +1077,70 @@ void RNA_struct_override_apply(Main *bmain, #endif } -IDOverrideLibraryProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop) +static char *rna_property_override_property_real_id_owner(PointerRNA *ptr, + PropertyRNA *prop, + ID **r_id) { ID *id = ptr->owner_id; + ID *owner_id = id; + const char *rna_path_prefix = NULL; + + *r_id = NULL; + + if (id == NULL) { + return NULL; + } - if (!id || !id->override_library) { + if (id->flag & (LIB_EMBEDDED_DATA | LIB_EMBEDDED_DATA_LIB_OVERRIDE)) { + /* XXX this is very bad band-aid code, but for now it will do. + * We should at least use a #define for those prop names. + * Ideally RNA as a whole should be aware of those PITA of embedded IDs, and have a way to + * retrieve their owner IDs and generate paths from those. + */ + + switch (GS(id->name)) { + case ID_KE: + owner_id = ((Key *)id)->from; + rna_path_prefix = "shape_keys."; + break; + case ID_GR: + /* Master collection, TODO. */ + break; + case ID_NT: + /* Root node trees, TODO. */ + break; + default: + BLI_assert(0); + } + } + + if (!ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) { return NULL; } char *rna_path = RNA_path_from_ID_to_property(ptr, prop); if (rna_path) { - IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(id->override_library, - rna_path); + char *rna_path_full = rna_path; + if (rna_path_prefix != NULL) { + rna_path_full = BLI_sprintfN("%s%s", rna_path_prefix, rna_path); + MEM_freeN(rna_path); + } + + *r_id = owner_id; + return rna_path_full; + } + return NULL; +} + +IDOverrideLibraryProperty *RNA_property_override_property_find(PointerRNA *ptr, + PropertyRNA *prop, + ID **r_owner_id) +{ + char *rna_path; + + if ((rna_path = rna_property_override_property_real_id_owner(ptr, prop, r_owner_id)) != NULL) { + IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find( + (*r_owner_id)->override_library, rna_path); MEM_freeN(rna_path); return op; } @@ -1067,14 +1151,10 @@ IDOverrideLibraryProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created) { - ID *id = ptr->owner_id; - - if (!id || !id->override_library) { - return NULL; - } + ID *id; + char *rna_path; - char *rna_path = RNA_path_from_ID_to_property(ptr, prop); - if (rna_path) { + if ((rna_path = rna_property_override_property_real_id_owner(ptr, prop, &id)) != NULL) { IDOverrideLibraryProperty *op = BKE_lib_override_library_property_get( id->override_library, rna_path, r_created); MEM_freeN(rna_path); @@ -1086,7 +1166,8 @@ IDOverrideLibraryProperty *RNA_property_override_property_get(PointerRNA *ptr, IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_find( PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict) { - IDOverrideLibraryProperty *op = RNA_property_override_property_find(ptr, prop); + ID *owner_id; + IDOverrideLibraryProperty *op = RNA_property_override_property_find(ptr, prop, &owner_id); if (!op) { return NULL; @@ -1119,13 +1200,13 @@ eRNAOverrideStatus RNA_property_override_library_status(PointerRNA *ptr, PropertyRNA *prop, const int index) { - int override_status = 0; + uint override_status = 0; if (!BKE_lib_override_library_is_enabled()) { return override_status; } - if (!ptr || !prop || !ptr->owner_id || !(ptr->owner_id)->override_library) { + if (!ptr || !prop || !ptr->owner_id || !ID_IS_OVERRIDE_LIBRARY(ptr->owner_id)) { return override_status; } diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index e67366fc7ef..cec32877c0b 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -569,7 +569,6 @@ static void rna_def_dopesheet(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_FILE, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); -# ifdef WITH_NEW_OBJECT_TYPES prop = RNA_def_property(srna, "show_hairs", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag2", ADS_FILTER_NOHAIR); RNA_def_property_ui_text( @@ -583,7 +582,6 @@ static void rna_def_dopesheet(BlenderRNA *brna) prop, "Display Point Cloud", "Include visualization of point cloud related animation data"); RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_POINTCLOUD, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); -# endif prop = RNA_def_property(srna, "show_volumes", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag2", ADS_FILTER_NOVOLUME); diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index cc5cd97a8a0..b139e4609cd 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -99,6 +99,8 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_CLOTH, "CLOTH", ICON_BRUSH_SCULPT_DRAW, "Cloth", ""}, {SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""}, {SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""}, + {SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_SCULPT_DRAW, "Paint", ""}, + {SCULPT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SCULPT_DRAW, "Smear", ""}, {SCULPT_TOOL_DRAW_FACE_SETS, "DRAW_FACE_SETS", ICON_BRUSH_MASK, "Draw Face Sets", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -314,7 +316,8 @@ static bool rna_BrushCapabilitiesSculpt_has_topology_rake_get(PointerRNA *ptr) static bool rna_BrushCapabilitiesSculpt_has_auto_smooth_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return !ELEM(br->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH); + return !ELEM( + br->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR); } static bool rna_BrushCapabilitiesSculpt_has_height_get(PointerRNA *ptr) @@ -409,6 +412,12 @@ static bool rna_BrushCapabilitiesSculpt_has_sculpt_plane_get(PointerRNA *ptr) SCULPT_TOOL_SMOOTH); } +static bool rna_BrushCapabilitiesSculpt_has_color_get(PointerRNA *ptr) +{ + Brush *br = (Brush *)ptr->data; + return ELEM(br->sculpt_tool, SCULPT_TOOL_PAINT); +} + static bool rna_BrushCapabilitiesSculpt_has_secondary_color_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; @@ -1053,6 +1062,7 @@ static void rna_def_sculpt_capabilities(BlenderRNA *brna) SCULPT_TOOL_CAPABILITY(has_plane_offset, "Has Plane Offset"); SCULPT_TOOL_CAPABILITY(has_random_texture_angle, "Has Random Texture Angle"); SCULPT_TOOL_CAPABILITY(has_sculpt_plane, "Has Sculpt Plane"); + SCULPT_TOOL_CAPABILITY(has_color, "Has Color"); SCULPT_TOOL_CAPABILITY(has_secondary_color, "Has Secondary Color"); SCULPT_TOOL_CAPABILITY(has_smooth_stroke, "Has Smooth Stroke"); SCULPT_TOOL_CAPABILITY(has_space_attenuation, "Has Space Attenuation"); @@ -2221,6 +2231,46 @@ static void rna_def_brush(BlenderRNA *brna) prop, "Strength", "How powerful the effect of the brush is when applied"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "flow", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "flow"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3); + RNA_def_property_ui_text(prop, "Flow", "Amount of paint that is applied per stroke sample"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "wet_mix", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "wet_mix"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3); + RNA_def_property_ui_text( + prop, "Wet Mix", "Amount of paint that is picked from the surface into the brush color"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "wet_persistence", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "wet_persistence"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3); + RNA_def_property_ui_text( + prop, + "Wet Persistence", + "Amount of wet paint that stays in the brush after applyig paint to the surface"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "density"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3); + RNA_def_property_ui_text( + prop, "Density", "Amount of random elements that are going to be affected by the brush"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "tip_scale_x", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "tip_scale_x"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3); + RNA_def_property_ui_text(prop, "Tip Scale X", "Scale of the brush tip in the X axis"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "dash_ratio", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "dash_ratio"); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -2312,6 +2362,14 @@ static void rna_def_brush(BlenderRNA *brna) prop, "Pose Origin Offset", "Offset of the pose origin in relation to the brush radius"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "disconnected_distance_max", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "disconnected_distance_max"); + RNA_def_property_range(prop, 0.0f, 10.0f); + RNA_def_property_ui_text(prop, + "Max Element Distance", + "Maximum distance to search for disconnected loose parts in the mesh"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "surface_smooth_shape_preservation", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "surface_smooth_shape_preservation"); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -2607,6 +2665,11 @@ static void rna_def_brush(BlenderRNA *brna) prop, "Keep Anchor Point", "Keep the position of the last segment in the IK chain fixed"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_connected_only", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_USE_CONNECTED_ONLY); + RNA_def_property_ui_text(prop, "Connected Only", "Affect only topologically connected elements"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "invert_to_scrape_fill", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_INVERT_TO_SCRAPE_FILL); RNA_def_property_ui_text(prop, diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c index 7b4b7c11c17..f9275ef1993 100644 --- a/source/blender/makesrna/intern/rna_cachefile.c +++ b/source/blender/makesrna/intern/rna_cachefile.c @@ -69,9 +69,13 @@ static void rna_def_alembic_object_path(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Object Path", "Path of an object inside of an Alembic archive"); RNA_def_struct_ui_icon(srna, ICON_NONE); + RNA_define_lib_overridable(true); + PropertyRNA *prop = RNA_def_property(srna, "path", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Path", "Object path"); RNA_def_struct_name_property(srna, prop); + + RNA_define_lib_overridable(false); } /* cachefile.object_paths */ @@ -90,6 +94,8 @@ static void rna_def_cachefile(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "CacheFile", ""); RNA_def_struct_ui_icon(srna, ICON_FILE); + RNA_define_lib_overridable(true); + PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); RNA_def_property_ui_text(prop, "File Path", "Path to external displacements file"); RNA_def_property_update(prop, 0, "rna_CacheFile_update"); @@ -167,6 +173,9 @@ static void rna_def_cachefile(BlenderRNA *brna) RNA_def_property_srna(prop, "AlembicObjectPaths"); RNA_def_property_ui_text( prop, "Object Paths", "Paths of the objects inside the Alembic archive"); + + RNA_define_lib_overridable(false); + rna_def_cachefile_object_paths(brna, prop); rna_def_animdata_common(srna); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 5405cb4e24a..af300f6e088 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -2483,7 +2483,7 @@ static void rna_def_constraint_location_limit(BlenderRNA *brna) prop = RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag2", LIMIT_TRANSFORM); RNA_def_property_ui_text( - prop, "For Transform", "Transforms are affected by this constraint as well"); + prop, "Affect Transform", "Transforms are affected by this constraint as well"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); RNA_define_lib_overridable(false); @@ -2556,7 +2556,7 @@ static void rna_def_constraint_rotation_limit(BlenderRNA *brna) prop = RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag2", LIMIT_TRANSFORM); RNA_def_property_ui_text( - prop, "For Transform", "Transforms are affected by this constraint as well"); + prop, "Affect Transform", "Transforms are affected by this constraint as well"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); RNA_define_lib_overridable(false); @@ -2644,7 +2644,7 @@ static void rna_def_constraint_size_limit(BlenderRNA *brna) prop = RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag2", LIMIT_TRANSFORM); RNA_def_property_ui_text( - prop, "For Transform", "Transforms are affected by this constraint as well"); + prop, "Affect Transform", "Transforms are affected by this constraint as well"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); RNA_define_lib_overridable(false); @@ -2684,7 +2684,7 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna) prop = RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LIMITDIST_TRANSFORM); RNA_def_property_ui_text( - prop, "For Transform", "Transforms are affected by this constraint as well"); + prop, "Affect Transform", "Transforms are affected by this constraint as well"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); RNA_define_lib_overridable(false); @@ -3380,7 +3380,7 @@ void RNA_def_constraint(BlenderRNA *brna) prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_EXPAND); + RNA_def_property_boolean_sdna(prop, NULL, "ui_expand_flag", 0); RNA_def_property_ui_text(prop, "Expanded", "Constraint's panel is expanded in UI"); RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1); diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 8b2658c7e0c..771235c85aa 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -687,7 +687,8 @@ static Nurb *rna_Curve_spline_new(Curve *cu, int type) nu->pntsv = 1; nu->orderu = nu->orderv = 4; - nu->resolu = nu->resolv = 12; + nu->resolu = cu->resolu; + nu->resolv = cu->resolv; nu->flag = CU_SMOOTH; if ((cu->flag & CU_3D) == 0) { @@ -1533,6 +1534,8 @@ static void rna_def_curve(BlenderRNA *brna) prop = RNA_def_property(srna, "shape_keys", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "key"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Shape Keys", ""); prop = RNA_def_property(srna, "splines", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_curveprofile.c b/source/blender/makesrna/intern/rna_curveprofile.c index 94a35bdede8..ce91fc79085 100644 --- a/source/blender/makesrna/intern/rna_curveprofile.c +++ b/source/blender/makesrna/intern/rna_curveprofile.c @@ -62,6 +62,22 @@ # include "IMB_colormanagement.h" # include "IMB_imbuf.h" +/** + * Set both handle types for all selected points in the profile-- faster than changing types + * for many points individually. Also set both handles for the points. + */ +static void rna_CurveProfilePoint_handle_type_set(PointerRNA *ptr, int value) +{ + CurveProfilePoint *point = ptr->data; + CurveProfile *profile = point->profile; + + if (profile) { + BKE_curveprofile_selected_handle_set(profile, value, value); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); + WM_main_add_notifier(NC_GEOM | ND_DATA, NULL); + } +} + static void rna_CurveProfile_clip_set(PointerRNA *ptr, bool value) { CurveProfile *profile = (CurveProfile *)ptr->data; @@ -73,7 +89,7 @@ static void rna_CurveProfile_clip_set(PointerRNA *ptr, bool value) profile->flag &= ~PROF_USE_CLIP; } - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_CLIP); } static void rna_CurveProfile_sample_straight_set(PointerRNA *ptr, bool value) @@ -87,7 +103,7 @@ static void rna_CurveProfile_sample_straight_set(PointerRNA *ptr, bool value) profile->flag &= ~PROF_SAMPLE_STRAIGHT_EDGES; } - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); } static void rna_CurveProfile_sample_even_set(PointerRNA *ptr, bool value) @@ -101,7 +117,7 @@ static void rna_CurveProfile_sample_even_set(PointerRNA *ptr, bool value) profile->flag &= ~PROF_SAMPLE_EVEN_LENGTHS; } - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_NONE); } static void rna_CurveProfile_remove_point(CurveProfile *profile, @@ -135,14 +151,16 @@ static void rna_CurveProfile_initialize(struct CurveProfile *profile, int segmen static void rna_CurveProfile_update(struct CurveProfile *profile) { - BKE_curveprofile_update(profile, false); + BKE_curveprofile_update(profile, PROF_UPDATE_REMOVE_DOUBLES | PROF_UPDATE_CLIP); } #else static const EnumPropertyItem prop_handle_type_items[] = { - {HD_AUTO, "AUTO", 0, "Auto Handle", ""}, - {HD_VECT, "VECTOR", 0, "Vector Handle", ""}, + {HD_AUTO, "AUTO", ICON_HANDLE_AUTO, "Auto Handle", ""}, + {HD_VECT, "VECTOR", ICON_HANDLE_VECTOR, "Vector Handle", ""}, + {HD_FREE, "FREE", ICON_HANDLE_FREE, "Free Handle", ""}, + {HD_ALIGN, "ALIGN", ICON_HANDLE_ALIGNED, "Aligned Free Handles", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -162,14 +180,14 @@ static void rna_def_curveprofilepoint(BlenderRNA *brna) prop = RNA_def_property(srna, "handle_type_1", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "h1"); RNA_def_property_enum_items(prop, prop_handle_type_items); - RNA_def_property_ui_text( - prop, "First Handle Type", "Path interpolation at this point: Bezier or vector"); + RNA_def_property_enum_funcs(prop, NULL, "rna_CurveProfilePoint_handle_type_set", NULL); + RNA_def_property_ui_text(prop, "First Handle Type", "Path interpolation at this point"); prop = RNA_def_property(srna, "handle_type_2", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "h2"); RNA_def_property_enum_items(prop, prop_handle_type_items); - RNA_def_property_ui_text( - prop, "Second Handle Type", "Path interpolation at this point: Bezier or vector"); + RNA_def_property_enum_funcs(prop, NULL, "rna_CurveProfilePoint_handle_type_set", NULL); + RNA_def_property_ui_text(prop, "Second Handle Type", "Path interpolation at this point"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PROF_SELECT); @@ -260,7 +278,7 @@ static void rna_def_curveprofile(BlenderRNA *brna) RNA_def_property_boolean_funcs(prop, NULL, "rna_CurveProfile_sample_even_set"); func = RNA_def_function(srna, "update", "rna_CurveProfile_update"); - RNA_def_function_ui_description(func, "Update the profile"); + RNA_def_function_ui_description(func, "Refresh internal data, remove doubles and clip points"); func = RNA_def_function(srna, "initialize", "rna_CurveProfile_initialize"); parm = RNA_def_int(func, diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index d6bedc61424..bb791dd6e2d 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -1324,7 +1324,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, switch (type) { case PROP_BOOLEAN: if (DefRNA.preprocess) { - if ((subtype & ~(PROP_LAYER_MEMBER)) != PROP_NONE) { + if ((subtype & ~PROP_LAYER_MEMBER) != PROP_NONE) { CLOG_ERROR(&LOG, "subtype does not apply to 'PROP_BOOLEAN' \"%s.%s\"", CONTAINER_RNA_ID(cont), @@ -1515,6 +1515,9 @@ void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag) void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag) { prop->flag &= ~flag; + if (flag & PROP_PTR_NO_OWNERSHIP) { + prop->flag_internal |= PROP_INTERN_PTR_OWNERSHIP_FORCED; + } } void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag) diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index e49186f4cb1..3ae16f8577a 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -687,7 +687,7 @@ static void rna_FModifier_start_frame_set(PointerRNA *ptr, float value) } } -static void rna_FModifer_end_frame_set(PointerRNA *ptr, float value) +static void rna_FModifier_end_frame_set(PointerRNA *ptr, float value) { FModifier *fcm = (FModifier *)ptr->data; @@ -1665,7 +1665,7 @@ static void rna_def_fmodifier(BlenderRNA *brna) prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "efra"); RNA_def_property_float_funcs( - prop, NULL, "rna_FModifer_end_frame_set", "rna_FModifier_end_frame_range"); + prop, NULL, "rna_FModifier_end_frame_set", "rna_FModifier_end_frame_range"); RNA_def_property_ui_text( prop, "End Frame", diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index 94ba09b2bb8..b4fa791362f 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -557,7 +557,7 @@ static const EnumPropertyItem *rna_Fluid_cachetype_mesh_itemf(bContext *UNUSED(C } static const EnumPropertyItem *rna_Fluid_cachetype_volume_itemf(bContext *UNUSED(C), - PointerRNA *UNUSED(ptr), + PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { @@ -579,11 +579,16 @@ static const EnumPropertyItem *rna_Fluid_cachetype_volume_itemf(bContext *UNUSED RNA_enum_item_add(&item, &totitem, &tmp); # endif - tmp.value = FLUID_DOMAIN_FILE_RAW; - tmp.identifier = "RAW"; - tmp.name = "Raw Cache"; - tmp.description = "Raw file format (.raw)"; - RNA_enum_item_add(&item, &totitem, &tmp); + /* Support for deprecated .raw format. */ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + if (mds->cache_data_format == FLUID_DOMAIN_FILE_RAW || + mds->cache_noise_format == FLUID_DOMAIN_FILE_RAW) { + tmp.value = FLUID_DOMAIN_FILE_RAW; + tmp.identifier = "RAW"; + tmp.name = "Raw Cache"; + tmp.description = "Raw file format (.raw)"; + RNA_enum_item_add(&item, &totitem, &tmp); + } RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -1058,27 +1063,18 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) }; static EnumPropertyItem cache_types[] = { - {FLUID_DOMAIN_CACHE_REPLAY, - "REPLAY", - 0, - "Replay", - "Use the timeline to bake the scene. Pausing and resuming possible"}, + {FLUID_DOMAIN_CACHE_REPLAY, "REPLAY", 0, "Replay", "Use the timeline to bake the scene"}, {FLUID_DOMAIN_CACHE_MODULAR, "MODULAR", 0, "Modular", - "Bake every stage of the simulation separately. Pausing and resuming possible"}, - {FLUID_DOMAIN_CACHE_FINAL, - "FINAL", - 0, - "Final", - "Bake the entire simulation at once. Only generates the most essential cache files. " - "Pausing and resuming not possible"}, + "Bake every stage of the simulation separately"}, + {FLUID_DOMAIN_CACHE_ALL, "ALL", 0, "All", "Bake all simulation settings at once"}, {0, NULL, 0, NULL, NULL}}; - static const EnumPropertyItem smoke_data_depth_items[] = { - {16, "16", 0, "Float (Half)", "Half float (16 bit data)"}, - {0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */ + static const EnumPropertyItem fluid_data_depth_items[] = { + {VDB_PRECISION_HALF_FLOAT, "16", 0, "Half", "Half float (16 bit data)"}, + {VDB_PRECISION_FULL_FLOAT, "32", 0, "Full", "Full float (32 bit data)"}, {0, NULL, 0, NULL, NULL}, }; @@ -2072,6 +2068,16 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Type", "Change the cache type of the simulation"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_domain_reset"); + prop = RNA_def_property(srna, "cache_resumable", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_RESUMABLE_CACHE); + RNA_def_property_ui_text( + prop, + "Resumable", + "Additional data will be saved so that the bake jobs can be resumed after pausing. Because " + "more data will be written to disk it is recommended to avoid enabling this option when " + "baking at high resolutions"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset"); + prop = RNA_def_property(srna, "cache_directory", PROP_STRING, PROP_DIRPATH); RNA_def_property_string_maxlength(prop, FILE_MAX); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Fluid_cache_directory_set"); @@ -2320,13 +2326,13 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) /* OpenVDB options */ prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp"); + RNA_def_property_enum_sdna(prop, NULL, "openvdb_compression"); RNA_def_property_enum_items(prop, prop_compression_items); - RNA_def_property_ui_text(prop, "Compression", "Compression method to be used"); + RNA_def_property_ui_text(prop, "Compression", "facession method to be used"); - prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth"); - RNA_def_property_enum_items(prop, smoke_data_depth_items); + prop = RNA_def_property(srna, "openvdb_data_depth", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "openvdb_data_depth"); + RNA_def_property_enum_items(prop, fluid_data_depth_items); RNA_def_property_ui_text(prop, "Data Depth", "Bit depth for writing all scalar (including vector) " diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index c707ad9b84e..c8d16ab65cc 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1011,6 +1011,12 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna) RNA_def_property_ui_text(prop, "UV Rotation", "Internal UV factor for dot mode"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + prop = RNA_def_property(srna, "uv_fill", PROP_FLOAT, PROP_XYZ); + RNA_def_property_float_sdna(prop, NULL, "uv_fill"); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "UV Fill", "Internal UV factor for filling"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SPOINT_SELECT); RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_point_select_set"); diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 3a8ded1a275..1c39ad3a1a8 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -128,12 +128,12 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { ICON_MOD_OPACITY, "Opacity", "Opacity of the strokes"}, - {eGpencilModifierType_Tint, "GP_TINT", ICON_MOD_TINT, "Tint", "Tint strokes with new color"}, {eGpencilModifierType_Texture, "GP_TEXTURE", ICON_TEXTURE, "Texture Mapping", "Change stroke uv texture values"}, + {eGpencilModifierType_Tint, "GP_TINT", ICON_MOD_TINT, "Tint", "Tint strokes with new color"}, {0, NULL, 0, NULL, NULL}, }; @@ -1490,7 +1490,7 @@ static void rna_def_modifier_gpencilarray(BlenderRNA *brna) RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "relative_offset", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "relative_offset", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "shift"); RNA_def_property_ui_text( prop, @@ -2127,8 +2127,7 @@ static void rna_def_modifier_gpencilmultiply(BlenderRNA *brna) prop = RNA_def_property(srna, "use_fade", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", GP_MULTIPLY_ENABLE_FADING); - RNA_def_property_ui_text( - prop, "Enable Fade", "Fade the stroke thickness for each generated stroke"); + RNA_def_property_ui_text(prop, "Fade", "Fade the stroke thickness for each generated stroke"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_ANGLE); @@ -2183,12 +2182,12 @@ static void rna_def_modifier_gpenciltexture(BlenderRNA *brna) {GP_TEX_CONSTANT_LENGTH, "CONSTANT_LENGTH", 0, - "Keep Texture at Constant Length", + "Constant Length", "Keep the texture at a constant length regardless of the length of each stroke"}, {GP_TEX_FIT_STROKE, "FIT_STROKE", 0, - "Fit Texture to Stroke Length", + "Stroke Length", "Scale the texture to fit the length of each stroke"}, {0, NULL, 0, NULL, NULL}, }; @@ -2269,7 +2268,7 @@ static void rna_def_modifier_gpenciltexture(BlenderRNA *brna) RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_ui_range(prop, -100.0, 100.0, 0.1, 3); RNA_def_property_float_default(prop, 0.0f); - RNA_def_property_ui_text(prop, "Offset UVs", "Offset value to add to stroke UVs"); + RNA_def_property_ui_text(prop, "UV Offset", "Offset value to add to stroke UVs"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "uv_scale", PROP_FLOAT, PROP_NONE); @@ -2360,7 +2359,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna) prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); - RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Expanded); + RNA_def_property_boolean_sdna(prop, NULL, "ui_expand_flag", 0); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Expanded", "Set modifier expanded in the user interface"); RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1); diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index cbc376c863f..887bded8540 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -915,13 +915,13 @@ static void rna_def_image(BlenderRNA *brna) prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); - RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_string_sdna(prop, NULL, "filepath"); RNA_def_property_ui_text(prop, "File Name", "Image/Movie file name"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update"); /* eek. this is horrible but needed so we can save to a new name without blanking the data :( */ prop = RNA_def_property(srna, "filepath_raw", PROP_STRING, PROP_FILEPATH); - RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_string_sdna(prop, NULL, "filepath"); RNA_def_property_ui_text(prop, "File Name", "Image/Movie file name (without data refreshing)"); prop = RNA_def_property(srna, "file_format", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index fe3ef21d15e..41c0e724234 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -116,7 +116,7 @@ static void rna_Image_save(Image *image, Main *bmain, bContext *C, ReportList *r ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); if (ibuf) { char filename[FILE_MAX]; - BLI_strncpy(filename, image->name, sizeof(filename)); + BLI_strncpy(filename, image->filepath, sizeof(filename)); BLI_path_abs(filename, ID_BLEND_PATH(bmain, &image->id)); /* note, we purposefully ignore packed files here, @@ -138,7 +138,7 @@ static void rna_Image_save(Image *image, Main *bmain, bContext *C, ReportList *r RPT_ERROR, "Image '%s' could not be saved to '%s'", image->id.name + 2, - image->name); + image->filepath); } } else { diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 381cee64d80..71971cf3cca 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -499,6 +499,7 @@ int rna_property_override_diff_default(struct Main *bmain, const int mode, struct IDOverrideLibrary *override, const char *rna_path, + const size_t rna_path_len, const int flags, bool *r_override_changed); diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index 0e3fc851a9b..345d84fc5b1 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -176,6 +176,7 @@ typedef int (*RNAPropOverrideDiff)(struct Main *bmain, const int mode, struct IDOverrideLibrary *override, const char *rna_path, + const size_t rna_path_len, const int flags, bool *r_override_changed); @@ -328,6 +329,9 @@ typedef enum PropertyFlagIntern { PROP_INTERN_RAW_ACCESS = (1 << 2), PROP_INTERN_RAW_ARRAY = (1 << 3), PROP_INTERN_FREE_POINTERS = (1 << 4), + /* Negative mirror of PROP_PTR_NO_OWNERSHIP, used to prevent automatically setting that one in + * makesrna when pointer is an ID... */ + PROP_INTERN_PTR_OWNERSHIP_FORCED = (1 << 5), } PropertyFlagIntern; /* Property Types */ diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index 7955109d9bc..f0de7317913 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -918,6 +918,7 @@ static void rna_def_keyblock(BlenderRNA *brna) * (to test results) */ prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "curval"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_float_funcs(prop, NULL, "rna_ShapeKey_value_set", "rna_ShapeKey_value_range"); RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3); RNA_def_property_ui_text(prop, "Value", "Value of shape key at the current frame"); @@ -944,6 +945,7 @@ static void rna_def_keyblock(BlenderRNA *brna) prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYBLOCK_MUTE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Mute", "Toggle this shape key"); RNA_def_property_ui_icon(prop, ICON_CHECKBOX_HLT, -1); RNA_def_property_update(prop, 0, "rna_Key_update_data"); @@ -966,6 +968,7 @@ static void rna_def_keyblock(BlenderRNA *brna) prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "data", "totelem"); RNA_def_property_struct_type(prop, "UnknownType"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Data", ""); RNA_def_property_collection_funcs(prop, "rna_ShapeKey_data_begin", @@ -1028,6 +1031,7 @@ static void rna_def_key(BlenderRNA *brna) prop = RNA_def_property(srna, "key_blocks", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "block", NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_struct_type(prop, "ShapeKey"); RNA_def_property_ui_text(prop, "Key Blocks", "Shape keys"); @@ -1051,6 +1055,7 @@ static void rna_def_key(BlenderRNA *brna) prop = RNA_def_property(srna, "eval_time", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "ctime"); RNA_def_property_range(prop, MINFRAME, MAXFRAME); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Evaluation Time", "Evaluation time for absolute shape keys"); RNA_def_property_update(prop, 0, "rna_Key_update_data"); } diff --git a/source/blender/makesrna/intern/rna_lattice.c b/source/blender/makesrna/intern/rna_lattice.c index 176fb838e91..fbbee1f5900 100644 --- a/source/blender/makesrna/intern/rna_lattice.c +++ b/source/blender/makesrna/intern/rna_lattice.c @@ -382,6 +382,8 @@ static void rna_def_lattice(BlenderRNA *brna) prop = RNA_def_property(srna, "shape_keys", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "key"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Shape Keys", ""); prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c index 2caf315e09e..e43079c967f 100644 --- a/source/blender/makesrna/intern/rna_light.c +++ b/source/blender/makesrna/intern/rna_light.c @@ -173,6 +173,7 @@ static void rna_def_light(BlenderRNA *brna) /* nodes */ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based lights"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index 788246f5edd..64c50b82d1f 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -2188,6 +2188,7 @@ static void rna_def_linestyle(BlenderRNA *brna) /* nodes */ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node-based shaders"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index 2f37e4079c7..1670e08325f 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -109,9 +109,7 @@ RNA_MAIN_LISTBASE_FUNCS_DEF(collections) RNA_MAIN_LISTBASE_FUNCS_DEF(curves) RNA_MAIN_LISTBASE_FUNCS_DEF(fonts) RNA_MAIN_LISTBASE_FUNCS_DEF(gpencils) -# ifdef WITH_NEW_OBJECT_TYPES RNA_MAIN_LISTBASE_FUNCS_DEF(hairs) -# endif RNA_MAIN_LISTBASE_FUNCS_DEF(images) RNA_MAIN_LISTBASE_FUNCS_DEF(lattices) RNA_MAIN_LISTBASE_FUNCS_DEF(libraries) @@ -128,15 +126,11 @@ RNA_MAIN_LISTBASE_FUNCS_DEF(objects) RNA_MAIN_LISTBASE_FUNCS_DEF(paintcurves) RNA_MAIN_LISTBASE_FUNCS_DEF(palettes) RNA_MAIN_LISTBASE_FUNCS_DEF(particles) -# ifdef WITH_NEW_OBJECT_TYPES RNA_MAIN_LISTBASE_FUNCS_DEF(pointclouds) -# endif RNA_MAIN_LISTBASE_FUNCS_DEF(scenes) RNA_MAIN_LISTBASE_FUNCS_DEF(screens) RNA_MAIN_LISTBASE_FUNCS_DEF(shapekeys) -# ifdef WITH_NEW_SIMULATION_TYPE RNA_MAIN_LISTBASE_FUNCS_DEF(simulations) -# endif RNA_MAIN_LISTBASE_FUNCS_DEF(sounds) RNA_MAIN_LISTBASE_FUNCS_DEF(speakers) RNA_MAIN_LISTBASE_FUNCS_DEF(texts) @@ -390,7 +384,6 @@ void RNA_def_main(BlenderRNA *brna) "LightProbes", "LightProbe data-blocks", RNA_def_main_lightprobes}, -# ifdef WITH_NEW_OBJECT_TYPES {"hairs", "Hair", "rna_Main_hairs_begin", "Hairs", "Hair data-blocks", RNA_def_main_hairs}, {"pointclouds", "PointCloud", @@ -398,21 +391,18 @@ void RNA_def_main(BlenderRNA *brna) "Point Clouds", "Point cloud data-blocks", RNA_def_main_pointclouds}, -# endif {"volumes", "Volume", "rna_Main_volumes_begin", "Volumes", "Volume data-blocks", RNA_def_main_volumes}, -# ifdef WITH_NEW_SIMULATION_TYPE {"simulations", "Simulation", "rna_Main_simulations_begin", "Simulations", "Simulation data-blocks", RNA_def_main_simulations}, -# endif {NULL, NULL, NULL, NULL, NULL, NULL}, }; @@ -455,7 +445,7 @@ void RNA_def_main(BlenderRNA *brna) 0, INT_MAX, "Version", - "Version of Blender the .blend was saved with", + "File format version the .blend file was saved with", 0, INT_MAX); RNA_def_property_int_funcs(prop, "rna_Main_version_get", NULL, NULL); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 093fd8b3bd5..990a5412093 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -708,7 +708,6 @@ static bGPdata *rna_Main_gpencils_new(Main *bmain, const char *name) return gpd; } -# ifdef WITH_NEW_OBJECT_TYPES static Hair *rna_Main_hairs_new(Main *bmain, const char *name) { char safe_name[MAX_ID_NAME - 2]; @@ -728,7 +727,6 @@ static PointCloud *rna_Main_pointclouds_new(Main *bmain, const char *name) id_us_min(&pointcloud->id); return pointcloud; } -# endif static Volume *rna_Main_volumes_new(Main *bmain, const char *name) { @@ -740,7 +738,6 @@ static Volume *rna_Main_volumes_new(Main *bmain, const char *name) return volume; } -# ifdef WITH_NEW_SIMULATION_TYPE static Simulation *rna_Main_simulations_new(Main *bmain, const char *name) { char safe_name[MAX_ID_NAME - 2]; @@ -750,7 +747,6 @@ static Simulation *rna_Main_simulations_new(Main *bmain, const char *name) id_us_min(&simulation->id); return simulation; } -# endif /* tag functions, all the same */ # define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \ @@ -794,14 +790,10 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(cachefiles, cachefiles, ID_CF) RNA_MAIN_ID_TAG_FUNCS_DEF(paintcurves, paintcurves, ID_PC) RNA_MAIN_ID_TAG_FUNCS_DEF(workspaces, workspaces, ID_WS) RNA_MAIN_ID_TAG_FUNCS_DEF(lightprobes, lightprobes, ID_LP) -# ifdef WITH_NEW_OBJECT_TYPES RNA_MAIN_ID_TAG_FUNCS_DEF(hairs, hairs, ID_HA) RNA_MAIN_ID_TAG_FUNCS_DEF(pointclouds, pointclouds, ID_PT) -# endif RNA_MAIN_ID_TAG_FUNCS_DEF(volumes, volumes, ID_VO) -# ifdef WITH_NEW_SIMULATION_TYPE RNA_MAIN_ID_TAG_FUNCS_DEF(simulations, simulations, ID_SIM) -# endif # undef RNA_MAIN_ID_TAG_FUNCS_DEF diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 5191869be3a..1004fc94d16 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -542,7 +542,7 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_ONIONSKIN); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_HIDE_ONIONSKIN); RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0); RNA_def_property_ui_text( prop, "Show in Ghosts", "Display strokes using this color when showing onion skins"); @@ -784,6 +784,7 @@ void RNA_def_material(BlenderRNA *brna) /* nodetree */ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based materials"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 5f986c28964..506bfdb8c75 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -721,8 +721,6 @@ static void rna_MeshUVLoopLayer_clone_set(PointerRNA *ptr, bool value) DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_color, ldata, CD_MLOOPCOL) DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM( vertex_color, ldata, CD_MLOOPCOL, active, MeshLoopColorLayer) -DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM( - vertex_color, ldata, CD_MLOOPCOL, render, MeshLoopColorLayer) static void rna_MeshLoopColorLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { @@ -758,6 +756,46 @@ static void rna_MeshLoopColorLayer_active_set(PointerRNA *ptr, bool value) rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPCOL, 0); } +/* sculpt_vertex_color_layers */ + +DEFINE_CUSTOMDATA_LAYER_COLLECTION(sculpt_vertex_color, vdata, CD_PROP_COLOR) +DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM( + sculpt_vertex_color, vdata, CD_PROP_COLOR, active, MeshVertColorLayer) + +static void rna_MeshVertColorLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + CustomDataLayer *layer = (CustomDataLayer *)ptr->data; + rna_iterator_array_begin( + iter, layer->data, sizeof(MPropCol), (me->edit_mesh) ? 0 : me->totvert, 0, NULL); +} + +static int rna_MeshVertColorLayer_data_length(PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + return (me->edit_mesh) ? 0 : me->totvert; +} + +static bool rna_MeshVertColorLayer_active_render_get(PointerRNA *ptr) +{ + return rna_CustomDataLayer_active_get(ptr, rna_mesh_vdata(ptr), CD_PROP_COLOR, 1); +} + +static bool rna_MeshVertColorLayer_active_get(PointerRNA *ptr) +{ + return rna_CustomDataLayer_active_get(ptr, rna_mesh_vdata(ptr), CD_PROP_COLOR, 0); +} + +static void rna_MeshVertColorLayer_active_render_set(PointerRNA *ptr, bool value) +{ + rna_CustomDataLayer_active_set(ptr, rna_mesh_vdata(ptr), value, CD_PROP_COLOR, 1); +} + +static void rna_MeshVertColorLayer_active_set(PointerRNA *ptr, bool value) +{ + rna_CustomDataLayer_active_set(ptr, rna_mesh_vdata(ptr), value, CD_PROP_COLOR, 0); +} + static int rna_float_layer_check(CollectionPropertyIterator *UNUSED(iter), void *data) { CustomDataLayer *layer = (CustomDataLayer *)data; @@ -1218,6 +1256,19 @@ static char *rna_MeshColor_path(PointerRNA *ptr) return rna_LoopCustomData_data_path(ptr, "vertex_colors", CD_MLOOPCOL); } +static char *rna_MeshVertColorLayer_path(PointerRNA *ptr) +{ + CustomDataLayer *cdl = ptr->data; + char name_esc[sizeof(cdl->name) * 2]; + BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + return BLI_sprintfN("sculpt_vertex_colors[\"%s\"]", name_esc); +} + +static char *rna_MeshVertColor_path(PointerRNA *ptr) +{ + return rna_VertCustomData_data_path(ptr, "sculpt_vertex_colors", CD_PROP_COLOR); +} + /**** Float Property Layer API ****/ static char *rna_MeshVertexFloatPropertyLayer_path(PointerRNA *ptr) { @@ -1439,6 +1490,33 @@ static void rna_Mesh_vertex_color_remove(struct Mesh *me, } } +static PointerRNA rna_Mesh_sculpt_vertex_color_new(struct Mesh *me, + const char *name, + const bool do_init) +{ + PointerRNA ptr; + CustomData *vdata; + CustomDataLayer *cdl = NULL; + int index = ED_mesh_sculpt_color_add(me, name, false, do_init); + + if (index != -1) { + vdata = rna_mesh_vdata_helper(me); + cdl = &vdata->layers[CustomData_get_layer_index_n(vdata, CD_PROP_COLOR, index)]; + } + + RNA_pointer_create(&me->id, &RNA_MeshVertColorLayer, cdl, &ptr); + return ptr; +} + +static void rna_Mesh_sculpt_vertex_color_remove(struct Mesh *me, + ReportList *reports, + CustomDataLayer *layer) +{ + if (ED_mesh_sculpt_color_remove_named(me, layer->name) == false) { + BKE_reportf(reports, RPT_ERROR, "Sculpt vertex color '%s' not found", layer->name); + } +} + # define DEFINE_CUSTOMDATA_PROPERTY_API( \ elemname, datatype, cd_prop_type, cdata, countvar, layertype) \ static PointerRNA rna_Mesh_##elemname##_##datatype##_property_new(struct Mesh *me, \ @@ -1510,10 +1588,6 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void) (void)rna_Mesh_uv_layer_render_index_get; (void)rna_Mesh_uv_layer_render_index_set; (void)rna_Mesh_uv_layer_render_set; - (void)rna_Mesh_vertex_color_render_get; - (void)rna_Mesh_vertex_color_render_index_get; - (void)rna_Mesh_vertex_color_render_index_set; - (void)rna_Mesh_vertex_color_render_set; (void)rna_Mesh_face_map_index_range; (void)rna_Mesh_face_map_active_index_set; (void)rna_Mesh_face_map_active_index_get; @@ -2034,6 +2108,65 @@ static void rna_def_mloopcol(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); } +static void rna_def_MPropCol(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "MeshVertColorLayer", NULL); + RNA_def_struct_ui_text(srna, + "Mesh Sculpt Vertex Color Layer", + "Layer of sculpt vertex colors in a Mesh data-block"); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_path_func(srna, "rna_MeshVertColorLayer_path"); + RNA_def_struct_ui_icon(srna, ICON_GROUP_VCOL); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshVertexLayer_name_set"); + RNA_def_property_ui_text(prop, "Name", "Name of Sculpt Vertex color layer"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); + + prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_MeshVertColorLayer_active_get", "rna_MeshVertColorLayer_active_set"); + RNA_def_property_ui_text( + prop, "Active", "Sets the sculpt vertex color layer as active for display and editing"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); + + prop = RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0); + RNA_def_property_boolean_funcs(prop, + "rna_MeshVertColorLayer_active_render_get", + "rna_MeshVertColorLayer_active_render_set"); + RNA_def_property_ui_text( + prop, "Active Render", "Sets the sculpt vertex color layer as active for rendering"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); + + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "MeshVertColor"); + RNA_def_property_ui_text(prop, "Data", ""); + RNA_def_property_collection_funcs(prop, + "rna_MeshVertColorLayer_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_MeshVertColorLayer_data_length", + NULL, + NULL, + NULL); + + srna = RNA_def_struct(brna, "MeshVertColor", NULL); + RNA_def_struct_sdna(srna, "MPropCol"); + RNA_def_struct_ui_text(srna, "Mesh Sculpt Vertex Color", "Vertex colors in a Mesh"); + RNA_def_struct_path_func(srna, "rna_MeshVertColor_path"); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_array(prop, 4); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Color", ""); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); +} static void rna_def_mproperties(BlenderRNA *brna) { StructRNA *srna; @@ -2373,6 +2506,60 @@ static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_update(prop, 0, "rna_Mesh_update_data_edit_active_color"); } +static void rna_def_vert_colors(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + PropertyRNA *prop; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "VertColors"); + srna = RNA_def_struct(brna, "VertColors", NULL); + RNA_def_struct_sdna(srna, "Mesh"); + RNA_def_struct_ui_text(srna, "Vert Colors", "Collection of sculpt vertex colors"); + + func = RNA_def_function(srna, "new", "rna_Mesh_sculpt_vertex_color_new"); + RNA_def_function_ui_description(func, "Add a sculpt vertex color layer to Mesh"); + RNA_def_string(func, "name", "Col", 0, "", "Sculpt Vertex color name"); + RNA_def_boolean(func, + "do_init", + true, + "", + "Whether new layer's data should be initialized by copying current active one"); + parm = RNA_def_pointer(func, "layer", "MeshVertColorLayer", "", "The newly created layer"); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "rna_Mesh_sculpt_vertex_color_remove"); + RNA_def_function_ui_description(func, "Remove a vertex color layer"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "layer", "MeshVertColorLayer", "", "The layer to remove"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "MeshVertColorLayer"); + RNA_def_property_pointer_funcs(prop, + "rna_Mesh_sculpt_vertex_color_active_get", + "rna_Mesh_sculpt_vertex_color_active_set", + NULL, + NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); + RNA_def_property_ui_text( + prop, "Active Sculpt Vertex Color Layer", "Active sculpt vertex color layer"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data_edit_active_color"); + + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_funcs(prop, + "rna_Mesh_sculpt_vertex_color_active_index_get", + "rna_Mesh_sculpt_vertex_color_active_index_set", + "rna_Mesh_sculpt_vertex_color_index_range"); + RNA_def_property_ui_text( + prop, "Active Sculpt Vertex Color Index", "Active sculpt vertex color index"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data_edit_active_color"); +} + static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; @@ -2739,30 +2926,35 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "vertices", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "mvert", "totvert"); RNA_def_property_struct_type(prop, "MeshVertex"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Vertices", "Vertices of the mesh"); rna_def_mesh_vertices(brna, prop); prop = RNA_def_property(srna, "edges", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "medge", "totedge"); RNA_def_property_struct_type(prop, "MeshEdge"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Edges", "Edges of the mesh"); rna_def_mesh_edges(brna, prop); prop = RNA_def_property(srna, "loops", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "mloop", "totloop"); RNA_def_property_struct_type(prop, "MeshLoop"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Loops", "Loops of the mesh (polygon corners)"); rna_def_mesh_loops(brna, prop); prop = RNA_def_property(srna, "polygons", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "mpoly", "totpoly"); RNA_def_property_struct_type(prop, "MeshPolygon"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Polygons", "Polygons of the mesh"); rna_def_mesh_polygons(brna, prop); prop = RNA_def_property(srna, "loop_triangles", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "runtime.looptris.array", "runtime.looptris.len"); RNA_def_property_struct_type(prop, "MeshLoopTriangle"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Loop Triangles", "Tessellation of mesh polygons into triangles"); rna_def_mesh_looptris(brna, prop); @@ -2789,6 +2981,7 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshUVLoopLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "UV Loop Layers", "All UV loop layers"); rna_def_uv_layers(brna, prop); @@ -2836,9 +3029,27 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshLoopColorLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Vertex Colors", "All vertex colors"); rna_def_loop_colors(brna, prop); + /* Sculpt Vertex colors */ + + prop = RNA_def_property(srna, "sculpt_vertex_colors", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer"); + RNA_def_property_collection_funcs(prop, + "rna_Mesh_sculpt_vertex_colors_begin", + NULL, + NULL, + NULL, + "rna_Mesh_sculpt_vertex_colors_length", + NULL, + NULL, + NULL); + RNA_def_property_struct_type(prop, "MeshVertColorLayer"); + RNA_def_property_ui_text(prop, "Sculpt Vertex Colors", "All vertex colors"); + rna_def_vert_colors(brna, prop); + /* TODO, edge customdata layers (bmesh py api can access already) */ prop = RNA_def_property(srna, "vertex_layers_float", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer"); @@ -2852,6 +3063,7 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshVertexFloatPropertyLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Float Property Layers", ""); rna_def_vertex_float_layers(brna, prop); @@ -2867,6 +3079,7 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshVertexIntPropertyLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Int Property Layers", ""); rna_def_vertex_int_layers(brna, prop); @@ -2882,6 +3095,7 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshVertexStringPropertyLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "String Property Layers", ""); rna_def_vertex_string_layers(brna, prop); @@ -2897,6 +3111,7 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshPolygonFloatPropertyLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Float Property Layers", ""); rna_def_polygon_float_layers(brna, prop); @@ -2912,6 +3127,7 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshPolygonIntPropertyLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Int Property Layers", ""); rna_def_polygon_int_layers(brna, prop); @@ -2927,6 +3143,7 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshPolygonStringPropertyLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "String Property Layers", ""); rna_def_polygon_string_layers(brna, prop); @@ -2943,6 +3160,7 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshFaceMapLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "FaceMap", ""); rna_def_face_maps(brna, prop); @@ -2959,6 +3177,7 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshSkinVertexLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Skin Vertices", "All skin vertices"); rna_def_skin_vertices(brna, prop); /* End skin vertices */ @@ -2976,6 +3195,7 @@ static void rna_def_mesh(BlenderRNA *brna) NULL, NULL); RNA_def_property_struct_type(prop, "MeshPaintMaskLayer"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Vertex Paint Mask", "Vertex paint mask"); rna_def_paint_mask(brna, prop); /* End paint mask */ @@ -3033,6 +3253,13 @@ static void rna_def_mesh(BlenderRNA *brna) prop, "Preserve Face Sets", "Keep the current Face Sets on the new mesh"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + prop = RNA_def_property(srna, "use_remesh_preserve_vertex_colors", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_VERTEX_COLORS); + RNA_def_property_boolean_default(prop, false); + RNA_def_property_ui_text( + prop, "Preserve Vertex Colors", "Keep the current vertex colors on the new mesh"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + prop = RNA_def_property(srna, "remesh_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "remesh_mode"); RNA_def_property_enum_items(prop, rna_enum_mesh_remesh_mode_items); @@ -3077,6 +3304,8 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "shape_keys", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "key"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Shape Keys", ""); /* texture space */ @@ -3183,6 +3412,7 @@ void RNA_def_mesh(BlenderRNA *brna) rna_def_mpolygon(brna); rna_def_mloopuv(brna); rna_def_mloopcol(brna); + rna_def_MPropCol(brna); rna_def_mproperties(brna); rna_def_face_map(brna); } diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index ffd9bb772cc..57e46314777 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -290,13 +290,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = { "Spawn particles from the shape"}, {eModifierType_Softbody, "SOFT_BODY", ICON_MOD_SOFT, "Soft Body", ""}, {eModifierType_Surface, "SURFACE", ICON_MODIFIER, "Surface", ""}, -#ifdef WITH_NEW_SIMULATION_TYPE {eModifierType_Simulation, "SIMULATION", ICON_PHYSICS, "Simulation", ""}, /* TODO: Use correct icon. */ -#endif {0, NULL, 0, NULL, NULL}, }; @@ -1163,7 +1161,7 @@ static PointerRNA rna_CollisionModifier_settings_get(PointerRNA *ptr) static void rna_BevelModifier_update_segments(Main *bmain, Scene *scene, PointerRNA *ptr) { BevelModifierData *bmd = (BevelModifierData *)ptr->data; - if (RNA_boolean_get(ptr, "use_custom_profile")) { + if (RNA_enum_get(ptr, "profile_type") == MOD_BEVEL_PROFILE_CUSTOM) { short segments = (short)RNA_int_get(ptr, "segments"); BKE_curveprofile_initialize(bmd->custom_profile, segments); } @@ -1632,7 +1630,6 @@ static void rna_ParticleInstanceModifier_particle_system_set(PointerRNA *ptr, CLAMP_MIN(psmd->psys, 1); } -# ifdef WITH_NEW_SIMULATION_TYPE static void rna_SimulationModifier_simulation_update(Main *bmain, Scene *scene, PointerRNA *ptr) { SimulationModifierData *smd = ptr->data; @@ -1641,11 +1638,10 @@ static void rna_SimulationModifier_simulation_update(Main *bmain, Scene *scene, } rna_Modifier_dependency_update(bmain, scene, ptr); } -# endif /** * Special set callback that just changes the first bit of the expansion flag. - * This way the expansion state of all the subpanels is not changed by RNA. + * This way the expansion state of all the sub-panels is not changed by RNA. */ static void rna_Modifier_show_expanded_set(PointerRNA *ptr, bool value) { @@ -3948,6 +3944,25 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) 0, "Percent", "Amount is percent of adjacent edge length"}, + {MOD_BEVEL_AMT_ABSOLUTE, + "ABSOLUTE", + 0, + "Absolute", + "Amount is absolute distance along adjacent edge"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem prop_profile_type_items[] = { + {MOD_BEVEL_PROFILE_SUPERELLIPSE, + "SUPERELLIPSE", + 0, + "Superellipse", + "The profile can be a concave or convex curve"}, + {MOD_BEVEL_PROFILE_CUSTOM, + "CUSTOM", + 0, + "Custom", + "The profile can be any arbitrary path between its endpoints"}, {0, NULL, 0, NULL, NULL}, }; @@ -4061,6 +4076,13 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Width Type", "What distance Width measures"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "profile_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "profile_type"); + RNA_def_property_enum_items(prop, prop_profile_type_items); + RNA_def_property_ui_text( + prop, "Profile Type", "The type of shape used to rebuild a beveled section"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "profile", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.05, 2); @@ -4120,12 +4142,6 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Spread", "Spread distance for inner miter arcs"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); - prop = RNA_def_property(srna, "use_custom_profile", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_BEVEL_CUSTOM_PROFILE); - RNA_def_property_ui_text( - prop, "Custom Profile", "Whether to use a user inputted curve for the bevel's profile"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); - prop = RNA_def_property(srna, "custom_profile", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "CurveProfile"); RNA_def_property_pointer_sdna(prop, NULL, "custom_profile"); @@ -5021,7 +5037,7 @@ static void rna_def_modifier_weightvgedit(BlenderRNA *brna) {MOD_WVG_MAPPING_RANDOM, "RANDOM", ICON_RNDCURVE, "Random", ""}, {MOD_WVG_MAPPING_STEP, "STEP", - ICON_NOCURVE /* Would need a better icon... */, + ICON_IPO_CONSTANT, "Median Step", "Map all values below 0.5 to 0.0, and all others to 1.0"}, {0, NULL, 0, NULL, NULL}, @@ -5272,7 +5288,7 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) {MOD_WVG_MAPPING_RANDOM, "RANDOM", ICON_RNDCURVE, "Random", ""}, {MOD_WVG_MAPPING_STEP, "STEP", - ICON_NOCURVE /* Would need a better icon... */, + ICON_IPO_CONSTANT, "Median Step", "Map all values below 0.5 to 0.0, and all others to 1.0"}, {0, NULL, 0, NULL, NULL}, @@ -5438,6 +5454,7 @@ static void rna_def_modifier_remesh(BlenderRNA *brna) prop = RNA_def_property(srna, "voxel_size", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "voxel_size"); + RNA_def_property_range(prop, 0.0001f, FLT_MAX); RNA_def_property_ui_range(prop, 0.0001, 2, 0.1, 3); RNA_def_property_ui_text(prop, "Voxel Size", @@ -6818,12 +6835,10 @@ static void rna_def_modifier_simulation(BlenderRNA *brna) RNA_define_lib_overridable(true); -# ifdef WITH_NEW_SIMULATION_TYPE prop = RNA_def_property(srna, "simulation", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Simulation", "Simulation to access"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_update(prop, 0, "rna_SimulationModifier_simulation_update"); -# endif prop = RNA_def_property(srna, "data_path", PROP_STRING, PROP_NONE); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index f55d44e7bad..f3c73e75434 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -329,7 +329,7 @@ static void rna_def_movieclip(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_SEQUENCE); prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); - RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_string_sdna(prop, NULL, "filepath"); RNA_def_property_ui_text(prop, "File Path", "Filename of the movie or sequence file"); RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClip_reload_update"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 32999c91fad..6312c84cf9f 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3629,8 +3629,8 @@ static void rna_ShaderNodeTexIES_mode_set(PointerRNA *ptr, int value) if (node->id) { Text *text = (Text *)node->id; - if (value == NODE_IES_EXTERNAL && text->name) { - BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath)); + if (value == NODE_IES_EXTERNAL && text->filepath) { + BLI_strncpy(nss->filepath, text->filepath, sizeof(nss->filepath)); BLI_path_rel(nss->filepath, BKE_main_blendfile_path_from_global()); } @@ -3654,8 +3654,8 @@ static void rna_ShaderNodeScript_mode_set(PointerRNA *ptr, int value) if (node->id) { Text *text = (Text *)node->id; - if (value == NODE_SCRIPT_EXTERNAL && text->name) { - BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath)); + if (value == NODE_SCRIPT_EXTERNAL && text->filepath) { + BLI_strncpy(nss->filepath, text->filepath, sizeof(nss->filepath)); BLI_path_rel(nss->filepath, BKE_main_blendfile_path_from_global()); } @@ -4405,8 +4405,9 @@ static void def_sh_tex(StructRNA *srna) static void def_sh_tex_sky(StructRNA *srna) { static const EnumPropertyItem prop_sky_type[] = { - {SHD_SKY_OLD, "PREETHAM", 0, "Preetham", ""}, - {SHD_SKY_NEW, "HOSEK_WILKIE", 0, "Hosek / Wilkie", ""}, + {SHD_SKY_PREETHAM, "PREETHAM", 0, "Preetham", "Preetham 1999"}, + {SHD_SKY_HOSEK, "HOSEK_WILKIE", 0, "Hosek / Wilkie", "Hosek / Wilkie 2012"}, + {SHD_SKY_NISHITA, "NISHITA", 0, "Nishita", "Nishita 1993 improved"}, {0, NULL, 0, NULL, NULL}, }; static float default_dir[3] = {0.0f, 0.0f, 1.0f}; @@ -4419,7 +4420,7 @@ static void def_sh_tex_sky(StructRNA *srna) prop = RNA_def_property(srna, "sky_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "sky_model"); RNA_def_property_enum_items(prop, prop_sky_type); - RNA_def_property_ui_text(prop, "Sky Type", ""); + RNA_def_property_ui_text(prop, "Sky Type", "Which sky model should be used"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "sun_direction", PROP_FLOAT, PROP_DIRECTION); @@ -4439,6 +4440,54 @@ static void def_sh_tex_sky(StructRNA *srna) RNA_def_property_ui_text( prop, "Ground Albedo", "Ground color that is subtly reflected in the sky"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "sun_disc", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_ui_text(prop, "Sun Disc", "Include the sun itself in the output"); + RNA_def_property_boolean_sdna(prop, NULL, "sun_disc", 1); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "sun_size", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_ui_text(prop, "Sun Size", "Size of sun disc (angular diameter)"); + RNA_def_property_range(prop, 0.0f, M_PI_2); + RNA_def_property_float_default(prop, DEG2RADF(0.545)); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "sun_elevation", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_ui_text(prop, "Sun Elevation", "Angle between sun and horizon"); + RNA_def_property_range(prop, -M_PI_2, M_PI_2); + RNA_def_property_float_default(prop, M_PI_2); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "sun_rotation", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_ui_text(prop, "Sun Rotation", "Rotation of sun around zenith"); + RNA_def_property_range(prop, 0.0f, 2.0f * M_PI); + RNA_def_property_float_default(prop, 0.0f); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "altitude", PROP_INT, PROP_NONE); + RNA_def_property_ui_text(prop, "Altitude", "Altitude height from sea level in meters"); + RNA_def_property_range(prop, 0, 60000); + RNA_def_property_int_default(prop, 0); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "air_density", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_ui_text(prop, "Air", "Density of air molecules (Rayleigh scattering)"); + RNA_def_property_range(prop, 0.0f, 10.0f); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "dust_density", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_ui_text(prop, "Dust", "Density of dust and water molecules (Mie scattering)"); + RNA_def_property_range(prop, 0.0f, 10.0f); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "ozone_density", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_ui_text(prop, "Ozone", "Density of Ozone layer (Ozone absorption)"); + RNA_def_property_range(prop, 0.0f, 10.0f); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static const EnumPropertyItem sh_tex_prop_interpolation_items[] = { @@ -8971,7 +9020,7 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna) /* XXX These types should eventually be registered at runtime. * Then use the nodeStaticSocketType and nodeStaticSocketInterfaceType functions * to get the idname strings from int type and subtype - * (see node_socket.c, register_standard_node_socket_types). + * (see node_socket.cc, register_standard_node_socket_types). */ rna_def_node_socket_float(brna, "NodeSocketFloat", "NodeSocketInterfaceFloat", PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 79a9e0be051..089410ffd25 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -234,10 +234,8 @@ const EnumPropertyItem rna_enum_object_type_items[] = { OBTYPE_CU_SURF, {OB_MBALL, "META", 0, "Meta", ""}, OBTYPE_CU_FONT, -#ifdef WITH_NEW_OBJECT_TYPES {OB_HAIR, "HAIR", 0, "Hair", ""}, {OB_POINTCLOUD, "POINTCLOUD", 0, "PointCloud", ""}, -#endif {OB_VOLUME, "VOLUME", 0, "Volume", ""}, {0, "", 0, NULL, NULL}, {OB_ARMATURE, "ARMATURE", 0, "Armature", ""}, @@ -565,12 +563,10 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr) return &RNA_LightProbe; case OB_GPENCIL: return &RNA_GreasePencil; -# ifdef WITH_NEW_OBJECT_TYPES case OB_HAIR: return &RNA_Hair; case OB_POINTCLOUD: return &RNA_PointCloud; -# endif case OB_VOLUME: return &RNA_Volume; default: @@ -1501,6 +1497,17 @@ static void rna_Object_constraints_move( WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT, object); } +static bConstraint *rna_Object_constraints_copy(Object *object, Main *bmain, PointerRNA *con_ptr) +{ + bConstraint *con = con_ptr->data; + bConstraint *new_con = BKE_constraint_copy_for_object(object, con); + + ED_object_constraint_tag_update(bmain, object, new_con); + WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, object); + + return new_con; +} + bool rna_Object_constraints_override_apply(Main *UNUSED(bmain), PointerRNA *ptr_dst, PointerRNA *ptr_src, @@ -2134,6 +2141,8 @@ static void rna_def_material_slot(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Material Slot", "Material slot in an object"); RNA_def_struct_ui_icon(srna, ICON_MATERIAL_DATA); + RNA_define_lib_overridable(true); + /* WARNING! Order is crucial for override to work properly here... :/ * 'link' must come before material pointer, * since it defines where (in object or obdata) that one is set! */ @@ -2141,7 +2150,6 @@ static void rna_def_material_slot(BlenderRNA *brna) RNA_def_property_enum_items(prop, link_items); RNA_def_property_enum_funcs( prop, "rna_MaterialSlot_link_get", "rna_MaterialSlot_link_set", NULL); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Link", "Link material to object or the object's data"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update"); @@ -2149,7 +2157,6 @@ static void rna_def_material_slot(BlenderRNA *brna) RNA_def_property_struct_type(prop, "Material"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_editable_func(prop, "rna_MaterialSlot_material_editable"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", @@ -2163,8 +2170,12 @@ static void rna_def_material_slot(BlenderRNA *brna) prop, "rna_MaterialSlot_name_get", "rna_MaterialSlot_name_length", NULL); RNA_def_property_ui_text(prop, "Name", "Material slot name"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_struct_name_property(srna, prop); + RNA_define_lib_overridable(false); + RNA_def_struct_path_func(srna, "rna_MaterialSlot_path"); } @@ -2221,6 +2232,21 @@ static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "to_index", -1, INT_MIN, INT_MAX, "To Index", "Target index", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "copy", "rna_Object_constraints_copy"); + RNA_def_function_ui_description(func, "Add a new constraint that is a copy of the given one"); + RNA_def_function_flag(func, FUNC_USE_MAIN); + /* constraint to copy */ + parm = RNA_def_pointer(func, + "constraint", + "Constraint", + "", + "Constraint to copy - may belong to a different object"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + /* return type */ + parm = RNA_def_pointer(func, "new_constraint", "Constraint", "", "New constraint"); + RNA_def_function_return(func, parm); } /* object.modifiers */ @@ -2521,11 +2547,15 @@ static void rna_def_object_display(BlenderRNA *brna) RNA_def_struct_nested(brna, srna, "Object"); RNA_def_struct_path_func(srna, "rna_ObjectDisplay_path"); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "show_shadows", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "dtx", OB_DRAW_NO_SHADOW_CAST); RNA_def_property_boolean_default(prop, true); RNA_def_property_ui_text(prop, "Shadow", "Object cast shadows in the 3d viewport"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + RNA_define_lib_overridable(false); } static void rna_def_object(BlenderRNA *brna) @@ -2572,12 +2602,13 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT); RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "data", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "ID"); RNA_def_property_pointer_funcs( prop, NULL, "rna_Object_data_set", "rna_Object_data_typef", "rna_Object_data_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Data", "Object data"); RNA_def_property_update(prop, 0, "rna_Object_internal_update_data_dependency"); @@ -2585,6 +2616,7 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, rna_enum_object_type_items); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Type", "Type of Object"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); @@ -2598,6 +2630,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "bound_box", PROP_FLOAT, PROP_NONE); RNA_def_property_multi_array(prop, 2, boundbox_dimsize); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_float_funcs(prop, "rna_Object_boundbox_get", NULL, NULL); RNA_def_property_ui_text( prop, @@ -2609,7 +2642,6 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_parent_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_parent_override_apply"); RNA_def_property_ui_text(prop, "Parent", "Parent Object"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update"); @@ -2662,11 +2694,13 @@ static void rna_def_object(BlenderRNA *brna) /* proxy */ prop = RNA_def_property(srna, "proxy", PROP_POINTER, PROP_NONE); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Proxy", "Library object this proxy object controls"); prop = RNA_def_property(srna, "proxy_collection", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "proxy_group"); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Proxy Collection", "Library collection duplicator object this proxy object controls"); @@ -2674,8 +2708,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "material_slots", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol"); RNA_def_property_struct_type(prop, "MaterialSlot"); - RNA_def_property_override_flag(prop, - PROPOVERRIDE_OVERRIDABLE_LIBRARY | PROPOVERRIDE_NO_PROP_NAME); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_PROP_NAME); /* don't dereference pointer! */ RNA_def_property_collection_funcs( prop, NULL, NULL, NULL, "rna_iterator_array_get", NULL, NULL, NULL, NULL); @@ -2689,7 +2722,6 @@ static void rna_def_object(BlenderRNA *brna) NULL, "rna_MaterialSlot_material_poll"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_editable_func(prop, "rna_Object_active_material_editable"); RNA_def_property_ui_text(prop, "Active Material", "Active material being displayed"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update"); @@ -2697,7 +2729,6 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "active_material_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "actcol"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_int_funcs(prop, "rna_Object_active_material_index_get", "rna_Object_active_material_index_set", @@ -2709,7 +2740,6 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "loc"); RNA_def_property_editable_array_func(prop, "rna_Object_location_editable"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Location", "Location of the object"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2717,7 +2747,6 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION); RNA_def_property_float_sdna(prop, NULL, "quat"); RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2730,7 +2759,6 @@ static void rna_def_object(BlenderRNA *brna) prop, "rna_Object_rotation_axis_angle_get", "rna_Object_rotation_axis_angle_set", NULL); RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable"); RNA_def_property_float_array_default(prop, rna_default_axis_angle); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2738,7 +2766,6 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER); RNA_def_property_float_sdna(prop, NULL, "rot"); RNA_def_property_editable_array_func(prop, "rna_Object_rotation_euler_editable"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2751,7 +2778,6 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ); RNA_def_property_flag(prop, PROP_PROPORTIONAL); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_editable_array_func(prop, "rna_Object_scale_editable"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3); RNA_def_property_ui_text(prop, "Scale", "Scaling of the object"); @@ -2761,6 +2787,8 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_array(prop, 3); /* Only as convenient helper for py API, and conflicts with animating scale. */ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_float_funcs( prop, "rna_Object_dimensions_get", "rna_Object_dimensions_set", NULL); RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); @@ -2859,12 +2887,16 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "obmat"); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Matrix World", "Worldspace transformation matrix"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_matrix_world_update"); prop = RNA_def_property(srna, "matrix_local", PROP_FLOAT, PROP_MATRIX); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Local Matrix", @@ -2878,6 +2910,8 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "matrix_basis", PROP_FLOAT, PROP_MATRIX); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Input Matrix", "Matrix access to location, rotation and scale (including deltas), " @@ -2890,7 +2924,6 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "matrix_parent_inverse", PROP_FLOAT, PROP_MATRIX); RNA_def_property_float_sdna(prop, NULL, "parentinv"); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Parent Inverse Matrix", "Inverse of object's parent matrix at time of parenting"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2901,8 +2934,7 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Modifiers", "Modifiers affecting the geometric data of the object"); RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_modifiers_override_apply"); - RNA_def_property_override_flag( - prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY | PROPOVERRIDE_LIBRARY_INSERTION); + RNA_def_property_override_flag(prop, PROPOVERRIDE_LIBRARY_INSERTION); rna_def_object_modifiers(brna, prop); /* Grease Pencil modifiers. */ @@ -2913,8 +2945,7 @@ static void rna_def_object(BlenderRNA *brna) prop, "Grease Pencil Modifiers", "Modifiers affecting the data of the grease pencil object"); RNA_def_property_override_funcs( prop, NULL, NULL, "rna_Object_greasepencil_modifiers_override_apply"); - RNA_def_property_override_flag( - prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY | PROPOVERRIDE_LIBRARY_INSERTION); + RNA_def_property_override_flag(prop, PROPOVERRIDE_LIBRARY_INSERTION); rna_def_object_grease_pencil_modifiers(brna, prop); /* Shader FX. */ @@ -2922,13 +2953,14 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "shader_fx", NULL); RNA_def_property_struct_type(prop, "ShaderFx"); RNA_def_property_ui_text(prop, "Shader Effects", "Effects affecting display of object"); + RNA_define_lib_overridable(false); rna_def_object_shaderfxs(brna, prop); + RNA_define_lib_overridable(true); /* constraints */ prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Constraint"); - RNA_def_property_override_flag( - prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY | PROPOVERRIDE_LIBRARY_INSERTION); + RNA_def_property_override_flag(prop, PROPOVERRIDE_LIBRARY_INSERTION); RNA_def_property_ui_text( prop, "Constraints", "Constraints affecting the transformation of the object"); RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_constraints_override_apply"); @@ -2942,6 +2974,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "vertex_groups", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "defbase", NULL); RNA_def_property_struct_type(prop, "VertexGroup"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Vertex Groups", "Vertex groups of the object"); rna_def_object_vertex_groups(brna, prop); @@ -2949,6 +2982,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "face_maps", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "fmaps", NULL); RNA_def_property_struct_type(prop, "FaceMap"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Face Maps", "Maps of faces of the object"); rna_def_object_face_maps(brna, prop); @@ -3083,7 +3117,6 @@ static void rna_def_object(BlenderRNA *brna) /* restrict */ prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_VIEWPORT); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Disable in Viewports", "Globally disable in viewports"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update"); @@ -3091,14 +3124,12 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_SELECT); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Disable Selection", "Disable selection in viewport"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, -1); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update"); prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_RENDER); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Disable in Renders", "Globally disable in renders"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, -1); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update"); @@ -3115,12 +3146,6 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_update( prop, NC_OBJECT | ND_DRAW, "rna_Object_duplicator_visibility_flag_update"); - /* anim */ - rna_def_animdata_common(srna); - - rna_def_animviz_common(srna); - rna_def_motionpath_common(srna); - /* instancing */ prop = RNA_def_property(srna, "instance_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "transflag"); @@ -3150,7 +3175,6 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_struct_type(prop, "Collection"); RNA_def_property_pointer_sdna(prop, NULL, "instance_collection"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_dup_collection_set", NULL, NULL); RNA_def_property_ui_text(prop, "Instance Collection", "Instance an existing collection"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update"); @@ -3158,6 +3182,8 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "is_instancer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "transflag", OB_DUPLI); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* drawing */ prop = RNA_def_property(srna, "display_type", PROP_ENUM, PROP_NONE); @@ -3229,7 +3255,6 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "pose", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "pose"); RNA_def_property_struct_type(prop, "Pose"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Pose", "Current pose for armatures"); /* shape keys */ @@ -3249,6 +3274,8 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "active_shape_key", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "ShapeKey"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE | PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_pointer_funcs(prop, "rna_Object_active_shape_key_get", NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Active Shape Key", "Current shape key"); @@ -3273,11 +3300,15 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "base_flag", BASE_FROM_DUPLI); RNA_def_property_ui_text(prop, "Base from Instancer", "Object comes from a instancer"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); prop = RNA_def_property(srna, "is_from_set", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "base_flag", BASE_FROM_SET); RNA_def_property_ui_text(prop, "Base from Set", "Object comes from a background set"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* Object Display */ prop = RNA_def_property(srna, "display", PROP_POINTER, PROP_NONE); @@ -3286,6 +3317,14 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_Object_display_get", NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Object Display", "Object display settings for 3d viewport"); + RNA_define_lib_overridable(false); + + /* anim */ + rna_def_animdata_common(srna); + + rna_def_animviz_common(srna); + rna_def_motionpath_common(srna); + RNA_api_object(srna); } diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 30e0ba19608..0a4e714c2ef 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1517,6 +1517,15 @@ static void rna_def_field(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Flow", "Convert effector force into air flow velocity"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); + prop = RNA_def_property(srna, "wind_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "f_wind_factor"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text( + prop, + "Wind Factor", + "How much the force is reduced when acting parallel to a surface, e.g. cloth"); + RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); + /* different ui range to above */ prop = RNA_def_property(srna, "inflow", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f_flow"); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 8f28fc56712..8dd3670087a 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -637,6 +637,21 @@ static void rna_PoseChannel_constraints_move( WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT, ob); } +static bConstraint *rna_PoseChannel_constraints_copy(ID *id, + bPoseChannel *pchan, + Main *bmain, + PointerRNA *con_ptr) +{ + Object *ob = (Object *)id; + bConstraint *con = con_ptr->data; + bConstraint *new_con = BKE_constraint_copy_for_pose(ob, pchan, con); + + ED_object_constraint_dependency_tag_update(bmain, ob, new_con); + WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, id); + + return new_con; +} + bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain), PointerRNA *ptr_dst, PointerRNA *ptr_src, @@ -978,6 +993,21 @@ static void rna_def_pose_channel_constraints(BlenderRNA *brna, PropertyRNA *cpro RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "to_index", -1, INT_MIN, INT_MAX, "To Index", "Target index", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "copy", "rna_PoseChannel_constraints_copy"); + RNA_def_function_ui_description(func, "Add a new constraint that is a copy of the given one"); + RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_SELF_ID); + /* constraint to copy */ + parm = RNA_def_pointer(func, + "constraint", + "Constraint", + "", + "Constraint to copy - may belong to a different object"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + /* return type */ + parm = RNA_def_pointer(func, "new_constraint", "Constraint", "", "New constraint"); + RNA_def_function_return(func, parm); } static void rna_def_pose_channel(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 6af031eb7b0..a41abb1a1dd 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -299,7 +299,7 @@ static void rna_RenderEngine_unregister(Main *bmain, StructRNA *type) BLI_freelinkN(&R_engines, et); /* Stop all renders in case we were using this one. */ - ED_render_engine_changed(bmain); + ED_render_engine_changed(bmain, false); } static StructRNA *rna_RenderEngine_register(Main *bmain, diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index d7e93975d31..623b5864f5b 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -1133,6 +1133,7 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, * (if they are IDs, or have different names or RNA type, then this would be meaningless). */ static bool rna_property_override_diff_propptr_validate_diffing(PointerRNA *propptr_a, PointerRNA *propptr_b, + const bool no_ownership, const bool no_prop_name, bool *r_is_id, bool *r_is_null, @@ -1172,7 +1173,7 @@ static bool rna_property_override_diff_propptr_validate_diffing(PointerRNA *prop *r_is_id = RNA_struct_is_ID(propptr_a->type); *r_is_null = (ELEM(NULL, propptr_b, propptr_b->type, propptr_b->data)); *r_is_type_diff = (propptr_b == NULL || propptr_b->type != propptr_a->type); - is_valid_for_diffing = !(*r_is_id || *r_is_null); + is_valid_for_diffing = !((*r_is_id && no_ownership) || *r_is_null); } if (propptr_b == NULL || propptr_a->type != propptr_b->type) { @@ -1248,6 +1249,7 @@ static int rna_property_override_diff_propptr(Main *bmain, const bool no_prop_name, IDOverrideLibrary *override, const char *rna_path, + size_t rna_path_len, const char *rna_itemname_a, const char *rna_itemname_b, const int rna_itemindex_a, @@ -1265,6 +1267,7 @@ static int rna_property_override_diff_propptr(Main *bmain, * so no point in going inside of it at all! */ bool is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing(propptr_a, propptr_b, + no_ownership, no_prop_name, &is_id, &is_null, @@ -1278,7 +1281,7 @@ static int rna_property_override_diff_propptr(Main *bmain, if (is_id) { /* For now, once we deal with nodetrees we'll want to get rid of that one. */ - BLI_assert(no_ownership); + // BLI_assert(no_ownership); } if (override) { @@ -1324,16 +1327,7 @@ static int rna_property_override_diff_propptr(Main *bmain, char extended_rna_path_buffer[RNA_PATH_BUFFSIZE]; char *extended_rna_path = extended_rna_path_buffer; - -# define RNA_PATH_PRINTF(_str, ...) \ - if (BLI_snprintf(extended_rna_path_buffer, RNA_PATH_BUFFSIZE, (_str), __VA_ARGS__) >= \ - RNA_PATH_BUFFSIZE - 1) { \ - extended_rna_path = BLI_sprintfN((_str), __VA_ARGS__); \ - } \ - (void)0 -# define RNA_PATH_FREE() \ - if (extended_rna_path != extended_rna_path_buffer && extended_rna_path != rna_path) \ - MEM_freeN(extended_rna_path) + size_t extended_rna_path_len = 0; /* There may be a propname defined in some cases, while no actual name set * (e.g. happens with point cache), in that case too we want to fall back to index. @@ -1342,31 +1336,82 @@ static int rna_property_override_diff_propptr(Main *bmain, if ((rna_itemname_a != NULL && rna_itemname_a[0] != '\0') && (rna_itemname_b != NULL && rna_itemname_b[0] != '\0')) { BLI_assert(STREQ(rna_itemname_a, rna_itemname_b)); + char esc_item_name[RNA_PATH_BUFFSIZE]; - BLI_strescape(esc_item_name, rna_itemname_a, RNA_PATH_BUFFSIZE); - RNA_PATH_PRINTF("%s[\"%s\"]", rna_path, esc_item_name); + const size_t esc_item_name_len = BLI_strescape( + esc_item_name, rna_itemname_a, RNA_PATH_BUFFSIZE); + extended_rna_path_len = rna_path_len + 2 + esc_item_name_len + 2; + if (extended_rna_path_len >= RNA_PATH_BUFFSIZE) { + extended_rna_path = MEM_mallocN(extended_rna_path_len + 1, __func__); + } + + memcpy(extended_rna_path, rna_path, rna_path_len); + extended_rna_path[rna_path_len] = '['; + extended_rna_path[rna_path_len + 1] = '"'; + memcpy(extended_rna_path + rna_path_len + 2, esc_item_name, esc_item_name_len); + extended_rna_path[rna_path_len + 2 + esc_item_name_len] = '"'; + extended_rna_path[rna_path_len + 2 + esc_item_name_len + 1] = ']'; + extended_rna_path[extended_rna_path_len] = '\0'; } else if (rna_itemindex_a != -1) { /* Based on index... */ BLI_assert(rna_itemindex_a == rna_itemindex_b); - RNA_PATH_PRINTF("%s[%d]", rna_path, rna_itemindex_a); + + /* low-level specific highly-efficient conversion of positive integer to string. */ + char item_index_buff[32]; + size_t item_index_buff_len = 0; + if (rna_itemindex_a == 0) { + item_index_buff[0] = '0'; + item_index_buff_len = 1; + } + else { + uint index; + for (index = rna_itemindex_a; + index > 0 && item_index_buff_len < sizeof(item_index_buff); + index /= 10) { + item_index_buff[item_index_buff_len++] = '0' + (char)(index % 10); + } + BLI_assert(index == 0); + } + + extended_rna_path_len = rna_path_len + item_index_buff_len + 2; + if (extended_rna_path_len >= RNA_PATH_BUFFSIZE) { + extended_rna_path = MEM_mallocN(extended_rna_path_len + 1, __func__); + } + + memcpy(extended_rna_path, rna_path, rna_path_len); + extended_rna_path[rna_path_len] = '['; + for (size_t i = 1; i <= item_index_buff_len; i++) { + /* The first loop above generated inverted string representation of our index number. + */ + extended_rna_path[rna_path_len + i] = item_index_buff[item_index_buff_len - i]; + } + extended_rna_path[rna_path_len + 1 + item_index_buff_len] = ']'; + extended_rna_path[extended_rna_path_len] = '\0'; } else { extended_rna_path = (char *)rna_path; + extended_rna_path_len = rna_path_len; } } eRNAOverrideMatchResult report_flags = 0; - const bool match = RNA_struct_override_matches( - bmain, propptr_a, propptr_b, extended_rna_path, override, flags, &report_flags); + const bool match = RNA_struct_override_matches(bmain, + propptr_a, + propptr_b, + extended_rna_path, + extended_rna_path_len, + override, + flags, + &report_flags); if (r_override_changed && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) != 0) { *r_override_changed = true; } - RNA_PATH_FREE(); + if (extended_rna_path != extended_rna_path_buffer && extended_rna_path != rna_path) { + MEM_freeN(extended_rna_path); + } # undef RNA_PATH_BUFFSIZE -# undef RNA_PATH_PRINTF -# undef RNA_PATH_FREE return !match; } @@ -1395,6 +1440,7 @@ int rna_property_override_diff_default(Main *bmain, const int mode, IDOverrideLibrary *override, const char *rna_path, + const size_t rna_path_len, const int flags, bool *r_override_changed) { @@ -1684,6 +1730,7 @@ int rna_property_override_diff_default(Main *bmain, no_prop_name, override, rna_path, + rna_path_len, NULL, NULL, -1, @@ -1700,6 +1747,7 @@ int rna_property_override_diff_default(Main *bmain, const bool use_insertion = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_LIBRARY_INSERTION) && do_create; + const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0; const bool no_prop_name = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_NO_PROP_NAME) != 0; bool equals = true; @@ -1733,6 +1781,7 @@ int rna_property_override_diff_default(Main *bmain, is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing( &iter_a.ptr, &iter_b.ptr, + no_ownership, no_prop_name, &is_id, &is_null, @@ -1750,6 +1799,7 @@ int rna_property_override_diff_default(Main *bmain, /* We still need propname from 'a' item... */ rna_property_override_diff_propptr_validate_diffing(&iter_a.ptr, NULL, + no_ownership, no_prop_name, &is_id, &is_null, @@ -1835,7 +1885,6 @@ int rna_property_override_diff_default(Main *bmain, } else if (is_id || is_valid_for_diffing) { if (equals || do_create) { - const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0; const int eq = rna_property_override_diff_propptr(bmain, &iter_a.ptr, &iter_b.ptr, @@ -1844,6 +1893,7 @@ int rna_property_override_diff_default(Main *bmain, no_prop_name, override, rna_path, + rna_path_len, propname_a, propname_b, idx_a, diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index edbf4c90524..d141e6f3b19 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1662,7 +1662,7 @@ static void rna_RenderSettings_engine_update(Main *bmain, Scene *UNUSED(unused), PointerRNA *UNUSED(ptr)) { - ED_render_engine_changed(bmain); + ED_render_engine_changed(bmain, true); } static bool rna_RenderSettings_multiple_engines_get(PointerRNA *UNUSED(ptr)) @@ -3090,6 +3090,13 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop, "Transform Parents", "Transform the parents, leaving the children in place"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "use_transform_correct_face_attributes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "uvcalc_flag", UVCALC_TRANSFORM_CORRECT); + RNA_def_property_ui_text(prop, + "Correct Face Attributes", + "Correct data such as UV's and vertex colors when transforming"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + prop = RNA_def_property(srna, "use_mesh_automerge", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "automerge", AUTO_MERGE); RNA_def_property_ui_text( @@ -7150,12 +7157,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna) RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_UNSIGNED); - RNA_def_property_ui_text(prop, "Samples", "Number of samples to take with motion blur"); - RNA_def_property_range(prop, 1, 64); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close"); RNA_def_property_range(prop, 0.0f, FLT_MAX); @@ -7163,6 +7164,33 @@ static void rna_def_scene_eevee(BlenderRNA *brna) RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "motion_blur_depth_scale", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, + "Background Separation", + "Lower values will reduce background" + " bleeding onto foreground elements"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.01f, 1000.0f, 1, 2); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + + prop = RNA_def_property(srna, "motion_blur_max", PROP_INT, PROP_PIXEL); + RNA_def_property_ui_text(prop, "Max Blur", "Maximum blur distance a pixel can spread over"); + RNA_def_property_range(prop, 0, 2048); + RNA_def_property_ui_range(prop, 0, 512, 1, -1); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + + prop = RNA_def_property(srna, "motion_blur_steps", PROP_INT, PROP_NONE); + RNA_def_property_ui_text(prop, + "Motion steps", + "Controls accuracy of motion blur, " + "more steps means longer render time"); + RNA_def_property_range(prop, 1, INT_MAX); + RNA_def_property_ui_range(prop, 1, 64, 1, -1); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + /* Shadows */ prop = RNA_def_property(srna, "shadow_cube_size", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, eevee_shadow_size_items); @@ -7469,6 +7497,7 @@ void RNA_def_scene(BlenderRNA *brna) /* Nodes (Compositing) */ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Node Tree", "Compositing node tree"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); @@ -7699,6 +7728,7 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "master_collection"); RNA_def_property_struct_type(prop, "Collection"); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text( prop, "Collection", diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 381908f7ada..8532bf9afab 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -763,12 +763,6 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Lock Z", "Disallow changes to the Z axis of vertices"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "use_threaded", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_USE_OPENMP); - RNA_def_property_ui_text( - prop, "Use OpenMP", "Take advantage of multiple CPU cores to improve sculpting performance"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "use_deform_only", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_ONLY_DEFORM); RNA_def_property_ui_text(prop, diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 39ea054456f..7342879e9e6 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -2565,29 +2565,25 @@ static void rna_def_wipe(StructRNA *srna) RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Blur Width", "Width of the blur edge, in percentage relative to the image size"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); RNA_def_property_range(prop, DEG2RADF(-90.0f), DEG2RADF(90.0f)); RNA_def_property_ui_text(prop, "Angle", "Edge angle"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "forward"); RNA_def_property_enum_items(prop, wipe_direction_items); RNA_def_property_ui_text(prop, "Direction", "Wipe direction"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "transition_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "wipetype"); RNA_def_property_enum_items(prop, wipe_type_items); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SEQUENCE); RNA_def_property_ui_text(prop, "Transition Type", ""); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); } static void rna_def_glow(StructRNA *srna) @@ -2600,42 +2596,36 @@ static void rna_def_glow(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "fMini"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Threshold", "Minimum intensity to trigger a glow"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "clamp", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "fClamp"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Clamp", "Brightness limit of intensity"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "boost_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fBoost"); RNA_def_property_range(prop, 0.0f, 10.0f); RNA_def_property_ui_text(prop, "Boost Factor", "Brightness multiplier"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "blur_radius", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "dDist"); RNA_def_property_range(prop, 0.5f, 20.0f); RNA_def_property_ui_text(prop, "Blur Distance", "Radius of glow effect"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "quality", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "dQuality"); RNA_def_property_range(prop, 1, 5); RNA_def_property_ui_text(prop, "Quality", "Accuracy of the blur effect"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "use_only_boost", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "bNoComp", 0); RNA_def_property_ui_text(prop, "Only Boost", "Show the glow buffer only"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); } static void rna_def_transform(StructRNA *srna) @@ -2661,57 +2651,49 @@ static void rna_def_transform(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "ScalexIni"); RNA_def_property_ui_text(prop, "Scale X", "Amount to scale the input in the X axis"); RNA_def_property_ui_range(prop, 0, 10, 3, 6); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "scale_start_y", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "ScaleyIni"); RNA_def_property_ui_text(prop, "Scale Y", "Amount to scale the input in the Y axis"); RNA_def_property_ui_range(prop, 0, 10, 3, 6); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "use_uniform_scale", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uniform_scale", 0); RNA_def_property_ui_text(prop, "Uniform Scale", "Scale uniformly, preserving aspect ratio"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "translate_start_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "xIni"); RNA_def_property_ui_text(prop, "Translate X", "Amount to move the input on the X axis"); RNA_def_property_ui_range(prop, -4000.0f, 4000.0f, 3, 6); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "translate_start_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "yIni"); RNA_def_property_ui_text(prop, "Translate Y", "Amount to move the input on the Y axis"); RNA_def_property_ui_range(prop, -4000.0f, 4000.0f, 3, 6); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "rotation_start", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "rotIni"); RNA_def_property_ui_text(prop, "Rotation", "Degrees to rotate the input"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "translation_unit", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "percent"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* not meant to be animated */ RNA_def_property_enum_items(prop, translation_unit_items); RNA_def_property_ui_text(prop, "Translation Unit", "Unit of measure to translate the input"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, interpolation_items); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* not meant to be animated */ RNA_def_property_ui_text( prop, "Interpolation", "Method to determine how missing pixels are created"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); } static void rna_def_solid_color(StructRNA *srna) @@ -2738,29 +2720,25 @@ static void rna_def_speed_control(StructRNA *srna) RNA_def_property_ui_text( prop, "Multiply Speed", "Multiply the resulting speed after the speed factor"); RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, -1); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "use_as_speed", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_INTEGRATE); RNA_def_property_ui_text( prop, "Use as Speed", "Interpret the value as speed instead of a frame number"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "use_scale_to_length", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_COMPRESS_IPO_Y); RNA_def_property_ui_text( prop, "Scale to Length", "Scale values from 0.0 to 1.0 to target sequence length"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "frame_interpolation_mode", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_USE_INTERPOLATION); RNA_def_property_ui_text( prop, "Frame interpolation", "Do crossfade blending between current and next frame"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); } static void rna_def_gaussian_blur(StructRNA *srna) @@ -2771,14 +2749,12 @@ static void rna_def_gaussian_blur(StructRNA *srna) prop = RNA_def_property(srna, "size_x", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_ui_text(prop, "Size X", "Size of the blur along X axis"); RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, -1); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "size_y", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_ui_text(prop, "Size Y", "Size of the blur along Y axis"); RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, -1); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); } static void rna_def_text(StructRNA *srna) @@ -2807,71 +2783,61 @@ static void rna_def_text(StructRNA *srna) RNA_def_property_ui_text(prop, "Font", "Font of the text. Falls back to the UI font by default"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_pointer_funcs(prop, NULL, "rna_Sequence_text_font_set", NULL, NULL); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "text_size"); RNA_def_property_ui_text(prop, "Size", "Size of the text"); RNA_def_property_range(prop, 0.0, 2000); RNA_def_property_ui_range(prop, 0.0f, 1000, 1, -1); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "color"); RNA_def_property_ui_text(prop, "Color", "Text color"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "shadow_color"); RNA_def_property_ui_text(prop, "Shadow Color", ""); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "loc"); RNA_def_property_ui_text(prop, "Location", "Location of the text"); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "wrap_width", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "wrap_width"); RNA_def_property_ui_text(prop, "Wrap Width", "Word wrap width as factor, zero disables"); RNA_def_property_range(prop, 0, FLT_MAX); RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "align"); RNA_def_property_enum_items(prop, text_align_x_items); RNA_def_property_ui_text( prop, "Align X", "Align the text along the X axis, relative to the text bounds"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "align_y"); RNA_def_property_enum_items(prop, text_align_y_items); RNA_def_property_ui_text( prop, "Align Y", "Align the text along the Y axis, relative to the text bounds"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "text", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Text", "Text that will be displayed"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "use_shadow", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_TEXT_SHADOW); RNA_def_property_ui_text(prop, "Shadow", "Display shadow behind text"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); } static void rna_def_color_mix(StructRNA *srna) @@ -2914,15 +2880,13 @@ static void rna_def_color_mix(StructRNA *srna) RNA_def_property_enum_items(prop, blend_color_items); RNA_def_property_ui_text( prop, "Blending Mode", "Method for controlling how the strip combines with other strips"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Blend Factor", "Percentage of how much the strip's colors affect other strips"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); } static EffectInfo def_effects[] = { diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 6c8f51f97a1..28603132c77 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -114,7 +114,7 @@ static Sequence *rna_Sequences_new_clip(ID *id, Scene *scene = (Scene *)id; Sequence *seq; - seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MOVIECLIP, clip->name); + seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MOVIECLIP, clip->filepath); seq->clip = clip; seq->len = BKE_movieclip_get_duration(clip); id_us_plus((ID *)clip); @@ -265,7 +265,8 @@ static Sequence *rna_Sequences_new_sound(ID *id, BKE_report(reports, RPT_ERROR, "Sequences.new_sound: unable to open sound file"); return NULL; } - seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_SOUND_RAM, sound->name); + seq = alloc_generic_sequence( + ed, name, frame_start, channel, SEQ_TYPE_SOUND_RAM, sound->filepath); seq->sound = sound; seq->len = ceil((double)info.length * FPS); @@ -447,6 +448,21 @@ static void rna_SequenceElements_pop(ID *id, Sequence *seq, ReportList *reports, WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); } +static void rna_Sequence_invalidate_cache_rnafunc(ID *id, Sequence *self, int type) +{ + switch (type) { + case SEQ_CACHE_STORE_RAW: + BKE_sequence_invalidate_cache_raw((Scene *)id, self); + break; + case SEQ_CACHE_STORE_PREPROCESSED: + BKE_sequence_invalidate_cache_preprocessed((Scene *)id, self); + break; + case SEQ_CACHE_STORE_COMPOSITE: + BKE_sequence_invalidate_cache_composite((Scene *)id, self); + break; + } +} + #else void RNA_api_sequence_strip(StructRNA *srna) @@ -454,6 +470,13 @@ void RNA_api_sequence_strip(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; + static const EnumPropertyItem seq_cahce_type_items[] = { + {SEQ_CACHE_STORE_RAW, "RAW", 0, "Raw", ""}, + {SEQ_CACHE_STORE_PREPROCESSED, "PREPROCESSED", 0, "Preprocessed", ""}, + {SEQ_CACHE_STORE_COMPOSITE, "COMPOSITE", 0, "Composite", ""}, + {0, NULL, 0, NULL, NULL}, + }; + func = RNA_def_function(srna, "update", "rna_Sequence_update_rnafunc"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Update the strip dimensions"); @@ -479,6 +502,13 @@ void RNA_api_sequence_strip(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "other", "Sequence", "Other", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + + func = RNA_def_function(srna, "invalidate_cache", "rna_Sequence_invalidate_cache_rnafunc"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + RNA_def_function_ui_description(func, + "Invalidate Cached images for strip and all dependant strips. "); + parm = RNA_def_enum(func, "type", seq_cahce_type_items, 0, "Type", "Cache Type"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); } void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c index 71f767fa93b..80f3cab147c 100644 --- a/source/blender/makesrna/intern/rna_shader_fx.c +++ b/source/blender/makesrna/intern/rna_shader_fx.c @@ -336,11 +336,9 @@ static void rna_def_shader_fx_pixel(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Size", "Pixel size"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); - RNA_def_property_range(prop, 0.0, 1.0); - RNA_def_property_float_sdna(prop, NULL, "rgba"); - RNA_def_property_array(prop, 4); - RNA_def_property_ui_text(prop, "Color", "Color used for lines"); + prop = RNA_def_property(srna, "use_antialiasing", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", FX_PIXEL_FILTER_NEAREST); + RNA_def_property_ui_text(prop, "Antialiasing", "Antialiase pixels"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); } @@ -424,7 +422,7 @@ static void rna_def_shader_fx_shadow(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Offset", "Offset of the shadow"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); - prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "scale"); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_ui_text(prop, "Scale", "Offset of the shadow"); @@ -681,9 +679,9 @@ void RNA_def_shader_fx(BlenderRNA *brna) prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); - RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Expanded); + RNA_def_property_boolean_sdna(prop, NULL, "ui_expand_flag", 0); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); - RNA_def_property_ui_text(prop, "Expanded", "Set effect expanded in the user interface"); + RNA_def_property_ui_text(prop, "Expanded", "Set effect expansion in the user interface"); RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1); /* types */ diff --git a/source/blender/makesrna/intern/rna_simulation.c b/source/blender/makesrna/intern/rna_simulation.c index 789ea299feb..cc9a4bec2e7 100644 --- a/source/blender/makesrna/intern/rna_simulation.c +++ b/source/blender/makesrna/intern/rna_simulation.c @@ -42,6 +42,7 @@ static void rna_def_simulation(BlenderRNA *brna) prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Node Tree", "Node tree defining the simulation"); /* common */ diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c index 28a1c0f3cca..2fb50c2e89e 100644 --- a/source/blender/makesrna/intern/rna_sound.c +++ b/source/blender/makesrna/intern/rna_sound.c @@ -62,7 +62,7 @@ static void rna_def_sound(BlenderRNA *brna) /*rna_def_ipo_common(srna); */ prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); - RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_string_sdna(prop, NULL, "filepath"); RNA_def_property_ui_text(prop, "File Path", "Sound sample file used by this Sound data-block"); RNA_def_property_update(prop, 0, "rna_Sound_update"); diff --git a/source/blender/makesrna/intern/rna_sound_api.c b/source/blender/makesrna/intern/rna_sound_api.c index 418205426d2..82da0adf0fe 100644 --- a/source/blender/makesrna/intern/rna_sound_api.c +++ b/source/blender/makesrna/intern/rna_sound_api.c @@ -34,7 +34,8 @@ static void rna_Sound_pack(bSound *sound, Main *bmain, ReportList *reports) { - sound->packedfile = BKE_packedfile_new(reports, sound->name, ID_BLEND_PATH(bmain, &sound->id)); + sound->packedfile = BKE_packedfile_new( + reports, sound->filepath, ID_BLEND_PATH(bmain, &sound->id)); } static void rna_Sound_unpack(bSound *sound, Main *bmain, ReportList *reports, int method) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index df0d514fabf..49a21799d5b 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2181,7 +2181,6 @@ static void rna_SpaceNodeEditor_node_tree_update(const bContext *C, PointerRNA * ED_node_tree_update(C); } -# ifdef WITH_NEW_SIMULATION_TYPE static PointerRNA rna_SpaceNodeEditor_simulation_get(PointerRNA *ptr) { SpaceNode *snode = (SpaceNode *)ptr->data; @@ -2213,7 +2212,6 @@ static void rna_SpaceNodeEditor_simulation_set(PointerRNA *ptr, } snode->id = &sim->id; } -# endif static int rna_SpaceNodeEditor_tree_type_get(PointerRNA *ptr) { @@ -4317,12 +4315,10 @@ static void rna_def_space_view3d(BlenderRNA *brna) {"Surface", (1 << OB_SURF), {"show_object_viewport_surf", "show_object_select_surf"}}, {"Meta", (1 << OB_MBALL), {"show_object_viewport_meta", "show_object_select_meta"}}, {"Font", (1 << OB_FONT), {"show_object_viewport_font", "show_object_select_font"}}, -# ifdef WITH_NEW_OBJECT_TYPES {"Hair", (1 << OB_HAIR), {"show_object_viewport_hair", "show_object_select_hair"}}, {"Point Cloud", (1 << OB_POINTCLOUD), {"show_object_viewport_pointcloud", "show_object_select_pointcloud"}}, -# endif {"Volume", (1 << OB_VOLUME), {"show_object_viewport_volume", "show_object_select_volume"}}, {"Armature", (1 << OB_ARMATURE), @@ -5534,9 +5530,7 @@ static void rna_def_fileselect_idfilter(BlenderRNA *brna) "Grease Pencil", "Show Grease pencil data-blocks"}, {FILTER_ID_GR, "filter_group", ICON_GROUP, "Collections", "Show Collection data-blocks"}, -# ifdef WITH_NEW_OBJECT_TYPES {FILTER_ID_HA, "filter_hair", ICON_HAIR_DATA, "Hairs", "Show/hide Hair data-blocks"}, -# endif {FILTER_ID_IM, "filter_image", ICON_IMAGE_DATA, "Images", "Show Image data-blocks"}, {FILTER_ID_LA, "filter_light", ICON_LIGHT_DATA, "Lights", "Show Light data-blocks"}, {FILTER_ID_LP, @@ -5580,21 +5574,17 @@ static void rna_def_fileselect_idfilter(BlenderRNA *brna) ICON_CURVE_BEZCURVE, "Paint Curves", "Show Paint Curve data-blocks"}, -# ifdef WITH_NEW_OBJECT_TYPES {FILTER_ID_PT, "filter_pointcloud", ICON_POINTCLOUD_DATA, "Point Clouds", "Show/hide Point Cloud data-blocks"}, -# endif {FILTER_ID_SCE, "filter_scene", ICON_SCENE_DATA, "Scenes", "Show Scene data-blocks"}, -# ifdef WITH_NEW_SIMULATION_TYPE {FILTER_ID_SIM, "filter_simulation", ICON_PHYSICS, "Simulations", "Show Simulation data-blocks"}, /* TODO: Use correct icon. */ -# endif {FILTER_ID_SPK, "filter_speaker", ICON_SPEAKER, "Speakers", "Show Speaker data-blocks"}, {FILTER_ID_SO, "filter_sound", ICON_SOUND, "Sounds", "Show Sound data-blocks"}, {FILTER_ID_TE, "filter_texture", ICON_TEXTURE_DATA, "Textures", "Show Texture data-blocks"}, @@ -6276,7 +6266,6 @@ static void rna_def_space_node(BlenderRNA *brna) RNA_def_property_ui_text( prop, "ID From", "Data-block from which the edited data-block is linked"); -# ifdef WITH_NEW_SIMULATION_TYPE prop = RNA_def_property(srna, "simulation", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "Simulation"); @@ -6287,7 +6276,6 @@ static void rna_def_space_node(BlenderRNA *brna) NULL, NULL); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL); -# endif prop = RNA_def_property(srna, "path", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "treepath", NULL); diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c index c8797a8bc74..1351c027004 100644 --- a/source/blender/makesrna/intern/rna_text.c +++ b/source/blender/makesrna/intern/rna_text.c @@ -43,8 +43,8 @@ static void rna_Text_filename_get(PointerRNA *ptr, char *value) { Text *text = (Text *)ptr->data; - if (text->name) { - strcpy(value, text->name); + if (text->filepath) { + strcpy(value, text->filepath); } else { value[0] = '\0'; @@ -54,22 +54,22 @@ static void rna_Text_filename_get(PointerRNA *ptr, char *value) static int rna_Text_filename_length(PointerRNA *ptr) { Text *text = (Text *)ptr->data; - return (text->name) ? strlen(text->name) : 0; + return (text->filepath) ? strlen(text->filepath) : 0; } static void rna_Text_filename_set(PointerRNA *ptr, const char *value) { Text *text = (Text *)ptr->data; - if (text->name) { - MEM_freeN(text->name); + if (text->filepath) { + MEM_freeN(text->filepath); } if (value[0]) { - text->name = BLI_strdup(value); + text->filepath = BLI_strdup(value); } else { - text->name = NULL; + text->filepath = NULL; } } diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 9184c54ae88..4d5f0f6c2fa 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -1634,6 +1634,7 @@ static void rna_def_texture(BlenderRNA *brna) prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node-based textures"); RNA_def_property_update(prop, 0, "rna_Texture_nodes_update"); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index fd65b713d15..8dfa54b95da 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -530,6 +530,22 @@ static void rna_uiTemplateEventFromKeymapItem( uiTemplateEventFromKeymapItem(layout, name, kmi, true); } +static uiLayout *rna_uiLayoutRowWithHeading( + uiLayout *layout, bool align, const char *heading, const char *heading_ctxt, bool translate) +{ + /* Get translated heading. */ + heading = rna_translate_ui_text(heading, heading_ctxt, NULL, NULL, translate); + return uiLayoutRowWithHeading(layout, align, heading); +} + +static uiLayout *rna_uiLayoutColumnWithHeading( + uiLayout *layout, bool align, const char *heading, const char *heading_ctxt, bool translate) +{ + /* Get translated heading. */ + heading = rna_translate_ui_text(heading, heading_ctxt, NULL, NULL, translate); + return uiLayoutColumnWithHeading(layout, align, heading); +} + static int rna_ui_get_rnaptr_icon(bContext *C, PointerRNA *ptr_icon) { return UI_rnaptr_icon_get(C, ptr_icon, RNA_struct_ui_icon(ptr_icon->type), false); @@ -639,6 +655,24 @@ static int rna_ui_get_enum_icon(bContext *C, #else +static void api_ui_item_common_heading(FunctionRNA *func) +{ + RNA_def_string(func, + "heading", + NULL, + UI_MAX_NAME_STR, + "Heading", + "Label to insert into the layout for this sub-layout"); + RNA_def_string(func, + "heading_ctxt", + NULL, + 0, + "", + "Override automatic translation context of the given heading"); + RNA_def_boolean( + func, "translate", true, "", "Translate the given heading, when UI translation is enabled"); +} + static void api_ui_item_common_text(FunctionRNA *func) { PropertyRNA *prop; @@ -708,7 +742,7 @@ void RNA_api_ui_layout(StructRNA *srna) static float node_socket_color_default[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* simple layout specifiers */ - func = RNA_def_function(srna, "row", "uiLayoutRowWithHeading"); + func = RNA_def_function(srna, "row", "rna_uiLayoutRowWithHeading"); parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); RNA_def_function_return(func, parm); RNA_def_function_ui_description( @@ -716,14 +750,9 @@ void RNA_api_ui_layout(StructRNA *srna) "Sub-layout. Items placed in this sublayout are placed next to each other " "in a row"); RNA_def_boolean(func, "align", false, "", "Align buttons to each other"); - RNA_def_string(func, - "heading", - NULL, - UI_MAX_NAME_STR, - "Heading", - "Label to insert into the layout for this row"); + api_ui_item_common_heading(func); - func = RNA_def_function(srna, "column", "uiLayoutColumnWithHeading"); + func = RNA_def_function(srna, "column", "rna_uiLayoutColumnWithHeading"); parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); RNA_def_function_return(func, parm); RNA_def_function_ui_description( @@ -731,12 +760,7 @@ void RNA_api_ui_layout(StructRNA *srna) "Sub-layout. Items placed in this sublayout are placed under each other " "in a column"); RNA_def_boolean(func, "align", false, "", "Align buttons to each other"); - RNA_def_string(func, - "heading", - NULL, - UI_MAX_NAME_STR, - "Heading", - "Label to insert into the layout for this column"); + api_ui_item_common_heading(func); func = RNA_def_function(srna, "column_flow", "uiLayoutColumnFlow"); RNA_def_int(func, "columns", 0, 0, INT_MAX, "", "Number of columns, 0 is automatic", 0, INT_MAX); @@ -1213,21 +1237,23 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_CONTEXT); RNA_def_function_ui_description(func, "Generates the UI layout for the modifier stack"); - func = RNA_def_function(srna, "template_greasepencil_modifier", "uiTemplateGpencilModifier"); + func = RNA_def_function(srna, "template_constraints", "uiTemplateConstraints"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); - RNA_def_function_ui_description(func, "Generates the UI layout for grease pencil modifiers"); - parm = RNA_def_pointer(func, "data", "GpencilModifier", "", "Modifier data"); - RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); - parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); - RNA_def_function_return(func, parm); + RNA_def_function_ui_description(func, "Generates the panels for the constraint stack"); + RNA_def_boolean(func, + "use_bone_constraints", + true, + "", + "Add panels for bone constraints instead of object constraints"); + + func = RNA_def_function(srna, "template_grease_pencil_modifiers", "uiTemplateGpencilModifiers"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, + "Generates the panels for the grease pencil modifier stack"); func = RNA_def_function(srna, "template_shaderfx", "uiTemplateShaderFx"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); - RNA_def_function_ui_description(func, "Generates the UI layout for shader effect"); - parm = RNA_def_pointer(func, "data", "ShaderFx", "", "Shader data"); - RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); - parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); - RNA_def_function_return(func, parm); + RNA_def_function_ui_description(func, "Generates the panels for the shader effect stack"); func = RNA_def_function(srna, "template_greasepencil_color", "uiTemplateGpencilColorPreview"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); @@ -1251,12 +1277,10 @@ void RNA_api_ui_layout(StructRNA *srna) "", "Optionally limit the items which can be selected"); - func = RNA_def_function(srna, "template_constraint", "uiTemplateConstraint"); - RNA_def_function_ui_description(func, "Generates the UI layout for constraints"); + func = RNA_def_function(srna, "template_constraint_header", "uiTemplateConstraintHeader"); + RNA_def_function_ui_description(func, "Generates the header for constraint panels"); parm = RNA_def_pointer(func, "data", "Constraint", "", "Constraint data"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); - parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); - RNA_def_function_return(func, parm); func = RNA_def_function(srna, "template_preview", "uiTemplatePreview"); RNA_def_function_ui_description( diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 49a0121dadb..c31b313d827 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -328,6 +328,8 @@ static void rna_userdef_language_update(Main *UNUSED(bmain), else { U.transopts |= (USER_TR_IFACE | USER_TR_TOOLTIPS | USER_TR_NEWDATANAME); } + + USERDEF_TAG_DIRTY; } static void rna_userdef_script_autoexec_update(Main *UNUSED(bmain), @@ -5044,7 +5046,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna) prop = RNA_def_property(srna, "use_duplicate_action", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_ACT); RNA_def_property_ui_text( - prop, "Duplicate Action", "Causes actions to be duplicated with the object"); + prop, "Duplicate Action", "Causes actions to be duplicated with the data-blocks"); prop = RNA_def_property(srna, "use_duplicate_particle", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_PSYS); @@ -5061,7 +5063,6 @@ static void rna_def_userdef_edit(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Duplicate GPencil", "Causes grease pencil data to be duplicated with the object"); -# ifdef WITH_NEW_OBJECT_TYPES prop = RNA_def_property(srna, "use_duplicate_hair", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_HAIR); RNA_def_property_ui_text( @@ -5071,7 +5072,6 @@ static void rna_def_userdef_edit(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_POINTCLOUD); RNA_def_property_ui_text( prop, "Duplicate Point Cloud", "Causes point cloud data to be duplicated with the object"); -# endif prop = RNA_def_property(srna, "use_duplicate_volume", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_VOLUME); @@ -5887,9 +5887,9 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) static const EnumPropertyItem anim_player_presets[] = { {0, "INTERNAL", 0, "Internal", "Built-in animation player"}, - {2, "DJV", 0, "Djv", "Open source frame player: http://djv.sourceforge.net"}, + {2, "DJV", 0, "DJV", "Open source frame player: http://djv.sourceforge.net"}, {3, "FRAMECYCLER", 0, "FrameCycler", "Frame player from IRIDAS"}, - {4, "RV", 0, "rv", "Frame player from Tweak Software"}, + {4, "RV", 0, "RV", "Frame player from Tweak Software"}, {5, "MPLAYER", 0, "MPlayer", "Media player for video & png/jpeg/sgi image sequences"}, {50, "CUSTOM", 0, "Custom", "Custom animation player executable path"}, {0, NULL, 0, NULL, NULL}, @@ -6070,6 +6070,20 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) prop, "Undo Legacy", "Use legacy undo (slower than the new default one, but may be more stable in some cases)"); + + prop = RNA_def_property(srna, "use_new_particle_system", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_new_particle_system", 1); + RNA_def_property_ui_text( + prop, "New Particle System", "Enable the new particle system in the ui"); + + prop = RNA_def_property(srna, "use_new_hair_type", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_new_hair_type", 1); + RNA_def_property_ui_text(prop, "New Hair Type", "Enable the new hair type in the ui"); + + prop = RNA_def_property(srna, "use_cycles_debug", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_cycles_debug", 1); + RNA_def_property_ui_text(prop, "Cycles Debug", "Enable Cycles debugging options for developers"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); } static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/makesrna/intern/rna_vfont.c b/source/blender/makesrna/intern/rna_vfont.c index 3e96b5816e5..a98a52c2252 100644 --- a/source/blender/makesrna/intern/rna_vfont.c +++ b/source/blender/makesrna/intern/rna_vfont.c @@ -72,7 +72,7 @@ void RNA_def_vfont(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_FILE_FONT); prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); - RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_string_sdna(prop, NULL, "filepath"); RNA_def_property_editable_func(prop, "rna_VectorFont_filepath_editable"); RNA_def_property_ui_text(prop, "File Path", ""); RNA_def_property_update(prop, NC_GEOM | ND_DATA, "rna_VectorFont_reload_update"); diff --git a/source/blender/makesrna/intern/rna_vfont_api.c b/source/blender/makesrna/intern/rna_vfont_api.c index 1bf61db4871..80e0511caf9 100644 --- a/source/blender/makesrna/intern/rna_vfont_api.c +++ b/source/blender/makesrna/intern/rna_vfont_api.c @@ -34,7 +34,8 @@ static void rna_VectorFont_pack(VFont *vfont, Main *bmain, ReportList *reports) { - vfont->packedfile = BKE_packedfile_new(reports, vfont->name, ID_BLEND_PATH(bmain, &vfont->id)); + vfont->packedfile = BKE_packedfile_new( + reports, vfont->filepath, ID_BLEND_PATH(bmain, &vfont->id)); } static void rna_VectorFont_unpack(VFont *vfont, Main *bmain, ReportList *reports, int method) diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 6749aa9495a..bfd99c01551 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -251,7 +251,7 @@ const EnumPropertyItem rna_enum_event_type_items[] = { {EVT_RETKEY, "RET", 0, "Return", "Enter"}, {EVT_SPACEKEY, "SPACE", 0, "Spacebar", "Space"}, {EVT_LINEFEEDKEY, "LINE_FEED", 0, "Line Feed", ""}, - {EVT_BACKSPACEKEY, "BACK_SPACE", 0, "Back Space", "BkSpace"}, + {EVT_BACKSPACEKEY, "BACK_SPACE", 0, "Backspace", "BkSpace"}, {EVT_DELKEY, "DEL", 0, "Delete", "Del"}, {EVT_SEMICOLONKEY, "SEMI_COLON", 0, ";", ""}, {EVT_PERIODKEY, "PERIOD", 0, ".", ""}, diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index 07db2755523..1ca0eb74cf5 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -236,6 +236,7 @@ void RNA_def_world(BlenderRNA *brna) /* nodes */ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); + RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based worlds"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index 460f697a0a9..80a1ebab64e 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -175,3 +175,7 @@ endif() add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_modifiers "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +# Some modifiers include BLO_read_write.h, which includes dna_type_offsets.h +# which is generated by bf_dna. Need to ensure compilaiton order here. +add_dependencies(bf_modifiers bf_dna) diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 9cc1f4596a9..b62c03d1b03 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -49,6 +49,8 @@ #include "RNA_access.h" +#include "BLO_read_write.h" + #include "DEG_depsgraph_query.h" #include "bmesh.h" @@ -249,7 +251,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(col, &ptr, "use_deform_preserve_volume", 0, NULL, ICON_NONE); uiItemR(col, &ptr, "use_multi_modifier", 0, NULL, ICON_NONE); - col = uiLayoutColumnWithHeading(layout, true, "Bind to"); + col = uiLayoutColumnWithHeading(layout, true, IFACE_("Bind to")); uiItemR(col, &ptr, "use_vertex_groups", 0, IFACE_("Vertex Groups"), ICON_NONE); uiItemR(col, &ptr, "use_bone_envelopes", 0, IFACE_("Bone Envelopes"), ICON_NONE); @@ -261,6 +263,13 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_Armature, panel_draw); } +static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) +{ + ArmatureModifierData *amd = (ArmatureModifierData *)md; + + amd->vert_coords_prev = NULL; +} + ModifierTypeInfo modifierType_Armature = { /* name */ "Armature", /* structName */ "ArmatureModifierData", @@ -293,5 +302,5 @@ ModifierTypeInfo modifierType_Armature = { /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 35e3bb97fc3..0a1eb8eba10 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -51,6 +51,8 @@ #include "MOD_ui_common.h" #include "MOD_util.h" +#include "BLO_read_write.h" + #include "BKE_curveprofile.h" #include "bmesh.h" #include "bmesh_tools.h" @@ -118,6 +120,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0; const bool do_clamp = !(bmd->flags & MOD_BEVEL_OVERLAP_OK); const int offset_type = bmd->val_flags; + const int profile_type = bmd->profile_type; const float value = bmd->value; const int mat = CLAMPIS(bmd->mat, -1, ctx->object->totcol - 1); const bool loop_slide = (bmd->flags & MOD_BEVEL_EVEN_WIDTHS) == 0; @@ -128,7 +131,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * const int miter_outer = bmd->miter_outer; const int miter_inner = bmd->miter_inner; const float spread = bmd->spread; - const bool use_custom_profile = (bmd->flags & MOD_BEVEL_CUSTOM_PROFILE); const int vmesh_method = bmd->vmesh_method; const bool invert_vgroup = (bmd->flags & MOD_BEVEL_INVERT_VGROUP) != 0; @@ -225,6 +227,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * BM_mesh_bevel(bm, value, offset_type, + profile_type, bmd->res, bmd->profile, vertex_only, @@ -242,7 +245,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * miter_inner, spread, mesh->smoothresh, - use_custom_profile, bmd->custom_profile, vmesh_method); @@ -302,6 +304,9 @@ static void panel_draw(const bContext *C, Panel *panel) case BEVEL_AMT_OFFSET: offset_name = "Offset"; break; + case BEVEL_AMT_ABSOLUTE: + offset_name = "Absolute"; + break; } uiItemR(col, &ptr, "width", 0, IFACE_(offset_name), ICON_NONE); } @@ -371,53 +376,64 @@ static void shading_panel_draw(const bContext *C, Panel *panel) static void profile_panel_draw(const bContext *C, Panel *panel) { - PointerRNA ptr; - modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - uiLayout *layout = panel->layout; - - uiLayoutSetPropSep(layout, true); - - uiItemR(layout, &ptr, "profile", UI_ITEM_R_SLIDER, IFACE_("Shape"), ICON_NONE); -} - -static void custom_profile_panel_draw_header(const bContext *C, Panel *panel) -{ uiLayout *layout = panel->layout; PointerRNA ptr; modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - uiItemR(layout, &ptr, "use_custom_profile", 0, NULL, ICON_NONE); -} + int profile_type = RNA_enum_get(&ptr, "profile_type"); -static void custom_profile_panel_draw(const bContext *C, Panel *panel) -{ - PointerRNA ptr; - modifier_panel_get_property_pointers(C, panel, NULL, &ptr); - uiLayout *layout = panel->layout; + uiItemR(layout, &ptr, "profile_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiLayoutSetActive(layout, RNA_boolean_get(&ptr, "use_custom_profile")); + uiLayoutSetPropSep(layout, true); - uiTemplateCurveProfile(layout, &ptr, "custom_profile"); + if (ELEM(profile_type, MOD_BEVEL_PROFILE_SUPERELLIPSE, MOD_BEVEL_PROFILE_CUSTOM)) { + uiItemR(layout, + &ptr, + "profile", + UI_ITEM_R_SLIDER, + (profile_type == MOD_BEVEL_PROFILE_SUPERELLIPSE) ? IFACE_("Shape") : + IFACE_("Miter Shape"), + ICON_NONE); + + if (profile_type == MOD_BEVEL_PROFILE_CUSTOM) { + uiLayout *sub = uiLayoutColumn(layout, false); + uiLayoutSetPropDecorate(sub, false); + uiTemplateCurveProfile(sub, &ptr, "custom_profile"); + } + } } static void panelRegister(ARegionType *region_type) { PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Bevel, panel_draw); - PanelType *bevel_profil_panel = modifier_subpanel_register( + modifier_subpanel_register( region_type, "profile", "Profile", NULL, profile_panel_draw, panel_type); - modifier_subpanel_register(region_type, - "custom", - "", - custom_profile_panel_draw_header, - custom_profile_panel_draw, - bevel_profil_panel); modifier_subpanel_register( region_type, "geometry", "Geometry", NULL, geometry_panel_draw, panel_type); modifier_subpanel_register( region_type, "shading", "Shading", NULL, shading_panel_draw, panel_type); } +static void blendWrite(BlendWriter *writer, const ModifierData *md) +{ + const BevelModifierData *bmd = (const BevelModifierData *)md; + + if (bmd->custom_profile) { + BKE_curveprofile_blend_write(writer, bmd->custom_profile); + } +} + +static void blendRead(BlendDataReader *reader, ModifierData *md) +{ + BevelModifierData *bmd = (BevelModifierData *)md; + + BLO_read_data_address(reader, &bmd->custom_profile); + if (bmd->custom_profile) { + BKE_curveprofile_blend_read(reader, bmd->custom_profile); + } +} + ModifierTypeInfo modifierType_Bevel = { /* name */ "Bevel", /* structName */ "BevelModifierData", @@ -446,6 +462,6 @@ ModifierTypeInfo modifierType_Bevel = { /* foreachTexLink */ NULL, /* freeRuntimeData */ NULL, /* uiPanel */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ blendWrite, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 9f588a4d345..cc9def73e12 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -565,7 +565,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "object", 0, NULL, ICON_NONE); if (!RNA_pointer_is_null(&cast_object_ptr)) { - uiItemR(layout, &ptr, "use_radius_as_size", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "use_transform", 0, NULL, ICON_NONE); } modifier_panel_end(layout, &ptr); diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index 7a338b59e98..a355558a3ba 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -54,6 +54,8 @@ #include "MOD_ui_common.h" #include "MOD_util.h" +#include "BLO_read_write.h" + #include "DEG_depsgraph_query.h" static void initData(ModifierData *md) @@ -269,6 +271,34 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_Collision, panel_draw); } +static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) +{ + CollisionModifierData *collmd = (CollisionModifierData *)md; +#if 0 + // TODO: CollisionModifier should use pointcache + // + have proper reset events before enabling this + collmd->x = newdataadr(fd, collmd->x); + collmd->xnew = newdataadr(fd, collmd->xnew); + collmd->mfaces = newdataadr(fd, collmd->mfaces); + + collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x"); + collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew"); + collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v"); +#endif + + collmd->x = NULL; + collmd->xnew = NULL; + collmd->current_x = NULL; + collmd->current_xnew = NULL; + collmd->current_v = NULL; + collmd->time_x = collmd->time_xnew = -1000; + collmd->mvert_num = 0; + collmd->tri_num = 0; + collmd->is_static = false; + collmd->bvhtree = NULL; + collmd->tri = NULL; +} + ModifierTypeInfo modifierType_Collision = { /* name */ "Collision", /* structName */ "CollisionModifierData", @@ -300,5 +330,5 @@ ModifierTypeInfo modifierType_Collision = { /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index ba343854d41..ac91056ed7d 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -54,6 +54,8 @@ #include "MOD_ui_common.h" #include "MOD_util.h" +#include "BLO_read_write.h" + #include "BLI_strict_flags.h" #include "DEG_depsgraph_query.h" @@ -817,6 +819,28 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_CorrectiveSmooth, panel_draw); } +static void blendWrite(BlendWriter *writer, const ModifierData *md) +{ + const CorrectiveSmoothModifierData *csmd = (const CorrectiveSmoothModifierData *)md; + + if (csmd->bind_coords) { + BLO_write_float3_array(writer, (int)csmd->bind_coords_num, (float *)csmd->bind_coords); + } +} + +static void blendRead(BlendDataReader *reader, ModifierData *md) +{ + CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; + + if (csmd->bind_coords) { + BLO_read_float3_array(reader, (int)csmd->bind_coords_num, (float **)&csmd->bind_coords); + } + + /* runtime only */ + csmd->delta_cache.deltas = NULL; + csmd->delta_cache.totverts = 0; +} + ModifierTypeInfo modifierType_CorrectiveSmooth = { /* name */ "CorrectiveSmooth", /* structName */ "CorrectiveSmoothModifierData", @@ -847,6 +871,6 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = { /* foreachTexLink */ NULL, /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ blendWrite, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index 4fa7bf4cd63..75fd558ae39 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -239,14 +239,14 @@ static void panel_draw(const bContext *C, Panel *panel) int decimate_type = RNA_enum_get(&ptr, "decimate_type"); char count_info[32]; - snprintf(count_info, 32, IFACE_("Face Count: %d"), RNA_int_get(&ptr, "face_count")); + snprintf(count_info, 32, "%s: %d", IFACE_("Face Count"), RNA_int_get(&ptr, "face_count")); uiItemR(layout, &ptr, "decimate_type", 0, NULL, ICON_NONE); if (decimate_type == MOD_DECIM_MODE_COLLAPSE) { uiItemR(layout, &ptr, "ratio", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - row = uiLayoutRowWithHeading(layout, true, "Symmetry"); + row = uiLayoutRowWithHeading(layout, true, IFACE_("Symmetry")); uiLayoutSetPropDecorate(row, false); sub = uiLayoutRow(row, true); uiItemR(sub, &ptr, "use_symmetry", 0, "", ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 32e36fbd09e..894a48d9f62 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -440,6 +440,8 @@ static void panel_draw(const bContext *C, Panel *panel) PointerRNA ob_ptr; modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); + PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data"); + PointerRNA texture_ptr = RNA_pointer_get(&ptr, "texture"); bool has_texture = !RNA_pointer_is_null(&texture_ptr); int texture_coords = RNA_enum_get(&ptr, "texture_coords"); @@ -467,7 +469,7 @@ static void panel_draw(const bContext *C, Panel *panel) } } else if (texture_coords == MOD_DISP_MAP_UV && RNA_enum_get(&ob_ptr, "type") == OB_MESH) { - uiItemR(col, &ptr, "uv_layer", 0, NULL, ICON_NONE); + uiItemPointerR(col, &ptr, "uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE); } uiItemS(layout); diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 00e39a7ea6c..29f7294c202 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -49,6 +49,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "DEG_depsgraph_query.h" @@ -1228,6 +1230,13 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_Explode, panel_draw); } +static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) +{ + ExplodeModifierData *psmd = (ExplodeModifierData *)md; + + psmd->facepa = NULL; +} + ModifierTypeInfo modifierType_Explode = { /* name */ "Explode", /* structName */ "ExplodeModifierData", @@ -1258,5 +1267,5 @@ ModifierTypeInfo modifierType_Explode = { /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 4305c32071d..c8cfc07562f 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -46,6 +46,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "DEG_depsgraph_query.h" @@ -468,6 +470,29 @@ static void panelRegister(ARegionType *region_type) region_type, "falloff", "Falloff", NULL, falloff_panel_draw, panel_type); } +static void blendWrite(BlendWriter *writer, const ModifierData *md) +{ + const HookModifierData *hmd = (const HookModifierData *)md; + + if (hmd->curfalloff) { + BKE_curvemapping_blend_write(writer, hmd->curfalloff); + } + + BLO_write_int32_array(writer, hmd->totindex, hmd->indexar); +} + +static void blendRead(BlendDataReader *reader, ModifierData *md) +{ + HookModifierData *hmd = (HookModifierData *)md; + + BLO_read_data_address(reader, &hmd->curfalloff); + if (hmd->curfalloff) { + BKE_curvemapping_blend_read(reader, hmd->curfalloff); + } + + BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar); +} + ModifierTypeInfo modifierType_Hook = { /* name */ "Hook", /* structName */ "HookModifierData", @@ -498,6 +523,6 @@ ModifierTypeInfo modifierType_Hook = { /* foreachTexLink */ NULL, /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ blendWrite, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index f324a6f92b9..e53de598218 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -49,6 +49,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "MEM_guardedalloc.h" @@ -607,6 +609,35 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_MeshDeform, panel_draw); } +static void blendWrite(BlendWriter *writer, const ModifierData *md) +{ + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; + int size = mmd->dyngridsize; + + BLO_write_struct_array(writer, MDefInfluence, mmd->totinfluence, mmd->bindinfluences); + BLO_write_int32_array(writer, mmd->totvert + 1, mmd->bindoffsets); + BLO_write_float3_array(writer, mmd->totcagevert, mmd->bindcagecos); + BLO_write_struct_array(writer, MDefCell, size * size * size, mmd->dyngrid); + BLO_write_struct_array(writer, MDefInfluence, mmd->totinfluence, mmd->dyninfluences); + BLO_write_int32_array(writer, mmd->totvert, mmd->dynverts); +} + +static void blendRead(BlendDataReader *reader, ModifierData *md) +{ + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; + + BLO_read_data_address(reader, &mmd->bindinfluences); + BLO_read_int32_array(reader, mmd->totvert + 1, &mmd->bindoffsets); + BLO_read_float3_array(reader, mmd->totcagevert, &mmd->bindcagecos); + BLO_read_data_address(reader, &mmd->dyngrid); + BLO_read_data_address(reader, &mmd->dyninfluences); + BLO_read_int32_array(reader, mmd->totvert, &mmd->dynverts); + + /* Deprecated storage. */ + BLO_read_float_array(reader, mmd->totvert, &mmd->bindweights); + BLO_read_float3_array(reader, mmd->totcagevert, &mmd->bindcos); +} + ModifierTypeInfo modifierType_MeshDeform = { /* name */ "MeshDeform", /* structName */ "MeshDeformModifierData", @@ -638,6 +669,6 @@ ModifierTypeInfo modifierType_MeshDeform = { /* foreachTexLink */ NULL, /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ blendWrite, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index b4269513f8e..9eae7ae941f 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -44,6 +44,8 @@ #include "RNA_access.h" +#include "BLO_read_write.h" + #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" @@ -229,6 +231,13 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_MeshSequenceCache, panel_draw); } +static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) +{ + MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md; + msmcd->reader = NULL; + msmcd->reader_object_path[0] = '\0'; +} + ModifierTypeInfo modifierType_MeshSequenceCache = { /* name */ "MeshSequenceCache", /* structName */ "MeshSeqCacheModifierData", @@ -260,5 +269,5 @@ ModifierTypeInfo modifierType_MeshSequenceCache = { /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 6abea36df35..5f67d591e60 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -181,18 +181,17 @@ static void data_panel_draw(const bContext *C, Panel *panel) uiLayoutSetPropSep(layout, true); - col = uiLayoutColumnWithHeading(layout, false, IFACE_("Mirror U")); - row = uiLayoutRow(col, true); + col = uiLayoutColumn(layout, true); + row = uiLayoutRowWithHeading(col, true, IFACE_("Mirror U")); uiLayoutSetPropDecorate(row, false); sub = uiLayoutRow(row, true); uiItemR(sub, &ptr, "use_mirror_u", 0, "", ICON_NONE); sub = uiLayoutRow(sub, true); uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_mirror_u")); uiItemR(sub, &ptr, "mirror_offset_u", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemDecoratorR(row, &ptr, "mirror_offset_v", 0); + uiItemDecoratorR(row, &ptr, "mirror_offset_u", 0); - col = uiLayoutColumnWithHeading(layout, false, "V"); - row = uiLayoutRow(col, true); + row = uiLayoutRowWithHeading(col, true, IFACE_("V")); uiLayoutSetPropDecorate(row, false); sub = uiLayoutRow(row, true); uiItemR(sub, &ptr, "use_mirror_v", 0, "", ICON_NONE); @@ -201,6 +200,10 @@ static void data_panel_draw(const bContext *C, Panel *panel) uiItemR(sub, &ptr, "mirror_offset_v", UI_ITEM_R_SLIDER, "", ICON_NONE); uiItemDecoratorR(row, &ptr, "mirror_offset_v", 0); + col = uiLayoutColumn(layout, true); + uiItemR(col, &ptr, "offset_u", UI_ITEM_R_SLIDER, IFACE_("Offset U"), ICON_NONE); + uiItemR(col, &ptr, "offset_v", UI_ITEM_R_SLIDER, IFACE_("V"), ICON_NONE); + uiItemR(layout, &ptr, "use_mirror_vertex_groups", 0, IFACE_("Vertex Groups"), ICON_NONE); uiItemR(layout, &ptr, "use_mirror_udim", 0, IFACE_("Flip UDIM"), ICON_NONE); } diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index e56ff991b6f..53e53315cfe 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -296,10 +296,10 @@ static void panel_draw(const bContext *C, Panel *panel) /** * Changing some of the properties can not be done once there is an - * actual displacement stored for this multires modifier. This check - * will disallow changes for those properties. - * This check is a bit stupif but it should be sufficient for the usual - * multires usage. It might become less strict and only disallow + * actual displacement stored for this multi-resolution modifier. + * This check will disallow changes for those properties. + * This check is a bit stupid but it should be sufficient for the usual + * multi-resolution usage. It might become less strict and only disallow * modifications if there is CD_MDISPS layer, or if there is actual * non-zero displacement, but such checks will be too slow to be done * on every redraw. diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 1cdba84bb27..88581464a02 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -49,6 +49,8 @@ #include "RNA_access.h" +#include "BLO_read_write.h" + #include "WM_types.h" /* For UI free bake operator. */ #include "DEG_depsgraph_query.h" @@ -674,6 +676,13 @@ static void panelRegister(ARegionType *region_type) #endif /* WITH_OCEANSIM */ } +static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) +{ + OceanModifierData *omd = (OceanModifierData *)md; + omd->oceancache = NULL; + omd->ocean = NULL; +} + ModifierTypeInfo modifierType_Ocean = { /* name */ "Ocean", /* structName */ "OceanModifierData", @@ -706,5 +715,5 @@ ModifierTypeInfo modifierType_Ocean = { /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index 8c25c3eb4ba..ea0c63da1b0 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -46,6 +46,8 @@ #include "DEG_depsgraph_query.h" +#include "BLO_read_write.h" + #include "MOD_ui_common.h" #include "MOD_util.h" @@ -295,6 +297,18 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_ParticleSystem, panel_draw); } +static void blendRead(BlendDataReader *reader, ModifierData *md) +{ + ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; + + psmd->mesh_final = NULL; + psmd->mesh_original = NULL; + /* This is written as part of ob->particlesystem. */ + BLO_read_data_address(reader, &psmd->psys); + psmd->flag &= ~eParticleSystemFlag_psys_updated; + psmd->flag |= eParticleSystemFlag_file_loaded; +} + ModifierTypeInfo modifierType_ParticleSystem = { /* name */ "ParticleSystem", /* structName */ "ParticleSystemModifierData", @@ -330,5 +344,5 @@ ModifierTypeInfo modifierType_ParticleSystem = { /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c index b1e6e12b4b3..6fc564448c3 100644 --- a/source/blender/modifiers/intern/MOD_remesh.c +++ b/source/blender/modifiers/intern/MOD_remesh.c @@ -190,8 +190,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx) break; } /* TODO(jbakker): Dualcon crashes when run in parallel. Could be related to incorrect - * input data or that the library isn't thread safe. This was identified when changing the task - * isolations during T76553. */ + * input data or that the library isn't thread safe. + * This was identified when changing the task isolation's during T76553. */ static ThreadMutex dualcon_mutex = BLI_MUTEX_INITIALIZER; BLI_mutex_lock(&dualcon_mutex); output = dualcon(&input, diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index f8d372f4d2b..82a8227c33a 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -128,7 +128,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "use_even_offset", 0, NULL, ICON_NONE); } - col = uiLayoutColumnWithHeading(layout, false, "Rim"); + col = uiLayoutColumnWithHeading(layout, false, IFACE_("Rim")); uiItemR(col, &ptr, "use_rim", 0, IFACE_("Fill"), ICON_NONE); sub = uiLayoutColumn(col, false); uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_rim")); diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index 75d2be5292e..a56194354f8 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -76,7 +76,7 @@ BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref) } /** - * \param dm: Mesh to calculate normals for. + * \param mesh: Mesh to calculate normals for. * \param poly_nors: Precalculated face normals. * \param r_vert_nors: Return vert normals. */ diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index aca4cad95b8..cbd2c2d27be 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -57,6 +57,8 @@ #include "MOD_modifiertypes.h" #include "MOD_ui_common.h" +#include "BLO_read_write.h" + #include "intern/CCGSubSurf.h" typedef struct SubsurfRuntimeData { @@ -414,8 +416,6 @@ static void advanced_panel_draw(const bContext *C, Panel *panel) uiItemR(layout, &ptr, "quality", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "uv_smooth", 0, NULL, ICON_NONE); uiItemR(layout, &ptr, "use_creases", 0, NULL, ICON_NONE); - - modifier_panel_end(layout, &ptr); } static void panelRegister(ARegionType *region_type) @@ -425,6 +425,13 @@ static void panelRegister(ARegionType *region_type) region_type, "advanced", "Advanced", NULL, advanced_panel_draw, panel_type); } +static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) +{ + SubsurfModifierData *smd = (SubsurfModifierData *)md; + + smd->emCache = smd->mCache = NULL; +} + ModifierTypeInfo modifierType_Subsurf = { /* name */ "Subdivision", /* structName */ "SubsurfModifierData", @@ -458,5 +465,5 @@ ModifierTypeInfo modifierType_Subsurf = { /* freeRuntimeData */ freeRuntimeData, /* panelRegister */ panelRegister, /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index 32b342b1471..e476e01a9f2 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -51,6 +51,8 @@ #include "MOD_ui_common.h" #include "MOD_util.h" +#include "BLO_read_write.h" + #include "MEM_guardedalloc.h" static void initData(ModifierData *md) @@ -210,6 +212,17 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_Surface, panel_draw); } +static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) +{ + SurfaceModifierData *surmd = (SurfaceModifierData *)md; + + surmd->mesh = NULL; + surmd->bvhtree = NULL; + surmd->x = NULL; + surmd->v = NULL; + surmd->numverts = 0; +} + ModifierTypeInfo modifierType_Surface = { /* name */ "Surface", /* structName */ "SurfaceModifierData", @@ -242,5 +255,5 @@ ModifierTypeInfo modifierType_Surface = { /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index e1bc6305b0a..fc41afb6613 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -47,6 +47,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "DEG_depsgraph.h" @@ -1438,6 +1440,64 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_SurfaceDeform, panel_draw); } +static void blendWrite(BlendWriter *writer, const ModifierData *md) +{ + const SurfaceDeformModifierData *smd = (const SurfaceDeformModifierData *)md; + + BLO_write_struct_array(writer, SDefVert, smd->numverts, smd->verts); + + if (smd->verts) { + for (int i = 0; i < smd->numverts; i++) { + BLO_write_struct_array(writer, SDefBind, smd->verts[i].numbinds, smd->verts[i].binds); + + if (smd->verts[i].binds) { + for (int j = 0; j < smd->verts[i].numbinds; j++) { + BLO_write_uint32_array( + writer, smd->verts[i].binds[j].numverts, smd->verts[i].binds[j].vert_inds); + + if (smd->verts[i].binds[j].mode == MOD_SDEF_MODE_CENTROID || + smd->verts[i].binds[j].mode == MOD_SDEF_MODE_LOOPTRI) { + BLO_write_float3_array(writer, 1, smd->verts[i].binds[j].vert_weights); + } + else { + BLO_write_float_array( + writer, smd->verts[i].binds[j].numverts, smd->verts[i].binds[j].vert_weights); + } + } + } + } + } +} + +static void blendRead(BlendDataReader *reader, ModifierData *md) +{ + SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; + + BLO_read_data_address(reader, &smd->verts); + + if (smd->verts) { + for (int i = 0; i < smd->numverts; i++) { + BLO_read_data_address(reader, &smd->verts[i].binds); + + if (smd->verts[i].binds) { + for (int j = 0; j < smd->verts[i].numbinds; j++) { + BLO_read_uint32_array( + reader, smd->verts[i].binds[j].numverts, &smd->verts[i].binds[j].vert_inds); + + if (smd->verts[i].binds[j].mode == MOD_SDEF_MODE_CENTROID || + smd->verts[i].binds[j].mode == MOD_SDEF_MODE_LOOPTRI) { + BLO_read_float3_array(reader, 1, &smd->verts[i].binds[j].vert_weights); + } + else { + BLO_read_float_array( + reader, smd->verts[i].binds[j].numverts, &smd->verts[i].binds[j].vert_weights); + } + } + } + } + } +} + ModifierTypeInfo modifierType_SurfaceDeform = { /* name */ "SurfaceDeform", /* structName */ "SurfaceDeformModifierData", @@ -1468,6 +1528,6 @@ ModifierTypeInfo modifierType_SurfaceDeform = { /* foreachTexLink */ NULL, /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ blendWrite, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c index cc0d3d8ccee..63ec9a2d929 100644 --- a/source/blender/modifiers/intern/MOD_ui_common.c +++ b/source/blender/modifiers/intern/MOD_ui_common.c @@ -127,7 +127,7 @@ void modifier_panel_end(uiLayout *layout, PointerRNA *ptr) /** * Gets RNA pointers for the active object and the panel's modifier data. Also locks - * the layout if the modifer is from a linked object, and sets the context pointer. + * the layout if the modifier is from a linked object, and sets the context pointer. */ #define ERROR_LIBDATA_MESSAGE TIP_("External library data") void modifier_panel_get_property_pointers(const bContext *C, @@ -146,8 +146,7 @@ void modifier_panel_get_property_pointers(const bContext *C, } uiBlock *block = uiLayoutGetBlock(panel->layout); - UI_block_lock_set( - block, BKE_object_obdata_is_libdata(ob) || ID_IS_LINKED(ob), ERROR_LIBDATA_MESSAGE); + UI_block_lock_set(block, ID_IS_LINKED(ob), ERROR_LIBDATA_MESSAGE); uiLayoutSetContextPointer(panel->layout, "modifier", r_md_ptr); } @@ -222,19 +221,29 @@ static bool modifier_can_delete(ModifierData *md) return true; } -static void modifier_ops_extra_draw(bContext *UNUSED(C), uiLayout *layout, void *md_v) +static void modifier_ops_extra_draw(bContext *C, uiLayout *layout, void *md_v) { + PointerRNA op_ptr; + uiLayout *row; ModifierData *md = (ModifierData *)md_v; + PointerRNA ptr; + Object *ob = get_modifier_object(C); + RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr); + uiLayoutSetContextPointer(layout, "modifier", &ptr); uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + uiLayoutSetUnitsX(layout, 4.0f); + + /* Apply. */ uiItemEnumO(layout, "OBJECT_OT_modifier_apply", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"), - 0, + ICON_CHECKMARK, "apply_as", MODIFIER_APPLY_DATA); + /* Apply as shapekey. */ if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) { uiItemEnumO(layout, "OBJECT_OT_modifier_apply", @@ -244,6 +253,7 @@ static void modifier_ops_extra_draw(bContext *UNUSED(C), uiLayout *layout, void MODIFIER_APPLY_SHAPE); } + /* Duplicate. */ if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody, @@ -256,17 +266,42 @@ static void modifier_ops_extra_draw(bContext *UNUSED(C), uiLayout *layout, void "OBJECT_OT_modifier_copy"); } - if (modifier_can_delete(md) && !modifier_is_simulation(md)) { - uiItemO(layout, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete"), - ICON_X, - "OBJECT_OT_modifier_remove"); + uiItemS(layout); + + /* Move to first. */ + row = uiLayoutColumn(layout, false); + uiItemFullO(row, + "OBJECT_OT_modifier_move_to_index", + IFACE_("Move to First"), + ICON_TRIA_UP, + NULL, + WM_OP_INVOKE_DEFAULT, + 0, + &op_ptr); + RNA_int_set(&op_ptr, "index", 0); + if (!md->prev) { + uiLayoutSetEnabled(row, false); + } + + /* Move to last. */ + row = uiLayoutColumn(layout, false); + uiItemFullO(row, + "OBJECT_OT_modifier_move_to_index", + IFACE_("Move to Last"), + ICON_TRIA_DOWN, + NULL, + WM_OP_INVOKE_DEFAULT, + 0, + &op_ptr); + RNA_int_set(&op_ptr, "index", BLI_listbase_count(&ob->modifiers) - 1); + if (!md->next) { + uiLayoutSetEnabled(row, false); } } static void modifier_panel_header(const bContext *C, Panel *panel) { - uiLayout *row, *sub; + uiLayout *row, *sub, *name_row; uiLayout *layout = panel->layout; PointerRNA ptr; @@ -280,32 +315,22 @@ static void modifier_panel_header(const bContext *C, Panel *panel) const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); Scene *scene = CTX_data_scene(C); int index = panel->runtime.list_index; - bool narrow_panel = (panel->sizex < UI_UNIT_X * 8 && panel->sizex != 0); /* Modifier Icon. */ - row = uiLayoutRow(layout, false); + sub = uiLayoutRow(layout, true); if (mti->isDisabled && mti->isDisabled(scene, md, 0)) { - uiLayoutSetRedAlert(row, true); + uiLayoutSetRedAlert(sub, true); } - uiItemL(row, "", RNA_struct_ui_icon(ptr.type)); + uiItemL(sub, "", RNA_struct_ui_icon(ptr.type)); - /* Modifier Name. */ - if (!narrow_panel) { - uiItemR(layout, &ptr, "name", 0, "", ICON_NONE); - } + row = uiLayoutRow(layout, true); - /* Switch context buttons. */ - if (modifier_is_simulation(md) == 1) { - uiItemStringO( - layout, "", ICON_PROPERTIES, "WM_OT_properties_context_change", "context", "PHYSICS"); - } - else if (modifier_is_simulation(md) == 2) { - uiItemStringO( - layout, "", ICON_PROPERTIES, "WM_OT_properties_context_change", "context", "PARTICLES"); - } + /* Modifier Name. + * Count how many buttons are added to the header to check if there is enough space. */ + int buttons_number = 0; + name_row = uiLayoutRow(row, true); - /* Mode switching buttons. */ - row = uiLayoutRow(layout, true); + /* Display mode switching buttons. */ if (ob->type == OB_MESH) { int last_cage_index; int cage_index = BKE_modifiers_get_cage_index(scene, ob, &last_cage_index, 0); @@ -315,12 +340,14 @@ static void modifier_panel_header(const bContext *C, Panel *panel) uiLayoutSetActive(sub, false); } uiItemR(sub, &ptr, "show_on_cage", 0, "", ICON_NONE); + buttons_number++; } } /* Tessellation point for curve-typed objects. */ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { if (mti->type != eModifierTypeType_Constructive) { /* Constructive modifiers tessellates curve before applying. */ - uiItemR(layout, &ptr, "use_apply_on_spline", 0, "", ICON_NONE); + uiItemR(row, &ptr, "use_apply_on_spline", 0, "", ICON_NONE); + buttons_number++; } } /* Collision and Surface are always enabled, hide buttons. */ @@ -330,15 +357,45 @@ static void modifier_panel_header(const bContext *C, Panel *panel) sub = uiLayoutRow(row, true); uiLayoutSetActive(sub, (md->mode & eModifierMode_Realtime)); uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE); + buttons_number++; } uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE); uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE); + buttons_number += 2; } - row = uiLayoutRow(layout, false); + /* Extra operators menu. */ uiItemMenuF(row, "", ICON_DOWNARROW_HLT, modifier_ops_extra_draw, md); - /* Some padding at the end, so the buttons aren't too close to the drag button. */ + /* Delete button. */ + if (modifier_can_delete(md) && !modifier_is_simulation(md)) { + sub = uiLayoutRow(row, false); + uiLayoutSetEmboss(sub, UI_EMBOSS_NONE); + uiItemO(sub, "", ICON_X, "OBJECT_OT_modifier_remove"); + buttons_number++; + } + + /* Switch context buttons. */ + if (modifier_is_simulation(md) == 1) { + uiItemStringO( + row, "", ICON_PROPERTIES, "WM_OT_properties_context_change", "context", "PHYSICS"); + buttons_number++; + } + else if (modifier_is_simulation(md) == 2) { + uiItemStringO( + row, "", ICON_PROPERTIES, "WM_OT_properties_context_change", "context", "PARTICLES"); + buttons_number++; + } + + bool display_name = (panel->sizex / UI_UNIT_X - buttons_number > 5) || (panel->sizex == 0); + if (display_name) { + uiItemR(name_row, &ptr, "name", 0, "", ICON_NONE); + } + else { + uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); + } + + /* Extra padding for delete button. */ uiItemS(layout); } @@ -369,7 +426,7 @@ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, panel_type->poll = modifier_ui_poll; /* Give the panel the special flag that says it was built here and corresponds to a - * modifer rather than a PanelType. */ + * modifier rather than a #PanelType. */ panel_type->flag = PNL_LAYOUT_HEADER_EXPAND | PNL_DRAW_BOX | PNL_INSTANCED; panel_type->reorder = modifier_reorder; panel_type->get_list_data_expand_flag = get_modifier_expand_flag; @@ -381,7 +438,7 @@ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, } /** - * Add a shild panel to the parent. + * Add a child panel to the parent. * * \note To create the panel type's idname, it appends the \a name argument to the \a parent's * idname. diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index b32efa3fb8f..2b67b26e620 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -49,6 +49,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "DEG_depsgraph.h" @@ -510,6 +512,25 @@ static void panelRegister(ARegionType *region_type) region_type, "texture", "Texture", NULL, texture_panel_draw, panel_type); } +static void blendWrite(BlendWriter *writer, const ModifierData *md) +{ + const WarpModifierData *tmd = (const WarpModifierData *)md; + + if (tmd->curfalloff) { + BKE_curvemapping_blend_write(writer, tmd->curfalloff); + } +} + +static void blendRead(BlendDataReader *reader, ModifierData *md) +{ + WarpModifierData *tmd = (WarpModifierData *)md; + + BLO_read_data_address(reader, &tmd->curfalloff); + if (tmd->curfalloff) { + BKE_curvemapping_blend_read(reader, tmd->curfalloff); + } +} + ModifierTypeInfo modifierType_Warp = { /* name */ "Warp", /* structName */ "WarpModifierData", @@ -540,6 +561,6 @@ ModifierTypeInfo modifierType_Warp = { /* foreachTexLink */ foreachTexLink, /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ blendWrite, + /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index c1fe8e1f009..789b65dbde3 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -388,7 +388,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiLayoutSetPropSep(layout, true); - row = uiLayoutRowWithHeading(layout, true, "Motion"); + row = uiLayoutRowWithHeading(layout, true, IFACE_("Motion")); uiItemR(row, &ptr, "use_x", UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE, NULL, ICON_NONE); uiItemR(row, &ptr, "use_y", UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE, NULL, ICON_NONE); diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index 9dfc2f653cd..8039856172a 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -47,6 +47,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "DEG_depsgraph_build.h" @@ -399,6 +401,25 @@ static void panelRegister(ARegionType *region_type) region_type, "influence", "Influence", NULL, influence_panel_draw, panel_type); } +static void blendWrite(BlendWriter *writer, const ModifierData *md) +{ + const WeightVGEditModifierData *wmd = (const WeightVGEditModifierData *)md; + + if (wmd->cmap_curve) { + BKE_curvemapping_blend_write(writer, wmd->cmap_curve); + } +} + +static void blendRead(BlendDataReader *reader, ModifierData *md) +{ + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; + + BLO_read_data_address(reader, &wmd->cmap_curve); + if (wmd->cmap_curve) { + BKE_curvemapping_blend_read(reader, wmd->cmap_curve); + } +} + ModifierTypeInfo modifierType_WeightVGEdit = { /* name */ "VertexWeightEdit", /* structName */ "WeightVGEditModifierData", @@ -430,6 +451,6 @@ ModifierTypeInfo modifierType_WeightVGEdit = { /* foreachTexLink */ foreachTexLink, /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ blendWrite, + /* blendRead */ blendRead, }; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 80bf0f7c5e2..31b5e922dab 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -273,7 +273,7 @@ set(SRC intern/node_common.c intern/node_exec.c - intern/node_socket.c + intern/node_socket.cc intern/node_util.c composite/node_composite_util.h diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index 534e9012693..6b1dd239294 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -26,6 +26,10 @@ #include "BKE_node.h" +#ifdef __cplusplus +extern "C" { +#endif + extern struct bNodeTreeType *ntreeType_Composite; /* ****************** types array for all composite nodes ****************** */ @@ -143,4 +147,8 @@ const char *node_cmp_rlayers_sock_to_pass(int sock_index); void register_node_type_cmp_custom_group(bNodeType *ntype); +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index a89a9e927b9..bf548aea5f4 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -26,6 +26,10 @@ #include "BKE_node.h" +#ifdef __cplusplus +extern "C" { +#endif + extern struct bNodeTreeType *ntreeType_Shader; /* the type definitions array */ @@ -139,4 +143,8 @@ void register_node_type_sh_tex_white_noise(void); void register_node_type_sh_custom_group(bNodeType *ntype); +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/nodes/NOD_socket.h b/source/blender/nodes/NOD_socket.h index b1b1a0e40c6..ce6f0da4aee 100644 --- a/source/blender/nodes/NOD_socket.h +++ b/source/blender/nodes/NOD_socket.h @@ -35,6 +35,10 @@ struct bNode; struct bNodeTree; +#ifdef __cplusplus +extern "C" { +#endif + struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, @@ -46,4 +50,8 @@ void node_socket_init_default_value(struct bNodeSocket *sock); void node_socket_copy_default_value(struct bNodeSocket *to, const struct bNodeSocket *from); void register_standard_node_socket_types(void); +#ifdef __cplusplus +} #endif + +#endif /* __NOD_SOCKET_H__ */ diff --git a/source/blender/nodes/NOD_texture.h b/source/blender/nodes/NOD_texture.h index eaa4952e7e6..07a05f01bc5 100644 --- a/source/blender/nodes/NOD_texture.h +++ b/source/blender/nodes/NOD_texture.h @@ -26,6 +26,10 @@ #include "BKE_node.h" +#ifdef __cplusplus +extern "C" { +#endif + extern struct bNodeTreeType *ntreeType_Texture; /* ****************** types array for all texture nodes ****************** */ @@ -71,4 +75,8 @@ void register_node_type_tex_proc_noise(void); void register_node_type_tex_proc_stucci(void); void register_node_type_tex_proc_distnoise(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/nodes/composite/node_composite_util.h b/source/blender/nodes/composite/node_composite_util.h index 4372ef78bc0..0edc864e98f 100644 --- a/source/blender/nodes/composite/node_composite_util.h +++ b/source/blender/nodes/composite/node_composite_util.h @@ -49,6 +49,10 @@ /* only for forward declarations */ #include "NOD_composite.h" +#ifdef __cplusplus +extern "C" { +#endif + #define CMP_SCALE_MAX 12000 bool cmp_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree); @@ -56,4 +60,8 @@ void cmp_node_update_default(struct bNodeTree *UNUSED(ntree), struct bNode *node void cmp_node_type_base( struct bNodeType *ntype, int type, const char *name, short nclass, short flag); +#ifdef __cplusplus +} +#endif + #endif /* __NODE_COMPOSITE_UTIL_H__ */ diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index 765fa84439f..996fb93eb76 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -125,7 +125,7 @@ static bNodeSocket *group_verify_socket( bNodeSocket *sock; for (sock = verify_lb->first; sock; sock = sock->next) { - if (STREQ(sock->identifier, iosock->identifier)) { + if (sock->typeinfo == iosock->typeinfo && STREQ(sock->identifier, iosock->identifier)) { break; } } diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h index 07c12dc7c46..87a61f0a490 100644 --- a/source/blender/nodes/intern/node_exec.h +++ b/source/blender/nodes/intern/node_exec.h @@ -34,6 +34,10 @@ #include "RNA_types.h" +#ifdef __cplusplus +extern "C" { +#endif + struct bNode; struct bNodeStack; struct bNodeTree; @@ -98,4 +102,8 @@ struct bNodeTreeExec *ntreeTexBeginExecTree_internal(struct bNodeExecContext *co bNodeInstanceKey parent_key); void ntreeTexEndExecTree_internal(struct bNodeTreeExec *exec); +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.cc index 668dd3829cc..b23511c3bdb 100644 --- a/source/blender/nodes/intern/node_socket.c +++ b/source/blender/nodes/intern/node_socket.cc @@ -53,26 +53,26 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, /* initialize default_value */ switch (stemp->type) { case SOCK_FLOAT: { - bNodeSocketValueFloat *dval = sock->default_value; + bNodeSocketValueFloat *dval = (bNodeSocketValueFloat *)sock->default_value; dval->value = stemp->val1; dval->min = stemp->min; dval->max = stemp->max; break; } case SOCK_INT: { - bNodeSocketValueInt *dval = sock->default_value; + bNodeSocketValueInt *dval = (bNodeSocketValueInt *)sock->default_value; dval->value = (int)stemp->val1; dval->min = (int)stemp->min; dval->max = (int)stemp->max; break; } case SOCK_BOOLEAN: { - bNodeSocketValueBoolean *dval = sock->default_value; + bNodeSocketValueBoolean *dval = (bNodeSocketValueBoolean *)sock->default_value; dval->value = (int)stemp->val1; break; } case SOCK_VECTOR: { - bNodeSocketValueVector *dval = sock->default_value; + bNodeSocketValueVector *dval = (bNodeSocketValueVector *)sock->default_value; dval->value[0] = stemp->val1; dval->value[1] = stemp->val2; dval->value[2] = stemp->val3; @@ -81,7 +81,7 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, break; } case SOCK_RGBA: { - bNodeSocketValueRGBA *dval = sock->default_value; + bNodeSocketValueRGBA *dval = (bNodeSocketValueRGBA *)sock->default_value; dval->value[0] = stemp->val1; dval->value[1] = stemp->val2; dval->value[2] = stemp->val3; @@ -98,7 +98,7 @@ static bNodeSocket *verify_socket_template( { bNodeSocket *sock; - for (sock = socklist->first; sock; sock = sock->next) { + for (sock = (bNodeSocket *)socklist->first; sock; sock = sock->next) { if (STREQLEN(sock->name, stemp->name, NODE_MAXSTR)) { break; } @@ -153,12 +153,11 @@ static void verify_socket_template_list(bNodeTree *ntree, /* and we put back the verified sockets */ stemp = stemp_first; if (socklist->first) { - /* some dynamic sockets left, store the list start - * so we can add static sockets infront of it. - */ - sock = socklist->first; + /* Some dynamic sockets left, store the list start + * so we can add static sockets in front of it. */ + sock = (bNodeSocket *)socklist->first; while (stemp->type != -1) { - /* put static sockets infront of dynamic */ + /* Put static sockets in front of dynamic. */ BLI_insertlinkbefore(socklist, sock, stemp->sock); stemp++; } @@ -201,8 +200,8 @@ void node_socket_init_default_value(bNodeSocket *sock) switch (type) { case SOCK_FLOAT: { - bNodeSocketValueFloat *dval = MEM_callocN(sizeof(bNodeSocketValueFloat), - "node socket value float"); + bNodeSocketValueFloat *dval = (bNodeSocketValueFloat *)MEM_callocN( + sizeof(bNodeSocketValueFloat), "node socket value float"); dval->subtype = subtype; dval->value = 0.0f; dval->min = -FLT_MAX; @@ -212,8 +211,8 @@ void node_socket_init_default_value(bNodeSocket *sock) break; } case SOCK_INT: { - bNodeSocketValueInt *dval = MEM_callocN(sizeof(bNodeSocketValueInt), - "node socket value int"); + bNodeSocketValueInt *dval = (bNodeSocketValueInt *)MEM_callocN(sizeof(bNodeSocketValueInt), + "node socket value int"); dval->subtype = subtype; dval->value = 0; dval->min = INT_MIN; @@ -223,8 +222,8 @@ void node_socket_init_default_value(bNodeSocket *sock) break; } case SOCK_BOOLEAN: { - bNodeSocketValueBoolean *dval = MEM_callocN(sizeof(bNodeSocketValueBoolean), - "node socket value bool"); + bNodeSocketValueBoolean *dval = (bNodeSocketValueBoolean *)MEM_callocN( + sizeof(bNodeSocketValueBoolean), "node socket value bool"); dval->value = false; sock->default_value = dval; @@ -232,8 +231,8 @@ void node_socket_init_default_value(bNodeSocket *sock) } case SOCK_VECTOR: { static float default_value[] = {0.0f, 0.0f, 0.0f}; - bNodeSocketValueVector *dval = MEM_callocN(sizeof(bNodeSocketValueVector), - "node socket value vector"); + bNodeSocketValueVector *dval = (bNodeSocketValueVector *)MEM_callocN( + sizeof(bNodeSocketValueVector), "node socket value vector"); dval->subtype = subtype; copy_v3_v3(dval->value, default_value); dval->min = -FLT_MAX; @@ -244,16 +243,16 @@ void node_socket_init_default_value(bNodeSocket *sock) } case SOCK_RGBA: { static float default_value[] = {0.0f, 0.0f, 0.0f, 1.0f}; - bNodeSocketValueRGBA *dval = MEM_callocN(sizeof(bNodeSocketValueRGBA), - "node socket value color"); + bNodeSocketValueRGBA *dval = (bNodeSocketValueRGBA *)MEM_callocN( + sizeof(bNodeSocketValueRGBA), "node socket value color"); copy_v4_v4(dval->value, default_value); sock->default_value = dval; break; } case SOCK_STRING: { - bNodeSocketValueString *dval = MEM_callocN(sizeof(bNodeSocketValueString), - "node socket value string"); + bNodeSocketValueString *dval = (bNodeSocketValueString *)MEM_callocN( + sizeof(bNodeSocketValueString), "node socket value string"); dval->subtype = subtype; dval->value[0] = '\0'; @@ -261,16 +260,16 @@ void node_socket_init_default_value(bNodeSocket *sock) break; } case SOCK_OBJECT: { - bNodeSocketValueObject *dval = MEM_callocN(sizeof(bNodeSocketValueObject), - "node socket value object"); + bNodeSocketValueObject *dval = (bNodeSocketValueObject *)MEM_callocN( + sizeof(bNodeSocketValueObject), "node socket value object"); dval->value = NULL; sock->default_value = dval; break; } case SOCK_IMAGE: { - bNodeSocketValueImage *dval = MEM_callocN(sizeof(bNodeSocketValueImage), - "node socket value image"); + bNodeSocketValueImage *dval = (bNodeSocketValueImage *)MEM_callocN( + sizeof(bNodeSocketValueImage), "node socket value image"); dval->value = NULL; sock->default_value = dval; @@ -299,51 +298,51 @@ void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from) switch (from->typeinfo->type) { case SOCK_FLOAT: { - bNodeSocketValueFloat *toval = to->default_value; - bNodeSocketValueFloat *fromval = from->default_value; + bNodeSocketValueFloat *toval = (bNodeSocketValueFloat *)to->default_value; + bNodeSocketValueFloat *fromval = (bNodeSocketValueFloat *)from->default_value; *toval = *fromval; break; } case SOCK_INT: { - bNodeSocketValueInt *toval = to->default_value; - bNodeSocketValueInt *fromval = from->default_value; + bNodeSocketValueInt *toval = (bNodeSocketValueInt *)to->default_value; + bNodeSocketValueInt *fromval = (bNodeSocketValueInt *)from->default_value; *toval = *fromval; break; } case SOCK_BOOLEAN: { - bNodeSocketValueBoolean *toval = to->default_value; - bNodeSocketValueBoolean *fromval = from->default_value; + bNodeSocketValueBoolean *toval = (bNodeSocketValueBoolean *)to->default_value; + bNodeSocketValueBoolean *fromval = (bNodeSocketValueBoolean *)from->default_value; *toval = *fromval; break; } case SOCK_VECTOR: { - bNodeSocketValueVector *toval = to->default_value; - bNodeSocketValueVector *fromval = from->default_value; + bNodeSocketValueVector *toval = (bNodeSocketValueVector *)to->default_value; + bNodeSocketValueVector *fromval = (bNodeSocketValueVector *)from->default_value; *toval = *fromval; break; } case SOCK_RGBA: { - bNodeSocketValueRGBA *toval = to->default_value; - bNodeSocketValueRGBA *fromval = from->default_value; + bNodeSocketValueRGBA *toval = (bNodeSocketValueRGBA *)to->default_value; + bNodeSocketValueRGBA *fromval = (bNodeSocketValueRGBA *)from->default_value; *toval = *fromval; break; } case SOCK_STRING: { - bNodeSocketValueString *toval = to->default_value; - bNodeSocketValueString *fromval = from->default_value; + bNodeSocketValueString *toval = (bNodeSocketValueString *)to->default_value; + bNodeSocketValueString *fromval = (bNodeSocketValueString *)from->default_value; *toval = *fromval; break; } case SOCK_OBJECT: { - bNodeSocketValueObject *toval = to->default_value; - bNodeSocketValueObject *fromval = from->default_value; + bNodeSocketValueObject *toval = (bNodeSocketValueObject *)to->default_value; + bNodeSocketValueObject *fromval = (bNodeSocketValueObject *)from->default_value; *toval = *fromval; id_us_plus(&toval->value->id); break; } case SOCK_IMAGE: { - bNodeSocketValueImage *toval = to->default_value; - bNodeSocketValueImage *fromval = from->default_value; + bNodeSocketValueImage *toval = (bNodeSocketValueImage *)to->default_value; + bNodeSocketValueImage *fromval = (bNodeSocketValueImage *)from->default_value; *toval = *fromval; id_us_plus(&toval->value->id); break; @@ -390,22 +389,22 @@ static void standard_node_socket_interface_verify_socket(bNodeTree *UNUSED(ntree switch (stemp->typeinfo->type) { case SOCK_FLOAT: { - bNodeSocketValueFloat *toval = sock->default_value; - bNodeSocketValueFloat *fromval = stemp->default_value; + bNodeSocketValueFloat *toval = (bNodeSocketValueFloat *)sock->default_value; + bNodeSocketValueFloat *fromval = (bNodeSocketValueFloat *)stemp->default_value; toval->min = fromval->min; toval->max = fromval->max; break; } case SOCK_INT: { - bNodeSocketValueInt *toval = sock->default_value; - bNodeSocketValueInt *fromval = stemp->default_value; + bNodeSocketValueInt *toval = (bNodeSocketValueInt *)sock->default_value; + bNodeSocketValueInt *fromval = (bNodeSocketValueInt *)stemp->default_value; toval->min = fromval->min; toval->max = fromval->max; break; } case SOCK_VECTOR: { - bNodeSocketValueVector *toval = sock->default_value; - bNodeSocketValueVector *fromval = stemp->default_value; + bNodeSocketValueVector *toval = (bNodeSocketValueVector *)sock->default_value; + bNodeSocketValueVector *fromval = (bNodeSocketValueVector *)stemp->default_value; toval->min = fromval->min; toval->max = fromval->max; break; @@ -423,16 +422,16 @@ static void standard_node_socket_interface_from_socket(bNodeTree *UNUSED(ntree), node_socket_copy_default_value(stemp, sock); } +extern "C" void ED_init_standard_node_socket_type(bNodeSocketType *); + static bNodeSocketType *make_standard_socket_type(int type, int subtype) { - extern void ED_init_standard_node_socket_type(bNodeSocketType *); - const char *socket_idname = nodeStaticSocketType(type, subtype); const char *interface_idname = nodeStaticSocketInterfaceType(type, subtype); bNodeSocketType *stype; StructRNA *srna; - stype = MEM_callocN(sizeof(bNodeSocketType), "node socket C type"); + stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type"); stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN; BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname)); @@ -467,15 +466,15 @@ static bNodeSocketType *make_standard_socket_type(int type, int subtype) return stype; } +extern "C" void ED_init_node_socket_type_virtual(bNodeSocketType *); + static bNodeSocketType *make_socket_type_virtual(void) { - extern void ED_init_node_socket_type_virtual(bNodeSocketType *); - const char *socket_idname = "NodeSocketVirtual"; bNodeSocketType *stype; StructRNA *srna; - stype = MEM_callocN(sizeof(bNodeSocketType), "node socket C type"); + stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type"); stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN; BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname)); diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h index 8834de0633e..fbb9979cdfa 100644 --- a/source/blender/nodes/shader/node_shader_util.h +++ b/source/blender/nodes/shader/node_shader_util.h @@ -69,6 +69,10 @@ #include "GPU_texture.h" #include "GPU_uniformbuffer.h" +#ifdef __cplusplus +extern "C" { +#endif + bool sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree); void sh_node_type_base( struct bNodeType *ntype, int type, const char *name, short nclass, short flag); @@ -101,4 +105,8 @@ void ntreeExecGPUNodes(struct bNodeTreeExec *exec, struct GPUMaterial *mat, struct bNode *output_node); +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c index cb91e086cf4..0daa948c139 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c @@ -41,8 +41,15 @@ static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node) tex->sun_direction[2] = 1.0f; tex->turbidity = 2.2f; tex->ground_albedo = 0.3f; - tex->sky_model = SHD_SKY_NEW; - + tex->sun_disc = true; + tex->sun_size = DEG2RADF(0.545); + tex->sun_elevation = M_PI_2; + tex->sun_rotation = 0.0f; + tex->altitude = 0; + tex->air_density = 1.0f; + tex->dust_density = 1.0f; + tex->ozone_density = 1.0f; + tex->sky_model = SHD_SKY_NISHITA; node->storage = tex; } diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h index b3407f68857..7b8581c1f89 100644 --- a/source/blender/nodes/texture/node_texture_util.h +++ b/source/blender/nodes/texture/node_texture_util.h @@ -64,6 +64,10 @@ #include "RE_pipeline.h" #include "RE_shader_ext.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct TexCallData { TexResult *target; /* all float[3] */ @@ -124,4 +128,8 @@ void tex_do_preview(bNodePreview *preview, void params_from_cdata(TexParams *out, TexCallData *in); +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index 18fab5215a6..051f11aa1d9 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -137,6 +137,35 @@ static float cloth_calc_volume(ClothModifierData *clmd) return vol; } +static float cloth_calc_rest_volume(ClothModifierData *clmd) +{ + /* Calculate the (closed) cloth volume. */ + Cloth *cloth = clmd->clothObject; + const MVertTri *tri = cloth->tri; + const ClothVertex *v = cloth->verts; + float weights[3] = {1.0f, 1.0f, 1.0f}; + float vol = 0; + + /* Early exit for hair, as it never has volume. */ + if (clmd->hairdata) { + return 0.0f; + } + + for (unsigned int i = 0; i < cloth->primitive_num; i++) { + const MVertTri *vt = &tri[i]; + + if (cloth_get_pressure_weights(clmd, vt, weights)) { + vol += volume_tri_tetrahedron_signed_v3_6x( + v[vt->tri[0]].xrest, v[vt->tri[1]].xrest, v[vt->tri[2]].xrest); + } + } + + /* We need to divide by 6 to get the actual volume. */ + vol = vol / 6.0f; + + return vol; +} + static float cloth_calc_average_pressure(ClothModifierData *clmd, const float *vertex_pressure) { Cloth *cloth = clmd->clothObject; @@ -219,7 +248,7 @@ void BKE_cloth_solver_set_volume(ClothModifierData *clmd) { Cloth *cloth = clmd->clothObject; - cloth->initial_mesh_volume = cloth_calc_volume(clmd); + cloth->initial_mesh_volume = cloth_calc_rest_volume(clmd); } /* Init constraint matrix @@ -683,23 +712,42 @@ static void cloth_calc_force( /* handle external forces like wind */ if (effectors) { + bool is_not_hair = (clmd->hairdata == NULL) && (cloth->primitive_num > 0); + bool has_wind = false, has_force = false; + /* cache per-vertex forces to avoid redundant calculation */ - float(*winvec)[3] = (float(*)[3])MEM_callocN(sizeof(float[3]) * mvert_num, "effector forces"); + float(*winvec)[3] = (float(*)[3])MEM_callocN(sizeof(float[3]) * mvert_num * 2, + "effector forces"); + float(*forcevec)[3] = is_not_hair ? winvec + mvert_num : winvec; + for (i = 0; i < cloth->mvert_num; i++) { float x[3], v[3]; EffectedPoint epoint; BPH_mass_spring_get_motion_state(data, i, x, v); pd_point_from_loc(scene, x, v, i, &epoint); - BKE_effectors_apply( - effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL); + BKE_effectors_apply(effectors, + NULL, + clmd->sim_parms->effector_weights, + &epoint, + forcevec[i], + winvec[i], + NULL); + + has_wind = has_wind || !is_zero_v3(winvec[i]); + has_force = has_force || !is_zero_v3(forcevec[i]); } /* Hair has only edges. */ - if ((clmd->hairdata == NULL) && (cloth->primitive_num > 0)) { + if (is_not_hair) { for (i = 0; i < cloth->primitive_num; i++) { const MVertTri *vt = &tri[i]; - BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec); + if (has_wind) { + BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec); + } + if (has_force) { + BPH_mass_spring_force_face_extern(data, vt->tri[0], vt->tri[1], vt->tri[2], forcevec); + } } } else { diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h index 69b50f7fa48..8bc09755180 100644 --- a/source/blender/physics/intern/implicit.h +++ b/source/blender/physics/intern/implicit.h @@ -126,9 +126,12 @@ void BPH_mass_spring_force_drag(struct Implicit_Data *data, float drag); /* Custom external force */ void BPH_mass_spring_force_extern( struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3]); -/* Wind force, acting on a face */ +/* Wind force, acting on a face (only generates pressure from the normal component) */ void BPH_mass_spring_force_face_wind( struct Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3]); +/* Arbitrary per-unit-area vector force field acting on a face. */ +void BPH_mass_spring_force_face_extern( + struct Implicit_Data *data, int v1, int v2, int v3, const float (*forcevec)[3]); /* Wind force, acting on an edge */ void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c index 063c224f158..5ec4c750d5d 100644 --- a/source/blender/physics/intern/implicit_blender.c +++ b/source/blender/physics/intern/implicit_blender.c @@ -1469,22 +1469,71 @@ void BPH_mass_spring_force_face_wind( Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3]) { const float effector_scale = 0.02f; + int vs[3] = {v1, v2, v3}; float win[3], nor[3], area; - float factor; + float factor, base_force; + float force[3]; /* calculate face normal and area */ area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]); /* The force is calculated and split up evenly for each of the three face verts */ factor = effector_scale * area / 3.0f; - world_to_root_v3(data, v1, win, winvec[v1]); - madd_v3_v3fl(data->F[v1], nor, factor * dot_v3v3(win, nor)); + /* Calculate wind pressure at each vertex by projecting the wind field on the normal. */ + for (int i = 0; i < 3; i++) { + world_to_root_v3(data, vs[i], win, winvec[vs[i]]); - world_to_root_v3(data, v2, win, winvec[v2]); - madd_v3_v3fl(data->F[v2], nor, factor * dot_v3v3(win, nor)); + force[i] = dot_v3v3(win, nor); + } - world_to_root_v3(data, v3, win, winvec[v3]); - madd_v3_v3fl(data->F[v3], nor, factor * dot_v3v3(win, nor)); + /* Compute per-vertex force values from local pressures. + * From integrating the pressure over the triangle and deriving + * equivalent vertex forces, it follows that: + * + * force[idx] = (sum(pressure) + pressure[idx]) * area / 12 + * + * Effectively, 1/4 of the pressure acts just on its vertex, + * while 3/4 is split evenly over all three. + */ + mul_v3_fl(force, factor / 4.0f); + + base_force = force[0] + force[1] + force[2]; + + /* add pressure to each of the face verts */ + madd_v3_v3fl(data->F[v1], nor, base_force + force[0]); + madd_v3_v3fl(data->F[v2], nor, base_force + force[1]); + madd_v3_v3fl(data->F[v3], nor, base_force + force[2]); +} + +void BPH_mass_spring_force_face_extern( + Implicit_Data *data, int v1, int v2, int v3, const float (*forcevec)[3]) +{ + const float effector_scale = 0.02f; + int vs[3] = {v1, v2, v3}; + float nor[3], area; + float factor, base_force[3]; + float force[3][3]; + + /* calculate face normal and area */ + area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]); + /* The force is calculated and split up evenly for each of the three face verts */ + factor = effector_scale * area / 3.0f; + + /* Compute common and per-vertex force vectors from the original inputs. */ + zero_v3(base_force); + + for (int i = 0; i < 3; i++) { + world_to_root_v3(data, vs[i], force[i], forcevec[vs[i]]); + + mul_v3_fl(force[i], factor / 4.0f); + add_v3_v3(base_force, force[i]); + } + + /* Apply the common and vertex components to all vertices. */ + for (int i = 0; i < 3; i++) { + add_v3_v3(force[i], base_force); + add_v3_v3(data->F[vs[i]], force[i]); + } } float BPH_tri_tetra_volume_signed_6x(Implicit_Data *data, int v1, int v2, int v3) diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index 340286191b8..8615da653ae 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -98,7 +98,8 @@ PyDoc_STRVAR( PyDoc_STRVAR(bpy_bmlayeraccess_collection__bevel_weight_doc, "Bevel weight float in [0 - 1].\n\n:type: :class:`BMLayerCollection`"); PyDoc_STRVAR(bpy_bmlayeraccess_collection__crease_doc, - "Edge crease for subdivision surface - float in [0 - 1].\n\n:type: :class:`BMLayerCollection`"); + "Edge crease for subdivision surface - float in [0 - 1].\n\n:type: " + ":class:`BMLayerCollection`"); PyDoc_STRVAR( bpy_bmlayeraccess_collection__uv_doc, "Accessor for :class:`BMLoopUV` UV (as a 2D Vector).\n\ntype: :class:`BMLayerCollection`"); diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c index fec0cef7b05..66d20dd357f 100644 --- a/source/blender/python/intern/bpy_library_write.c +++ b/source/blender/python/intern/bpy_library_write.c @@ -35,6 +35,8 @@ #include "BKE_main.h" #include "BKE_report.h" +#include "BLO_writefile.h" + #include "RNA_types.h" #include "bpy_capi_utils.h" @@ -45,8 +47,7 @@ PyDoc_STRVAR( bpy_lib_write_doc, - ".. method:: write(filepath, datablocks, relative_remap=False, fake_user=False, " - "compress=False)\n" + ".. method:: write(filepath, datablocks, path_remap=False, fake_user=False, compress=False)\n" "\n" " Write data-blocks into a blend file.\n" "\n" @@ -58,8 +59,14 @@ PyDoc_STRVAR( " :type filepath: string\n" " :arg datablocks: set of data-blocks (:class:`bpy.types.ID` instances).\n" " :type datablocks: set\n" - " :arg relative_remap: When True, make paths relative to the current blend-file.\n" - " :type relative_remap: bool\n" + " :arg path_remap: Optionally remap paths when writing the file:\n" + "\n" + " - ``NONE`` No path manipulation (default).\n" + " - ``RELATIVE`` Remap paths that are already relative to the new location.\n" + " - ``RELATIVE_ALL`` Remap all paths to be relative to the new location.\n" + " - ``ABSOLUTE`` Make all paths absolute on writing.\n" + "\n" + " :type path_remap: string\n" " :arg fake_user: When True, data-blocks will be written with fake-user flag enabled.\n" " :type fake_user: bool\n" " :arg compress: When True, write a compressed blend file.\n" @@ -70,13 +77,23 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject const char *filepath; char filepath_abs[FILE_MAX]; PyObject *datablocks = NULL; - bool use_relative_remap = false, use_fake_user = false, use_compress = false; + + const struct PyC_StringEnumItems path_remap_items[] = { + {BLO_WRITE_PATH_REMAP_NONE, "NONE"}, + {BLO_WRITE_PATH_REMAP_RELATIVE, "RELATIVE"}, + {BLO_WRITE_PATH_REMAP_RELATIVE_ALL, "RELATIVE_ALL"}, + {BLO_WRITE_PATH_REMAP_ABSOLUTE, "ABSOLUTE"}, + {0, NULL}, + }; + struct PyC_StringEnum path_remap = {path_remap_items, BLO_WRITE_PATH_REMAP_NONE}; + + bool use_fake_user = false, use_compress = false; static const char *_keywords[] = { "filepath", "datablocks", /* optional */ - "relative_remap", + "path_remap", "fake_user", "compress", NULL, @@ -88,8 +105,8 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject &filepath, &PySet_Type, &datablocks, - PyC_ParseBool, - &use_relative_remap, + PyC_ParseStringEnum, + &path_remap, PyC_ParseBool, &use_fake_user, PyC_ParseBool, @@ -100,10 +117,6 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject Main *bmain_src = G_MAIN; int write_flags = 0; - if (use_relative_remap) { - write_flags |= G_FILE_RELATIVE_REMAP; - } - if (use_compress) { write_flags |= G_FILE_COMPRESS; } @@ -162,8 +175,8 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject ReportList reports; BKE_reports_init(&reports, RPT_STORE); - - retval = BKE_blendfile_write_partial(bmain_src, filepath_abs, write_flags, &reports); + retval = BKE_blendfile_write_partial( + bmain_src, filepath_abs, write_flags, path_remap.value_found, &reports); /* cleanup state */ BKE_blendfile_write_partial_end(bmain_src); diff --git a/source/blender/python/intern/bpy_msgbus.c b/source/blender/python/intern/bpy_msgbus.c index c068182fe27..45c5aba1e3e 100644 --- a/source/blender/python/intern/bpy_msgbus.c +++ b/source/blender/python/intern/bpy_msgbus.c @@ -206,7 +206,7 @@ static void bpy_msgbus_subscribe_value_free_data(struct wmMsgSubscribeKey *UNUSE PyDoc_STRVAR( bpy_msgbus_subscribe_rna_doc, - ".. function:: subscribe_rna(data, owner, args, notify, options=set())\n" + ".. function:: subscribe_rna(key, owner, args, notify, options=set())\n" "\n" BPY_MSGBUS_RNA_MSGKEY_DOC " :arg owner: Handle for this subscription (compared by identity).\n" " :type owner: Any type.\n" @@ -314,7 +314,7 @@ static PyObject *bpy_msgbus_subscribe_rna(PyObject *UNUSED(self), PyObject *args PyDoc_STRVAR( bpy_msgbus_publish_rna_doc, - ".. function:: publish_rna(data, owner, args, notify)\n" + ".. function:: publish_rna(key)\n" "\n" BPY_MSGBUS_RNA_MSGKEY_DOC "\n" " Notify subscribers of changes to this property\n" diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index ade02780210..3df0d805c5b 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -1366,14 +1366,14 @@ static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pro } /* utility function we need for parsing int's in an if statement */ -static int py_long_as_int(PyObject *py_long, int *r_int) +static bool py_long_as_int(PyObject *py_long, int *r_int) { if (PyLong_CheckExact(py_long)) { *r_int = (int)PyLong_AS_LONG(py_long); - return 0; + return true; } else { - return -1; + return false; } } @@ -1422,7 +1422,8 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, Py_ssize_t totbuf = 0; int i; short def_used = 0; - const char *def_cmp = NULL; + const char *def_string_cmp = NULL; + int def_int_cmp = 0; if (is_enum_flag) { if (seq_len > RNA_ENUM_BITFLAG_SIZE) { @@ -1441,13 +1442,15 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, } else { if (def) { - def_cmp = _PyUnicode_AsString(def); - if (def_cmp == NULL) { - PyErr_Format(PyExc_TypeError, - "EnumProperty(...): default option must be a 'str' " - "type when ENUM_FLAG is disabled, not a '%.200s'", - Py_TYPE(def)->tp_name); - return NULL; + if (!py_long_as_int(def, &def_int_cmp)) { + def_string_cmp = _PyUnicode_AsString(def); + if (def_string_cmp == NULL) { + PyErr_Format(PyExc_TypeError, + "EnumProperty(...): default option must be a 'str' or 'int' " + "type when ENUM_FLAG is disabled, not a '%.200s'", + Py_TYPE(def)->tp_name); + return NULL; + } } } } @@ -1474,10 +1477,10 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, (tmp.description = _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 2), &desc_str_size)) && /* TODO, number isn't ensured to be unique from the script author */ - (item_size != 4 || py_long_as_int(PyTuple_GET_ITEM(item, 3), &tmp.value) != -1) && - (item_size != 5 || ((py_long_as_int(PyTuple_GET_ITEM(item, 3), &tmp.icon) != -1 || + (item_size != 4 || py_long_as_int(PyTuple_GET_ITEM(item, 3), &tmp.value)) && + (item_size != 5 || ((py_long_as_int(PyTuple_GET_ITEM(item, 3), &tmp.icon) || (tmp_icon = _PyUnicode_AsString(PyTuple_GET_ITEM(item, 3)))) && - py_long_as_int(PyTuple_GET_ITEM(item, 4), &tmp.value) != -1))) { + py_long_as_int(PyTuple_GET_ITEM(item, 4), &tmp.value)))) { if (is_enum_flag) { if (item_size < 4) { tmp.value = 1 << i; @@ -1493,9 +1496,12 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, tmp.value = i; } - if (def && def_used == 0 && STREQ(def_cmp, tmp.identifier)) { - *defvalue = tmp.value; - def_used++; /* only ever 1 */ + if (def && def_used == 0) { + if ((def_string_cmp != NULL && STREQ(def_string_cmp, tmp.identifier)) || + (def_string_cmp == NULL && def_int_cmp == tmp.value)) { + *defvalue = tmp.value; + def_used++; /* only ever 1 */ + } } } @@ -1537,9 +1543,16 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, if (def && def_used == 0) { MEM_freeN(items); - PyErr_Format(PyExc_TypeError, - "EnumProperty(..., default=\'%s\'): not found in enum members", - def_cmp); + if (def_string_cmp) { + PyErr_Format(PyExc_TypeError, + "EnumProperty(..., default=\'%s\'): not found in enum members", + def_string_cmp); + } + else { + PyErr_Format(PyExc_TypeError, + "EnumProperty(..., default=%d): not found in enum members", + def_int_cmp); + } return NULL; } } @@ -3001,13 +3014,12 @@ PyDoc_STRVAR( " :type items: sequence of string tuples or a function\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC " :arg default: The default value for this enum, a string from the identifiers used in " - "*items*.\n" + "*items*, or integer matching an item number.\n" " If the *ENUM_FLAG* option is used this must be a set of such string identifiers " "instead.\n" - " WARNING: It shall not be specified (or specified to its default *None* value) for " - "dynamic enums\n" + " WARNING: Strings can not be specified for dynamic enums\n" " (i.e. if a callback function is given as *items* parameter).\n" - " :type default: string or set\n" BPY_PROPDEF_OPTIONS_ENUM_DOC BPY_PROPDEF_TAGS_DOC + " :type default: string, integer or set\n" BPY_PROPDEF_OPTIONS_ENUM_DOC BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC); static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) { @@ -3095,10 +3107,14 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) } if (def) { - /* note, using type error here is odd but python does this for invalid arguments */ - PyErr_SetString(PyExc_TypeError, - "EnumProperty(...): 'default' can't be set when 'items' is a function"); - return NULL; + /* Only support getting integer default values here. */ + if (!py_long_as_int(def, &defvalue)) { + /* note, using type error here is odd but python does this for invalid arguments */ + PyErr_SetString( + PyExc_TypeError, + "EnumProperty(...): 'default' can only be an integer when 'items' is a function"); + return NULL; + } } is_itemf = true; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 179daad2f60..ebbbc8f3140 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -2498,7 +2498,7 @@ static int pyrna_prop_collection_subscript_str_lib_pair_ptr(BPy_PropertyRNA *sel else if (PyUnicode_Check(keylib)) { Main *bmain = self->ptr.data; const char *keylib_str = _PyUnicode_AsString(keylib); - lib = BLI_findstring(&bmain->libraries, keylib_str, offsetof(Library, name)); + lib = BLI_findstring(&bmain->libraries, keylib_str, offsetof(Library, filepath)); if (lib == NULL) { if (err_not_found) { PyErr_Format(PyExc_KeyError, diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 7896b939d77..63137e094b7 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -42,7 +42,8 @@ static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix); static PyObject *Matrix_copy(MatrixObject *self); static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args); static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value); -static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self); +static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *), + MatrixObject *self); static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type); static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row) @@ -395,14 +396,15 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } -static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self) +static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *), + MatrixObject *self) { PyObject *ret = Matrix_copy(self); if (ret) { - PyObject *ret_dummy = matrix_func(ret); + PyObject *ret_dummy = matrix_func((MatrixObject *)ret); if (ret_dummy) { Py_DECREF(ret_dummy); - return (PyObject *)ret; + return ret; } else { /* error */ Py_DECREF(ret); @@ -1634,16 +1636,17 @@ static PyObject *Matrix_inverted_noargs(MatrixObject *self) Py_RETURN_NONE; } -PyDoc_STRVAR(Matrix_invert_safe_doc, - ".. method:: invert_safe()\n" - "\n" - " Set the matrix to its inverse, will never error.\n" - " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, " - "to get an invertible one.\n" - " If tweaked matrix is still degenerated, set to the identity matrix instead.\n" - "\n" - " .. seealso:: `Inverse Matrix <https://en.wikipedia.org/wiki/Inverse_matrix>`__ on " - "Wikipedia.\n"); +PyDoc_STRVAR( + Matrix_invert_safe_doc, + ".. method:: invert_safe()\n" + "\n" + " Set the matrix to its inverse, will never error.\n" + " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, " + "to get an invertible one.\n" + " If tweaked matrix is still degenerated, set to the identity matrix instead.\n" + "\n" + " .. seealso:: `Inverse Matrix <https://en.wikipedia.org/wiki/Inverse_matrix>`__ on " + "Wikipedia.\n"); static PyObject *Matrix_invert_safe(MatrixObject *self) { if (BaseMath_ReadCallback_ForWrite(self) == -1) { @@ -1737,7 +1740,7 @@ PyDoc_STRVAR( " .. note:: When the matrix cant be adjugated a :exc:`ValueError` exception is raised.\n"); static PyObject *Matrix_adjugated(MatrixObject *self) { - return matrix__apply_to_copy((PyNoArgsFunction)Matrix_adjugate, self); + return matrix__apply_to_copy(Matrix_adjugate, self); } PyDoc_STRVAR( @@ -1945,7 +1948,7 @@ PyDoc_STRVAR(Matrix_transposed_doc, " :rtype: :class:`Matrix`\n"); static PyObject *Matrix_transposed(MatrixObject *self) { - return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self); + return matrix__apply_to_copy(Matrix_transpose, self); } /*---------------------------matrix.normalize() ------------------*/ @@ -1991,7 +1994,7 @@ PyDoc_STRVAR(Matrix_normalized_doc, " :rtype: :class:`Matrix`\n"); static PyObject *Matrix_normalized(MatrixObject *self) { - return matrix__apply_to_copy((PyNoArgsFunction)Matrix_normalize, self); + return matrix__apply_to_copy(Matrix_normalize, self); } /*---------------------------matrix.zero() -----------------------*/ diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c index 39d84c1ac96..7ce0ea5f249 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.c +++ b/source/blender/python/mathutils/mathutils_Quaternion.c @@ -34,7 +34,8 @@ #define QUAT_SIZE 4 -static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self); +static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *), + QuaternionObject *self); static void quat__axis_angle_sanitize(float axis[3], float *angle); static PyObject *Quaternion_copy(QuaternionObject *self); static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args); @@ -463,7 +464,7 @@ PyDoc_STRVAR(Quaternion_normalized_doc, " :rtype: :class:`Quaternion`\n"); static PyObject *Quaternion_normalized(QuaternionObject *self) { - return quat__apply_to_copy((PyNoArgsFunction)Quaternion_normalize, self); + return quat__apply_to_copy(Quaternion_normalize, self); } PyDoc_STRVAR(Quaternion_invert_doc, @@ -490,7 +491,7 @@ PyDoc_STRVAR(Quaternion_inverted_doc, " :rtype: :class:`Quaternion`\n"); static PyObject *Quaternion_inverted(QuaternionObject *self) { - return quat__apply_to_copy((PyNoArgsFunction)Quaternion_invert, self); + return quat__apply_to_copy(Quaternion_invert, self); } PyDoc_STRVAR(Quaternion_identity_doc, @@ -553,7 +554,7 @@ PyDoc_STRVAR(Quaternion_conjugated_doc, " :rtype: :class:`Quaternion`\n"); static PyObject *Quaternion_conjugated(QuaternionObject *self) { - return quat__apply_to_copy((PyNoArgsFunction)Quaternion_conjugate, self); + return quat__apply_to_copy(Quaternion_conjugate, self); } PyDoc_STRVAR(Quaternion_copy_doc, @@ -1385,10 +1386,11 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw return Quaternion_CreatePyObject(quat, type); } -static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self) +static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *), + QuaternionObject *self) { PyObject *ret = Quaternion_copy(self); - PyObject *ret_dummy = quat_func(ret); + PyObject *ret_dummy = quat_func((QuaternionObject *)ret); if (ret_dummy) { Py_DECREF(ret_dummy); return ret; diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index ace7480ee81..15ae811fd91 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -96,10 +96,10 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return Vector_CreatePyObject_alloc(vec, size, type); } -static PyObject *vec__apply_to_copy(PyNoArgsFunction vec_func, VectorObject *self) +static PyObject *vec__apply_to_copy(PyObject *(*vec_func)(VectorObject *), VectorObject *self) { PyObject *ret = Vector_copy(self); - PyObject *ret_dummy = vec_func(ret); + PyObject *ret_dummy = vec_func((VectorObject *)ret); if (ret_dummy) { Py_DECREF(ret_dummy); return (PyObject *)ret; @@ -376,7 +376,7 @@ PyDoc_STRVAR(Vector_normalized_doc, " :rtype: :class:`Vector`\n"); static PyObject *Vector_normalized(VectorObject *self) { - return vec__apply_to_copy((PyNoArgsFunction)Vector_normalize, self); + return vec__apply_to_copy(Vector_normalize, self); } PyDoc_STRVAR(Vector_resize_doc, diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c index 8ec0c9ce44a..eece782f6d0 100644 --- a/source/blender/python/mathutils/mathutils_noise.c +++ b/source/blender/python/mathutils/mathutils_noise.c @@ -121,7 +121,7 @@ static void init_genrand(ulong s) const float range = 32; /* range in both pos/neg direction */ for (j = 0; j < ARRAY_SIZE(state_offset_vector); j++, state_offset++) { /* overflow is fine here */ - state_offset_vector[j] = (float)(int)(*state_offset) * (1.0f / (INT_MAX / range)); + state_offset_vector[j] = (float)(int)(*state_offset) * (1.0f / ((float)INT_MAX / range)); } } } diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index af3a6fdd384..5391775cab8 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -838,9 +838,11 @@ int RE_engine_render(Render *re, int do_all) engine->resolution_x = re->winx; engine->resolution_y = re->winy; + BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE); RE_parts_init(re); engine->tile_x = re->partx; engine->tile_y = re->party; + BLI_rw_mutex_unlock(&re->partsmutex); if (re->result->do_exr_tile) { render_result_exr_file_begin(re, engine); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index c66c43ec467..b335862abe0 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1844,7 +1844,7 @@ static void validate_render_settings(Render *re) { if (RE_engine_is_external(re)) { /* not supported yet */ - re->r.scemode &= ~(R_FULL_SAMPLE); + re->r.scemode &= ~R_FULL_SAMPLE; } } diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index ee484924bf9..9926e08c968 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -1322,7 +1322,7 @@ static int multitex_nodes_intern(Tex *tex, texnode_preview, use_nodes); - if (mtex->mapto & (MAP_COL)) { + if (mtex->mapto & MAP_COL) { ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); /* don't linearize float buffers, assumed to be linear */ diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt index 9835c5c0588..740f7c126d1 100644 --- a/source/blender/shader_fx/CMakeLists.txt +++ b/source/blender/shader_fx/CMakeLists.txt @@ -24,12 +24,15 @@ set(INC intern ../blenfont ../blenkernel + ../blentranslation ../blenlib ../bmesh ../depsgraph + ../editors/include ../makesdna ../makesrna ../render/extern/include + ../windowmanager ../../../intern/eigen ../../../intern/guardedalloc ) @@ -40,6 +43,7 @@ set(INC_SYS set(SRC intern/FX_shader_util.h + intern/FX_ui_common.c intern/FX_shader_blur.c intern/FX_shader_colorize.c @@ -52,6 +56,7 @@ set(SRC intern/FX_shader_util.c intern/FX_shader_wave.c + intern/FX_ui_common.h FX_shader_types.h ) diff --git a/source/blender/shader_fx/intern/FX_shader_blur.c b/source/blender/shader_fx/intern/FX_shader_blur.c index 8881f147af8..8e3e7588818 100644 --- a/source/blender/shader_fx/intern/FX_shader_blur.c +++ b/source/blender/shader_fx/intern/FX_shader_blur.c @@ -26,7 +26,20 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + +#include "BKE_context.h" +#include "BKE_screen.h" + +#include "DNA_screen_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "FX_shader_types.h" +#include "FX_ui_common.h" static void initData(ShaderFxData *fx) { @@ -41,6 +54,32 @@ static void copyData(const ShaderFxData *md, ShaderFxData *target) BKE_shaderfx_copydata_generic(md, target); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "samples", 0, NULL, ICON_NONE); + + uiItemR(layout, &ptr, "use_dof_mode", 0, IFACE_("Use Depth of Field"), ICON_NONE); + col = uiLayoutColumn(layout, false); + uiLayoutSetActive(col, !RNA_boolean_get(&ptr, "use_dof_mode")); + uiItemR(col, &ptr, "size", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "rotation", 0, NULL, ICON_NONE); + + shaderfx_panel_end(layout, &ptr); +} + +static void panelRegister(ARegionType *region_type) +{ + shaderfx_panel_register(region_type, eShaderFxType_Blur, panel_draw); +} + ShaderFxTypeInfo shaderfx_Type_Blur = { /* name */ "Blur", /* structName */ "BlurShaderFxData", @@ -57,4 +96,5 @@ ShaderFxTypeInfo shaderfx_Type_Blur = { /* dependsOnTime */ NULL, /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/shader_fx/intern/FX_shader_colorize.c b/source/blender/shader_fx/intern/FX_shader_colorize.c index 5fea2cd0ff8..969171332fa 100644 --- a/source/blender/shader_fx/intern/FX_shader_colorize.c +++ b/source/blender/shader_fx/intern/FX_shader_colorize.c @@ -23,11 +23,23 @@ #include <stdio.h> -#include "DNA_shader_fx_types.h" +#include "BKE_context.h" +#include "BKE_screen.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + +#include "DNA_screen_types.h" +#include "DNA_shader_fx_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "FX_shader_types.h" +#include "FX_ui_common.h" static void initData(ShaderFxData *fx) { @@ -43,6 +55,38 @@ static void copyData(const ShaderFxData *md, ShaderFxData *target) BKE_shaderfx_copydata_generic(md, target); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + int mode = RNA_enum_get(&ptr, "mode"); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "mode", 0, NULL, ICON_NONE); + + if (ELEM(mode, eShaderFxColorizeMode_Custom, eShaderFxColorizeMode_Duotone)) { + const char *text = (mode == eShaderFxColorizeMode_Duotone) ? IFACE_("Low Color") : + IFACE_("Color"); + uiItemR(layout, &ptr, "low_color", 0, text, ICON_NONE); + } + if (mode == eShaderFxColorizeMode_Duotone) { + uiItemR(layout, &ptr, "high_color", 0, NULL, ICON_NONE); + } + + uiItemR(layout, &ptr, "factor", 0, NULL, ICON_NONE); + + shaderfx_panel_end(layout, &ptr); +} + +static void panelRegister(ARegionType *region_type) +{ + shaderfx_panel_register(region_type, eShaderFxType_Colorize, panel_draw); +} + ShaderFxTypeInfo shaderfx_Type_Colorize = { /* name */ "Colorize", /* structName */ "ColorizeShaderFxData", @@ -59,4 +103,5 @@ ShaderFxTypeInfo shaderfx_Type_Colorize = { /* dependsOnTime */ NULL, /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/shader_fx/intern/FX_shader_flip.c b/source/blender/shader_fx/intern/FX_shader_flip.c index b915fb8e591..325d2c2608f 100644 --- a/source/blender/shader_fx/intern/FX_shader_flip.c +++ b/source/blender/shader_fx/intern/FX_shader_flip.c @@ -26,10 +26,22 @@ #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + +#include "BKE_context.h" +#include "BKE_screen.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "FX_shader_types.h" +#include "FX_ui_common.h" static void initData(ShaderFxData *fx) { @@ -42,6 +54,29 @@ static void copyData(const ShaderFxData *md, ShaderFxData *target) BKE_shaderfx_copydata_generic(md, target); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *row; + uiLayout *layout = panel->layout; + int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + row = uiLayoutRowWithHeading(layout, true, IFACE_("Axis")); + uiItemR(row, &ptr, "flip_horizontal", toggles_flag, NULL, ICON_NONE); + uiItemR(row, &ptr, "flip_vertical", toggles_flag, NULL, ICON_NONE); + + shaderfx_panel_end(layout, &ptr); +} + +static void panelRegister(ARegionType *region_type) +{ + shaderfx_panel_register(region_type, eShaderFxType_Flip, panel_draw); +} + ShaderFxTypeInfo shaderfx_Type_Flip = { /* name */ "Flip", /* structName */ "FlipShaderFxData", @@ -58,4 +93,5 @@ ShaderFxTypeInfo shaderfx_Type_Flip = { /* dependsOnTime */ NULL, /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/shader_fx/intern/FX_shader_glow.c b/source/blender/shader_fx/intern/FX_shader_glow.c index 1194e95ce79..4398fdc13bb 100644 --- a/source/blender/shader_fx/intern/FX_shader_glow.c +++ b/source/blender/shader_fx/intern/FX_shader_glow.c @@ -26,14 +26,23 @@ #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BKE_context.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "BKE_shader_fx.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "FX_shader_types.h" +#include "FX_ui_common.h" static void initData(ShaderFxData *md) { @@ -50,6 +59,44 @@ static void copyData(const ShaderFxData *md, ShaderFxData *target) BKE_shaderfx_copydata_generic(md, target); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + int mode = RNA_enum_get(&ptr, "mode"); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "mode", 0, NULL, ICON_NONE); + + if (mode == eShaderFxGlowMode_Luminance) { + uiItemR(layout, &ptr, "threshold", 0, NULL, ICON_NONE); + } + else { + uiItemR(layout, &ptr, "select_color", 0, NULL, ICON_NONE); + } + uiItemR(layout, &ptr, "glow_color", 0, NULL, ICON_NONE); + + uiItemS(layout); + + uiItemR(layout, &ptr, "blend_mode", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "opacity", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "size", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "rotation", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "samples", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "use_glow_under", 0, NULL, ICON_NONE); + + shaderfx_panel_end(layout, &ptr); +} + +static void panelRegister(ARegionType *region_type) +{ + shaderfx_panel_register(region_type, eShaderFxType_Glow, panel_draw); +} + ShaderFxTypeInfo shaderfx_Type_Glow = { /* name */ "Glow", /* structName */ "GlowShaderFxData", @@ -66,4 +113,5 @@ ShaderFxTypeInfo shaderfx_Type_Glow = { /* dependsOnTime */ NULL, /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/shader_fx/intern/FX_shader_light.c b/source/blender/shader_fx/intern/FX_shader_light.c index 17d2f518d44..2fd93bff8aa 100644 --- a/source/blender/shader_fx/intern/FX_shader_light.c +++ b/source/blender/shader_fx/intern/FX_shader_light.c @@ -26,14 +26,23 @@ #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BLI_utildefines.h" +#include "BKE_context.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "BKE_shader_fx.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "FX_shader_types.h" +#include "FX_ui_common.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -93,4 +102,5 @@ ShaderFxTypeInfo shaderfx_Type_Light = { /* dependsOnTime */ NULL, /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, + /* panelRegister */ NULL, }; diff --git a/source/blender/shader_fx/intern/FX_shader_pixel.c b/source/blender/shader_fx/intern/FX_shader_pixel.c index 04bf9ae5b6d..bdc4f141017 100644 --- a/source/blender/shader_fx/intern/FX_shader_pixel.c +++ b/source/blender/shader_fx/intern/FX_shader_pixel.c @@ -25,7 +25,20 @@ #include "BLI_utildefines.h" +#include "BLT_translation.h" + +#include "BKE_context.h" +#include "BKE_screen.h" + +#include "DNA_screen_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "FX_shader_types.h" +#include "FX_ui_common.h" static void initData(ShaderFxData *fx) { @@ -39,6 +52,32 @@ static void copyData(const ShaderFxData *md, ShaderFxData *target) BKE_shaderfx_copydata_generic(md, target); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + /* Add the X, Y labels manually because size is a #PROP_PIXEL. */ + col = uiLayoutColumn(layout, true); + PropertyRNA *prop = RNA_struct_find_property(&ptr, "size"); + uiItemFullR(col, &ptr, prop, 0, 0, 0, IFACE_("Size X"), ICON_NONE); + uiItemFullR(col, &ptr, prop, 1, 0, 0, IFACE_("Y"), ICON_NONE); + + uiItemR(layout, &ptr, "use_antialiasing", 0, NULL, ICON_NONE); + + shaderfx_panel_end(layout, &ptr); +} + +static void panelRegister(ARegionType *region_type) +{ + shaderfx_panel_register(region_type, eShaderFxType_Pixel, panel_draw); +} + ShaderFxTypeInfo shaderfx_Type_Pixel = { /* name */ "Pixelate", /* structName */ "PixelShaderFxData", @@ -55,4 +94,5 @@ ShaderFxTypeInfo shaderfx_Type_Pixel = { /* dependsOnTime */ NULL, /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/shader_fx/intern/FX_shader_rim.c b/source/blender/shader_fx/intern/FX_shader_rim.c index 16c6a6716a0..eaaa10af54c 100644 --- a/source/blender/shader_fx/intern/FX_shader_rim.c +++ b/source/blender/shader_fx/intern/FX_shader_rim.c @@ -23,11 +23,23 @@ #include <stdio.h> +#include "DNA_screen_types.h" #include "DNA_shader_fx_types.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + +#include "BKE_context.h" +#include "BKE_screen.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "FX_shader_types.h" +#include "FX_ui_common.h" static void initData(ShaderFxData *fx) { @@ -46,6 +58,54 @@ static void copyData(const ShaderFxData *md, ShaderFxData *target) BKE_shaderfx_copydata_generic(md, target); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "rim_color", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "mask_color", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "mode", 0, IFACE_("Blend Mode"), ICON_NONE); + + /* Add the X, Z labels manually because offset is a #PROP_PIXEL. */ + col = uiLayoutColumn(layout, true); + PropertyRNA *prop = RNA_struct_find_property(&ptr, "offset"); + uiItemFullR(col, &ptr, prop, 0, 0, 0, IFACE_("Offset X"), ICON_NONE); + uiItemFullR(col, &ptr, prop, 1, 0, 0, IFACE_("Z"), ICON_NONE); + + shaderfx_panel_end(layout, &ptr); +} + +static void blur_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + /* Add the X, Z labels manually because blur is a #PROP_PIXEL. */ + col = uiLayoutColumn(layout, true); + PropertyRNA *prop = RNA_struct_find_property(&ptr, "blur"); + uiItemFullR(col, &ptr, prop, 0, 0, 0, IFACE_("Blur X"), ICON_NONE); + uiItemFullR(col, &ptr, prop, 1, 0, 0, IFACE_("Z"), ICON_NONE); + + uiItemR(layout, &ptr, "samples", 0, NULL, ICON_NONE); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = shaderfx_panel_register(region_type, eShaderFxType_Rim, panel_draw); + shaderfx_subpanel_register(region_type, "blur", "Blur", NULL, blur_panel_draw, panel_type); +} + ShaderFxTypeInfo shaderfx_Type_Rim = { /* name */ "Rim", /* structName */ "RimShaderFxData", @@ -62,4 +122,5 @@ ShaderFxTypeInfo shaderfx_Type_Rim = { /* dependsOnTime */ NULL, /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/shader_fx/intern/FX_shader_shadow.c b/source/blender/shader_fx/intern/FX_shader_shadow.c index dcf66ec89e0..11690d2cca0 100644 --- a/source/blender/shader_fx/intern/FX_shader_shadow.c +++ b/source/blender/shader_fx/intern/FX_shader_shadow.c @@ -26,14 +26,25 @@ #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + +#include "BKE_context.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "BKE_shader_fx.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "FX_shader_types.h" +#include "FX_ui_common.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -88,6 +99,88 @@ static void foreachObjectLink(ShaderFxData *fx, walk(userData, ob, &fxd->object, IDWALK_CB_NOP); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *row, *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "shadow_color", 0, NULL, ICON_NONE); + + /* Add the X, Y labels manually because size is a #PROP_PIXEL. */ + col = uiLayoutColumn(layout, true); + PropertyRNA *prop = RNA_struct_find_property(&ptr, "offset"); + uiItemFullR(col, &ptr, prop, 0, 0, 0, IFACE_("Offset X"), ICON_NONE); + uiItemFullR(col, &ptr, prop, 1, 0, 0, IFACE_("Y"), ICON_NONE); + + uiItemR(layout, &ptr, "scale", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "rotation", 0, NULL, ICON_NONE); + + row = uiLayoutRowWithHeading(layout, true, IFACE_("Object Pivot")); + uiItemR(row, &ptr, "use_object", 0, "", ICON_NONE); + uiItemR(row, &ptr, "object", 0, "", ICON_NONE); + + shaderfx_panel_end(layout, &ptr); +} + +static void blur_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + /* Add the X, Y labels manually because size is a #PROP_PIXEL. */ + col = uiLayoutColumn(layout, true); + PropertyRNA *prop = RNA_struct_find_property(&ptr, "blur"); + uiItemFullR(col, &ptr, prop, 0, 0, 0, IFACE_("Blur X"), ICON_NONE); + uiItemFullR(col, &ptr, prop, 1, 0, 0, IFACE_("Y"), ICON_NONE); + + uiItemR(layout, &ptr, "samples", 0, NULL, ICON_NONE); +} + +static void wave_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiItemR(layout, &ptr, "use_wave", 0, IFACE_("Wave Effect"), ICON_NONE); +} + +static void wave_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiLayoutSetActive(layout, RNA_boolean_get(&ptr, "use_wave")); + + uiItemR(layout, &ptr, "orientation", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, &ptr, "amplitude", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "period", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "phase", 0, NULL, ICON_NONE); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = shaderfx_panel_register(region_type, eShaderFxType_Shadow, panel_draw); + shaderfx_subpanel_register(region_type, "blur", "Blur", NULL, blur_panel_draw, panel_type); + shaderfx_subpanel_register( + region_type, "wave", "", wave_header_draw, wave_panel_draw, panel_type); +} + ShaderFxTypeInfo shaderfx_Type_Shadow = { /* name */ "Shadow", /* structName */ "ShadowShaderFxData", @@ -104,4 +197,5 @@ ShaderFxTypeInfo shaderfx_Type_Shadow = { /* dependsOnTime */ NULL, /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/shader_fx/intern/FX_shader_swirl.c b/source/blender/shader_fx/intern/FX_shader_swirl.c index 990b43748da..65e861fa46f 100644 --- a/source/blender/shader_fx/intern/FX_shader_swirl.c +++ b/source/blender/shader_fx/intern/FX_shader_swirl.c @@ -26,15 +26,24 @@ #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BLI_math_base.h" #include "BLI_utildefines.h" +#include "BKE_context.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" +#include "BKE_screen.h" #include "BKE_shader_fx.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "FX_shader_types.h" +#include "FX_ui_common.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -77,6 +86,28 @@ static void foreachObjectLink(ShaderFxData *fx, walk(userData, ob, &fxd->object, IDWALK_CB_NOP); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + PointerRNA ob_ptr; + shaderfx_panel_get_property_pointers(C, panel, &ob_ptr, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "object", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "radius", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "angle", 0, NULL, ICON_NONE); + + shaderfx_panel_end(layout, &ptr); +} + +static void panelRegister(ARegionType *region_type) +{ + shaderfx_panel_register(region_type, eShaderFxType_Swirl, panel_draw); +} + ShaderFxTypeInfo shaderfx_Type_Swirl = { /* name */ "Swirl", /* structName */ "SwirlShaderFxData", @@ -93,4 +124,5 @@ ShaderFxTypeInfo shaderfx_Type_Swirl = { /* dependsOnTime */ NULL, /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/shader_fx/intern/FX_shader_wave.c b/source/blender/shader_fx/intern/FX_shader_wave.c index 7dc72bcb669..3b8256edae3 100644 --- a/source/blender/shader_fx/intern/FX_shader_wave.c +++ b/source/blender/shader_fx/intern/FX_shader_wave.c @@ -26,10 +26,20 @@ #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" + +#include "BKE_context.h" +#include "BKE_screen.h" #include "BLI_utildefines.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + #include "FX_shader_types.h" +#include "FX_ui_common.h" static void initData(ShaderFxData *fx) { @@ -45,8 +55,30 @@ static void copyData(const ShaderFxData *md, ShaderFxData *target) BKE_shaderfx_copydata_generic(md, target); } +static void panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, &ptr, "orientation", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, &ptr, "amplitude", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "period", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "phase", 0, NULL, ICON_NONE); + + shaderfx_panel_end(layout, &ptr); +} + +static void panelRegister(ARegionType *region_type) +{ + shaderfx_panel_register(region_type, eShaderFxType_Wave, panel_draw); +} + ShaderFxTypeInfo shaderfx_Type_Wave = { - /* name */ "Wave Distortion", + /* name */ "WaveDistortion", /* structName */ "WaveShaderFxData", /* structSize */ sizeof(WaveShaderFxData), /* type */ eShaderFxType_GpencilType, @@ -61,4 +93,5 @@ ShaderFxTypeInfo shaderfx_Type_Wave = { /* dependsOnTime */ NULL, /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, + /* panelRegister */ panelRegister, }; diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c new file mode 100644 index 00000000000..3a1df937c9f --- /dev/null +++ b/source/blender/shader_fx/intern/FX_ui_common.c @@ -0,0 +1,272 @@ +/* This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup modifiers + */ + +#include <string.h> + +#include "BLI_listbase.h" + +#include "MEM_guardedalloc.h" + +#include "BKE_context.h" +#include "BKE_object.h" +#include "BKE_screen.h" +#include "BKE_shader_fx.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_shader_fx_types.h" +#include "DNA_space_types.h" + +#include "ED_object.h" + +#include "BLT_translation.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "FX_ui_common.h" /* Self include */ + +static Object *get_context_object(const bContext *C) +{ + SpaceProperties *sbuts = CTX_wm_space_properties(C); + if (sbuts != NULL && (sbuts->pinid != NULL) && GS(sbuts->pinid->name) == ID_OB) { + return (Object *)sbuts->pinid; + } + else { + return CTX_data_active_object(C); + } +} + +/* -------------------------------------------------------------------- */ +/** \name Panel Drag and Drop, Expansion Saving + * \{ */ + +/** + * Move an effect to the index it's moved to after a drag and drop. + */ +static void shaderfx_reorder(bContext *C, Panel *panel, int new_index) +{ + Object *ob = get_context_object(C); + + ShaderFxData *fx = BLI_findlink(&ob->shader_fx, panel->runtime.list_index); + PointerRNA props_ptr; + wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_shaderfx_move_to_index", false); + WM_operator_properties_create_ptr(&props_ptr, ot); + RNA_string_set(&props_ptr, "shaderfx", fx->name); + RNA_int_set(&props_ptr, "index", new_index); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr); +} + +/** + * Get the expand flag from the active effect to use for the panel. + */ +static short get_shaderfx_expand_flag(const bContext *C, Panel *panel) +{ + Object *ob = get_context_object(C); + ShaderFxData *fx = BLI_findlink(&ob->shader_fx, panel->runtime.list_index); + return fx->ui_expand_flag; +} + +/** + * Save the expand flag for the panel and sub-panels to the effect. + */ +static void set_shaderfx_expand_flag(const bContext *C, Panel *panel, short expand_flag) +{ + Object *ob = get_context_object(C); + ShaderFxData *fx = BLI_findlink(&ob->shader_fx, panel->runtime.list_index); + fx->ui_expand_flag = expand_flag; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ShaderFx Panel Layouts + * \{ */ + +/** + * Draw shaderfx error message. + */ +void shaderfx_panel_end(uiLayout *layout, PointerRNA *ptr) +{ + ShaderFxData *fx = ptr->data; + if (fx->error) { + uiLayout *row = uiLayoutRow(layout, false); + uiItemL(row, IFACE_(fx->error), ICON_ERROR); + } +} + +/** + * Gets RNA pointers for the active object and the panel's shaderfx data. + */ +void shaderfx_panel_get_property_pointers(const bContext *C, + Panel *panel, + PointerRNA *r_ob_ptr, + PointerRNA *r_md_ptr) +{ + Object *ob = get_context_object(C); + ShaderFxData *md = BLI_findlink(&ob->shader_fx, panel->runtime.list_index); + + RNA_pointer_create(&ob->id, &RNA_ShaderFx, md, r_md_ptr); + + if (r_ob_ptr != NULL) { + RNA_pointer_create(&ob->id, &RNA_Object, ob, r_ob_ptr); + } + + uiLayoutSetContextPointer(panel->layout, "shaderfx", r_md_ptr); +} + +#define ERROR_LIBDATA_MESSAGE TIP_("External library data") + +static void shaderfx_panel_header(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + bool narrow_panel = (panel->sizex < UI_UNIT_X * 7 && panel->sizex != 0); + + PointerRNA ptr; + shaderfx_panel_get_property_pointers(C, panel, NULL, &ptr); + Object *ob = get_context_object(C); + ShaderFxData *fx = (ShaderFxData *)ptr.data; + + const ShaderFxTypeInfo *fxti = BKE_shaderfx_get_info(fx->type); + + UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE); + + /* Effect type icon. */ + uiLayout *row = uiLayoutRow(layout, false); + if (fxti->isDisabled && fxti->isDisabled(fx, 0)) { + uiLayoutSetRedAlert(row, true); + } + uiItemL(row, "", RNA_struct_ui_icon(ptr.type)); + + /* Effect name. */ + row = uiLayoutRow(layout, true); + if (!narrow_panel) { + uiItemR(row, &ptr, "name", 0, "", ICON_NONE); + } + + /* Mode enabling buttons. */ + if (fxti->flags & eShaderFxTypeFlag_SupportsEditmode) { + uiLayout *sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, false); + uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE); + } + uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE); + uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE); + + row = uiLayoutRow(row, false); + uiLayoutSetEmboss(row, UI_EMBOSS_NONE); + uiItemO(row, "", ICON_X, "OBJECT_OT_shaderfx_remove"); + + /* Some padding so the X isn't too close to the drag icon. */ + uiItemS(layout); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ShaderFx Registration Helpers + * \{ */ + +static bool shaderfx_ui_poll(const bContext *C, PanelType *UNUSED(pt)) +{ + Object *ob = get_context_object(C); + + return (ob != NULL) && (ob->type == OB_GPENCIL); +} + +/** + * Create a panel in the context's region + */ +PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw) +{ + + /* Get the name for the effect's panel. */ + char panel_idname[BKE_ST_MAXNAME]; + BKE_shaderfxType_panel_id(type, panel_idname); + + PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + + strcpy(panel_type->idname, panel_idname); + strcpy(panel_type->label, ""); + strcpy(panel_type->context, "shaderfx"); + strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + + panel_type->draw_header = shaderfx_panel_header; + panel_type->draw = draw; + panel_type->poll = shaderfx_ui_poll; + + /* Give the panel the special flag that says it was built here and corresponds to a + * shader effect rather than a PanelType. */ + panel_type->flag = PNL_LAYOUT_HEADER_EXPAND | PNL_DRAW_BOX | PNL_INSTANCED; + panel_type->reorder = shaderfx_reorder; + panel_type->get_list_data_expand_flag = get_shaderfx_expand_flag; + panel_type->set_list_data_expand_flag = set_shaderfx_expand_flag; + + BLI_addtail(®ion_type->paneltypes, panel_type); + + return panel_type; +} + +/** + * Add a child panel to the parent. + * + * \note To create the panel type's idname, it appends the \a name argument to the \a parent's + * idname. + */ +PanelType *shaderfx_subpanel_register(ARegionType *region_type, + const char *name, + const char *label, + PanelDrawFn draw_header, + PanelDrawFn draw, + PanelType *parent) +{ + /* Create the subpanel's ID name. */ + char panel_idname[BKE_ST_MAXNAME]; + strcpy(panel_idname, parent->idname); + strcat(panel_idname, "_"); + strcat(panel_idname, name); + + PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + + strcpy(panel_type->idname, panel_idname); + strcpy(panel_type->label, label); + strcpy(panel_type->context, "shaderfx"); + strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + + panel_type->draw_header = draw_header; + panel_type->draw = draw; + panel_type->poll = shaderfx_ui_poll; + panel_type->flag = (PNL_DEFAULT_CLOSED | PNL_DRAW_BOX); + + BLI_assert(parent != NULL); + strcpy(panel_type->parent_id, parent->idname); + panel_type->parent = parent; + BLI_addtail(&parent->children, BLI_genericNodeN(panel_type)); + BLI_addtail(®ion_type->paneltypes, panel_type); + + return panel_type; +} + +/** \} */ diff --git a/source/blender/shader_fx/intern/FX_ui_common.h b/source/blender/shader_fx/intern/FX_ui_common.h new file mode 100644 index 00000000000..877855b98e4 --- /dev/null +++ b/source/blender/shader_fx/intern/FX_ui_common.h @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup modifiers + */ + +#ifndef __FX_UI_COMMON_H__ +#define __FX_UI_COMMON_H__ + +#include "FX_shader_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct ARegionType; +struct bContext; +struct PanelType; +struct uiLayout; +typedef void (*PanelDrawFn)(const bContext *, Panel *); + +void shaderfx_panel_end(struct uiLayout *layout, PointerRNA *ptr); + +void shaderfx_panel_get_property_pointers(const bContext *C, + struct Panel *panel, + struct PointerRNA *r_ob_ptr, + struct PointerRNA *r_ptr); + +PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw); + +struct PanelType *shaderfx_subpanel_register(struct ARegionType *region_type, + const char *name, + const char *label, + PanelDrawFn draw_header, + PanelDrawFn draw, + struct PanelType *parent); + +#ifdef __cplusplus +} +#endif + +#endif /* __FX_UI_COMMON_H__ */ diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c index df571e84d31..e687af15982 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c @@ -108,7 +108,7 @@ wmGizmo *WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, Pointer } /** - * \param name: Must be a valid gizmo type name, + * \param idname: Must be a valid gizmo type name, * if you need to check it exists use #WM_gizmo_new_ptr * because callers of this function don't NULL check the return value. */ diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 0032a341610..2112477e62a 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -165,10 +165,10 @@ void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op) /** * Use with extreme care!, - * properties, customdata etc - must be compatible. + * properties, custom-data etc - must be compatible. * * \param op: Operator to assign the type to. - * \param ot: OperatorType to assign. + * \param ot: Operator type to assign. */ void WM_operator_type_set(wmOperator *op, wmOperatorType *ot) { diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index fa12d6cf974..3c2bc14837d 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -69,6 +69,8 @@ #include "wm_surface.h" #include "wm_window.h" +#include "UI_resources.h" + #ifdef WITH_OPENSUBDIV # include "BKE_subsurf.h" #endif @@ -128,6 +130,28 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Post Draw Region on display handlers + * \{ */ + +static void wm_region_draw_overlay(bContext *C, ScrArea *area, ARegion *region) +{ + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); + + /* Don't draw overlay with locked interface. Drawing could access scene data that another thread + * may be modifying. */ + if (wm->is_interface_locked) { + return; + } + + wmViewport(®ion->winrct); + UI_SetTheme(area->spacetype, region->regiontype); + region->type->draw_overlay(C, region); + wmWindowViewport(win); +} + +/** \} */ +/* -------------------------------------------------------------------- */ /** \name Internal Utilities * \{ */ @@ -749,25 +773,30 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) } } - /* Draw paint cursors. */ - if (wm->paintcursors.first) { - ED_screen_areas_iter (win, screen, area) { - LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - if (region->visible && region == screen->active_region) { - CTX_wm_area_set(C, area); - CTX_wm_region_set(C, region); + /* Draw overlays and paint cursors. */ + ED_screen_areas_iter (win, screen, area) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + if (region->visible) { + const bool do_paint_cursor = (wm->paintcursors.first && region == screen->active_region); + const bool do_draw_overlay = (region->type && region->type->draw_overlay); + if (!(do_paint_cursor || do_draw_overlay)) { + continue; + } - /* make region ready for draw, scissor, pixelspace */ + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); + if (do_draw_overlay) { + wm_region_draw_overlay(C, area, region); + } + if (do_paint_cursor) { wm_paintcursor_draw(C, area, region); - - CTX_wm_region_set(C, NULL); - CTX_wm_area_set(C, NULL); } + CTX_wm_region_set(C, NULL); + CTX_wm_area_set(C, NULL); } } - - wmWindowViewport(win); } + wmWindowViewport(win); /* Blend in overlapping area regions */ ED_screen_areas_iter (win, screen, area) { @@ -902,9 +931,9 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win) bool do_draw = false; for (region = screen->regionbase.first; region; region = region->next) { - if (region->do_draw_overlay) { + if (region->do_draw_paintcursor) { screen->do_draw_paintcursor = true; - region->do_draw_overlay = false; + region->do_draw_paintcursor = false; } if (region->visible && region->do_draw) { do_draw = true; @@ -983,7 +1012,7 @@ void wm_draw_update(bContext *C) wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; - GPU_free_unused_buffers(bmain); + GPU_free_unused_buffers(); for (win = wm->windows.first; win; win = win->next) { #ifdef WIN32 diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index ed1b29d61ce..d5a240a358e 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -679,7 +679,8 @@ static void wm_file_read_post(bContext *C, bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) { /* assume automated tasks with background, don't write recent file list */ - const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0); + const bool do_history_file_update = (G.background == false) && + (CTX_wm_manager(C)->op_undo_depth == 0); bool success = false; const bool use_data = true; @@ -745,7 +746,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) WM_check(C); /* opens window(s), checks keymaps */ if (success) { - if (do_history) { + if (do_history_file_update) { wm_history_file_update(); } } @@ -777,7 +778,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) if (success == false) { /* remove from recent files list */ - if (do_history) { + if (do_history_file_update) { RecentFile *recent = wm_file_history_find(filepath); if (recent) { wm_history_file_free(recent); @@ -905,6 +906,13 @@ void wm_homefile_read(bContext *C, SET_FLAG_FROM_TEST(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_FLAG_SCRIPT_AUTOEXEC); } + if (use_data) { + if (reset_app_template) { + /* Always load UI when switching to another template. */ + G.fileflags &= ~G_FILE_NO_UI; + } + } + if (use_userdef || reset_app_template) { #ifdef WITH_PYTHON /* This only runs once Blender has already started. */ @@ -1109,18 +1117,6 @@ void wm_homefile_read(bContext *C, BLI_strncpy(U.app_template, app_template_override, sizeof(U.app_template)); } - if (use_data) { - /* Prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. - * Screws up autosaves otherwise can remove this eventually, - * only in a 2.53 and older, now its not written. */ - G.fileflags &= ~G_FILE_RELATIVE_REMAP; - - if (reset_app_template) { - /* Always load UI when switching to another template. */ - G.fileflags &= ~G_FILE_NO_UI; - } - } - bmain = CTX_data_main(C); if (use_userdef) { @@ -1408,11 +1404,10 @@ static ImBuf *blend_file_thumb(const bContext *C, bool write_crash_blend(void) { char path[FILE_MAX]; - int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on crash file */ BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path)); BLI_path_extension_replace(path, sizeof(path), "_crash.blend"); - if (BLO_write_file(G_MAIN, path, fileflags, NULL, NULL)) { + if (BLO_write_file(G_MAIN, path, G.fileflags, &(const struct BlendFileWriteParams){0}, NULL)) { printf("written: %s\n", path); return 1; } @@ -1425,7 +1420,12 @@ bool write_crash_blend(void) /** * \see #wm_homefile_write_exec wraps #BLO_write_file in a similar way. */ -static bool wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *reports) +static bool wm_file_write(bContext *C, + const char *filepath, + int fileflags, + eBLO_WritePathRemap remap_mode, + bool use_save_as_copy, + ReportList *reports) { Main *bmain = CTX_data_main(C); Library *li; @@ -1458,7 +1458,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo /* send the OnSave event */ for (li = bmain->libraries.first; li; li = li->id.next) { - if (BLI_path_cmp(li->filepath, filepath) == 0) { + if (BLI_path_cmp(li->filepath_abs, filepath) == 0) { BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath); return ok; } @@ -1491,21 +1491,29 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo ED_editors_flush_edits(bmain); - fileflags |= G_FILE_HISTORY; /* write file history */ - /* first time saving */ /* XXX temp solution to solve bug, real fix coming (ton) */ - if ((BKE_main_blendfile_path(bmain)[0] == '\0') && !(fileflags & G_FILE_SAVE_COPY)) { + if ((BKE_main_blendfile_path(bmain)[0] == '\0') && (use_save_as_copy == false)) { BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); } /* XXX temp solution to solve bug, real fix coming (ton) */ bmain->recovered = 0; - if (BLO_write_file(CTX_data_main(C), filepath, fileflags, reports, thumb)) { - const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0); - - if (!(fileflags & G_FILE_SAVE_COPY)) { + if (BLO_write_file(CTX_data_main(C), + filepath, + fileflags, + &(const struct BlendFileWriteParams){ + .remap_mode = remap_mode, + .use_save_versions = true, + .use_save_as_copy = use_save_as_copy, + .thumb = thumb, + }, + reports)) { + const bool do_history_file_update = (G.background == false) && + (CTX_wm_manager(C)->op_undo_depth == 0); + + if (use_save_as_copy == false) { G.relbase_valid = 1; BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); /* is guaranteed current file */ @@ -1515,7 +1523,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS); /* prevent background mode scripts from clobbering history */ - if (do_history) { + if (do_history_file_update) { wm_history_file_update(); } @@ -1603,16 +1611,14 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt)) WM_event_remove_timer(wm, NULL, wm->autosavetimer); - /* if a modal operator is running, don't autosave, but try again in 10 seconds */ + /* If a modal operator is running, don't autosave because we might not be in + * a valid state to save. But try again in 10ms. */ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) { if (handler_base->type == WM_HANDLER_TYPE_OP) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; if (handler->op) { - wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 10.0); - if (G.debug) { - printf("Skipping auto-save, modal operator running, retrying in ten seconds...\n"); - } + wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 0.01); return; } } @@ -1630,12 +1636,12 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt)) } else { /* Save as regular blend file. */ - int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY); + const int fileflags = G.fileflags & ~G_FILE_COMPRESS; ED_editors_flush_edits(bmain); - /* Error reporting into console */ - BLO_write_file(bmain, filepath, fileflags, NULL, NULL); + /* Error reporting into console. */ + BLO_write_file(bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL); } /* do timer after file write, just in case file write takes a long time */ wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime * 60.0); @@ -1753,9 +1759,15 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) ED_editors_flush_edits(bmain); /* Force save as regular blend file. */ - fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY); - - if (BLO_write_file(bmain, filepath, fileflags, op->reports, NULL) == 0) { + fileflags = G.fileflags & ~G_FILE_COMPRESS; + + if (BLO_write_file(bmain, + filepath, + fileflags, + &(const struct BlendFileWriteParams){ + .remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE, + }, + op->reports) == 0) { printf("fail\n"); return OPERATOR_CANCELLED; } @@ -2670,7 +2682,15 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); char path[FILE_MAX]; const bool is_save_as = (op->type->invoke == wm_save_as_mainfile_invoke); - + const bool use_save_as_copy = (RNA_struct_property_is_set(op->ptr, "copy") && + RNA_boolean_get(op->ptr, "copy")); + + /* We could expose all options to the users however in most cases remapping + * existing relative paths is a good default. + * Users can manually make their paths relative & absolute if they wish. */ + const eBLO_WritePathRemap remap_mode = RNA_boolean_get(op->ptr, "relative_remap") ? + BLO_WRITE_PATH_REMAP_RELATIVE : + BLO_WRITE_PATH_REMAP_NONE; save_set_compress(op); if (RNA_struct_property_is_set(op->ptr, "filepath")) { @@ -2682,17 +2702,12 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) } const int fileflags_orig = G.fileflags; - int fileflags = G.fileflags & ~G_FILE_USERPREFS; + int fileflags = G.fileflags; /* set compression flag */ SET_FLAG_FROM_TEST(fileflags, RNA_boolean_get(op->ptr, "compress"), G_FILE_COMPRESS); - SET_FLAG_FROM_TEST(fileflags, RNA_boolean_get(op->ptr, "relative_remap"), G_FILE_RELATIVE_REMAP); - SET_FLAG_FROM_TEST( - fileflags, - (RNA_struct_property_is_set(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy")), - G_FILE_SAVE_COPY); - const bool ok = wm_file_write(C, path, fileflags, op->reports); + const bool ok = wm_file_write(C, path, fileflags, remap_mode, use_save_as_copy, op->reports); if ((op->flag & OP_IS_INVOKE) == 0) { /* OP_IS_INVOKE is set when the operator is called from the GUI. diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 3ffd6c4a334..c8574a5a7fb 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -681,10 +681,10 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Cannot relocate indirectly linked library '%s'", - lib->filepath); + lib->filepath_abs); return OPERATOR_CANCELLED; } - RNA_string_set(op->ptr, "filepath", lib->filepath); + RNA_string_set(op->ptr, "filepath", lib->filepath_abs); WM_event_add_fileselect(C, op); @@ -913,24 +913,24 @@ static void lib_relocate_do(Main *bmain, void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) { - if (!BLO_has_bfile_extension(lib->filepath)) { - BKE_reportf(reports, RPT_ERROR, "'%s' is not a valid library filepath", lib->filepath); + if (!BLO_has_bfile_extension(lib->filepath_abs)) { + BKE_reportf(reports, RPT_ERROR, "'%s' is not a valid library filepath", lib->filepath_abs); return; } - if (!BLI_exists(lib->filepath)) { + if (!BLI_exists(lib->filepath_abs)) { BKE_reportf(reports, RPT_ERROR, "Trying to reload library '%s' from invalid path '%s'", lib->id.name, - lib->filepath); + lib->filepath_abs); return; } WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT); - wm_link_append_data_library_add(lapp_data, lib->filepath); + wm_link_append_data_library_add(lapp_data, lib->filepath_abs); lib_relocate_do(CTX_data_main(C), lib, lapp_data, reports, true); @@ -963,7 +963,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Cannot relocate indirectly linked library '%s'", - lib->filepath); + lib->filepath_abs); return OPERATOR_CANCELLED; } @@ -986,7 +986,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) return OPERATOR_CANCELLED; } - if (BLI_path_cmp(lib->filepath, path) == 0) { + if (BLI_path_cmp(lib->filepath_abs, path) == 0) { #ifdef PRINT_DEBUG printf("We are supposed to reload '%s' lib (%d)...\n", lib->filepath, lib->id.us); #endif @@ -1023,7 +1023,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) BLI_join_dirfile(path, sizeof(path), root, relname); - if (BLI_path_cmp(path, lib->filepath) == 0 || !BLO_has_bfile_extension(relname)) { + if (BLI_path_cmp(path, lib->filepath_abs) == 0 || !BLO_has_bfile_extension(relname)) { continue; } diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c index 9fb368a02b4..74a94e997e0 100644 --- a/source/blender/windowmanager/intern/wm_gesture_ops.c +++ b/source/blender/windowmanager/intern/wm_gesture_ops.c @@ -272,7 +272,7 @@ void WM_gesture_box_cancel(bContext *C, wmOperator *op) /** \name Circle Gesture * * Currently only used for selection or modal paint stuff, - * calls #wmOperator.exec while hold mouse, exits on release + * calls #wmOperatorType.exec while hold mouse, exits on release * (with no difference between cancel and confirm). * * \{ */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 001acc459c2..cb5a039765a 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -494,13 +494,15 @@ void WM_exit_ex(bContext *C, const bool do_python) Main *bmain = CTX_data_main(C); char filename[FILE_MAX]; bool has_edited; - int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY); + const int fileflags = G.fileflags & ~G_FILE_COMPRESS; BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_base(), BLENDER_QUIT_FILE); has_edited = ED_editors_flush_edits(bmain); - if ((has_edited && BLO_write_file(bmain, filename, fileflags, NULL, NULL)) || + if ((has_edited && + BLO_write_file( + bmain, filename, fileflags, &(const struct BlendFileWriteParams){0}, NULL)) || (undo_memfile && BLO_memfile_write_file(undo_memfile, filename))) { printf("Saved session recovery to '%s'\n", filename); } @@ -576,7 +578,7 @@ void WM_exit_ex(bContext *C, const bool do_python) BKE_subdiv_exit(); if (opengl_is_init) { - GPU_free_unused_buffers(G_MAIN); + GPU_free_unused_buffers(); } BKE_blender_free(); /* blender.c, does entire library and spacetypes */ diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index 93cd757ea93..78d8fc9a20d 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -446,8 +446,8 @@ void WM_operator_properties_select_walk_direction(wmOperatorType *ot) * help getting the wanted behavior to work. Most generic logic should be handled in these, so that * the select operators only have to care for the case dependent handling. * - * Every select operator has slightly different requirements, e.g. VSE strip selection also needs - * to account for handle selection. This should be the baseline behavior though. + * Every select operator has slightly different requirements, e.g. sequencer strip selection + * also needs to account for handle selection. This should be the baseline behavior though. */ void WM_operator_properties_generic_select(wmOperatorType *ot) { diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 6fb1e3e251d..525f96329b7 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1269,7 +1269,7 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i if (is_relative_path) { if (exists == false) { if (idcode == ID_IM) { - BLI_path_rel(((Image *)id)->name, BKE_main_blendfile_path(bmain)); + BLI_path_rel(((Image *)id)->filepath, BKE_main_blendfile_path(bmain)); } else { BLI_assert(0); diff --git a/source/blender/windowmanager/intern/wm_surface.c b/source/blender/windowmanager/intern/wm_surface.c index e8850693d69..12e55790259 100644 --- a/source/blender/windowmanager/intern/wm_surface.c +++ b/source/blender/windowmanager/intern/wm_surface.c @@ -53,10 +53,17 @@ void wm_surfaces_iter(bContext *C, void (*cb)(bContext *C, wmSurface *)) void wm_surface_clear_drawable(void) { if (g_drawable) { + WM_opengl_context_release(g_drawable->ghost_ctx); + GPU_context_active_set(NULL); + BLF_batch_reset(); gpu_batch_presets_reset(); immDeactivate(); + if (g_drawable->deactivate) { + g_drawable->deactivate(); + } + g_drawable = NULL; } } @@ -67,7 +74,10 @@ void wm_surface_set_drawable(wmSurface *surface, bool activate) g_drawable = surface; if (activate) { - GHOST_ActivateOpenGLContext(surface->ghost_ctx); + if (surface->activate) { + surface->activate(); + } + WM_opengl_context_activate(surface->ghost_ctx); } GPU_context_active_set(surface->gpu_ctx); @@ -109,6 +119,8 @@ void wm_surface_remove(wmSurface *surface) void wm_surfaces_free(void) { + wm_surface_clear_drawable(); + for (wmSurface *surf = global_surface_list.first, *surf_next; surf; surf = surf_next) { surf_next = surf->next; wm_surface_remove(surf); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 1ba22652157..e1b2285313c 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -463,6 +463,7 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) BLI_assert(BKE_workspace_layout_screen_get(layout) == screen); BKE_workspace_layout_remove(bmain, workspace, layout); + WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTDELETE, NULL); } } diff --git a/source/blender/windowmanager/wm_surface.h b/source/blender/windowmanager/wm_surface.h index e1b00ae1ade..bc1cc825e4b 100644 --- a/source/blender/windowmanager/wm_surface.h +++ b/source/blender/windowmanager/wm_surface.h @@ -38,6 +38,11 @@ typedef struct wmSurface { void (*draw)(struct bContext *); /** Free customdata, not the surface itself (done by wm_surface API) */ void (*free_data)(struct wmSurface *); + + /** Called when surface is activated for drawing (made drawable). */ + void (*activate)(void); + /** Called when surface is deactivated for drawing (current drawable cleared). */ + void (*deactivate)(void); } wmSurface; /* Create/Free */ diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index e9ff38c5a92..2f72b2b25a5 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -315,12 +315,9 @@ static void wm_xr_session_surface_draw(bContext *C) wm_xr_session_draw_data_populate( &wm->xr, CTX_data_scene(C), CTX_data_ensure_evaluated_depsgraph(C), &draw_data); - DRW_xr_drawing_begin(); - GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data); GPU_offscreen_unbind(surface_data->offscreen, false); - DRW_xr_drawing_end(); } bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, @@ -391,6 +388,9 @@ static wmSurface *wm_xr_session_surface_create(void) surface->draw = wm_xr_session_surface_draw; surface->free_data = wm_xr_session_surface_free_data; + surface->activate = DRW_xr_drawing_begin; + surface->deactivate = DRW_xr_drawing_end; + surface->ghost_ctx = DRW_xr_opengl_context_get(); surface->gpu_ctx = DRW_xr_gpu_context_get(); diff --git a/source/creator/creator.c b/source/creator/creator.c index ea64184c826..abf55b8d52b 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -158,7 +158,7 @@ static void callback_mem_error(const char *errorStr) static void main_callback_setup(void) { - /* Error output from the alloc routines: */ + /* Error output from the guarded allocation routines. */ MEM_set_error_callback(callback_mem_error); } @@ -208,7 +208,7 @@ static void callback_clg_fatal(void *fp) static void *evil_C = NULL; # ifdef __APPLE__ -/* environ is not available in mac shared libraries */ +/* Environment is not available in macOS shared libraries. */ # include <crt_externs.h> char **environ = NULL; # endif @@ -246,20 +246,24 @@ int main(int argc, struct CreatorAtExitData app_init_data = {NULL}; BKE_blender_atexit_register(callback_main_atexit, &app_init_data); - /* Unbuffered stdout makes stdout and stderr better synchronized, and helps + /* Un-buffered `stdout` makes `stdout` and `stderr` better synchronized, and helps * when stepping through code in a debugger (prints are immediately - * visible). */ + * visible). However disabling buffering causes lock contention on windows + * see T76767 for details, since this is a debugging aid, we do not enable + * the un-buffered behavior for release builds. */ +#ifndef NDEBUG setvbuf(stdout, NULL, _IONBF, 0); +#endif #ifdef WIN32 - /* We delay loading of openmp so we can set the policy here. */ + /* We delay loading of OPENMP so we can set the policy here. */ # if defined(_MSC_VER) _putenv_s("OMP_WAIT_POLICY", "PASSIVE"); # endif - /* Win32 Unicode Args */ + /* Win32 Unicode Arguments. */ /* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized - * (it depends on the args passed in, which is what we're getting here!) + * (it depends on the arguments passed in, which is what we're getting here!) */ { wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc); @@ -341,7 +345,7 @@ int main(int argc, main_callback_setup(); #if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE) && !defined(WITH_HEADLESS) - /* patch to ignore argument finder gives us (pid?) */ + /* Patch to ignore argument finder gives us (PID?) */ if (argc == 2 && STREQLEN(argv[1], "-psn_", 5)) { extern int GHOST_HACK_getFirstFile(char buf[]); static char firstfilebuf[512]; @@ -415,7 +419,7 @@ int main(int argc, RE_engines_init(); init_nodesystem(); psys_init_rng(); - /* end second init */ + /* End second initialization. */ #if defined(WITH_PYTHON_MODULE) || defined(WITH_HEADLESS) /* Python module mode ALWAYS runs in background-mode (for now). */ @@ -471,7 +475,7 @@ int main(int argc, * #WM_init() before #BPY_python_start() crashes Blender at startup. */ - /* TODO - U.pythondir */ + /* TODO: #U.pythondir */ #else printf( "\n* WARNING * - Blender compiled without Python!\n" @@ -528,7 +532,7 @@ int main(int argc, WM_main(C); return 0; -} /* end of int main(argc, argv) */ +} /* End of int main(...) function. */ #ifdef WITH_PYTHON_MODULE void main_python_exit(void) |