diff options
author | Hans Goudey <h.goudey@me.com> | 2021-07-14 23:07:36 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2021-07-14 23:07:36 +0300 |
commit | dc0c71d3ae772c9afdec0718ae135b9b91f57e8b (patch) | |
tree | 3c89c71d0a33ecb3a3b4abfb67641051e34608f7 /source | |
parent | d7a74a2ad69914602f563852610efff3e8ed6e1c (diff) | |
parent | 093074aefe87259882b56a911d8eeb311408ff14 (diff) |
Merge branch 'master' into temp-geometry-nodes-curve-sample
Diffstat (limited to 'source')
295 files changed, 4764 insertions, 2642 deletions
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h index 6c07708b5ef..14ab9f21424 100644 --- a/source/blender/blenkernel/BKE_anim_data.h +++ b/source/blender/blenkernel/BKE_anim_data.h @@ -50,8 +50,8 @@ bool id_can_have_animdata(const struct ID *id); /* Get AnimData from the given ID-block */ struct AnimData *BKE_animdata_from_id(struct ID *id); -/* Add AnimData to the given ID-block */ -struct AnimData *BKE_animdata_add_id(struct ID *id); +/* Ensure AnimData is present in the ID-block (when supported). */ +struct AnimData *BKE_animdata_ensure_id(struct ID *id); /* Set active action used by AnimData from the given ID-block */ bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 9d286b94b04..dffd70c077f 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 8 +#define BLENDER_FILE_SUBVERSION 11 /* 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_deform.h b/source/blender/blenkernel/BKE_deform.h index 8b5fdf69bb0..0ab126a70ae 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -37,6 +37,19 @@ struct MLoop; struct MPoly; struct Object; struct bDeformGroup; +struct ID; + +bool BKE_object_supports_vertex_groups(const struct Object *ob); +const struct ListBase *BKE_object_defgroup_list(const struct Object *ob); +struct ListBase *BKE_object_defgroup_list_mutable(struct Object *ob); + +int BKE_object_defgroup_count(const struct Object *ob); +int BKE_object_defgroup_active_index_get(const struct Object *ob); +void BKE_object_defgroup_active_index_set(struct Object *ob, const int new_index); + +const struct ListBase *BKE_id_defgroup_list_get(const struct ID *id); +struct ListBase *BKE_id_defgroup_list_get_mutable(struct ID *id); +int BKE_id_defgroup_name_index(const struct ID *id, const char *name); struct bDeformGroup *BKE_object_defgroup_new(struct Object *ob, const char *name); void BKE_defgroup_copy_list(struct ListBase *outbase, const struct ListBase *inbase); @@ -171,6 +184,7 @@ void BKE_defvert_blend_write(struct BlendWriter *writer, int count, struct MDefo void BKE_defvert_blend_read(struct BlendDataReader *reader, int count, struct MDeformVert *mdverts); +void BKE_defbase_blend_write(struct BlendWriter *writer, const ListBase *defbase); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 9112877b5a3..ce7df62389f 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -24,7 +24,7 @@ * only concerned with low level operations on the #BMEditMesh structure. */ -#include "BKE_customdata.h" +#include "DNA_customdata_types.h" #include "bmesh.h" #ifdef __cplusplus @@ -44,34 +44,39 @@ struct Scene; /** * This structure is used for mesh edit-mode. * - * through this, you get access to both the edit #BMesh, - * its tessellation, and various stuff that doesn't belong in the BMesh - * struct itself. + * Through this, you get access to both the edit #BMesh, its tessellation, + * and various data that doesn't belong in the #BMesh struct itself + * (mostly related to mesh evaluation). * - * the entire derivedmesh and modifier system works with this structure, - * and not BMesh. Mesh->edit_bmesh stores a pointer to this structure. */ + * The entire modifier system works with this structure, and not #BMesh. + * #Mesh.edit_bmesh stores a pointer to this structure. */ typedef struct BMEditMesh { struct BMesh *bm; - /* we store tessellations as triplets of three loops, - * which each define a triangle. */ + /** + * Face triangulation (tessellation) is stored as triplets of three loops, + * which each define a triangle. + * + * \see #MLoopTri as the documentation gives useful hints that apply to this data too. + */ struct BMLoop *(*looptris)[3]; int tottri; struct Mesh *mesh_eval_final, *mesh_eval_cage; - /** Cached cage bounding box for selection. */ + /** Cached cage bounding box of `mesh_eval_cage` for selection. */ struct BoundBox *bb_cage; /** Evaluated mesh data-mask. */ CustomData_MeshMasks lastDataMask; - /* Selection mode. */ + /** Selection mode (#SCE_SELECT_VERTEX, #SCE_SELECT_EDGE & #SCE_SELECT_FACE). */ short selectmode; + /** The active material (assigned to newly created faces). */ short mat_nr; - /* Temp variables for x-mirror editing. */ - int mirror_cdlayer; /* -1 is invalid */ + /** Temp variables for x-mirror editing (-1 when the layer does not exist). */ + int mirror_cdlayer; /** * ID data is older than edit-mode data. @@ -94,11 +99,11 @@ void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em, void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em); -BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate); +BMEditMesh *BKE_editmesh_create(BMesh *bm); BMEditMesh *BKE_editmesh_copy(BMEditMesh *em); BMEditMesh *BKE_editmesh_from_object(struct Object *ob); -void BKE_editmesh_free_derivedmesh(BMEditMesh *em); -void BKE_editmesh_free(BMEditMesh *em); +void BKE_editmesh_free_derived_caches(BMEditMesh *em); +void BKE_editmesh_free_data(BMEditMesh *em); float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph, struct BMEditMesh *em, diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index c8d6f18baf8..c79977752c9 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -337,10 +337,6 @@ class MeshComponent : public GeometryComponent { private: Mesh *mesh_ = nullptr; GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned; - /* Due to historical design choices, vertex group data is stored in the mesh, but the vertex - * group names are stored on an object. Since we don't have an object here, we copy over the - * names into this map. */ - blender::Map<std::string, int> vertex_group_names_; public: MeshComponent(); @@ -350,14 +346,8 @@ class MeshComponent : public GeometryComponent { void clear(); bool has_mesh() const; void replace(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); - void replace_mesh_but_keep_vertex_group_names( - Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); Mesh *release(); - void copy_vertex_group_names_from_object(const struct Object &object); - const blender::Map<std::string, int> &vertex_group_names() const; - blender::Map<std::string, int> &vertex_group_names(); - const Mesh *get_for_read() const; Mesh *get_for_write(); diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index c11c34cb312..1f9c3e766aa 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -154,17 +154,6 @@ bool BKE_gpencil_merge_materials(struct Object *ob, /* statistics functions */ void BKE_gpencil_stats_update(struct bGPdata *gpd); -/* Utilities for creating and populating GP strokes */ -/* - Number of values defining each point in the built-in data - * buffers for primitives (e.g. 2D Monkey) - */ -#define GP_PRIM_DATABUF_SIZE 5 - -void BKE_gpencil_stroke_add_points(struct bGPDstroke *gps, - const float *array, - const int totpoints, - const float mat[4][4]); - struct bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness); struct bGPDstroke *BKE_gpencil_stroke_add( struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head); diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index 8fbc2112c77..33524e47473 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -325,6 +325,12 @@ struct bGPDframe *BKE_gpencil_frame_retime_get(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bGPDlayer *gpl); +int BKE_gpencil_time_modifier_cfra(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + struct bGPDlayer *gpl, + const int cfra, + const bool is_render); void BKE_gpencil_modifier_blend_write(struct BlendWriter *writer, struct ListBase *modbase); void BKE_gpencil_modifier_blend_read_data(struct BlendDataReader *reader, struct ListBase *lb); diff --git a/source/blender/blenkernel/BKE_mesh_types.h b/source/blender/blenkernel/BKE_mesh_types.h index aed8c44a031..b223d3872ff 100644 --- a/source/blender/blenkernel/BKE_mesh_types.h +++ b/source/blender/blenkernel/BKE_mesh_types.h @@ -27,6 +27,7 @@ typedef enum eMeshBatchDirtyMode { BKE_MESH_BATCH_DIRTY_SELECT, BKE_MESH_BATCH_DIRTY_SELECT_PAINT, BKE_MESH_BATCH_DIRTY_SHADING, + BKE_MESH_BATCH_DIRTY_DEFORM, BKE_MESH_BATCH_DIRTY_UVEDIT_ALL, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT, } eMeshBatchDirtyMode; diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 61d26379052..5e977fbc0cd 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1458,7 +1458,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_VIEWER 1067 #define GEO_NODE_CURVE_PRIMITIVE_LINE 1068 #define GEO_NODE_CURVE_ENDPOINTS 1069 -#define GEO_NODE_CURVE_SAMPLE 1070 +#define GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL 1070 +#define GEO_NODE_CURVE_SAMPLE 1071 /** \} */ diff --git a/source/blender/blenkernel/BKE_node_ui_storage.hh b/source/blender/blenkernel/BKE_node_ui_storage.hh deleted file mode 100644 index 4ec165aad8c..00000000000 --- a/source/blender/blenkernel/BKE_node_ui_storage.hh +++ /dev/null @@ -1,133 +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. - */ - -#pragma once - -#include <mutex> - -#include "BLI_hash.hh" -#include "BLI_map.hh" -#include "BLI_session_uuid.h" -#include "BLI_set.hh" - -#include "DNA_ID.h" -#include "DNA_customdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_session_uuid_types.h" - -#include "BKE_attribute.h" - -struct ModifierData; -struct Object; -struct bNode; -struct bNodeTree; -struct bContext; - -/** - * Contains the context necessary to determine when to display settings for a certain node tree - * that may be used for multiple modifiers and objects. The object name and modifier session UUID - * are used instead of pointers because they are re-allocated between evaluations. - * - * \note This does not yet handle the context of nested node trees. - */ -class NodeTreeEvaluationContext { - private: - std::string object_name_; - SessionUUID modifier_session_uuid_; - - public: - NodeTreeEvaluationContext(const Object &object, const ModifierData &modifier) - { - object_name_ = reinterpret_cast<const ID &>(object).name; - modifier_session_uuid_ = modifier.session_uuid; - } - - uint64_t hash() const - { - return blender::get_default_hash_2(object_name_, modifier_session_uuid_); - } - - friend bool operator==(const NodeTreeEvaluationContext &a, const NodeTreeEvaluationContext &b) - { - return a.object_name_ == b.object_name_ && - BLI_session_uuid_is_equal(&a.modifier_session_uuid_, &b.modifier_session_uuid_); - } -}; - -enum class NodeWarningType { - Error, - Warning, - Info, -}; - -struct NodeWarning { - NodeWarningType type; - std::string message; -}; - -struct AvailableAttributeInfo { - std::string name; - AttributeDomain domain; - CustomDataType data_type; - - uint64_t hash() const - { - return blender::get_default_hash(name); - } - - friend bool operator==(const AvailableAttributeInfo &a, const AvailableAttributeInfo &b) - { - return a.name == b.name; - } -}; - -struct NodeUIStorage { - blender::Vector<NodeWarning> warnings; - blender::Set<AvailableAttributeInfo> attribute_hints; -}; - -struct NodeTreeUIStorage { - std::mutex mutex; - blender::Map<NodeTreeEvaluationContext, blender::Map<std::string, NodeUIStorage>> context_map; - - /** - * Attribute search uses this to store the fake info for the string typed into a node, in order - * to pass the info to the execute callback that sets node socket values. This is mutable since - * we can count on only one attribute search being open at a time, and there is no real data - * stored here. - */ - mutable AvailableAttributeInfo dummy_info_for_search; -}; - -const NodeUIStorage *BKE_node_tree_ui_storage_get_from_context(const bContext *C, - const bNodeTree &ntree, - const bNode &node); - -void BKE_nodetree_ui_storage_free_for_context(bNodeTree &ntree, - const NodeTreeEvaluationContext &context); - -void BKE_nodetree_error_message_add(bNodeTree &ntree, - const NodeTreeEvaluationContext &context, - const bNode &node, - const NodeWarningType type, - std::string message); - -void BKE_nodetree_attribute_hint_add(bNodeTree &ntree, - const NodeTreeEvaluationContext &context, - const bNode &node, - const blender::StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index cd66f026828..a16822fd7dd 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -70,10 +70,6 @@ void BKE_object_free_curve_cache(struct Object *ob); void BKE_object_free_derived_caches(struct Object *ob); void BKE_object_free_caches(struct Object *object); -void BKE_object_preview_geometry_set_add(struct Object *ob, - const uint64_t key, - struct GeometrySet *geometry_set); - void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd); void BKE_object_modifier_gpencil_hook_reset(struct Object *ob, struct HookGpencilModifierData *hmd); @@ -378,6 +374,10 @@ void BKE_object_runtime_free_data(struct Object *object); void BKE_object_batch_cache_dirty_tag(struct Object *ob); void BKE_object_data_batch_cache_dirty_tag(struct ID *object_data); +void BKE_object_data_eval_batch_cache_dirty_tag(struct Depsgraph *depsgraph, + struct ID *object_data); +void BKE_object_data_eval_batch_cache_deform_tag(struct Depsgraph *depsgraph, + struct ID *object_data); /* this function returns a superset of the scenes selection based on relationships */ diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 9792f819bf9..6d58e165ea3 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -124,14 +124,16 @@ bool BKE_scene_camera_switch_update(struct Scene *scene); const char *BKE_scene_find_marker_name(const struct Scene *scene, int frame); const char *BKE_scene_find_last_marker_name(const struct Scene *scene, int frame); -int BKE_scene_frame_snap_by_seconds(struct Scene *scene, double interval_in_seconds, int cfra); +int BKE_scene_frame_snap_by_seconds(struct Scene *scene, double interval_in_seconds, int frame); /* checks for cycle, returns 1 if it's all OK */ bool BKE_scene_validate_setscene(struct Main *bmain, struct Scene *sce); +float BKE_scene_ctime_get(const struct Scene *scene); +float BKE_scene_frame_to_ctime(const struct Scene *scene, const int frame); + float BKE_scene_frame_get(const struct Scene *scene); -float BKE_scene_frame_to_ctime(const struct Scene *scene, const float frame); -void BKE_scene_frame_set(struct Scene *scene, double cfra); +void BKE_scene_frame_set(struct Scene *scene, float frame); struct TransformOrientationSlot *BKE_scene_orientation_slot_get_from_flag(struct Scene *scene, int flag); diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index d7b2dd181b4..f1c66de7773 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -343,6 +343,18 @@ class BezierSpline final : public Spline { blender::MutableSpan<blender::float3> positions) const; bool segment_is_vector(const int start_index) const; + /** See comment and diagram for #calculate_segment_insertion. */ + struct InsertResult { + blender::float3 handle_prev; + blender::float3 left_handle; + blender::float3 position; + blender::float3 right_handle; + blender::float3 handle_next; + }; + InsertResult calculate_segment_insertion(const int index, + const int next_index, + const float parameter); + private: void correct_end_tangents() const final; void copy_settings(Spline &dst) const final; diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h index 70b8743bcd2..59b1c2b28d9 100644 --- a/source/blender/blenkernel/BKE_studiolight.h +++ b/source/blender/blenkernel/BKE_studiolight.h @@ -145,7 +145,7 @@ typedef struct StudioLight { void BKE_studiolight_init(void); void BKE_studiolight_free(void); -void BKE_studiolight_default(SolidLight lights[4], float light_ambient[4]); +void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3]); struct StudioLight *BKE_studiolight_find(const char *name, int flag); struct StudioLight *BKE_studiolight_findindex(int index, int flag); struct StudioLight *BKE_studiolight_find_default(int flag); diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h index efac5d9097f..2973a432723 100644 --- a/source/blender/blenkernel/BKE_undo_system.h +++ b/source/blender/blenkernel/BKE_undo_system.h @@ -162,6 +162,13 @@ typedef enum UndoTypeFlags { * \note Callback is still supposed to properly deal with a NULL context pointer. */ UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE = 1 << 0, + + /** + * When the active undo step is of this type, it must be read before loading other undo steps. + * + * This is typically used for undo systems that store both before/after states. + */ + UNDOTYPE_FLAG_DECODE_ACTIVE_STEP = 1 << 1, } UndoTypeFlags; /* Expose since we need to perform operations on specific undo types (rarely). */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 1db23002c1e..2c25b940578 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -215,7 +215,6 @@ set(SRC intern/multires_versioning.c intern/nla.c intern/node.cc - intern/node_ui_storage.cc intern/object.c intern/object_deform.c intern/object_dupli.cc @@ -331,7 +330,6 @@ set(SRC BKE_customdata_file.h BKE_data_transfer.h BKE_deform.h - BKE_spline.hh BKE_displist.h BKE_displist_tangent.h BKE_duplilist.h @@ -399,7 +397,6 @@ set(SRC BKE_multires.h BKE_nla.h BKE_node.h - BKE_node_ui_storage.hh BKE_object.h BKE_object_deform.h BKE_object_facemap.h @@ -423,6 +420,7 @@ set(SRC BKE_softbody.h BKE_sound.h BKE_speaker.h + BKE_spline.hh BKE_studiolight.h BKE_subdiv.h BKE_subdiv_ccg.h @@ -767,6 +765,7 @@ add_dependencies(bf_blenkernel bf_dna) if(WITH_GTESTS) set(TEST_SRC + intern/action_test.cc intern/armature_test.cc intern/cryptomatte_test.cc intern/fcurve_test.cc diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 46dec073bab..ba8cf8debe9 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -900,7 +900,7 @@ static Mesh *prepare_geometry_set_for_mesh_modifier(Mesh *mesh, GeometrySet &r_g { /* Add the mesh to the geometry set. */ MeshComponent &mesh_component = r_geometry_set.get_component_for_write<MeshComponent>(); - mesh_component.replace_mesh_but_keep_vertex_group_names(mesh, GeometryOwnershipType::Editable); + mesh_component.replace(mesh, GeometryOwnershipType::Editable); } { /* Combine mesh and all instances into a single mesh that can be passed to the modifier. */ @@ -948,8 +948,7 @@ static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md, /* Replace only the mesh rather than the whole component, because the entire #MeshComponent * might have been replaced by data from a different object in the node tree, which means the * component contains vertex group name data for that object that should not be removed. */ - mesh_component.replace_mesh_but_keep_vertex_group_names(input_mesh, - GeometryOwnershipType::Editable); + mesh_component.replace(input_mesh, GeometryOwnershipType::Editable); /* Let the modifier change the geometry set. */ mti->modifyGeometrySet(md, &mectx, &geometry_set); @@ -993,12 +992,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* This geometry set contains the non-mesh data that might be generated by modifiers. */ GeometrySet geometry_set_final; - /* Add the initial mesh component, with a copy of the vertex group names from the object, - * since they need to be stored in the geometry set for evaluation. */ - MeshComponent &initial_mesh_component = - geometry_set_final.get_component_for_write<MeshComponent>(); - initial_mesh_component.copy_vertex_group_names_from_object(*ob); - BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); /* Deformed vertex locations array. Deform only modifier need this type of @@ -1602,12 +1595,6 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* This geometry set contains the non-mesh data that might be generated by modifiers. */ GeometrySet geometry_set_final; - /* Add the initial mesh component, with a copy of the vertex group names from the object, - * since they need to be stored in the geometry set for evaluation. */ - MeshComponent &initial_mesh_component = - geometry_set_final.get_component_for_write<MeshComponent>(); - initial_mesh_component.copy_vertex_group_names_from_object(*ob); - /* Deformed vertex locations array. Deform only modifier need this type of * float array rather than MVert*. Tracked along with mesh_final as an * optimization to avoid copying coordinates back and forth if there are @@ -1951,8 +1938,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph, /* Add the final mesh as read-only non-owning component to the geometry set. */ MeshComponent &mesh_component = geometry_set_eval->get_component_for_write<MeshComponent>(); - mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_eval, - GeometryOwnershipType::ReadOnly); + mesh_component.replace(mesh_eval, GeometryOwnershipType::ReadOnly); ob->runtime.geometry_set_eval = geometry_set_eval; ob->runtime.mesh_deform_eval = mesh_deform_eval; @@ -1990,7 +1976,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph, BKE_sculpt_update_object_before_eval(obedit); } - BKE_editmesh_free_derivedmesh(em); + BKE_editmesh_free_derived_caches(em); Mesh *me_cage; Mesh *me_final; diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 13ca5ecf23c..d55f023d209 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -497,9 +497,8 @@ void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve) } /* Reconstruct group channel pointers. - * Assumes that the channels are still in the proper order, i.e. that channels of the same group - * are adjacent in the act->channels list. It also assumes that the groups - * referred to by the FCurves are already in act->groups. + * Assumes that the groups referred to by the FCurves are already in act->groups. + * Reorders the main channel list to match group order. */ void BKE_action_groups_reconstruct(bAction *act) { @@ -514,23 +513,30 @@ void BKE_action_groups_reconstruct(bAction *act) BLI_listbase_clear(&group->channels); } - bActionGroup *grp; - bActionGroup *last_grp = NULL; - LISTBASE_FOREACH (FCurve *, fcurve, &act->curves) { - if (fcurve->grp == NULL) { - continue; - } + /* Sort the channels into the group lists, destroying the act->curves list. */ + ListBase ungrouped = {NULL, NULL}; - grp = fcurve->grp; - if (last_grp != grp) { - /* If this is the first time we see this group, this must be the first channel. */ - grp->channels.first = fcurve; + LISTBASE_FOREACH_MUTABLE (FCurve *, fcurve, &act->curves) { + if (fcurve->grp) { + BLI_assert(BLI_findindex(&act->groups, fcurve->grp) >= 0); + + BLI_addtail(&fcurve->grp->channels, fcurve); + } + else { + BLI_addtail(&ungrouped, fcurve); } + } + + /* Recombine into the main list. */ + BLI_listbase_clear(&act->curves); - /* This is the last channel, until it's overwritten by a later iteration. */ - grp->channels.last = fcurve; - last_grp = grp; + LISTBASE_FOREACH (bActionGroup *, group, &act->groups) { + /* Copy the list header to preserve the pointers in the group. */ + ListBase tmp = group->channels; + BLI_movelisttolist(&act->curves, &tmp); } + + BLI_movelisttolist(&act->curves, &ungrouped); } /* Remove the given channel from all groups */ diff --git a/source/blender/blenkernel/intern/action_test.cc b/source/blender/blenkernel/intern/action_test.cc new file mode 100644 index 00000000000..c02eca966ad --- /dev/null +++ b/source/blender/blenkernel/intern/action_test.cc @@ -0,0 +1,144 @@ +/* + * 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) 2021 Blender Foundation + * All rights reserved. + */ + +#include "BKE_action.h" + +#include "DNA_action_types.h" +#include "DNA_anim_types.h" + +#include "BLI_listbase.h" + +#include "testing/testing.h" + +namespace blender::bke::tests { + +TEST(action_groups, ReconstructGroupsWithReordering) +{ + /* Construct an Action with three groups. */ + bAction action = {{nullptr}}; + FCurve groupAcurve1 = {nullptr}; + FCurve groupAcurve2 = {nullptr}; + FCurve groupBcurve1 = {nullptr}; + FCurve groupBcurve2 = {nullptr}; + FCurve groupBcurve3 = {nullptr}; + /* Group C has no curves intentionally. */ + FCurve groupDcurve1 = {nullptr}; + FCurve groupDcurve2 = {nullptr}; + + groupAcurve1.rna_path = (char *)"groupAcurve1"; + groupAcurve2.rna_path = (char *)"groupAcurve2"; + groupBcurve1.rna_path = (char *)"groupBcurve1"; + groupBcurve2.rna_path = (char *)"groupBcurve2"; + groupDcurve1.rna_path = (char *)"groupDcurve1"; + groupBcurve3.rna_path = (char *)"groupBcurve3"; + groupDcurve2.rna_path = (char *)"groupDcurve2"; + + BLI_addtail(&action.curves, &groupAcurve1); + BLI_addtail(&action.curves, &groupAcurve2); + BLI_addtail(&action.curves, &groupBcurve1); + BLI_addtail(&action.curves, &groupBcurve2); + BLI_addtail(&action.curves, &groupDcurve1); + BLI_addtail(&action.curves, &groupBcurve3); /* <-- The error that should be corrected. */ + BLI_addtail(&action.curves, &groupDcurve2); + + /* Introduce another error type, by changing some `prev` pointers. */ + groupBcurve1.prev = nullptr; + groupBcurve3.prev = &groupBcurve2; + groupDcurve1.prev = &groupBcurve3; + + bActionGroup groupA = {nullptr}; + bActionGroup groupB = {nullptr}; + bActionGroup groupC = {nullptr}; + bActionGroup groupD = {nullptr}; + strcpy(groupA.name, "groupA"); + strcpy(groupB.name, "groupB"); + strcpy(groupC.name, "groupC"); + strcpy(groupD.name, "groupD"); + + BLI_addtail(&action.groups, &groupA); + BLI_addtail(&action.groups, &groupB); + BLI_addtail(&action.groups, &groupC); + BLI_addtail(&action.groups, &groupD); + + groupAcurve1.grp = &groupA; + groupAcurve2.grp = &groupA; + groupBcurve1.grp = &groupB; + groupBcurve2.grp = &groupB; + groupBcurve3.grp = &groupB; + groupDcurve1.grp = &groupD; + groupDcurve2.grp = &groupD; + + groupA.channels.first = &groupAcurve1; + groupA.channels.last = &groupAcurve2; + groupB.channels.first = &groupBcurve1; + groupB.channels.last = &groupBcurve3; /* The last channel in group B, after group C curve 1. */ + groupD.channels.first = &groupDcurve1; + groupD.channels.last = &groupDcurve2; + + EXPECT_EQ(groupA.channels.first, &groupAcurve1); + EXPECT_EQ(groupA.channels.last, &groupAcurve2); + EXPECT_EQ(groupB.channels.first, &groupBcurve1); + EXPECT_EQ(groupB.channels.last, &groupBcurve3); + EXPECT_EQ(groupC.channels.first, nullptr); + EXPECT_EQ(groupC.channels.last, nullptr); + EXPECT_EQ(groupD.channels.first, &groupDcurve1); + EXPECT_EQ(groupD.channels.last, &groupDcurve2); + + BKE_action_groups_reconstruct(&action); + + EXPECT_EQ(action.curves.first, &groupAcurve1); + EXPECT_EQ(action.curves.last, &groupDcurve2); + + EXPECT_EQ(groupA.prev, nullptr); + EXPECT_EQ(groupB.prev, &groupA); + EXPECT_EQ(groupC.prev, &groupB); + EXPECT_EQ(groupD.prev, &groupC); + + EXPECT_EQ(groupA.next, &groupB); + EXPECT_EQ(groupB.next, &groupC); + EXPECT_EQ(groupC.next, &groupD); + EXPECT_EQ(groupD.next, nullptr); + + EXPECT_EQ(groupA.channels.first, &groupAcurve1); + EXPECT_EQ(groupA.channels.last, &groupAcurve2); + EXPECT_EQ(groupB.channels.first, &groupBcurve1); + EXPECT_EQ(groupB.channels.last, &groupBcurve3); + EXPECT_EQ(groupC.channels.first, nullptr); + EXPECT_EQ(groupC.channels.last, nullptr); + EXPECT_EQ(groupD.channels.first, &groupDcurve1); + EXPECT_EQ(groupD.channels.last, &groupDcurve2); + + EXPECT_EQ(groupAcurve1.prev, nullptr); + EXPECT_EQ(groupAcurve2.prev, &groupAcurve1); + EXPECT_EQ(groupBcurve1.prev, &groupAcurve2); + EXPECT_EQ(groupBcurve2.prev, &groupBcurve1); + EXPECT_EQ(groupBcurve3.prev, &groupBcurve2); + EXPECT_EQ(groupDcurve1.prev, &groupBcurve3); + EXPECT_EQ(groupDcurve2.prev, &groupDcurve1); + + EXPECT_EQ(groupAcurve1.next, &groupAcurve2); + EXPECT_EQ(groupAcurve2.next, &groupBcurve1); + EXPECT_EQ(groupBcurve1.next, &groupBcurve2); + EXPECT_EQ(groupBcurve2.next, &groupBcurve3); + EXPECT_EQ(groupBcurve3.next, &groupDcurve1); + EXPECT_EQ(groupDcurve1.next, &groupDcurve2); + EXPECT_EQ(groupDcurve2.next, nullptr); +} + +} // namespace blender::bke::tests diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 4766fc6096b..7e4ab754500 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -89,16 +89,16 @@ bool id_can_have_animdata(const ID *id) return id_type_can_have_animdata(GS(id->name)); } -/* Get AnimData from the given ID-block. In order for this to work, we assume that - * the AnimData pointer is stored immediately after the given ID-block in the struct, - * as per IdAdtTemplate. +/** + * Get #AnimData from the given ID-block. */ AnimData *BKE_animdata_from_id(ID *id) { - /* only some ID-blocks have this info for now, so we cast the - * types that do to be of type IdAdtTemplate, and extract the - * AnimData that way - */ + /* In order for this to work, we assume that the #AnimData pointer is stored + * immediately after the given ID-block in the struct, as per IdAdtTemplate. */ + + /* Only some ID-blocks have this info for now, so we cast the types that do + * to be of type IdAdtTemplate, and add the AnimData to it using the template. */ if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; return iat->adt; @@ -106,16 +106,16 @@ AnimData *BKE_animdata_from_id(ID *id) return NULL; } -/* Add AnimData to the given ID-block. In order for this to work, we assume that - * the AnimData pointer is stored immediately after the given ID-block in the struct, - * as per IdAdtTemplate. Also note that +/** + * Ensure #AnimData exists in the given ID-block (when supported). */ -AnimData *BKE_animdata_add_id(ID *id) +AnimData *BKE_animdata_ensure_id(ID *id) { - /* Only some ID-blocks have this info for now, so we cast the - * types that do to be of type IdAdtTemplate, and add the AnimData - * to it using the template - */ + /* In order for this to work, we assume that the #AnimData pointer is stored + * immediately after the given ID-block in the struct, as per IdAdtTemplate. */ + + /* Only some ID-blocks have this info for now, so we cast the types that do + * to be of type IdAdtTemplate, and add the AnimData to it using the template. */ if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; @@ -667,7 +667,7 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa /* get animdata from src, and create for destination (if needed) */ srcAdt = BKE_animdata_from_id(srcID); - dstAdt = BKE_animdata_add_id(dstID); + dstAdt = BKE_animdata_ensure_id(dstID); if (ELEM(NULL, srcAdt, dstAdt)) { if (G.debug & G_DEBUG) { diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 22d6cfba893..b8ed519e8d1 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -2843,7 +2843,7 @@ void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob) * hopefully this is OK. */ BKE_pose_ensure(NULL, ob, arm, true); - ctime = BKE_scene_frame_get(scene); /* not accurate... */ + ctime = BKE_scene_ctime_get(scene); /* not accurate... */ /* In edit-mode or rest-position we read the data from the bones. */ if (arm->edbo || (arm->flag & ARM_RESTPOS)) { diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c index bca5503c8d2..5e9259f05bb 100644 --- a/source/blender/blenkernel/intern/armature_deform.c +++ b/source/blender/blenkernel/intern/armature_deform.c @@ -47,6 +47,7 @@ #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_lattice.h" @@ -485,7 +486,7 @@ static void armature_deform_coords_impl(const Object *ob_arm, int defbase_len = 0; /* safety for vertexgroup index overflow */ int i, dverts_len = 0; /* safety for vertexgroup overflow */ bool use_dverts = false; - int armature_def_nr; + int armature_def_nr = -1; int cd_dvert_offset = -1; /* in editmode, or not an armature */ @@ -500,11 +501,11 @@ static void armature_deform_coords_impl(const Object *ob_arm, BLI_assert(0); } - /* get the def_nr for the overall armature vertex group if present */ - armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name); - if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { - defbase_len = BLI_listbase_count(&ob_target->defbase); + /* get the def_nr for the overall armature vertex group if present */ + armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name); + + defbase_len = BKE_object_defgroup_count(ob_target); if (ob_target->type == OB_MESH) { if (em_target == NULL) { @@ -551,7 +552,8 @@ static void armature_deform_coords_impl(const Object *ob_arm, * * - Check whether keeping this consistent across frames gives speedup. */ - for (i = 0, dg = ob_target->defbase.first; dg; i++, dg = dg->next) { + const ListBase *defbase = BKE_object_defgroup_list(ob_target); + for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) { pchan_from_defbase[i] = BKE_pose_channel_find_name(ob_arm->pose, dg->name); /* exclude non-deforming bones */ if (pchan_from_defbase[i]) { diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 0a195f2ba55..35ae2d2dbef 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -828,7 +828,7 @@ void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph, Scene *scene, Object *ob { DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); BLI_assert(object->type == OB_ARMATURE); - const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + const float ctime = BKE_scene_ctime_get(scene); /* not accurate... */ bArmature *armature = (bArmature *)object->data; if (armature->flag & ARM_RESTPOS) { return; @@ -869,7 +869,7 @@ void BKE_pose_eval_bone(struct Depsgraph *depsgraph, Scene *scene, Object *objec else { if ((pchan->flag & POSE_DONE) == 0) { /* TODO(sergey): Use time source node for time. */ - float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + float ctime = BKE_scene_ctime_get(scene); /* not accurate... */ BKE_pose_where_is_bone(depsgraph, scene, object, pchan, ctime, 1); } } @@ -897,7 +897,7 @@ void BKE_pose_constraints_evaluate(struct Depsgraph *depsgraph, } else { if ((pchan->flag & POSE_DONE) == 0) { - float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + float ctime = BKE_scene_ctime_get(scene); /* not accurate... */ BKE_pose_where_is_bone(depsgraph, scene, object, pchan, ctime, 1); } } @@ -981,7 +981,7 @@ void BKE_pose_iktree_evaluate(struct Depsgraph *depsgraph, DEG_debug_print_eval_subdata( depsgraph, __func__, object->id.name, object, "rootchan", rootchan->name, rootchan); BLI_assert(object->type == OB_ARMATURE); - const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + const float ctime = BKE_scene_ctime_get(scene); /* not accurate... */ if (armature->flag & ARM_RESTPOS) { return; } @@ -1002,7 +1002,7 @@ void BKE_pose_splineik_evaluate(struct Depsgraph *depsgraph, DEG_debug_print_eval_subdata( depsgraph, __func__, object->id.name, object, "rootchan", rootchan->name, rootchan); BLI_assert(object->type == OB_ARMATURE); - const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + const float ctime = BKE_scene_ctime_get(scene); /* not accurate... */ if (armature->flag & ARM_RESTPOS) { return; } @@ -1031,7 +1031,7 @@ void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph, Scene *scene, Object *ob bPose *pose = object->pose; BLI_assert(pose != NULL); UNUSED_VARS_NDEBUG(pose); - const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + const float ctime = BKE_scene_ctime_get(scene); /* not accurate... */ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); BLI_assert(object->type == OB_ARMATURE); /* Release the IK tree. */ diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index f31d8f5ade7..912cc66920e 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -128,7 +128,7 @@ static void setup_app_userdef(BlendFileData *bfd) } /** - * Context matching, handle no-ui case + * Context matching, handle no-UI case. * * \note this is called on Undo so any slow conversion functions here * should be avoided or check (mode != LOAD_UNDO). diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 30e9ae39b67..eaba5d33a20 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -314,7 +314,7 @@ bool BKE_cachefile_filepath_get(const Main *bmain, if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) { Scene *scene = DEG_get_evaluated_scene(depsgraph); - const float ctime = BKE_scene_frame_get(scene); + const float ctime = BKE_scene_ctime_get(scene); const float fps = (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base); const float frame = BKE_cachefile_time_offset(cache_file, ctime, fps); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 2bca3f5da76..8678a659c0a 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -597,7 +597,7 @@ static void cloth_to_object(Object *ob, ClothModifierData *clmd, float (*vertexC Cloth *cloth = clmd->clothObject; if (clmd->clothObject) { - /* inverse matrix is not uptodate... */ + /* Inverse matrix is not up to date. */ invert_m4_m4(ob->imat, ob->obmat); for (i = 0; i < cloth->mvert_num; i++) { diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index aec849ebf59..605061570b8 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -1437,7 +1437,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph, if (vgroup_name) { mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT); if (mdef) { - vg_idx = BKE_object_defgroup_name_index(ob_dst, vgroup_name); + vg_idx = BKE_id_defgroup_name_index(&me_dst->id, vgroup_name); } } diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 19840a70bf0..f7ef84728b6 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -29,6 +29,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_gpencil_types.h" +#include "DNA_lattice_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -64,7 +66,9 @@ bDeformGroup *BKE_object_defgroup_new(Object *ob, const char *name) BLI_strncpy(defgroup->name, name, sizeof(defgroup->name)); - BLI_addtail(&ob->defbase, defgroup); + ListBase *defbase = BKE_object_defgroup_list_mutable(ob); + + BLI_addtail(defbase, defgroup); BKE_object_defgroup_unique_name(defgroup, ob); BKE_object_batch_cache_dirty_tag(ob); @@ -484,18 +488,120 @@ void BKE_defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int } } +bool BKE_object_supports_vertex_groups(const Object *ob) +{ + const ID *id = (const ID *)ob->data; + if (id == NULL) { + return false; + } + + return ELEM(GS(id->name), ID_ME, ID_LT, ID_GD); +} + +const ListBase *BKE_id_defgroup_list_get(const ID *id) +{ + switch (GS(id->name)) { + case ID_ME: { + const Mesh *me = (const Mesh *)id; + return &me->vertex_group_names; + } + case ID_LT: { + const Lattice *lt = (const Lattice *)id; + return <->vertex_group_names; + } + case ID_GD: { + const bGPdata *gpd = (const bGPdata *)id; + return &gpd->vertex_group_names; + } + default: { + BLI_assert_unreachable(); + } + } + return NULL; +} + +static const int *object_defgroup_active_index_get_p(const Object *ob) +{ + BLI_assert(BKE_object_supports_vertex_groups(ob)); + switch (ob->type) { + case OB_MESH: { + const Mesh *mesh = (const Mesh *)ob->data; + return &mesh->vertex_group_active_index; + } + case OB_LATTICE: { + const Lattice *lattice = (const Lattice *)ob->data; + return &lattice->vertex_group_active_index; + } + case OB_GPENCIL: { + const bGPdata *gpd = (const bGPdata *)ob->data; + return &gpd->vertex_group_active_index; + } + } + return NULL; +} + +ListBase *BKE_id_defgroup_list_get_mutable(ID *id) +{ + /* Cast away const just for the accessor. */ + return (ListBase *)BKE_id_defgroup_list_get(id); +} + bDeformGroup *BKE_object_defgroup_find_name(const Object *ob, const char *name) { - return (name && name[0] != '\0') ? - BLI_findstring(&ob->defbase, name, offsetof(bDeformGroup, name)) : - NULL; + if (name == NULL || name[0] == '\0') { + return NULL; + } + const ListBase *defbase = BKE_object_defgroup_list(ob); + return BLI_findstring(defbase, name, offsetof(bDeformGroup, name)); +} + +int BKE_id_defgroup_name_index(const ID *id, const char *name) +{ + if (name == NULL || name[0] == '\0') { + return -1; + } + const ListBase *defbase = BKE_id_defgroup_list_get(id); + return BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name)); +} + +const ListBase *BKE_object_defgroup_list(const Object *ob) +{ + BLI_assert(BKE_object_supports_vertex_groups(ob)); + return BKE_id_defgroup_list_get((const ID *)ob->data); } int BKE_object_defgroup_name_index(const Object *ob, const char *name) { - return (name && name[0] != '\0') ? - BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)) : - -1; + return BKE_id_defgroup_name_index((ID *)ob->data, name); +} + +ListBase *BKE_object_defgroup_list_mutable(Object *ob) +{ + BLI_assert(BKE_object_supports_vertex_groups(ob)); + return BKE_id_defgroup_list_get_mutable((ID *)ob->data); +} + +int BKE_object_defgroup_count(const Object *ob) +{ + return BLI_listbase_count(BKE_object_defgroup_list(ob)); +} + +/** + * \note For historical reasons, the index starts at 1 rather than 0. + */ +int BKE_object_defgroup_active_index_get(const Object *ob) +{ + return *object_defgroup_active_index_get_p(ob); +} + +/** + * \note For historical reasons, the index starts at 1 rather than 0. + */ +void BKE_object_defgroup_active_index_set(Object *ob, const int new_index) +{ + /* Cast away const just for the accessor. */ + int *index = (int *)object_defgroup_active_index_get_p(ob); + *index = new_index; } /** @@ -503,7 +609,8 @@ int BKE_object_defgroup_name_index(const Object *ob, const char *name) */ int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const bool use_default) { - int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase); + const ListBase *defbase = BKE_object_defgroup_list(ob); + int defbase_tot = *flip_map_len = BLI_listbase_count(defbase); if (defbase_tot == 0) { return NULL; @@ -517,7 +624,7 @@ int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const boo map[i] = -1; } - for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) { + for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) { if (map[i] == -1) { /* may be calculated previously */ /* in case no valid value is found, use this */ @@ -547,7 +654,8 @@ int *BKE_object_defgroup_flip_map_single(const Object *ob, const bool use_default, int defgroup) { - int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase); + const ListBase *defbase = BKE_object_defgroup_list(ob); + int defbase_tot = *flip_map_len = BLI_listbase_count(defbase); if (defbase_tot == 0) { return NULL; @@ -561,7 +669,7 @@ int *BKE_object_defgroup_flip_map_single(const Object *ob, map[i] = use_default ? i : -1; } - dg = BLI_findlink(&ob->defbase, defgroup); + dg = BLI_findlink(defbase, defgroup); BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip)); if (!STREQ(name_flip, dg->name)) { @@ -578,7 +686,8 @@ int *BKE_object_defgroup_flip_map_single(const Object *ob, int BKE_object_defgroup_flip_index(const Object *ob, int index, const bool use_default) { - bDeformGroup *dg = BLI_findlink(&ob->defbase, index); + const ListBase *defbase = BKE_object_defgroup_list(ob); + bDeformGroup *dg = BLI_findlink(defbase, index); int flip_index = -1; if (dg) { @@ -595,9 +704,10 @@ int BKE_object_defgroup_flip_index(const Object *ob, int index, const bool use_d static bool defgroup_find_name_dupe(const char *name, bDeformGroup *dg, Object *ob) { + const ListBase *defbase = BKE_object_defgroup_list(ob); bDeformGroup *curdef; - for (curdef = ob->defbase.first; curdef; curdef = curdef->next) { + for (curdef = defbase->first; curdef; curdef = curdef->next) { if (dg != curdef) { if (STREQ(curdef->name, name)) { return true; @@ -1189,7 +1299,10 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, { int idx_src; int idx_dst; - int tot_dst = BLI_listbase_count(&ob_dst->defbase); + const ListBase *src_list = BKE_object_defgroup_list(ob_src); + ListBase *dst_defbase = BKE_object_defgroup_list_mutable(ob_dst); + + int tot_dst = BLI_listbase_count(dst_defbase); const size_t elem_size = sizeof(*((MDeformVert *)NULL)); @@ -1218,7 +1331,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, } else if (use_delete && idx_dst > idx_src) { while (idx_dst-- > idx_src) { - BKE_object_defgroup_remove(ob_dst, ob_dst->defbase.last); + BKE_object_defgroup_remove(ob_dst, dst_defbase->last); } } if (r_map) { @@ -1255,7 +1368,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, if (use_delete) { /* Remove all unused dst vgroups first, simpler in this case. */ - for (dg_dst = ob_dst->defbase.first; dg_dst;) { + for (dg_dst = dst_defbase->first; dg_dst;) { bDeformGroup *dg_dst_next = dg_dst->next; if (BKE_object_defgroup_name_index(ob_src, dg_dst->name) == -1) { @@ -1265,7 +1378,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, } } - for (idx_src = 0, dg_src = ob_src->defbase.first; idx_src < num_layers_src; + for (idx_src = 0, dg_src = src_list->first; idx_src < num_layers_src; idx_src++, dg_src = dg_src->next) { if (!use_layers_src[idx_src]) { continue; @@ -1274,7 +1387,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, if ((idx_dst = BKE_object_defgroup_name_index(ob_dst, dg_src->name)) == -1) { if (use_create) { BKE_object_defgroup_add_name(ob_dst, dg_src->name); - idx_dst = ob_dst->actdef - 1; + idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1; } else { /* If we are not allowed to create missing dst vgroups, just skip matching src one. */ @@ -1340,8 +1453,12 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map, * This implies we may have to handle data layout itself while having NULL data itself, * and even have to support NULL data_src in transfer data code * (we always create a data_dst, though). + * + * Note: Above comment is outdated, but this function was written when that was true. */ - if (BLI_listbase_is_empty(&ob_src->defbase)) { + + const ListBase *src_defbase = BKE_object_defgroup_list(ob_src); + if (BLI_listbase_is_empty(src_defbase)) { if (use_delete) { BKE_object_defgroup_remove_all(ob_dst); } @@ -1361,35 +1478,37 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map, if (fromlayers >= 0) { idx_src = fromlayers; - if (idx_src >= BLI_listbase_count(&ob_src->defbase)) { + if (idx_src >= BLI_listbase_count(src_defbase)) { /* This can happen when vgroups are removed from source object... * Remapping would be really tricky here, we'd need to go over all objects in * Main every time we delete a vgroup... for now, simpler and safer to abort. */ return false; } } - else if ((idx_src = ob_src->actdef - 1) == -1) { + else if ((idx_src = BKE_object_defgroup_active_index_get(ob_src) - 1) == -1) { return false; } if (tolayers >= 0) { /* NOTE: in this case we assume layer exists! */ idx_dst = tolayers; - BLI_assert(idx_dst < BLI_listbase_count(&ob_dst->defbase)); + const ListBase *dst_defbase = BKE_object_defgroup_list(ob_dst); + BLI_assert(idx_dst < BLI_listbase_count(dst_defbase)); + UNUSED_VARS_NDEBUG(dst_defbase); } else if (tolayers == DT_LAYERS_ACTIVE_DST) { - if ((idx_dst = ob_dst->actdef - 1) == -1) { + if ((idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1) == -1) { bDeformGroup *dg_src; if (!use_create) { return true; } - dg_src = BLI_findlink(&ob_src->defbase, idx_src); + dg_src = BLI_findlink(src_defbase, idx_src); BKE_object_defgroup_add_name(ob_dst, dg_src->name); - idx_dst = ob_dst->actdef - 1; + idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1; } } else if (tolayers == DT_LAYERS_INDEX_DST) { - int num = BLI_listbase_count(&ob_src->defbase); + int num = BLI_listbase_count(src_defbase); idx_dst = idx_src; if (num <= idx_dst) { if (!use_create) { @@ -1402,13 +1521,13 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map, } } else if (tolayers == DT_LAYERS_NAME_DST) { - bDeformGroup *dg_src = BLI_findlink(&ob_src->defbase, idx_src); + bDeformGroup *dg_src = BLI_findlink(src_defbase, idx_src); if ((idx_dst = BKE_object_defgroup_name_index(ob_dst, dg_src->name)) == -1) { if (!use_create) { return true; } BKE_object_defgroup_add_name(ob_dst, dg_src->name); - idx_dst = ob_dst->actdef - 1; + idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1; } } else { @@ -1531,6 +1650,13 @@ void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight) /** \name .blend file I/O * \{ */ +void BKE_defbase_blend_write(BlendWriter *writer, const ListBase *defbase) +{ + LISTBASE_FOREACH (bDeformGroup *, defgroup, defbase) { + BLO_write_struct(writer, bDeformGroup, defgroup); + } +} + void BKE_defvert_blend_write(BlendWriter *writer, int count, MDeformVert *dvlist) { if (dvlist == NULL) { diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 6091e774d4a..52996e3bcc7 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -3818,7 +3818,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph, ob, true, SUBFRAME_RECURSION, - BKE_scene_frame_get(scene), + BKE_scene_ctime_get(scene), eModifierType_DynamicPaint); mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush), false); numOfVerts_p = mesh_p->totvert; @@ -3834,7 +3834,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph, ob, true, SUBFRAME_RECURSION, - BKE_scene_frame_get(scene), + BKE_scene_ctime_get(scene), eModifierType_DynamicPaint); mesh_c = dynamicPaint_brush_mesh_get(brush); numOfVerts_c = mesh_c->totvert; @@ -3894,7 +3894,7 @@ static void dynamicPaint_brushObjectCalculateVelocity( ob, false, SUBFRAME_RECURSION, - BKE_scene_frame_get(scene), + BKE_scene_ctime_get(scene), eModifierType_DynamicPaint); copy_m4_m4(prev_obmat, ob->obmat); @@ -3906,7 +3906,7 @@ static void dynamicPaint_brushObjectCalculateVelocity( ob, false, SUBFRAME_RECURSION, - BKE_scene_frame_get(scene), + BKE_scene_ctime_get(scene), eModifierType_DynamicPaint); /* calculate speed */ @@ -6271,7 +6271,7 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph, brushObj, true, SUBFRAME_RECURSION, - BKE_scene_frame_get(scene), + BKE_scene_ctime_get(scene), eModifierType_DynamicPaint); } @@ -6312,7 +6312,7 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph, brushObj, true, SUBFRAME_RECURSION, - BKE_scene_frame_get(scene), + BKE_scene_ctime_get(scene), eModifierType_DynamicPaint); } diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 2eb6b488da2..9cae74e4e9a 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -39,15 +39,14 @@ #include "BKE_mesh_wrapper.h" #include "BKE_object.h" -BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate) +/** + * \note The caller is responsible for ensuring triangulation data, + * typically by calling #BKE_editmesh_looptri_calc. + */ +BMEditMesh *BKE_editmesh_create(BMesh *bm) { BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__); - em->bm = bm; - if (do_tessellate) { - BKE_editmesh_looptri_calc(em); - } - return em; } @@ -209,7 +208,7 @@ void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em, }); } -void BKE_editmesh_free_derivedmesh(BMEditMesh *em) +void BKE_editmesh_free_derived_caches(BMEditMesh *em) { if (em->mesh_eval_cage) { BKE_id_free(NULL, em->mesh_eval_cage); @@ -223,9 +222,9 @@ void BKE_editmesh_free_derivedmesh(BMEditMesh *em) } /* Does not free the #BMEditMesh struct itself. */ -void BKE_editmesh_free(BMEditMesh *em) +void BKE_editmesh_free_data(BMEditMesh *em) { - BKE_editmesh_free_derivedmesh(em); + BKE_editmesh_free_derived_caches(em); if (em->looptris) { MEM_freeN(em->looptris); diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c index e5e639fa3f1..da4ea742656 100644 --- a/source/blender/blenkernel/intern/editmesh_tangent.c +++ b/source/blender/blenkernel/intern/editmesh_tangent.c @@ -25,6 +25,7 @@ #include "DNA_defs.h" #include "DNA_meshdata_types.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_editmesh_tangent.h" #include "BKE_mesh.h" diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 947417af55d..2b48683a3a8 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -1283,10 +1283,10 @@ static void compute_obstaclesemission(Scene *scene, # endif /* Update frame time, this is considering current subframe fraction * BLI_mutex_lock() called in manta_step(), so safe to update subframe here - * TODO(sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph) + * TODO(sebbas): Using BKE_scene_ctime_get(scene) instead of new DEG_get_ctime(depsgraph) * as subframes don't work with the latter yet. */ BKE_object_modifier_update_subframe( - depsgraph, scene, effecobj, true, 5, BKE_scene_frame_get(scene), eModifierType_Fluid); + depsgraph, scene, effecobj, true, 5, BKE_scene_ctime_get(scene), eModifierType_Fluid); if (subframes) { obstacles_from_mesh(effecobj, fds, fes, &bb_temp, subframe_dt); @@ -1616,7 +1616,7 @@ static void emit_from_particles(Object *flow_ob, } /* `DEG_get_ctime(depsgraph)` does not give sub-frame time. */ - state.time = BKE_scene_frame_get(scene); + state.time = BKE_scene_ctime_get(scene); if (psys_get_particle_state(&sim, p, &state, 0) == 0) { continue; @@ -2820,10 +2820,10 @@ static void compute_flowsemission(Scene *scene, # endif /* Update frame time, this is considering current subframe fraction * BLI_mutex_lock() called in manta_step(), so safe to update subframe here - * TODO(sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph) + * TODO(sebbas): Using BKE_scene_ctime_get(scene) instead of new DEG_get_ctime(depsgraph) * as subframes don't work with the latter yet. */ BKE_object_modifier_update_subframe( - depsgraph, scene, flowobj, true, 5, BKE_scene_frame_get(scene), eModifierType_Fluid); + depsgraph, scene, flowobj, true, 5, BKE_scene_ctime_get(scene), eModifierType_Fluid); /* Emission from particles. */ if (ffs->source == FLUID_FLOW_SOURCE_PARTICLES) { diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 28e46aab732..af500ab3427 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -53,7 +53,6 @@ GeometryComponent *MeshComponent::copy() const if (mesh_ != nullptr) { new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false); new_component->ownership_ = GeometryOwnershipType::Owned; - new_component->vertex_group_names_ = blender::Map(vertex_group_names_); } return new_component; } @@ -67,7 +66,6 @@ void MeshComponent::clear() } mesh_ = nullptr; } - vertex_group_names_.clear(); } bool MeshComponent::has_mesh() const @@ -84,23 +82,6 @@ void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership) ownership_ = ownership; } -/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to - * be able to replace the mesh data without losing the vertex group names, which may have come - * from another object. */ -void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh, - GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - if (mesh_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, mesh_); - } - mesh_ = nullptr; - } - mesh_ = mesh; - ownership_ = ownership; -} - /* Return the mesh and clear the component. The caller takes over responsibility for freeing the * mesh (if the component was responsible before). */ Mesh *MeshComponent::release() @@ -111,28 +92,6 @@ Mesh *MeshComponent::release() return mesh; } -void MeshComponent::copy_vertex_group_names_from_object(const Object &object) -{ - BLI_assert(this->is_mutable()); - vertex_group_names_.clear(); - int index = 0; - LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) { - vertex_group_names_.add(group->name, index); - index++; - } -} - -const blender::Map<std::string, int> &MeshComponent::vertex_group_names() const -{ - return vertex_group_names_; -} - -/* This is only exposed for the internal attribute API. */ -blender::Map<std::string, int> &MeshComponent::vertex_group_names() -{ - return vertex_group_names_; -} - /* Get the mesh from this component. This method can be used by multiple threads at the same * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */ const Mesh *MeshComponent::get_for_read() const @@ -864,8 +823,8 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); - const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( - attribute_name, -1); + const int vertex_group_index = BLI_findstringindex( + &mesh->vertex_group_names, attribute_name.data(), offsetof(bDeformGroup, name)); if (vertex_group_index < 0) { return {}; } @@ -889,8 +848,9 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { if (mesh == nullptr) { return {}; } - const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( - attribute_name, -1); + + const int vertex_group_index = BLI_findstringindex( + &mesh->vertex_group_names, attribute_name.data(), offsetof(bDeformGroup, name)); if (vertex_group_index < 0) { return {}; } @@ -913,13 +873,13 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { { BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); MeshComponent &mesh_component = static_cast<MeshComponent &>(component); + Mesh *mesh = mesh_component.get_for_write(); - const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as( - attribute_name, -1); + const int vertex_group_index = BLI_findstringindex( + &mesh->vertex_group_names, attribute_name.data(), offsetof(bDeformGroup, name)); if (vertex_group_index < 0) { return false; } - Mesh *mesh = mesh_component.get_for_write(); if (mesh == nullptr) { return true; } @@ -938,14 +898,14 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { { BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - for (const auto item : mesh_component.vertex_group_names().items()) { - const StringRefNull name = item.key; - const int vertex_group_index = item.value; - if (vertex_group_index >= 0) { - AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT}; - if (!callback(name, meta_data)) { - return false; - } + const Mesh *mesh = mesh_component.get_for_read(); + if (mesh == nullptr) { + return true; + } + + LISTBASE_FOREACH (const bDeformGroup *, group, &mesh->vertex_group_names) { + if (!callback(group->name, {ATTR_DOMAIN_POINT, CD_PROP_FLOAT})) { + return false; } } return true; diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 01b51d552a9..47c8df03375 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -48,7 +48,6 @@ static void add_final_mesh_as_geometry_component(const Object &object, GeometryS MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); - mesh_component.copy_vertex_group_names_from_object(object); } } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 647db970d09..e13b9d543d7 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -87,6 +87,8 @@ static void greasepencil_copy_data(Main *UNUSED(bmain), gpd_dst->mat = MEM_dupallocN(gpd_src->mat); } + BKE_defgroup_copy_list(&gpd_dst->vertex_group_names, &gpd_src->vertex_group_names); + /* copy layers */ BLI_listbase_clear(&gpd_dst->layers); LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) { @@ -165,6 +167,8 @@ static void greasepencil_blend_write(BlendWriter *writer, ID *id, const void *id BKE_animdata_blend_write(writer, gpd->adt); } + BKE_defbase_blend_write(writer, &gpd->vertex_group_names); + BLO_write_pointer_array(writer, gpd->totcol, gpd->mat); /* write grease-pencil layers to file */ @@ -227,6 +231,8 @@ void BKE_gpencil_blend_read_data(BlendDataReader *reader, bGPdata *gpd) } } + BLO_read_list(reader, &gpd->vertex_group_names); + /* Materials. */ BLO_read_pointer_array(reader, (void **)&gpd->mat); @@ -498,6 +504,8 @@ void BKE_gpencil_free(bGPdata *gpd, bool free_all) /* materials */ MEM_SAFE_FREE(gpd->mat); + BLI_freelistN(&gpd->vertex_group_names); + /* free all data */ if (free_all) { /* clear cache */ @@ -798,32 +806,6 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) /* Utilities for easier bulk-creation of geometry */ /** - * Populate stroke with point data from data buffers. - * \param gps: Grease pencil stroke - * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values. - * \param totpoints: Total of points - * \param mat: 4x4 transform matrix to transform points into the right coordinate space. - */ -void BKE_gpencil_stroke_add_points(bGPDstroke *gps, - const float *array, - const int totpoints, - const float mat[4][4]) -{ - for (int i = 0; i < totpoints; i++) { - bGPDspoint *pt = &gps->points[i]; - const int x = GP_PRIM_DATABUF_SIZE * i; - - pt->x = array[x]; - pt->y = array[x + 1]; - pt->z = array[x + 2]; - mul_m4_v3(mat, &pt->x); - - pt->pressure = array[x + 3]; - pt->strength = array[x + 4]; - } -} - -/** * Create a new stroke, with pre-allocated data buffers. * \param mat_idx: Index of the material * \param totpoints: Total points @@ -2087,8 +2069,9 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup) { bGPdata *gpd = ob->data; MDeformVert *dvert = NULL; - const int def_nr = BLI_findindex(&ob->defbase, defgroup); - const int totgrp = BLI_listbase_count(&ob->defbase); + + const int def_nr = BLI_findindex(&gpd->vertex_group_names, defgroup); + const int totgrp = BLI_listbase_count(&gpd->vertex_group_names); /* Remove points data */ if (gpd) { @@ -2117,7 +2100,7 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup) } /* Remove the group */ - BLI_freelinkN(&ob->defbase, defgroup); + BLI_freelinkN(&gpd->vertex_group_names, defgroup); DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); } diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 4d9c9878a67..0e2219e6c7f 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -257,9 +257,13 @@ bool BKE_gpencil_is_first_lineart_in_stack(const Object *ob, const GpencilModifi return false; } -/* apply time modifiers */ -static int gpencil_time_modifier( - Depsgraph *depsgraph, Scene *scene, Object *ob, bGPDlayer *gpl, int cfra, bool is_render) +/* Get Time modifier frame number. */ +int BKE_gpencil_time_modifier_cfra(Depsgraph *depsgraph, + Scene *scene, + Object *ob, + bGPDlayer *gpl, + const int cfra, + const bool is_render) { bGPdata *gpd = ob->data; const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); @@ -665,7 +669,7 @@ static int gpencil_remap_time_get(Depsgraph *depsgraph, Scene *scene, Object *ob int remap_cfra = cfra_eval; if (time_remap) { - remap_cfra = gpencil_time_modifier(depsgraph, scene, ob, gpl, cfra_eval, is_render); + remap_cfra = BKE_gpencil_time_modifier_cfra(depsgraph, scene, ob, gpl, cfra_eval, is_render); } return remap_cfra; diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index a1f82b1dcb6..8a70f065e40 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -2087,7 +2087,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* check if object has any animation data */ if (ob->nlastrips.first) { /* Add AnimData block */ - BKE_animdata_add_id(id); + BKE_animdata_ensure_id(id); /* IPO first to take into any non-NLA'd Object Animation */ if (ob->ipo) { @@ -2109,7 +2109,7 @@ void do_versions_ipos_to_animato(Main *bmain) } else if ((ob->ipo) || (ob->action)) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Action first - so that Action name get conserved */ if (ob->action) { @@ -2133,7 +2133,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* check PoseChannels for constraints with local data */ if (ob->pose) { /* Verify if there's AnimData block */ - BKE_animdata_add_id(id); + BKE_animdata_ensure_id(id); for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { @@ -2159,7 +2159,7 @@ void do_versions_ipos_to_animato(Main *bmain) */ if (con->ipo) { /* Verify if there's AnimData block, just in case */ - BKE_animdata_add_id(id); + BKE_animdata_ensure_id(id); /* although this was the constraint's local IPO, we still need to provide con * so that drivers can be added properly... @@ -2176,7 +2176,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* check constraint channels - we need to remove them anyway... */ if (ob->constraintChannels.first) { /* Verify if there's AnimData block */ - BKE_animdata_add_id(id); + BKE_animdata_ensure_id(id); for (conchan = ob->constraintChannels.first; conchan; conchan = conchann) { /* get pointer to next Constraint Channel */ @@ -2217,7 +2217,7 @@ void do_versions_ipos_to_animato(Main *bmain) */ if (key->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Shapekey data... */ ipo_to_animdata(bmain, id, key->ipo, NULL, NULL, NULL); @@ -2242,7 +2242,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (ma->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Material data... */ ipo_to_animdata(bmain, id, ma->ipo, NULL, NULL, NULL); @@ -2267,7 +2267,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (wo->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert World data... */ ipo_to_animdata(bmain, id, wo->ipo, NULL, NULL, NULL); @@ -2288,7 +2288,7 @@ void do_versions_ipos_to_animato(Main *bmain) if (ed && ed->seqbasep) { Sequence *seq; - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); SEQ_ALL_BEGIN (ed, seq) { IpoCurve *icu = (seq->ipo) ? seq->ipo->curve.first : NULL; @@ -2346,7 +2346,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (te->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Texture data... */ ipo_to_animdata(bmain, id, te->ipo, NULL, NULL, NULL); @@ -2371,7 +2371,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (ca->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Camera data... */ ipo_to_animdata(bmain, id, ca->ipo, NULL, NULL, NULL); @@ -2396,7 +2396,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (la->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Light data... */ ipo_to_animdata(bmain, id, la->ipo, NULL, NULL, NULL); @@ -2421,7 +2421,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (cu->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Curve data... */ ipo_to_animdata(bmain, id, cu->ipo, NULL, NULL, NULL); diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 6cc90f86b4a..52f888d9543 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -1317,7 +1317,7 @@ static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cac if (cache) { if (cache->defgroup_weights == NULL) { - int num_defgroup = BLI_listbase_count(&ob->defbase); + int num_defgroup = BKE_object_defgroup_count(ob); cache->defgroup_weights = MEM_callocN(sizeof(*cache->defgroup_weights) * num_defgroup, "cached defgroup weights"); cache->num_defgroup_weights = num_defgroup; diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 1357424d5ff..9875d776d33 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -87,6 +87,8 @@ static void lattice_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const i lattice_dst->key->from = &lattice_dst->id; } + BKE_defgroup_copy_list(&lattice_dst->vertex_group_names, &lattice_src->vertex_group_names); + if (lattice_src->dvert) { int tot = lattice_src->pntsu * lattice_src->pntsv * lattice_src->pntsw; lattice_dst->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); @@ -103,6 +105,8 @@ static void lattice_free_data(ID *id) BKE_lattice_batch_cache_free(lattice); + BLI_freelistN(&lattice->vertex_group_names); + MEM_SAFE_FREE(lattice->def); if (lattice->dvert) { BKE_defvert_array_free(lattice->dvert, lattice->pntsu * lattice->pntsv * lattice->pntsw); @@ -150,6 +154,7 @@ static void lattice_blend_write(BlendWriter *writer, ID *id, const void *id_addr /* direct data */ BLO_write_struct_array(writer, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def); + BKE_defbase_blend_write(writer, <->vertex_group_names); BKE_defvert_blend_write(writer, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert); } } @@ -161,6 +166,7 @@ static void lattice_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_data_address(reader, <->dvert); BKE_defvert_blend_read(reader, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert); + BLO_read_list(reader, <->vertex_group_names); lt->editlatt = NULL; lt->batch_cache = NULL; diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c index bd1972e9f1f..f9437eeaffa 100644 --- a/source/blender/blenkernel/intern/lattice_deform.c +++ b/source/blender/blenkernel/intern/lattice_deform.c @@ -112,7 +112,7 @@ LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Ob int defgrp_index = -1; const MDeformVert *dvert = BKE_lattice_deform_verts_get(oblatt); if (lt->vgroup[0] && dvert) { - defgrp_index = BKE_object_defgroup_name_index(oblatt, lt->vgroup); + defgrp_index = BKE_id_defgroup_name_index(<->id, lt->vgroup); if (defgrp_index != -1) { lattice_weights = MEM_malloc_arrayN(sizeof(float), num_points, "lattice_weights"); @@ -364,7 +364,7 @@ static void lattice_deform_coords_impl(const Object *ob_lattice, * We want either a Mesh/Lattice with no derived data, or derived data with deformverts. */ if (defgrp_name && defgrp_name[0] && ob_target && ELEM(ob_target->type, OB_MESH, OB_LATTICE)) { - defgrp_index = BKE_object_defgroup_name_index(ob_target, defgrp_name); + defgrp_index = BKE_id_defgroup_name_index((ID *)ob_target->data, defgrp_name); if (defgrp_index != -1) { /* if there's derived data without deformverts, don't use vgroups */ diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index d49eb0d4da8..60e42c09ff3 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -737,6 +737,73 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection * in at least one layer collection. That list is also synchronized here, and * stores state like selection. */ +static void layer_collection_objects_sync(ViewLayer *view_layer, + LayerCollection *layer, + ListBase *new_object_bases, + const short collection_restrict, + const short layer_restrict, + const ushort local_collections_bits) +{ + /* No need to sync objects if the collection is excluded. */ + if ((layer->flag & LAYER_COLLECTION_EXCLUDE) != 0) { + return; + } + + LISTBASE_FOREACH (CollectionObject *, cob, &layer->collection->gobject) { + if (cob->ob == NULL) { + continue; + } + + /* Tag linked object as a weak reference so we keep the object + * base pointer on file load and remember hidden state. */ + id_lib_indirect_weak_link(&cob->ob->id); + + void **base_p; + Base *base; + if (BLI_ghash_ensure_p(view_layer->object_bases_hash, cob->ob, &base_p)) { + /* Move from old base list to new base list. Base might have already + * been moved to the new base list and the first/last test ensure that + * case also works. */ + base = *base_p; + if (!ELEM(base, new_object_bases->first, new_object_bases->last)) { + BLI_remlink(&view_layer->object_bases, base); + BLI_addtail(new_object_bases, base); + } + } + else { + /* Create new base. */ + base = object_base_new(cob->ob); + base->local_collections_bits = local_collections_bits; + *base_p = base; + BLI_addtail(new_object_bases, base); + } + + if ((collection_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) { + base->flag_from_collection |= (BASE_ENABLED_VIEWPORT | BASE_VISIBLE_DEPSGRAPH); + if ((layer_restrict & LAYER_COLLECTION_HIDE) == 0) { + base->flag_from_collection |= BASE_VISIBLE_VIEWLAYER; + } + if (((collection_restrict & COLLECTION_RESTRICT_SELECT) == 0)) { + base->flag_from_collection |= BASE_SELECTABLE; + } + } + + if ((collection_restrict & COLLECTION_RESTRICT_RENDER) == 0) { + base->flag_from_collection |= BASE_ENABLED_RENDER; + } + + /* Holdout and indirect only */ + if (layer->flag & LAYER_COLLECTION_HOLDOUT) { + base->flag_from_collection |= BASE_HOLDOUT; + } + if (layer->flag & LAYER_COLLECTION_INDIRECT_ONLY) { + base->flag_from_collection |= BASE_INDIRECT_ONLY; + } + + layer->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS; + } +} + static void layer_collection_sync(ViewLayer *view_layer, const ListBase *lb_collections, ListBase *lb_layer_collections, @@ -812,7 +879,8 @@ static void layer_collection_sync(ViewLayer *view_layer, child_layer_restrict, local_collections_bits); - /* Layer collection exclude is not inherited. */ + /* Layer collection exclude is not inherited, we can skip the remaining process, including + * object bases synchronization. */ lc->runtime_flag = 0; if (lc->flag & LAYER_COLLECTION_EXCLUDE) { continue; @@ -829,60 +897,12 @@ static void layer_collection_sync(ViewLayer *view_layer, lc->runtime_flag |= LAYER_COLLECTION_VISIBLE_VIEW_LAYER; } - /* Sync objects, except if collection was excluded. */ - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - if (cob->ob == NULL) { - continue; - } - - /* Tag linked object as a weak reference so we keep the object - * base pointer on file load and remember hidden state. */ - id_lib_indirect_weak_link(&cob->ob->id); - - void **base_p; - Base *base; - if (BLI_ghash_ensure_p(view_layer->object_bases_hash, cob->ob, &base_p)) { - /* Move from old base list to new base list. Base might have already - * been moved to the new base list and the first/last test ensure that - * case also works. */ - base = *base_p; - if (!ELEM(base, new_object_bases->first, new_object_bases->last)) { - BLI_remlink(&view_layer->object_bases, base); - BLI_addtail(new_object_bases, base); - } - } - else { - /* Create new base. */ - base = object_base_new(cob->ob); - base->local_collections_bits = local_collections_bits; - *base_p = base; - BLI_addtail(new_object_bases, base); - } - - if ((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) { - base->flag_from_collection |= (BASE_ENABLED_VIEWPORT | BASE_VISIBLE_DEPSGRAPH); - if ((child_layer_restrict & LAYER_COLLECTION_HIDE) == 0) { - base->flag_from_collection |= BASE_VISIBLE_VIEWLAYER; - } - if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) { - base->flag_from_collection |= BASE_SELECTABLE; - } - } - - if ((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) { - base->flag_from_collection |= BASE_ENABLED_RENDER; - } - - /* Holdout and indirect only */ - if (lc->flag & LAYER_COLLECTION_HOLDOUT) { - base->flag_from_collection |= BASE_HOLDOUT; - } - if (lc->flag & LAYER_COLLECTION_INDIRECT_ONLY) { - base->flag_from_collection |= BASE_INDIRECT_ONLY; - } - - lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS; - } + layer_collection_objects_sync(view_layer, + lc, + new_object_bases, + child_restrict, + child_layer_restrict, + local_collections_bits); } /* Free potentially remaining unused layer collections in old list. diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c index 10ab0a06dd0..48179e0c3bf 100644 --- a/source/blender/blenkernel/intern/layer_utils.c +++ b/source/blender/blenkernel/intern/layer_utils.c @@ -23,6 +23,7 @@ #include "BLI_array.h" #include "BKE_collection.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_layer.h" diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index a92401d3ba0..c4186ad3180 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -39,6 +39,7 @@ #include "BLI_ghash.h" #include "BLI_hash.h" #include "BLI_linklist.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_string.h" @@ -125,6 +126,8 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int mesh_dst->mat = MEM_dupallocN(mesh_src->mat); + BKE_defgroup_copy_list(&mesh_dst->vertex_group_names, &mesh_src->vertex_group_names); + const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, alloc_type, mesh_dst->totvert); CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, alloc_type, mesh_dst->totedge); @@ -155,6 +158,8 @@ static void mesh_free_data(ID *id) { Mesh *mesh = (Mesh *)id; + BLI_freelistN(&mesh->vertex_group_names); + BKE_mesh_runtime_clear_cache(mesh); mesh_clear_geometry(mesh); MEM_SAFE_FREE(mesh->mat); @@ -229,6 +234,8 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address BKE_animdata_blend_write(writer, mesh->adt); } + BKE_defbase_blend_write(writer, &mesh->vertex_group_names); + BLO_write_pointer_array(writer, mesh->totcol, mesh->mat); BLO_write_raw(writer, sizeof(MSelect) * mesh->totselect, mesh->mselect); @@ -288,6 +295,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) /* Normally BKE_defvert_blend_read should be called in CustomData_blend_read, * but for backwards compatibility in do_versions to work we do it here. */ BKE_defvert_blend_read(reader, mesh->totvert, mesh->dvert); + BLO_read_list(reader, &mesh->vertex_group_names); CustomData_blend_read(reader, &mesh->vdata, mesh->totvert); CustomData_blend_read(reader, &mesh->edata, mesh->totedge); @@ -923,6 +931,12 @@ void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src) me_dst->texflag = me_src->texflag; copy_v3_v3(me_dst->loc, me_src->loc); copy_v3_v3(me_dst->size, me_src->size); + + /* Some callers call this on existing meshes, so free the existing vertex groups first. */ + BLI_freelistN(&me_dst->vertex_group_names); + BKE_defgroup_copy_list(&me_dst->vertex_group_names, &me_src->vertex_group_names); + + me_dst->vertex_group_active_index = me_src->vertex_group_active_index; } /** diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc index 369e3de2c67..91fd022a316 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.cc +++ b/source/blender/blenkernel/intern/mesh_evaluate.cc @@ -676,7 +676,7 @@ void BKE_mesh_calc_volume(const MVert *mverts, /** \} */ /* -------------------------------------------------------------------- */ -/** \name NGon Tessellation (NGon/Tessface Conversion) +/** \name NGon Tessellation (NGon to MFace Conversion) * \{ */ static void bm_corners_to_loops_ex(ID *id, @@ -750,9 +750,9 @@ static void bm_corners_to_loops_ex(ID *id, corners = multires_mdisp_corners(fd); if (corners == 0) { - /* Empty MDisp layers appear in at least one of the sintel.blend files. + /* Empty #MDisp layers appear in at least one of the `sintel.blend` files. * Not sure why this happens, but it seems fine to just ignore them here. - * If (corners == 0) for a non-empty layer though, something went wrong. */ + * If `corners == 0` for a non-empty layer though, something went wrong. */ BLI_assert(fd->totdisp == 0); } else { @@ -802,15 +802,16 @@ void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh) /** * The same as #BKE_mesh_convert_mfaces_to_mpolys - * but oriented to be used in #do_versions from readfile.c - * the difference is how active/render/clone/stencil indices are handled here + * but oriented to be used in #do_versions from `readfile.c` + * the difference is how active/render/clone/stencil indices are handled here. * - * normally thay're being set from pdata which totally makes sense for meshes which are already - * converted to bmesh structures, but when loading older files indices shall be updated in other - * way around, so newly added pdata and ldata would have this indices set based on fdata layer + * normally they're being set from `pdata` which totally makes sense for meshes which are already + * converted to #BMesh structures, but when loading older files indices shall be updated in other + * way around, so newly added `pdata` and `ldata` would have this indices set + * based on `fdata` layer. * * this is normally only needed when reading older files, - * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used + * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used. */ void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh) { diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 55882f961a2..715c2fa91d2 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -69,7 +69,6 @@ #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_node.h" -#include "BKE_node_ui_storage.hh" #include "BLI_ghash.h" #include "BLI_threads.h" @@ -220,10 +219,6 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c /* node tree will generate its own interface type */ ntree_dst->interface_type = nullptr; - - /* Don't copy error messages in the runtime struct. - * They should be filled during execution anyway. */ - ntree_dst->ui_storage = nullptr; } static void ntree_free_data(ID *id) @@ -277,8 +272,6 @@ static void ntree_free_data(ID *id) if (ntree->id.tag & LIB_TAG_LOCALIZED) { BKE_libblock_free_data(&ntree->id, true); } - - delete ntree->ui_storage; } static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock) @@ -621,7 +614,6 @@ static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_addres ntree->interface_type = nullptr; ntree->progress = nullptr; ntree->execdata = nullptr; - ntree->ui_storage = nullptr; BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id); @@ -653,7 +645,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) ntree->progress = nullptr; ntree->execdata = nullptr; - ntree->ui_storage = nullptr; BLO_read_data_address(reader, &ntree->adt); BKE_animdata_blend_read_data(reader, ntree->adt); @@ -5121,6 +5112,7 @@ static void registerGeometryNodes() register_node_type_geo_curve_primitive_circle(); register_node_type_geo_curve_primitive_line(); register_node_type_geo_curve_primitive_quadratic_bezier(); + register_node_type_geo_curve_primitive_quadrilateral(); register_node_type_geo_curve_primitive_spiral(); register_node_type_geo_curve_primitive_star(); register_node_type_geo_curve_sample(); diff --git a/source/blender/blenkernel/intern/node_ui_storage.cc b/source/blender/blenkernel/intern/node_ui_storage.cc deleted file mode 100644 index e5e9f00c7c3..00000000000 --- a/source/blender/blenkernel/intern/node_ui_storage.cc +++ /dev/null @@ -1,169 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "CLG_log.h" - -#include <mutex> - -#include "BLI_map.hh" -#include "BLI_string_ref.hh" -#include "BLI_vector.hh" - -#include "DNA_node_types.h" -#include "DNA_object_types.h" - -#include "BKE_context.h" -#include "BKE_node_ui_storage.hh" -#include "BKE_object.h" - -static CLG_LogRef LOG = {"bke.node_ui_storage"}; - -using blender::Map; -using blender::StringRef; -using blender::Vector; - -/* Use a global mutex because otherwise it would have to be stored directly in the - * bNodeTree struct in DNA. This could change if the node tree had a runtime struct. */ -static std::mutex global_ui_storage_mutex; - -static NodeTreeUIStorage &ui_storage_ensure(bNodeTree &ntree) -{ - /* As an optimization, only acquire a lock if the UI storage doesn't exist, - * because it only needs to be allocated once for every node tree. */ - if (ntree.ui_storage == nullptr) { - std::lock_guard<std::mutex> lock(global_ui_storage_mutex); - /* Check again-- another thread may have allocated the storage while this one waited. */ - if (ntree.ui_storage == nullptr) { - ntree.ui_storage = new NodeTreeUIStorage(); - } - } - return *ntree.ui_storage; -} - -const NodeUIStorage *BKE_node_tree_ui_storage_get_from_context(const bContext *C, - const bNodeTree &ntree, - const bNode &node) -{ - const NodeTreeUIStorage *ui_storage = ntree.ui_storage; - if (ui_storage == nullptr) { - return nullptr; - } - - const Object *active_object = CTX_data_active_object(C); - if (active_object == nullptr) { - return nullptr; - } - - const ModifierData *active_modifier = BKE_object_active_modifier(active_object); - if (active_modifier == nullptr) { - return nullptr; - } - - const NodeTreeEvaluationContext context(*active_object, *active_modifier); - const Map<std::string, NodeUIStorage> *storage = ui_storage->context_map.lookup_ptr(context); - if (storage == nullptr) { - return nullptr; - } - - return storage->lookup_ptr_as(StringRef(node.name)); -} - -/** - * Removes only the UI data associated with a particular evaluation context. The same node tree - * can be used for execution in multiple places, but the entire UI storage can't be removed when - * one execution starts, or all of the data associated with the node tree would be lost. - */ -void BKE_nodetree_ui_storage_free_for_context(bNodeTree &ntree, - const NodeTreeEvaluationContext &context) -{ - NodeTreeUIStorage *ui_storage = ntree.ui_storage; - if (ui_storage != nullptr) { - std::lock_guard<std::mutex> lock(ui_storage->mutex); - ui_storage->context_map.remove(context); - } -} - -static void node_error_message_log(bNodeTree &ntree, - const bNode &node, - const StringRef message, - const NodeWarningType type) -{ - switch (type) { - case NodeWarningType::Error: - CLOG_ERROR(&LOG, - "Node Tree: \"%s\", Node: \"%s\", %s", - ntree.id.name + 2, - node.name, - message.data()); - break; - case NodeWarningType::Warning: - CLOG_WARN(&LOG, - "Node Tree: \"%s\", Node: \"%s\", %s", - ntree.id.name + 2, - node.name, - message.data()); - break; - case NodeWarningType::Info: - CLOG_INFO(&LOG, - 2, - "Node Tree: \"%s\", Node: \"%s\", %s", - ntree.id.name + 2, - node.name, - message.data()); - break; - } -} - -static NodeUIStorage &node_ui_storage_ensure(NodeTreeUIStorage &locked_ui_storage, - const NodeTreeEvaluationContext &context, - const bNode &node) -{ - Map<std::string, NodeUIStorage> &node_tree_ui_storage = - locked_ui_storage.context_map.lookup_or_add_default(context); - NodeUIStorage &node_ui_storage = node_tree_ui_storage.lookup_or_add_default_as( - StringRef(node.name)); - return node_ui_storage; -} - -void BKE_nodetree_error_message_add(bNodeTree &ntree, - const NodeTreeEvaluationContext &context, - const bNode &node, - const NodeWarningType type, - std::string message) -{ - NodeTreeUIStorage &ui_storage = ui_storage_ensure(ntree); - std::lock_guard lock{ui_storage.mutex}; - - node_error_message_log(ntree, node, message, type); - - NodeUIStorage &node_ui_storage = node_ui_storage_ensure(ui_storage, context, node); - node_ui_storage.warnings.append({type, std::move(message)}); -} - -void BKE_nodetree_attribute_hint_add(bNodeTree &ntree, - const NodeTreeEvaluationContext &context, - const bNode &node, - const StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type) -{ - NodeTreeUIStorage &ui_storage = ui_storage_ensure(ntree); - std::lock_guard lock{ui_storage.mutex}; - - NodeUIStorage &node_ui_storage = node_ui_storage_ensure(ui_storage, context, node); - node_ui_storage.attribute_hints.add_as( - AvailableAttributeInfo{attribute_name, domain, data_type}); -} diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index e0b23958ec9..912b5e0a0dd 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -234,7 +234,7 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in BKE_pose_rebuild(bmain, ob_dst, ob_dst->data, do_pose_id_user); } } - BKE_defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase); + BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps); BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true); @@ -285,7 +285,6 @@ static void object_free_data(ID *id) MEM_SAFE_FREE(ob->iuser); MEM_SAFE_FREE(ob->runtime.bb); - BLI_freelistN(&ob->defbase); BLI_freelistN(&ob->fmaps); if (ob->pose) { BKE_pose_free_ex(ob->pose, false); @@ -510,13 +509,6 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) } } -static void write_defgroups(BlendWriter *writer, ListBase *defbase) -{ - LISTBASE_FOREACH (bDeformGroup *, defgroup, defbase) { - BLO_write_struct(writer, bDeformGroup, defgroup); - } -} - static void write_fmaps(BlendWriter *writer, ListBase *fbase) { LISTBASE_FOREACH (bFaceMap *, fmap, fbase) { @@ -561,7 +553,6 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre } BKE_pose_blend_write(writer, ob->pose, arm); - write_defgroups(writer, &ob->defbase); write_fmaps(writer, &ob->fmaps); BKE_constraint_blend_write(writer, &ob->constraints); animviz_motionpath_blend_write(writer, ob->mpath); @@ -644,7 +635,9 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id) animviz_motionpath_blend_read_data(reader, ob->mpath); } + /* Only for versioning, vertex group names are now stored on object data. */ BLO_read_list(reader, &ob->defbase); + BLO_read_list(reader, &ob->fmaps); /* XXX deprecated - old animation system <<< */ direct_link_nlastrips(reader, &ob->nlastrips); @@ -1760,10 +1753,6 @@ void BKE_object_free_derived_caches(Object *ob) BKE_geometry_set_free(ob->runtime.geometry_set_eval); ob->runtime.geometry_set_eval = NULL; } - if (ob->runtime.geometry_set_previews != NULL) { - BLI_ghash_free(ob->runtime.geometry_set_previews, NULL, (GHashValFreeFP)BKE_geometry_set_free); - ob->runtime.geometry_set_previews = NULL; - } } void BKE_object_free_caches(Object *object) @@ -1814,24 +1803,6 @@ void BKE_object_free_caches(Object *object) } } -/* Can be called from multiple threads. */ -void BKE_object_preview_geometry_set_add(Object *ob, - const uint64_t key, - struct GeometrySet *geometry_set) -{ - static ThreadMutex mutex = BLI_MUTEX_INITIALIZER; - BLI_mutex_lock(&mutex); - if (ob->runtime.geometry_set_previews == NULL) { - ob->runtime.geometry_set_previews = BLI_ghash_int_new(__func__); - } - BLI_ghash_reinsert(ob->runtime.geometry_set_previews, - POINTER_FROM_UINT(key), - geometry_set, - NULL, - (GHashValFreeFP)BKE_geometry_set_free); - BLI_mutex_unlock(&mutex); -} - /** * Actual check for internal data, not context or flags. */ @@ -2835,7 +2806,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) /* add new animdata block */ if (!ob->adt) { - ob->adt = BKE_animdata_add_id(&ob->id); + ob->adt = BKE_animdata_ensure_id(&ob->id); } /* make a copy of all the drivers (for now), then correct any links that need fixing */ @@ -2923,9 +2894,6 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob) ob->data = target->data; id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */ - /* copy vertex groups */ - BKE_defgroup_copy_list(&ob->defbase, &target->defbase); - /* copy material and index information */ ob->actcol = ob->totcol = 0; if (ob->mat) { @@ -4165,6 +4133,30 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph, return ok; } +struct GPencilStrokePointIterData { + const float (*obmat)[4]; + + void (*point_func_cb)(const float co[3], void *user_data); + void *user_data; +}; + +static void foreach_display_point_gpencil_stroke_fn(bGPDlayer *UNUSED(layer), + bGPDframe *UNUSED(frame), + bGPDstroke *stroke, + void *thunk) +{ + struct GPencilStrokePointIterData *iter_data = thunk; + { + bGPDspoint *pt; + int i; + for (i = 0, pt = stroke->points; i < stroke->totpoints; i++, pt++) { + float co[3]; + mul_v3_m4v3(co, iter_data->obmat, &pt->x); + iter_data->point_func_cb(co, iter_data->user_data); + } + } +} + void BKE_object_foreach_display_point(Object *ob, const float obmat[4][4], void (*func_cb)(const float[3], void *), @@ -4182,6 +4174,13 @@ void BKE_object_foreach_display_point(Object *ob, func_cb(co, user_data); } } + else if (ob->type == OB_GPENCIL) { + struct GPencilStrokePointIterData iter_data = { + .obmat = obmat, .point_func_cb = func_cb, .user_data = user_data}; + + BKE_gpencil_visible_stroke_iter( + ob->data, NULL, foreach_display_point_gpencil_stroke_fn, &iter_data); + } else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) { DispList *dl; diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index 1e7624d0d7d..c69326a23c6 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -33,6 +33,7 @@ #include "DNA_armature_types.h" #include "DNA_cloth_types.h" #include "DNA_curve_types.h" +#include "DNA_gpencil_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -123,8 +124,7 @@ bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name) } defgroup = BKE_object_defgroup_new(ob, name); - - ob->actdef = BLI_listbase_count(&ob->defbase); + BKE_object_defgroup_active_index_set(ob, BKE_object_defgroup_count(ob)); return defgroup; } @@ -171,7 +171,8 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id) bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection) { MDeformVert *dv; - const int def_nr = BLI_findindex(&ob->defbase, dg); + const ListBase *defbase = BKE_object_defgroup_list(ob); + const int def_nr = BLI_findindex(defbase, dg); bool changed = false; if (ob->type == OB_MESH) { @@ -249,7 +250,9 @@ bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection) bDeformGroup *dg; bool changed = false; - for (dg = ob->defbase.first; dg; dg = dg->next) { + const ListBase *defbase = BKE_object_defgroup_list(ob); + + for (dg = defbase->first; dg; dg = dg->next) { if (BKE_object_defgroup_clear(ob, dg, use_selection)) { changed = true; } @@ -265,7 +268,7 @@ bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection) static void object_defgroup_remove_update_users(Object *ob, const int idx) { - int i, defbase_tot = BLI_listbase_count(&ob->defbase) + 1; + int i, defbase_tot = BKE_object_defgroup_count(ob) + 1; int *map = MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del"); map[idx] = map[0] = 0; @@ -285,15 +288,18 @@ static void object_defgroup_remove_common(Object *ob, bDeformGroup *dg, const in object_defgroup_remove_update_users(ob, def_nr + 1); /* Remove the group */ - BLI_freelinkN(&ob->defbase, dg); + ListBase *defbase = BKE_object_defgroup_list_mutable(ob); + + BLI_freelinkN(defbase, dg); /* Update the active deform index if necessary */ - if (ob->actdef > def_nr) { - ob->actdef--; + const int active_index = BKE_object_defgroup_active_index_get(ob); + if (active_index > def_nr) { + BKE_object_defgroup_active_index_set(ob, active_index - 1); } /* remove all dverts */ - if (BLI_listbase_is_empty(&ob->defbase)) { + if (BLI_listbase_is_empty(defbase)) { if (ob->type == OB_MESH) { Mesh *me = ob->data; CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); @@ -307,8 +313,9 @@ static void object_defgroup_remove_common(Object *ob, bDeformGroup *dg, const in } } } - else if (ob->actdef < 1) { /* Keep a valid active index if we still have some vgroups. */ - ob->actdef = 1; + else if (BKE_object_defgroup_active_index_get(ob) < 1) { + /* Keep a valid active index if we still have some vgroups. */ + BKE_object_defgroup_active_index_set(ob, 1); } } @@ -316,7 +323,9 @@ static void object_defgroup_remove_object_mode(Object *ob, bDeformGroup *dg) { MDeformVert *dvert_array = NULL; int dvert_tot = 0; - const int def_nr = BLI_findindex(&ob->defbase, dg); + const ListBase *defbase = BKE_object_defgroup_list(ob); + + const int def_nr = BLI_findindex(defbase, dg); BLI_assert(def_nr != -1); @@ -347,7 +356,8 @@ static void object_defgroup_remove_object_mode(Object *ob, bDeformGroup *dg) static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg) { int i; - const int def_nr = BLI_findindex(&ob->defbase, dg); + const ListBase *defbase = BKE_object_defgroup_list(ob); + const int def_nr = BLI_findindex(defbase, dg); BLI_assert(def_nr != -1); @@ -425,7 +435,9 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup) */ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked) { - bDeformGroup *dg = (bDeformGroup *)ob->defbase.first; + ListBase *defbase = BKE_object_defgroup_list_mutable(ob); + + bDeformGroup *dg = (bDeformGroup *)defbase->first; const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob); if (dg) { @@ -444,7 +456,7 @@ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked) dg = next_dg; } } - else { /* ob->defbase is empty... */ + else { /* defbase is empty... */ /* remove all dverts */ if (ob->type == OB_MESH) { Mesh *me = ob->data; @@ -459,7 +471,7 @@ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked) } } /* Fix counters/indices */ - ob->actdef = 0; + BKE_object_defgroup_active_index_set(ob, 0); } } @@ -478,20 +490,23 @@ void BKE_object_defgroup_remove_all(struct Object *ob) */ int *BKE_object_defgroup_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len) { + const ListBase *src_defbase = BKE_object_defgroup_list(ob_src); + const ListBase *dst_defbase = BKE_object_defgroup_list(ob_dst); + /* Build src to merged mapping of vgroup indices. */ - if (BLI_listbase_is_empty(&ob_src->defbase) || BLI_listbase_is_empty(&ob_dst->defbase)) { + if (BLI_listbase_is_empty(src_defbase) || BLI_listbase_is_empty(dst_defbase)) { *r_map_len = 0; return NULL; } bDeformGroup *dg_src; - *r_map_len = BLI_listbase_count(&ob_src->defbase); + *r_map_len = BLI_listbase_count(src_defbase); int *vgroup_index_map = MEM_malloc_arrayN( *r_map_len, sizeof(*vgroup_index_map), "defgroup index map create"); bool is_vgroup_remap_needed = false; int i; - for (dg_src = ob_src->defbase.first, i = 0; dg_src; dg_src = dg_src->next, i++) { + for (dg_src = src_defbase->first, i = 0; dg_src; dg_src = dg_src->next, i++) { vgroup_index_map[i] = BKE_object_defgroup_name_index(ob_dst, dg_src->name); is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[i] != i); } @@ -576,17 +591,17 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t /** * gets the status of "flag" for each bDeformGroup - * in ob->defbase and returns an array containing them + * in the object data's vertex group list and returns an array containing them */ bool *BKE_object_defgroup_lock_flags_get(Object *ob, const int defbase_tot) { bool is_locked = false; int i; - // int defbase_tot = BLI_listbase_count(&ob->defbase); + ListBase *defbase = BKE_object_defgroup_list_mutable(ob); bool *lock_flags = MEM_mallocN(defbase_tot * sizeof(bool), "defflags"); bDeformGroup *defgroup; - for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; + for (i = 0, defgroup = defbase->first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) { lock_flags[i] = ((defgroup->flag & DG_LOCK_WEIGHT) != 0); is_locked |= lock_flags[i]; @@ -606,17 +621,17 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot) bool *defgroup_validmap; GHash *gh; int i, step1 = 1; - // int defbase_tot = BLI_listbase_count(&ob->defbase); + const ListBase *defbase = BKE_object_defgroup_list(ob); VirtualModifierData virtualModifierData; - if (BLI_listbase_is_empty(&ob->defbase)) { + if (BLI_listbase_is_empty(defbase)) { return NULL; } gh = BLI_ghash_str_new_ex(__func__, defbase_tot); /* add all names to a hash table */ - for (dg = ob->defbase.first; dg; dg = dg->next) { + for (dg = defbase->first; dg; dg = dg->next) { BLI_ghash_insert(gh, dg->name, NULL); } @@ -655,7 +670,7 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot) defgroup_validmap = MEM_mallocN(sizeof(*defgroup_validmap) * defbase_tot, "wpaint valid map"); /* add all names to a hash table */ - for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) { + for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) { defgroup_validmap[i] = (BLI_ghash_lookup(gh, dg->name) != NULL); } @@ -676,9 +691,11 @@ bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_fl Object *armob = BKE_object_pose_armature_get(ob); (*r_dg_flags_sel_tot) = 0; + const ListBase *defbase = BKE_object_defgroup_list(ob); + if (armob) { bPose *pose = armob->pose; - for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; + for (i = 0, defgroup = defbase->first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) { bPoseChannel *pchan = BKE_pose_channel_find_name(pose, defgroup->name); if (pchan && (pchan->bone->flag & BONE_SELECTED)) { @@ -774,11 +791,13 @@ void BKE_object_defgroup_mirror_selection(struct Object *ob, bool *dg_flags_sel, int *r_dg_flags_sel_tot) { + const ListBase *defbase = BKE_object_defgroup_list(ob); + bDeformGroup *defgroup; unsigned int i; int i_mirr; - for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; + for (i = 0, defgroup = defbase->first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) { if (dg_selection[i]) { char name_flip[MAXBONENAME]; @@ -804,11 +823,12 @@ bool *BKE_object_defgroup_subset_from_select_type(Object *ob, int *r_subset_count) { bool *defgroup_validmap = NULL; - *r_defgroup_tot = BLI_listbase_count(&ob->defbase); + + *r_defgroup_tot = BKE_object_defgroup_count(ob); switch (subset_type) { case WT_VGROUP_ACTIVE: { - const int def_nr_active = ob->actdef - 1; + const int def_nr_active = BKE_object_defgroup_active_index_get(ob) - 1; defgroup_validmap = MEM_mallocN(*r_defgroup_tot * sizeof(*defgroup_validmap), __func__); memset(defgroup_validmap, false, *r_defgroup_tot * sizeof(*defgroup_validmap)); if ((def_nr_active >= 0) && (def_nr_active < *r_defgroup_tot)) { diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index ab247ef5507..7cdea14e9bd 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -123,7 +123,7 @@ void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob) void BKE_object_eval_constraints(Depsgraph *depsgraph, Scene *scene, Object *ob) { bConstraintOb *cob; - float ctime = BKE_scene_frame_get(scene); + float ctime = BKE_scene_ctime_get(scene); DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); @@ -388,12 +388,31 @@ void BKE_object_batch_cache_dirty_tag(Object *ob) BKE_object_data_batch_cache_dirty_tag(ob->data); } +void BKE_object_data_eval_batch_cache_dirty_tag(Depsgraph *depsgraph, ID *object_data) +{ + DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data); + BKE_object_data_batch_cache_dirty_tag(object_data); +} + +void BKE_object_data_eval_batch_cache_deform_tag(Depsgraph *depsgraph, ID *object_data) +{ + DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data); + switch (GS(object_data->name)) { + case ID_ME: + BKE_mesh_batch_cache_dirty_tag((Mesh *)object_data, BKE_MESH_BATCH_DIRTY_DEFORM); + break; + default: + /* Only mesh is currently supported. Fallback to dirty all for other datablocks types. */ + BKE_object_data_batch_cache_dirty_tag(object_data); + break; + } +} + void BKE_object_eval_uber_data(Depsgraph *depsgraph, Scene *scene, Object *ob) { DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); BLI_assert(ob->type != OB_ARMATURE); BKE_object_handle_data_update(depsgraph, scene, ob); - BKE_object_batch_cache_dirty_tag(ob); } void BKE_object_eval_ptcache_reset(Depsgraph *depsgraph, Scene *scene, Object *object) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 7504fbeed19..db1fbb56125 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3961,7 +3961,7 @@ static ModifierData *object_add_or_copy_particle_system( psys->totpart = 0; psys->flag = PSYS_CURRENT; if (scene != NULL) { - psys->cfra = BKE_scene_frame_to_ctime(scene, CFRA + 1); + psys->cfra = BKE_scene_frame_to_ctime(scene, scene->r.cfra + 1); } DEG_relations_tag_update(bmain); diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 90018e64f78..9ed5b0230e6 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -2807,8 +2807,8 @@ void BKE_ptcache_id_time( cache = pid->cache; if (timescale) { - time = BKE_scene_frame_get(scene); - nexttime = BKE_scene_frame_to_ctime(scene, CFRA + 1.0f); + time = BKE_scene_ctime_get(scene); + nexttime = BKE_scene_frame_to_ctime(scene, scene->r.cfra + 1); *timescale = MAX2(nexttime - time, 0.0f); } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index f8f4d52fcf2..cc5a8536a5a 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -2299,10 +2299,7 @@ Object *BKE_scene_camera_switch_find(Scene *scene) return NULL; } - const int cfra = ((scene->r.images == scene->r.framapto) ? - scene->r.cfra : - (int)(scene->r.cfra * - ((float)scene->r.framapto / (float)scene->r.images))); + const int ctime = (int)BKE_scene_ctime_get(scene); int frame = -(MAXFRAME + 1); int min_frame = MAXFRAME + 1; Object *camera = NULL; @@ -2310,11 +2307,11 @@ Object *BKE_scene_camera_switch_find(Scene *scene) LISTBASE_FOREACH (TimeMarker *, m, &scene->markers) { if (m->camera && (m->camera->restrictflag & OB_RESTRICT_RENDER) == 0) { - if ((m->frame <= cfra) && (m->frame > frame)) { + if ((m->frame <= ctime) && (m->frame > frame)) { camera = m->camera; frame = m->frame; - if (frame == cfra) { + if (frame == ctime) { break; } } @@ -2396,13 +2393,13 @@ const char *BKE_scene_find_last_marker_name(const Scene *scene, int frame) return best_marker ? best_marker->name : NULL; } -int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, int cfra) +int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, int frame) { const int fps = round_db_to_int(FPS * interval_in_seconds); - const int second_prev = cfra - mod_i(cfra, fps); + const int second_prev = frame - mod_i(frame, fps); const int second_next = second_prev + fps; - const int delta_prev = cfra - second_prev; - const int delta_next = second_next - cfra; + const int delta_prev = frame - second_prev; + const int delta_next = second_next - frame; return (delta_prev < delta_next) ? second_prev : second_next; } @@ -2444,16 +2441,17 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce) return true; } -/** - * This function is needed to cope with fractional frames, needed for motion blur & physics. - */ -float BKE_scene_frame_get(const Scene *scene) +/* Return fractional frame number taking into account subframes and time + * remapping. This the time value used by animation, modifiers and physics + * evaluation. */ +float BKE_scene_ctime_get(const Scene *scene) { return BKE_scene_frame_to_ctime(scene, scene->r.cfra); } -/* This function is used to obtain arbitrary fractional frames */ -float BKE_scene_frame_to_ctime(const Scene *scene, const float frame) +/* Convert integer frame number to fractional frame number taking into account + * subframes and time remapping. */ +float BKE_scene_frame_to_ctime(const Scene *scene, const int frame) { float ctime = frame; ctime += scene->r.subframe; @@ -2461,13 +2459,18 @@ float BKE_scene_frame_to_ctime(const Scene *scene, const float frame) return ctime; } -/** - * Sets the frame int/float components. - */ -void BKE_scene_frame_set(struct Scene *scene, double cfra) + +/* Get current fractional frame based on frame and subframe. */ +float BKE_scene_frame_get(const Scene *scene) +{ + return scene->r.cfra + scene->r.subframe; +} + +/* Set current frame and subframe based on a fractional frame. */ +void BKE_scene_frame_set(Scene *scene, float frame) { double intpart; - scene->r.subframe = modf(cfra, &intpart); + scene->r.subframe = modf((double)frame, &intpart); scene->r.cfra = (int)intpart; } @@ -2736,8 +2739,8 @@ void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool cle * edits from callback are properly taken into account. Doing a time update on those would * lose any possible unkeyed changes made by the handler. */ if (pass == 0) { - const float ctime = BKE_scene_frame_get(scene); - DEG_evaluate_on_framechange(depsgraph, ctime); + const float frame = BKE_scene_frame_get(scene); + DEG_evaluate_on_framechange(depsgraph, frame); } else { DEG_evaluate_on_refresh(depsgraph); diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index a2809543b95..73658c3184e 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -1734,6 +1734,12 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) sfile->runtime = NULL; BLO_read_data_address(reader, &sfile->params); BLO_read_data_address(reader, &sfile->asset_params); + if (sfile->params) { + sfile->params->rename_id = NULL; + } + if (sfile->asset_params) { + sfile->asset_params->base_params.rename_id = NULL; + } } else if (sl->spacetype == SPACE_ACTION) { SpaceAction *saction = (SpaceAction *)sl; diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index adcc8551ba8..e4e2ed94b41 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2704,8 +2704,8 @@ static void mesh_to_softbody(Object *ob) bp = sb->bpoint; defgroup_index = me->dvert ? (sb->vertgroup - 1) : -1; - defgroup_index_mass = me->dvert ? BKE_object_defgroup_name_index(ob, sb->namedVG_Mass) : -1; - defgroup_index_spring = me->dvert ? BKE_object_defgroup_name_index(ob, sb->namedVG_Spring_K) : + defgroup_index_mass = me->dvert ? BKE_id_defgroup_name_index(&me->id, sb->namedVG_Mass) : -1; + defgroup_index_spring = me->dvert ? BKE_id_defgroup_name_index(&me->id, sb->namedVG_Spring_K) : -1; for (a = 0; a < me->totvert; a++, bp++) { @@ -2934,8 +2934,8 @@ static void lattice_to_softbody(Object *ob) bp = sb->bpoint; defgroup_index = lt->dvert ? (sb->vertgroup - 1) : -1; - defgroup_index_mass = lt->dvert ? BKE_object_defgroup_name_index(ob, sb->namedVG_Mass) : -1; - defgroup_index_spring = lt->dvert ? BKE_object_defgroup_name_index(ob, sb->namedVG_Spring_K) : + defgroup_index_mass = lt->dvert ? BKE_id_defgroup_name_index(<->id, sb->namedVG_Mass) : -1; + defgroup_index_spring = lt->dvert ? BKE_id_defgroup_name_index(<->id, sb->namedVG_Spring_K) : -1; /* same code used as for mesh vertices */ @@ -3086,7 +3086,7 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, if (sb->solverflags & SBSO_ESTIMATEIPO) { SB_estimate_transform(ob, sb->lcom, sb->lrot, sb->lscale); } - /* inverse matrix is not uptodate... */ + /* Inverse matrix is not up to date. */ invert_m4_m4(ob->imat, ob->obmat); for (a = 0; a < numVerts; a++, bp++) { diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc index 02d26ac715b..b6764f65631 100644 --- a/source/blender/blenkernel/intern/spline_bezier.cc +++ b/source/blender/blenkernel/intern/spline_bezier.cc @@ -333,6 +333,46 @@ void BezierSpline::correct_end_tangents() const } } +/** + * De Casteljau Bezier subdivision. + * \param index: The index of the segment's start control point. + * \param next_index: The index of the control point at the end of the segment. Could be 0, + * if the spline is cyclic. + * \param parameter: The factor along the segment, between 0 and 1. Note that this is used + * directly by the calculation, it doesn't correspond to a portion of the evaluated length. + * + * <pre> + * handle_prev handle_next + * x----------------x + * / \ + * / x---O---x \ + * / result \ + * / \ + * O O + * point_prev point_next + * </pre> + */ +BezierSpline::InsertResult BezierSpline::calculate_segment_insertion(const int index, + const int next_index, + const float parameter) +{ + BLI_assert(parameter <= 1.0f && parameter >= 0.0f); + BLI_assert(next_index == 0 || next_index == index + 1); + const float3 &point_prev = positions_[index]; + const float3 &handle_prev = handle_positions_right_[index]; + const float3 &handle_next = handle_positions_left_[next_index]; + const float3 &point_next = positions_[next_index]; + const float3 center_point = float3::interpolate(handle_prev, handle_next, parameter); + + BezierSpline::InsertResult result; + result.handle_prev = float3::interpolate(point_prev, handle_prev, parameter); + result.handle_next = float3::interpolate(handle_next, point_next, parameter); + result.left_handle = float3::interpolate(result.handle_prev, center_point, parameter); + result.right_handle = float3::interpolate(center_point, result.handle_next, parameter); + result.position = float3::interpolate(result.left_handle, result.right_handle, parameter); + return result; +} + static void bezier_forward_difference_3d(const float3 &point_0, const float3 &point_1, const float3 &point_2, diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index 4cc2d101b02..dc5162f201e 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -1352,7 +1352,7 @@ static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl) ITER_PIXELS_END; } -void BKE_studiolight_default(SolidLight lights[4], float light_ambient[4]) +void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3]) { copy_v3_fl3(light_ambient, 0.0, 0.0, 0.0); diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c index fe2aa701c63..03bd9323f39 100644 --- a/source/blender/blenkernel/intern/undo_system.c +++ b/source/blender/blenkernel/intern/undo_system.c @@ -722,6 +722,24 @@ eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack, } /** + * When reading undo steps for undo/redo, + * some extra checks are needed when so the correct undo step is decoded. + */ +static UndoStep *undosys_step_iter_first(UndoStep *us_reference, const eUndoStepDir undo_dir) +{ + if (us_reference->type->flags & UNDOTYPE_FLAG_DECODE_ACTIVE_STEP) { + /* Reading this step means an undo action reads undo twice. + * This should be avoided where possible, however some undo systems require it. + * + * Redo skips the current state as this represents the currently loaded state. */ + return (undo_dir == -1) ? us_reference : us_reference->next; + } + + /* Typical case, skip reading the current undo step. */ + return (undo_dir == -1) ? us_reference->prev : us_reference->next; +} + +/** * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one. * * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the @@ -786,15 +804,10 @@ bool BKE_undosys_step_load_data_ex(UndoStack *ustack, us_target->type->name, undo_dir); - /* Undo/Redo steps until we reach given target step (or beyond if it has to be skipped), from - * given reference step. - * - * NOTE: Unlike with redo case, where we can expect current active step to fully reflect current - * data status, in undo case we also do reload the active step. - * FIXME: this feels weak, and should probably not be actually needed? Or should also be done in - * redo case? */ + /* Undo/Redo steps until we reach given target step (or beyond if it has to be skipped), + * from given reference step. */ bool is_processing_extra_skipped_steps = false; - for (UndoStep *us_iter = (undo_dir == -1) ? us_reference : us_reference->next; us_iter != NULL; + for (UndoStep *us_iter = undosys_step_iter_first(us_reference, undo_dir); us_iter != NULL; us_iter = (undo_dir == -1) ? us_iter->prev : us_iter->next) { BLI_assert(us_iter != NULL); diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h index 2847bc960ad..52d41173a0e 100644 --- a/source/blender/blenlib/BLI_array_utils.h +++ b/source/blender/blenlib/BLI_array_utils.h @@ -28,52 +28,53 @@ extern "C" { #endif -void _bli_array_reverse(void *arr, unsigned int arr_len, size_t arr_stride); +void _bli_array_reverse(void *arr, uint arr_len, size_t arr_stride); #define BLI_array_reverse(arr, arr_len) _bli_array_reverse(arr, arr_len, sizeof(*(arr))) -void _bli_array_wrap(void *arr, unsigned int arr_len, size_t arr_stride, int dir); +void _bli_array_wrap(void *arr, uint arr_len, size_t arr_stride, int dir); #define BLI_array_wrap(arr, arr_len, dir) _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir) -void _bli_array_permute(void *arr, - const unsigned int arr_len, - const size_t arr_stride, - const unsigned int *order, - void *arr_temp); +void _bli_array_permute( + void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp); #define BLI_array_permute(arr, arr_len, order) \ _bli_array_permute(arr, arr_len, sizeof(*(arr)), order, NULL) #define BLI_array_permute_ex(arr, arr_len, order, arr_temp) \ _bli_array_permute(arr, arr_len, sizeof(*(arr)), order, arr_temp) -int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p); +uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride); +#define BLI_array_deduplicate_ordered(arr, arr_len) \ + _bli_array_deduplicate_ordered(arr, arr_len, sizeof(*(arr))) + +int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p); #define BLI_array_findindex(arr, arr_len, p) _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p) -int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p); +int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p); #define BLI_array_rfindindex(arr, arr_len, p) \ _bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p) void _bli_array_binary_and( - void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride); + void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride); #define BLI_array_binary_and(arr, arr_a, arr_b, arr_len) \ (CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_a)), \ CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \ _bli_array_binary_and(arr, arr_a, arr_b, arr_len, sizeof(*(arr)))) void _bli_array_binary_or( - void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride); + void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride); #define BLI_array_binary_or(arr, arr_a, arr_b, arr_len) \ (CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_a)), \ CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \ _bli_array_binary_or(arr, arr_a, arr_b, arr_len, sizeof(*(arr)))) bool _bli_array_iter_span(const void *arr, - unsigned int arr_len, + uint arr_len, size_t arr_stride, bool use_wrap, bool use_delimit_bounds, bool (*test_fn)(const void *arr_item, void *user_data), void *user_data, - unsigned int span_step[2], - unsigned int *r_span_len); + uint span_step[2], + uint *r_span_len); #define BLI_array_iter_span( \ arr, arr_len, use_wrap, use_delimit_bounds, test_fn, user_data, span_step, r_span_len) \ _bli_array_iter_span(arr, \ @@ -86,7 +87,7 @@ bool _bli_array_iter_span(const void *arr, span_step, \ r_span_len) -bool _bli_array_is_zeroed(const void *arr, unsigned int arr_len, size_t arr_stride); +bool _bli_array_is_zeroed(const void *arr, uint arr_len, size_t arr_stride); #define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr))) bool _bli_array_iter_spiral_square(const void *arr_v, diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h index 685f526b4ad..7f7bec425ce 100644 --- a/source/blender/blenlib/BLI_assert.h +++ b/source/blender/blenlib/BLI_assert.h @@ -31,6 +31,7 @@ extern "C" { /* Utility functions. */ void _BLI_assert_print_pos(const char *file, const int line, const char *function, const char *id); +void _BLI_assert_print_extra(const char *str); void _BLI_assert_print_backtrace(void); void _BLI_assert_abort(void); void _BLI_assert_unreachable_print(const char *file, const int line, const char *function); @@ -61,8 +62,17 @@ void _BLI_assert_unreachable_print(const char *file, const int line, const char _BLI_ASSERT_ABORT(), \ NULL)) : \ NULL) +/** A version of #BLI_assert() to pass an additional message to be printed on failure. */ +# define BLI_assert_msg(a, msg) \ + (void)((!(a)) ? ((_BLI_assert_print_backtrace(), \ + _BLI_ASSERT_PRINT_POS(a), \ + _BLI_assert_print_extra(msg), \ + _BLI_ASSERT_ABORT(), \ + NULL)) : \ + NULL) #else # define BLI_assert(a) ((void)0) +# define BLI_assert_msg(a, msg) ((void)0) #endif #if defined(__cplusplus) diff --git a/source/blender/blenlib/BLI_enumerable_thread_specific.hh b/source/blender/blenlib/BLI_enumerable_thread_specific.hh index 25fd02b41fb..3051d980d45 100644 --- a/source/blender/blenlib/BLI_enumerable_thread_specific.hh +++ b/source/blender/blenlib/BLI_enumerable_thread_specific.hh @@ -77,17 +77,18 @@ template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable { * their addresses do not change when the map grows. */ Map<int, std::reference_wrapper<T>> values_; Vector<std::unique_ptr<T>> owned_values_; - std::function<T()> initializer_; + std::function<void(void *)> initializer_; public: using iterator = typename Map<int, std::reference_wrapper<T>>::MutableValueIterator; - EnumerableThreadSpecific() : initializer_([]() { return T(); }) + EnumerableThreadSpecific() : initializer_([](void *buffer) { new (buffer) T(); }) { } template<typename F> - EnumerableThreadSpecific(F initializer) : initializer_(std::move(initializer)) + EnumerableThreadSpecific(F initializer) + : initializer_([=](void *buffer) { new (buffer) T(initializer()); }) { } @@ -96,11 +97,10 @@ template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable { const int thread_id = enumerable_thread_specific_utils::thread_id; std::lock_guard lock{mutex_}; return values_.lookup_or_add_cb(thread_id, [&]() { - /* `std::make_unique` does not work here if T is non-copyable and non-movable. */ - std::unique_ptr<T> value{new T(initializer_())}; - std::reference_wrapper<T> ref = *value; - owned_values_.append(std::move(value)); - return ref; + T *value = (T *)::operator new(sizeof(T)); + initializer_(value); + owned_values_.append(std::unique_ptr<T>{value}); + return std::reference_wrapper<T>{*value}; }); } diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 677df9db026..ea5572f1c8a 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -188,6 +188,7 @@ set(SRC BLI_dynstr.h BLI_easing.h BLI_edgehash.h + BLI_endian_defines.h BLI_endian_switch.h BLI_endian_switch_inline.h BLI_enumerable_thread_specific.hh diff --git a/source/blender/blenlib/intern/BLI_assert.c b/source/blender/blenlib/intern/BLI_assert.c index 887f583242f..cebc6f8957f 100644 --- a/source/blender/blenlib/intern/BLI_assert.c +++ b/source/blender/blenlib/intern/BLI_assert.c @@ -31,6 +31,11 @@ void _BLI_assert_print_pos(const char *file, const int line, const char *functio fprintf(stderr, "BLI_assert failed: %s:%d, %s(), at \'%s\'\n", file, line, function, id); } +void _BLI_assert_print_extra(const char *str) +{ + fprintf(stderr, " %s\n", str); +} + void _BLI_assert_unreachable_print(const char *file, const int line, const char *function) { fprintf(stderr, "Code marked as unreachable has been executed. Please report this as a bug.\n"); diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c index 25261e82cc9..9a12a7442b7 100644 --- a/source/blender/blenlib/intern/array_utils.c +++ b/source/blender/blenlib/intern/array_utils.c @@ -40,11 +40,11 @@ * * Access via #BLI_array_reverse */ -void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride) +void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride) { - const unsigned int arr_stride_uint = (unsigned int)arr_stride; - const unsigned int arr_half_stride = (arr_len / 2) * arr_stride_uint; - unsigned int i, i_end; + const uint arr_stride_uint = (uint)arr_stride; + const uint arr_half_stride = (arr_len / 2) * arr_stride_uint; + uint i, i_end; char *arr = arr_v; char *buf = BLI_array_alloca(buf, arr_stride); @@ -62,7 +62,7 @@ void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride) * * Access via #BLI_array_wrap */ -void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int dir) +void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir) { char *arr = arr_v; char *buf = BLI_array_alloca(buf, arr_stride); @@ -88,16 +88,13 @@ void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int d * * Access via #BLI_array_wrap */ -void _bli_array_permute(void *arr, - const unsigned int arr_len, - const size_t arr_stride, - const unsigned int *order, - void *arr_temp) +void _bli_array_permute( + void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp) { const size_t len = arr_len * arr_stride; - const unsigned int arr_stride_uint = (unsigned int)arr_stride; + const uint arr_stride_uint = (uint)arr_stride; void *arr_orig; - unsigned int i; + uint i; if (arr_temp == NULL) { arr_orig = MEM_mallocN(len, __func__); @@ -121,16 +118,45 @@ void _bli_array_permute(void *arr, } /** + * In-place array de-duplication of an ordered array. + * + * \return The new length of the array. + * + * Access via #BLI_array_deduplicate_ordered + */ +uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride) +{ + if (UNLIKELY(arr_len <= 1)) { + return arr_len; + } + + const uint arr_stride_uint = (uint)arr_stride; + uint j = 0; + for (uint i = 0; i < arr_len; i++) { + if ((i == j) || (memcmp(POINTER_OFFSET(arr, arr_stride_uint * i), + POINTER_OFFSET(arr, arr_stride_uint * j), + arr_stride) == 0)) { + continue; + } + j += 1; + memcpy(POINTER_OFFSET(arr, arr_stride_uint * j), + POINTER_OFFSET(arr, arr_stride_uint * i), + arr_stride); + } + return j + 1; +} + +/** * Find the first index of an item in an array. * * Access via #BLI_array_findindex * * \note Not efficient, use for error checks/asserts. */ -int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) +int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p) { const char *arr_step = (const char *)arr; - for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) { + for (uint i = 0; i < arr_len; i++, arr_step += arr_stride) { if (memcmp(arr_step, p, arr_stride) == 0) { return (int)i; } @@ -141,10 +167,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid /** * A version of #BLI_array_findindex that searches from the end of the list. */ -int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) +int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p) { const char *arr_step = (const char *)arr + (arr_stride * arr_len); - for (unsigned int i = arr_len; i-- != 0;) { + for (uint i = arr_len; i-- != 0;) { arr_step -= arr_stride; if (memcmp(arr_step, p, arr_stride) == 0) { return (int)i; @@ -154,7 +180,7 @@ int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stri } void _bli_array_binary_and( - void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride) + void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride) { char *dst = arr; const char *src_a = arr_a; @@ -167,7 +193,7 @@ void _bli_array_binary_and( } void _bli_array_binary_or( - void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride) + void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride) { char *dst = arr; const char *src_a = arr_a; @@ -196,14 +222,14 @@ void _bli_array_binary_or( * where calculating the length isn't a simple subtraction. */ bool _bli_array_iter_span(const void *arr, - unsigned int arr_len, + uint arr_len, size_t arr_stride, bool use_wrap, bool use_delimit_bounds, bool (*test_fn)(const void *arr_item, void *user_data), void *user_data, - unsigned int span_step[2], - unsigned int *r_span_len) + uint span_step[2], + uint *r_span_len) { if (arr_len == 0) { return false; @@ -212,11 +238,11 @@ bool _bli_array_iter_span(const void *arr, return false; } - const unsigned int arr_stride_uint = (unsigned int)arr_stride; + const uint arr_stride_uint = (uint)arr_stride; const void *item_prev; bool test_prev; - unsigned int i_curr; + uint i_curr; if ((span_step[0] == arr_len) && (span_step[1] == arr_len)) { if (use_wrap) { @@ -249,11 +275,11 @@ bool _bli_array_iter_span(const void *arr, while (i_curr < arr_len) { bool test_curr = test_fn(item_curr, user_data); if ((test_prev == false) && (test_curr == true)) { - unsigned int span_len; - unsigned int i_step_prev = i_curr; + uint span_len; + uint i_step_prev = i_curr; if (use_wrap) { - unsigned int i_step = i_curr + 1; + uint i_step = i_curr + 1; if (UNLIKELY(i_step == arr_len)) { i_step = 0; } @@ -273,7 +299,7 @@ bool _bli_array_iter_span(const void *arr, } } else { - unsigned int i_step = i_curr + 1; + uint i_step = i_curr + 1; while ((i_step != arr_len) && test_fn(POINTER_OFFSET(arr, i_step * arr_stride_uint), user_data)) { i_step_prev = i_step; @@ -307,7 +333,7 @@ bool _bli_array_iter_span(const void *arr, /** * Simple utility to check memory is zeroed. */ -bool _bli_array_is_zeroed(const void *arr_v, unsigned int arr_len, size_t arr_stride) +bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride) { const char *arr_step = (const char *)arr_v; size_t i = arr_stride * arr_len; diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index d86a88b977f..34baac6f2a4 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -373,7 +373,7 @@ void mat3_normalized_to_quat(float q[4], const float mat[3][3]) q[2] = (mat[2][1] + mat[1][2]) * s; } - /* Make sure w is nonnegative for a canonical result. */ + /* Make sure W is non-negative for a canonical result. */ if (q[0] < 0) { negate_v4(q); } diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index dddf8851767..8b8850c7cdb 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -1460,11 +1460,6 @@ static int find_cell_for_point_near_edge(mpq3 p, return c; } -static const Vert *max_x_vert(const Vert *a, const Vert *b) -{ - return (a->co_exact.x > b->co_exact.x) ? a : b; -} - /** * Find the ambient cell -- that is, the cell that is outside * all other cells. @@ -1492,7 +1487,9 @@ static int find_ambient_cell(const IMesh &tm, /* First find a vertex with the maximum x value. */ /* Prefer not to populate the verts in the #IMesh just for this. */ const Vert *v_extreme; - + auto max_x_vert = [](const Vert *a, const Vert *b) { + return (a->co_exact.x > b->co_exact.x) ? a : b; + }; if (component_patches == nullptr) { v_extreme = threading::parallel_reduce( tm.face_index_range(), diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 8969dd4f6b5..4d0dc43ed1e 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1275,7 +1275,7 @@ void BLI_setenv(const char *env, const char *val) { /* free windows */ -#if (defined(WIN32) || defined(WIN64)) +#if (defined(_WIN32) || defined(_WIN64)) uputenv(env, val); #else diff --git a/source/blender/blenlib/tests/BLI_array_utils_test.cc b/source/blender/blenlib/tests/BLI_array_utils_test.cc index 5d12b8fbd4d..1bf221c5335 100644 --- a/source/blender/blenlib/tests/BLI_array_utils_test.cc +++ b/source/blender/blenlib/tests/BLI_array_utils_test.cc @@ -189,3 +189,53 @@ TEST(array_utils, BinaryOrInt4Mix) BINARY_OR_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp)); } #undef BINARY_OR_TEST + +/* BLI_array_deduplicate_ordered */ +#define DEDUPLICATE_ORDERED_TEST(data, data_cmp) \ + { \ + const uint data_len_new = BLI_array_deduplicate_ordered(data, ARRAY_SIZE(data)); \ + EXPECT_EQ(data_len_new, ARRAY_SIZE(data_cmp)); \ + EXPECT_EQ_ARRAY(data, data_cmp, data_len_new); \ + /* Ensure running a second time does nothing. */ \ + const uint data_len_test = BLI_array_deduplicate_ordered(data, data_len_new); \ + EXPECT_EQ(data_len_test, ARRAY_SIZE(data_cmp)); \ + EXPECT_EQ_ARRAY(data, data_cmp, data_len_new); \ + } \ + ((void)0) + +TEST(array_utils, DeduplicateOrdered1) +{ + int data[] = {0}; + const int data_cmp[] = {0}; + DEDUPLICATE_ORDERED_TEST(data, data_cmp); +} + +TEST(array_utils, DeduplicateOrdered2) +{ + int data[] = {1, 2}; + const int data_cmp[] = {1, 2}; + DEDUPLICATE_ORDERED_TEST(data, data_cmp); +} + +TEST(array_utils, DeduplicateOrdered2Same) +{ + int data[] = {1, 1}; + const int data_cmp[] = {1}; + DEDUPLICATE_ORDERED_TEST(data, data_cmp); +} + +TEST(array_utils, DeduplicateOrdered3Same) +{ + int data[] = {1, 1, 1}; + const int data_cmp[] = {1}; + DEDUPLICATE_ORDERED_TEST(data, data_cmp); +} + +TEST(array_utils, DeduplicateOrdered3) +{ + int data[] = {3, 3, 2, 2, 1, 1}; + const int data_cmp[] = {3, 2, 1}; + DEDUPLICATE_ORDERED_TEST(data, data_cmp); +} + +#undef DEDUPLICATE_ORDERED_TEST diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 61a00ccdaa4..f5baf0dcb83 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -58,8 +58,8 @@ set(SRC intern/versioning_280.c intern/versioning_290.c intern/versioning_300.c - intern/versioning_cycles.c intern/versioning_common.cc + intern/versioning_cycles.c intern/versioning_defaults.c intern/versioning_dna.c intern/versioning_legacy.c diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index f16b73f3c7b..3c58c29c162 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -34,8 +34,10 @@ #include "DNA_modifier_types.h" #include "DNA_text_types.h" +#include "BKE_action.h" #include "BKE_animsys.h" #include "BKE_collection.h" +#include "BKE_deform.h" #include "BKE_fcurve_driver.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -89,6 +91,19 @@ static void assert_sorted_ids(Main *bmain) #endif } +static void move_vertex_group_names_to_object_data(Main *bmain) +{ + LISTBASE_FOREACH (Object *, object, &bmain->objects) { + if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + ListBase *new_defbase = BKE_object_defgroup_list_mutable(object); + + /* Clear the list in case the it was already assigned from another object. */ + BLI_freelistN(new_defbase); + *new_defbase = object->defbase; + } + } +} + void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports)) { if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) { @@ -133,6 +148,10 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports)) assert_sorted_ids(bmain); } + if (!MAIN_VERSION_ATLEAST(bmain, 300, 11)) { + move_vertex_group_names_to_object_data(bmain); + } + /** * Versioning code until next subversion bump goes here. * @@ -480,17 +499,13 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - "versioning_userdef.c", #blo_do_versions_userdef - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ + if (!MAIN_VERSION_ATLEAST(bmain, 300, 9)) { + /* Fix a bug where reordering FCurves and bActionGroups could cause some corruption. Just + * reconstruct all the action groups & ensure that the FCurves of a group are continuously + * stored (i.e. not mixed with other groups) to be sure. See T89435. */ + LISTBASE_FOREACH (bAction *, act, &bmain->actions) { + BKE_action_groups_reconstruct(act); + } FOREACH_NODETREE_BEGIN (bmain, ntree, id) { if (ntree->type == NTREE_GEOMETRY) { @@ -503,4 +518,27 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } FOREACH_NODETREE_END; } + + if (!MAIN_VERSION_ATLEAST(bmain, 300, 10)) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + ToolSettings *tool_settings = scene->toolsettings; + if (tool_settings->snap_uv_mode & (1 << 4)) { + tool_settings->snap_uv_mode |= (1 << 6); /* SCE_SNAP_MODE_INCREMENT */ + tool_settings->snap_uv_mode &= ~(1 << 4); + } + } + } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - "versioning_userdef.c", #blo_do_versions_userdef + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ + } } diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 7aee93bb157..423d64ba62c 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -23,6 +23,8 @@ * that benefit from accessing connectivity information. */ +#include "BLI_assert.h" + /* disable holes for now, * these are ifdef'd because they use more memory and can't be saved in DNA currently */ // #define USE_BMESH_HOLES diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c index 97d1de39027..dea6561fe9a 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_normals.c +++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c @@ -33,6 +33,7 @@ #include "BLI_task.h" #include "BLI_utildefines.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_global.h" #include "BKE_mesh.h" @@ -630,11 +631,14 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, { const BMVert *v_pivot = l_curr->v; const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co; - const BMVert *v_1 = BM_edge_other_vert(l_curr->e, v_pivot); + const BMVert *v_1 = l_curr->next->v; const float *co_1 = vcos ? vcos[BM_elem_index_get(v_1)] : v_1->co; - const BMVert *v_2 = BM_edge_other_vert(l_curr->prev->e, v_pivot); + const BMVert *v_2 = l_curr->prev->v; const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co; + BLI_assert(v_1 == BM_edge_other_vert(l_curr->e, v_pivot)); + BLI_assert(v_2 == BM_edge_other_vert(l_curr->prev->e, v_pivot)); + sub_v3_v3v3(vec_curr, co_1, co_pivot); normalize_v3(vec_curr); sub_v3_v3v3(vec_prev, co_2, co_pivot); @@ -700,9 +704,11 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, /* Only need to compute previous edge's vector once, * then we can just reuse old current one! */ { - const BMVert *v_2 = BM_edge_other_vert(e_next, v_pivot); + const BMVert *v_2 = lfan_pivot->next->v; const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co; + BLI_assert(v_2 == BM_edge_other_vert(e_next, v_pivot)); + sub_v3_v3v3(vec_org, co_2, co_pivot); normalize_v3(vec_org); copy_v3_v3(vec_curr, vec_org); diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 9466be4a300..3978959a425 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -724,7 +724,7 @@ static BMOpDefine bmo_edgenet_fill_def = { }; /* - * Edgenet Prepare. + * Edge-net Prepare. * * Identifies several useful edge loop cases and modifies them so * they'll become a face when edgenet_fill is called. The cases covered are: diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c index 51af4d24e52..242b269ed47 100644 --- a/source/blender/bmesh/tools/bmesh_edgenet.c +++ b/source/blender/bmesh/tools/bmesh_edgenet.c @@ -17,7 +17,7 @@ /** \file * \ingroup bmesh * - * Edgenet Fill. + * Edge-net Fill. */ #include <limits.h> diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c index 1e9adea2615..eb56075e136 100644 --- a/source/blender/bmesh/tools/bmesh_intersect_edges.c +++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c @@ -938,7 +938,7 @@ bool BM_mesh_intersect_edges( } if (va_dest == v_other_dest) { - /* Edge/Edgenet to vertex - we can't split the face. */ + /* Edge/Edge-net to vertex - we can't split the face. */ break; } if (edgenet_len == 0 && BM_edge_exists(va_dest, v_other_dest)) { diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 08d9be8b90e..20b56ceb55f 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -68,6 +68,7 @@ set(SRC intern/COM_Device.cc intern/COM_Device.h intern/COM_Enums.cc + intern/COM_Enums.h intern/COM_ExecutionGroup.cc intern/COM_ExecutionGroup.h intern/COM_ExecutionModel.cc @@ -446,14 +447,14 @@ set(SRC operations/COM_BrightnessOperation.h operations/COM_ColorCorrectionOperation.cc operations/COM_ColorCorrectionOperation.h + operations/COM_ConstantOperation.cc + operations/COM_ConstantOperation.h operations/COM_GammaOperation.cc operations/COM_GammaOperation.h operations/COM_MixOperation.cc operations/COM_MixOperation.h operations/COM_ReadBufferOperation.cc operations/COM_ReadBufferOperation.h - operations/COM_ConstantOperation.cc - operations/COM_ConstantOperation.h operations/COM_SetColorOperation.cc operations/COM_SetColorOperation.h operations/COM_SetValueOperation.cc diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h index 857cbf0beee..9f8e6f10215 100644 --- a/source/blender/compositor/COM_defines.h +++ b/source/blender/compositor/COM_defines.h @@ -60,9 +60,12 @@ constexpr int COM_data_type_num_channels(const DataType datatype) } constexpr int COM_DATA_TYPE_VALUE_CHANNELS = COM_data_type_num_channels(DataType::Value); +constexpr int COM_DATA_TYPE_VECTOR_CHANNELS = COM_data_type_num_channels(DataType::Vector); constexpr int COM_DATA_TYPE_COLOR_CHANNELS = COM_data_type_num_channels(DataType::Color); +constexpr float COM_VECTOR_ZERO[3] = {0.0f, 0.0f, 0.0f}; constexpr float COM_VALUE_ZERO[1] = {0.0f}; +constexpr float COM_VALUE_ONE[1] = {1.0f}; /** * Utility to get data type for given number of channels. diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc index af593b2e1b5..18973bb5a00 100644 --- a/source/blender/compositor/intern/COM_Converter.cc +++ b/source/blender/compositor/intern/COM_Converter.cc @@ -460,6 +460,9 @@ void COM_convert_resolution(NodeOperationBuilder &builder, NodeOperationOutput *fromSocket, NodeOperationInput *toSocket) { + /* Data type conversions are executed before resolutions to ensure convert operations have + * resolution. This method have to ensure same datatypes are linked for new operations. */ + BLI_assert(fromSocket->getDataType() == toSocket->getDataType()); ResizeMode mode = toSocket->getResizeMode(); NodeOperation *toOperation = &toSocket->getOperation(); @@ -515,7 +518,7 @@ void COM_convert_resolution(NodeOperationBuilder &builder, NodeOperation *first = nullptr; ScaleOperation *scaleOperation = nullptr; if (doScale) { - scaleOperation = new ScaleOperation(); + scaleOperation = new ScaleOperation(fromSocket->getDataType()); scaleOperation->getInputSocket(1)->setResizeMode(ResizeMode::None); scaleOperation->getInputSocket(2)->setResizeMode(ResizeMode::None); first = scaleOperation; @@ -535,7 +538,7 @@ void COM_convert_resolution(NodeOperationBuilder &builder, builder.addOperation(scaleOperation); } - TranslateOperation *translateOperation = new TranslateOperation(); + TranslateOperation *translateOperation = new TranslateOperation(toSocket->getDataType()); translateOperation->getInputSocket(1)->setResizeMode(ResizeMode::None); translateOperation->getInputSocket(2)->setResizeMode(ResizeMode::None); if (!first) { diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h index 89068a7b734..4ad0872b0b7 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.h +++ b/source/blender/compositor/intern/COM_MemoryBuffer.h @@ -264,11 +264,14 @@ class MemoryBuffer { x = 0; } if (x >= w) { - x = w; + x = w - 1; } break; case MemoryBufferExtend::Repeat: - x = (x >= 0.0f ? (x % w) : (x % w) + w); + x %= w; + if (x < 0) { + x += w; + } break; } @@ -280,13 +283,19 @@ class MemoryBuffer { y = 0; } if (y >= h) { - y = h; + y = h - 1; } break; case MemoryBufferExtend::Repeat: - y = (y >= 0.0f ? (y % h) : (y % h) + h); + y %= h; + if (y < 0) { + y += h; + } break; } + + x = x + m_rect.xmin; + y = y + m_rect.ymin; } inline void wrap_pixel(float &x, @@ -307,11 +316,14 @@ class MemoryBuffer { x = 0.0f; } if (x >= w) { - x = w; + x = w - 1; } break; case MemoryBufferExtend::Repeat: x = fmodf(x, w); + if (x < 0.0f) { + x += w; + } break; } @@ -323,13 +335,19 @@ class MemoryBuffer { y = 0.0f; } if (y >= h) { - y = h; + y = h - 1; } break; case MemoryBufferExtend::Repeat: y = fmodf(y, h); + if (y < 0.0f) { + y += h; + } break; } + + x = x + m_rect.xmin; + y = y + m_rect.ymin; } inline void read(float *result, diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cc b/source/blender/compositor/nodes/COM_TranslateNode.cc index 1b2ce341a66..3a3e98c3472 100644 --- a/source/blender/compositor/nodes/COM_TranslateNode.cc +++ b/source/blender/compositor/nodes/COM_TranslateNode.cc @@ -42,6 +42,7 @@ void TranslateNode::convertToOperations(NodeConverter &converter, NodeOutput *outputSocket = this->getOutputSocket(0); TranslateOperation *operation = new TranslateOperation(); + operation->set_wrapping(data->wrap_axis); if (data->relative) { const RenderData *rd = context.getRenderData(); const float render_size_factor = context.getRenderPercentageAsFactor(); @@ -55,11 +56,8 @@ void TranslateNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(inputXSocket, operation->getInputSocket(1)); converter.mapInputSocket(inputYSocket, operation->getInputSocket(2)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); - - /* FullFrame does not support using WriteBufferOperation. - * TODO: Implement TranslateOperation with wrap support in FullFrame. - */ if (data->wrap_axis && context.get_execution_model() != eExecutionModel::FullFrame) { + /* TODO: To be removed with tiled implementation. */ WriteBufferOperation *writeOperation = new WriteBufferOperation(DataType::Color); WrapOperation *wrapOperation = new WrapOperation(DataType::Color); wrapOperation->setMemoryProxy(writeOperation->getMemoryProxy()); diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cc b/source/blender/compositor/operations/COM_RenderLayersProg.cc index 1ac451b95c2..34fea705c75 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cc +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc @@ -43,6 +43,7 @@ RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elem this->m_inputBuffer = nullptr; this->m_elementsize = elementsize; this->m_rd = nullptr; + layer_buffer_ = nullptr; this->addOutputSocket(type); } @@ -65,6 +66,9 @@ void RenderLayersProg::initExecution() if (rl) { this->m_inputBuffer = RE_RenderLayerGetPass( rl, this->m_passName.c_str(), this->m_viewName); + if (m_inputBuffer) { + layer_buffer_ = new MemoryBuffer(m_inputBuffer, m_elementsize, getWidth(), getHeight()); + } } } } @@ -186,6 +190,10 @@ void RenderLayersProg::executePixelSampled(float output[4], float x, float y, Pi void RenderLayersProg::deinitExecution() { this->m_inputBuffer = nullptr; + if (layer_buffer_) { + delete layer_buffer_; + layer_buffer_ = nullptr; + } } void RenderLayersProg::determineResolution(unsigned int resolution[2], @@ -255,6 +263,20 @@ std::unique_ptr<MetaData> RenderLayersProg::getMetaData() return std::move(callback_data.meta_data); } +void RenderLayersProg::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> UNUSED(inputs)) +{ + BLI_assert(output->get_num_channels() >= m_elementsize); + if (layer_buffer_) { + output->copy_from(layer_buffer_, area, 0, m_elementsize, 0); + } + else { + std::unique_ptr<float[]> zero_elem = std::make_unique<float[]>(m_elementsize); + output->fill(area, 0, zero_elem.get(), m_elementsize); + } +} + /* ******** Render Layers AO Operation ******** */ void RenderLayersAOOperation::executePixelSampled(float output[4], float x, @@ -271,6 +293,21 @@ void RenderLayersAOOperation::executePixelSampled(float output[4], output[3] = 1.0f; } +void RenderLayersAOOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> UNUSED(inputs)) +{ + BLI_assert(output->get_num_channels() == COM_DATA_TYPE_COLOR_CHANNELS); + BLI_assert(m_elementsize == COM_DATA_TYPE_COLOR_CHANNELS); + if (layer_buffer_) { + output->copy_from(layer_buffer_, area, 0, COM_DATA_TYPE_VECTOR_CHANNELS, 0); + } + else { + output->fill(area, 0, COM_VECTOR_ZERO, COM_DATA_TYPE_VECTOR_CHANNELS); + } + output->fill(area, 3, COM_VALUE_ONE, COM_DATA_TYPE_VALUE_CHANNELS); +} + /* ******** Render Layers Alpha Operation ******** */ void RenderLayersAlphaProg::executePixelSampled(float output[4], float x, @@ -289,6 +326,20 @@ void RenderLayersAlphaProg::executePixelSampled(float output[4], } } +void RenderLayersAlphaProg::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> UNUSED(inputs)) +{ + BLI_assert(output->get_num_channels() == COM_DATA_TYPE_VALUE_CHANNELS); + BLI_assert(m_elementsize == COM_DATA_TYPE_COLOR_CHANNELS); + if (layer_buffer_) { + output->copy_from(layer_buffer_, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0); + } + else { + output->fill(area, COM_VALUE_ZERO); + } +} + /* ******** Render Layers Depth Operation ******** */ void RenderLayersDepthProg::executePixelSampled(float output[4], float x, @@ -309,4 +360,19 @@ void RenderLayersDepthProg::executePixelSampled(float output[4], } } +void RenderLayersDepthProg::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> UNUSED(inputs)) +{ + BLI_assert(output->get_num_channels() == COM_DATA_TYPE_VALUE_CHANNELS); + BLI_assert(m_elementsize == COM_DATA_TYPE_VALUE_CHANNELS); + if (layer_buffer_) { + output->copy_from(layer_buffer_, area); + } + else { + const float default_depth = 10e10f; + output->fill(area, &default_depth); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h index 56f83f691e8..dd76a56d645 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.h +++ b/source/blender/compositor/operations/COM_RenderLayersProg.h @@ -20,7 +20,7 @@ #include "BLI_listbase.h" #include "BLI_utildefines.h" -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -33,7 +33,7 @@ namespace blender::compositor { * * \todo Rename to operation. */ -class RenderLayersProg : public NodeOperation { +class RenderLayersProg : public MultiThreadedOperation { protected: /** * Reference to the scene object. @@ -50,8 +50,11 @@ class RenderLayersProg : public NodeOperation { */ const char *m_viewName; + const MemoryBuffer *layer_buffer_; + /** - * cached instance to the float buffer inside the layer + * Cached instance to the float buffer inside the layer. + * TODO: To be removed with tiled implementation. */ float *m_inputBuffer; @@ -126,6 +129,10 @@ class RenderLayersProg : public NodeOperation { void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; std::unique_ptr<MetaData> getMetaData() override; + + virtual void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; class RenderLayersAOOperation : public RenderLayersProg { @@ -135,6 +142,10 @@ class RenderLayersAOOperation : public RenderLayersProg { { } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; class RenderLayersAlphaProg : public RenderLayersProg { @@ -144,6 +155,10 @@ class RenderLayersAlphaProg : public RenderLayersProg { { } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; class RenderLayersDepthProg : public RenderLayersProg { @@ -153,6 +168,10 @@ class RenderLayersDepthProg : public RenderLayersProg { { } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc index 9dde73269fc..c3647a39909 100644 --- a/source/blender/compositor/operations/COM_SMAAOperation.cc +++ b/source/blender/compositor/operations/COM_SMAAOperation.cc @@ -36,12 +36,12 @@ namespace blender::compositor { * * http://www.iryoku.com/smaa/ * - * This file is based on smaa-cpp: + * This file is based on SMAA-CPP: * * https://github.com/iRi-E/smaa-cpp * * Currently only SMAA 1x mode is provided, so the operation will be done - * with no spatial multisampling nor temporal supersampling. + * with no spatial multi-sampling nor temporal super-sampling. * * NOTE: This program assumes the screen coordinates are DirectX style, so * the vertical direction is upside-down. "top" and "bottom" actually mean diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc index 18276fcc072..f03b9fcf34d 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cc +++ b/source/blender/compositor/operations/COM_ScaleOperation.cc @@ -37,12 +37,16 @@ BaseScaleOperation::BaseScaleOperation() m_variable_size = false; } -ScaleOperation::ScaleOperation() : BaseScaleOperation() +ScaleOperation::ScaleOperation() : ScaleOperation(DataType::Color) { - this->addInputSocket(DataType::Color); +} + +ScaleOperation::ScaleOperation(DataType data_type) : BaseScaleOperation() +{ + this->addInputSocket(data_type); this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); - this->addOutputSocket(DataType::Color); + this->addOutputSocket(data_type); this->setResolutionInputSocketIndex(0); this->m_inputOperation = nullptr; this->m_inputXOperation = nullptr; diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h index dc3de3602bf..2f9a7be92e6 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.h +++ b/source/blender/compositor/operations/COM_ScaleOperation.h @@ -55,6 +55,7 @@ class ScaleOperation : public BaseScaleOperation { public: ScaleOperation(); + ScaleOperation(DataType data_type); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cc b/source/blender/compositor/operations/COM_TranslateOperation.cc index 49135f25320..a3db086e974 100644 --- a/source/blender/compositor/operations/COM_TranslateOperation.cc +++ b/source/blender/compositor/operations/COM_TranslateOperation.cc @@ -20,12 +20,15 @@ namespace blender::compositor { -TranslateOperation::TranslateOperation() +TranslateOperation::TranslateOperation() : TranslateOperation(DataType::Color) { - this->addInputSocket(DataType::Color); +} +TranslateOperation::TranslateOperation(DataType data_type) +{ + this->addInputSocket(data_type); this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); - this->addOutputSocket(DataType::Color); + this->addOutputSocket(data_type); this->setResolutionInputSocketIndex(0); this->m_inputOperation = nullptr; this->m_inputXOperation = nullptr; @@ -33,6 +36,8 @@ TranslateOperation::TranslateOperation() this->m_isDeltaSet = false; this->m_factorX = 1.0f; this->m_factorY = 1.0f; + this->x_extend_mode_ = MemoryBufferExtend::Clip; + this->y_extend_mode_ = MemoryBufferExtend::Clip; } void TranslateOperation::initExecution() { @@ -83,4 +88,58 @@ void TranslateOperation::setFactorXY(float factorX, float factorY) m_factorY = factorY; } +void TranslateOperation::set_wrapping(int wrapping_type) +{ + switch (wrapping_type) { + case CMP_NODE_WRAP_X: + x_extend_mode_ = MemoryBufferExtend::Repeat; + break; + case CMP_NODE_WRAP_Y: + y_extend_mode_ = MemoryBufferExtend::Repeat; + break; + case CMP_NODE_WRAP_XY: + x_extend_mode_ = MemoryBufferExtend::Repeat; + y_extend_mode_ = MemoryBufferExtend::Repeat; + break; + default: + break; + } +} + +void TranslateOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + if (input_idx == 0) { + ensureDelta(); + r_input_area = output_area; + if (x_extend_mode_ == MemoryBufferExtend::Clip) { + const int delta_x = this->getDeltaX(); + BLI_rcti_translate(&r_input_area, -delta_x, 0); + } + if (y_extend_mode_ == MemoryBufferExtend::Clip) { + const int delta_y = this->getDeltaY(); + BLI_rcti_translate(&r_input_area, 0, -delta_y); + } + } +} + +void TranslateOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + MemoryBuffer *input = inputs[0]; + const int delta_x = this->getDeltaX(); + const int delta_y = this->getDeltaY(); + for (int y = area.ymin; y < area.ymax; y++) { + float *out = output->get_elem(area.xmin, y); + for (int x = area.xmin; x < area.xmax; x++) { + const int input_x = x - delta_x; + const int input_y = y - delta_y; + input->read(out, input_x, input_y, x_extend_mode_, y_extend_mode_); + out += output->elem_stride; + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TranslateOperation.h b/source/blender/compositor/operations/COM_TranslateOperation.h index eb3a664159f..ce1965cecef 100644 --- a/source/blender/compositor/operations/COM_TranslateOperation.h +++ b/source/blender/compositor/operations/COM_TranslateOperation.h @@ -18,11 +18,12 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_ConstantOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class TranslateOperation : public NodeOperation { +class TranslateOperation : public MultiThreadedOperation { private: SocketReader *m_inputOperation; SocketReader *m_inputXOperation; @@ -32,9 +33,12 @@ class TranslateOperation : public NodeOperation { bool m_isDeltaSet; float m_factorX; float m_factorY; + MemoryBufferExtend x_extend_mode_; + MemoryBufferExtend y_extend_mode_; public: TranslateOperation(); + TranslateOperation(DataType data_type); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; @@ -55,16 +59,38 @@ class TranslateOperation : public NodeOperation { inline void ensureDelta() { if (!this->m_isDeltaSet) { - float tempDelta[4]; - this->m_inputXOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest); - this->m_deltaX = tempDelta[0]; - this->m_inputYOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest); - this->m_deltaY = tempDelta[0]; + if (execution_model_ == eExecutionModel::Tiled) { + float tempDelta[4]; + this->m_inputXOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest); + this->m_deltaX = tempDelta[0]; + this->m_inputYOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest); + this->m_deltaY = tempDelta[0]; + } + else { + this->m_deltaX = 0; + NodeOperation *x_op = getInputOperation(1); + if (x_op->get_flags().is_constant_operation) { + this->m_deltaX = ((ConstantOperation *)x_op)->get_constant_elem()[0]; + } + this->m_deltaY = 0; + NodeOperation *y_op = getInputOperation(2); + if (y_op->get_flags().is_constant_operation) { + this->m_deltaY = ((ConstantOperation *)y_op)->get_constant_elem()[0]; + } + } + this->m_isDeltaSet = true; } } void setFactorXY(float factorX, float factorY); + void set_wrapping(int wrapping_type); + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 27441c9a7ae..749b1bba871 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -159,7 +159,7 @@ void DEG_ids_restore_recalc(Depsgraph *depsgraph); /* Graph Evaluation ----------------------------- */ /* Frame changed recalculation entry point. */ -void DEG_evaluate_on_framechange(Depsgraph *graph, float ctime); +void DEG_evaluate_on_framechange(Depsgraph *graph, float frame); /* Data changed recalculation entry point. */ void DEG_evaluate_on_refresh(Depsgraph *graph); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 56168739fae..bd3bc5d5ee7 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -114,6 +114,7 @@ #include "SEQ_iterator.h" #include "intern/builder/deg_builder.h" +#include "intern/builder/deg_builder_rna.h" #include "intern/depsgraph.h" #include "intern/depsgraph_tag.h" #include "intern/depsgraph_type.h" @@ -1199,7 +1200,7 @@ void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path if (prop == nullptr) { return; } - if (!RNA_property_is_idprop(prop)) { + if (!rna_prop_affects_parameters_node(&ptr, prop)) { return; } const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); @@ -1495,7 +1496,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob add_operation_node( &object->id, NodeType::BATCH_CACHE, - OperationCode::GEOMETRY_SELECT_UPDATE, + OperationCode::BATCH_UPDATE_SELECT, [object_cow](::Depsgraph *depsgraph) { BKE_object_select_update(depsgraph, object_cow); }); } @@ -1516,33 +1517,37 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool if (key) { build_shapekeys(key); } - /* Nodes for result of obdata's evaluation, and geometry - * evaluation on object. */ + + /* Geometry evaluation. */ + /* Entry operation, takes care of initialization, and some other + * relations which needs to be run prior to actual geometry evaluation. */ + op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + op_node->set_as_entry(); + + add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM); + const ID_Type id_type = GS(obdata->name); switch (id_type) { case ID_ME: { - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_mesh_eval_geometry(depsgraph, (Mesh *)obdata_cow); - }); - op_node->set_as_entry(); + add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_mesh_eval_geometry(depsgraph, (Mesh *)obdata_cow); + }); break; } case ID_MB: { - op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); - op_node->set_as_entry(); + add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); break; } case ID_CU: { - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow); - }); - op_node->set_as_entry(); + add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow); + }); /* Make sure objects used for bevel.taper are in the graph. * NOTE: This objects might be not linked to the scene. */ Curve *cu = (Curve *)obdata; @@ -1558,47 +1563,41 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool break; } case ID_LT: { - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_lattice_eval_geometry(depsgraph, (Lattice *)obdata_cow); - }); - op_node->set_as_entry(); + add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_lattice_eval_geometry(depsgraph, (Lattice *)obdata_cow); + }); break; } case ID_GD: { /* GPencil evaluation operations. */ - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_gpencil_frame_active_set(depsgraph, - (bGPdata *)obdata_cow); - }); - op_node->set_as_entry(); + add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_gpencil_frame_active_set(depsgraph, (bGPdata *)obdata_cow); + }); break; } case ID_HA: { - op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); - op_node->set_as_entry(); + add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); break; } case ID_PT: { - op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); - op_node->set_as_entry(); + add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); break; } case ID_VO: { /* Volume frame update. */ - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_volume_eval_geometry(depsgraph, (Volume *)obdata_cow); - }); - op_node->set_as_entry(); + add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_volume_eval_geometry(depsgraph, (Volume *)obdata_cow); + }); break; } default: @@ -1612,10 +1611,22 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool /* Batch cache. */ add_operation_node(obdata, NodeType::BATCH_CACHE, - OperationCode::GEOMETRY_SELECT_UPDATE, + OperationCode::BATCH_UPDATE_SELECT, [obdata_cow](::Depsgraph *depsgraph) { BKE_object_data_select_update(depsgraph, obdata_cow); }); + add_operation_node(obdata, + NodeType::BATCH_CACHE, + OperationCode::BATCH_UPDATE_DEFORM, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_object_data_eval_batch_cache_deform_tag(depsgraph, obdata_cow); + }); + add_operation_node(obdata, + NodeType::BATCH_CACHE, + OperationCode::BATCH_UPDATE_ALL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_object_data_eval_batch_cache_dirty_tag(depsgraph, obdata_cow); + }); } void DepsgraphNodeBuilder::build_armature(bArmature *armature) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index c269ad16824..5650e95f55a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -647,7 +647,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll /* Only create geometry relations to child objects, if they have a geometry component. */ OperationKey object_geometry_key{ - &cob->ob->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL}; + &cob->ob->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT}; if (find_node(object_geometry_key) != nullptr) { add_relation(object_geometry_key, collection_geometry_key, "Collection Geometry"); } @@ -1098,7 +1098,8 @@ void DepsgraphRelationBuilder::build_object_pointcache(Object *object) } else { flag = FLAG_GEOMETRY; - OperationKey geometry_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + OperationKey geometry_key( + &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); add_relation(point_cache_key, geometry_key, "Point Cache -> Geometry"); } BLI_assert(flag != -1); @@ -1610,7 +1611,7 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) } } } - if (property_entry_key.prop != nullptr && RNA_property_is_idprop(property_entry_key.prop)) { + if (rna_prop_affects_parameters_node(&property_entry_key.ptr, property_entry_key.prop)) { RNAPathKey property_exit_key(property_entry_key.id, property_entry_key.ptr, property_entry_key.prop, @@ -1713,7 +1714,7 @@ void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_ if (prop == nullptr) { return; } - if (!RNA_property_is_idprop(prop)) { + if (!rna_prop_affects_parameters_node(&ptr, prop)) { return; } const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); @@ -1868,7 +1869,8 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) void DepsgraphRelationBuilder::build_particle_systems(Object *object) { TimeSourceKey time_src_key; - OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + OperationKey obdata_ubereval_key( + &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); OperationKey eval_init_key( &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_INIT); OperationKey eval_done_key( @@ -2016,7 +2018,8 @@ void DepsgraphRelationBuilder::build_particle_system_visualization_object(Object { OperationKey psys_key( &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_EVAL, psys->name); - OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + OperationKey obdata_ubereval_key( + &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); ComponentKey dup_ob_key(&draw_object->id, NodeType::TRANSFORM); add_relation(dup_ob_key, psys_key, "Particle Object Visualization"); if (draw_object->type == OB_MBALL) { @@ -2073,15 +2076,15 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) /* Get nodes for result of obdata's evaluation, and geometry evaluation * on object. */ ComponentKey obdata_geom_key(obdata, NodeType::GEOMETRY); - ComponentKey geom_key(&object->id, NodeType::GEOMETRY); - /* Link components to each other. */ - add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data"); OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + /* Link components to each other. */ + add_relation(obdata_geom_key, obdata_ubereval_key, "Object Geometry Base Data"); + /* Special case: modifiers evaluation queries scene for various things like * data mask to be used. We add relation here to ensure object is never * evaluated prior to Scene's CoW is ready. */ OperationKey scene_key(&scene_->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL); - Relation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation"); + Relation *rel = add_relation(scene_key, geom_init_key, "CoW Relation"); rel->flag |= RELATION_FLAG_NO_FLUSH; /* Modifiers */ if (object->modifiers.first != nullptr) { @@ -2091,13 +2094,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); if (mti->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + DepsNodeHandle handle = create_node_handle(geom_init_key); ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); mti->updateDepsgraph(md, &ctx); } if (BKE_object_modifier_use_time(object, md)) { TimeSourceKey time_src_key; - add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + add_relation(time_src_key, geom_init_key, "Time Source"); } } } @@ -2110,13 +2113,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info( (GpencilModifierType)md->type); if (mti->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + DepsNodeHandle handle = create_node_handle(geom_init_key); ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); mti->updateDepsgraph(md, &ctx, graph_->mode); } if (BKE_object_modifier_gpencil_use_time(object, md)) { TimeSourceKey time_src_key; - add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + add_relation(time_src_key, geom_init_key, "Time Source"); } } } @@ -2128,13 +2131,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) LISTBASE_FOREACH (ShaderFxData *, fx, &object->shader_fx) { const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info((ShaderFxType)fx->type); if (fxi->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + DepsNodeHandle handle = create_node_handle(geom_init_key); ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); fxi->updateDepsgraph(fx, &ctx); } if (BKE_object_shaderfx_use_time(object, fx)) { TimeSourceKey time_src_key; - add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + add_relation(time_src_key, geom_init_key, "Time Source"); } } } @@ -2160,6 +2163,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) add_relation(mom_transform_key, mom_geom_key, "Metaball Motherball Transform -> Geometry"); } else { + ComponentKey geom_key(&object->id, NodeType::GEOMETRY); ComponentKey transform_key(&object->id, NodeType::TRANSFORM); add_relation(geom_key, mom_geom_key, "Metaball Motherball"); add_relation(transform_key, mom_geom_key, "Metaball Motherball"); @@ -2174,9 +2178,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) * Ideally we need to get rid of this relation. */ if (object_particles_depends_on_time(object)) { TimeSourceKey time_key; - OperationKey obdata_ubereval_key( - &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); - add_relation(time_key, obdata_ubereval_key, "Legacy particle time"); + add_relation(time_key, geom_init_key, "Legacy particle time"); } /* Object data data-block. */ build_object_data_geometry_datablock((ID *)object->data); @@ -2198,12 +2200,33 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) add_relation(final_geometry_key, synchronize_key, "Synchronize to Original"); /* Batch cache. */ OperationKey object_data_select_key( - obdata, NodeType::BATCH_CACHE, OperationCode::GEOMETRY_SELECT_UPDATE); + obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_SELECT); OperationKey object_select_key( - &object->id, NodeType::BATCH_CACHE, OperationCode::GEOMETRY_SELECT_UPDATE); + &object->id, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_SELECT); + add_relation(object_data_select_key, object_select_key, "Data Selection -> Object Selection"); + add_relation(final_geometry_key, + object_select_key, + "Object Geometry -> Select Update", + RELATION_FLAG_NO_FLUSH); + + OperationKey object_data_geom_deform_key( + obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM); + OperationKey object_data_geom_init_key( + obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + + OperationKey object_data_batch_deform_key( + obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_DEFORM); + OperationKey object_data_batch_all_key( + obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_ALL); + + add_relation(geom_init_key, object_data_batch_all_key, "Object Geometry -> Batch Update All"); + add_relation( - geom_key, object_select_key, "Object Geometry -> Select Update", RELATION_FLAG_NO_FLUSH); + object_data_geom_init_key, object_data_batch_all_key, "Data Init -> Batch Update All"); + add_relation(object_data_geom_deform_key, + object_data_batch_deform_key, + "Data Deform -> Batch Update Deform"); } void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) @@ -2221,8 +2244,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) build_shapekeys(key); } /* Link object data evaluation node to exit operation. */ + OperationKey obdata_geom_deform_key( + obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM); + OperationKey obdata_geom_init_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); OperationKey obdata_geom_eval_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); OperationKey obdata_geom_done_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE); + add_relation(obdata_geom_init_key, obdata_geom_eval_key, "ObData Init -> Geom Eval"); + add_relation(obdata_geom_deform_key, obdata_geom_eval_key, "ObData Deform -> Geom Eval"); add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done"); /* Type-specific links. */ const ID_Type id_type = GS(obdata->name); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index 54c51adec66..8e3960e1a15 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -180,7 +180,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, node_identifier.operation_name = ""; node_identifier.operation_name_tag = -1; /* Handling of commonly known scenarios. */ - if (prop != nullptr && RNA_property_is_idprop(prop)) { + if (rna_prop_affects_parameters_node(ptr, prop)) { node_identifier.type = NodeType::PARAMETERS; node_identifier.operation_code = OperationCode::ID_PROPERTY; node_identifier.operation_name = RNA_property_identifier( @@ -397,4 +397,12 @@ RNANodeQueryIDData *RNANodeQuery::ensure_id_data(const ID *id) return id_data.get(); } +bool rna_prop_affects_parameters_node(const PointerRNA *ptr, const PropertyRNA *prop) +{ + return prop != nullptr && RNA_property_is_idprop(prop) && + /* ID properties in the geometry nodes modifier don't affect that parameters node. Instead + they affect the modifier and therefore the geometry node directly. */ + !RNA_struct_is_a(ptr->type, &RNA_NodesModifier); +} + } // namespace blender::deg diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h index d03903d508c..24d7f5f3a30 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h @@ -108,5 +108,7 @@ class RNANodeQuery { static bool contains(const char *prop_identifier, const char *rna_path_component); }; +bool rna_prop_affects_parameters_node(const PointerRNA *ptr, const PropertyRNA *prop); + } // namespace deg } // namespace blender diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 6fe7d5f5d8b..076e15a3175 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -68,7 +68,8 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati scene(scene), view_layer(view_layer), mode(mode), - ctime(BKE_scene_frame_get(scene)), + frame(BKE_scene_frame_get(scene)), + ctime(BKE_scene_ctime_get(scene)), scene_cow(nullptr), is_active(false), is_evaluating(false), diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index ff536c19c05..913b61ca563 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -140,7 +140,9 @@ struct Depsgraph { ViewLayer *view_layer; eEvaluationMode mode; - /* Time at which dependency graph is being or was last evaluated. */ + /* Time at which dependency graph is being or was last evaluated. + * frame is the value before, and ctime the value after time remapping. */ + float frame; float ctime; /* Evaluated version of datablocks we access a lot. diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index 1ad3fdbc9da..cc7ce871419 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -51,7 +51,7 @@ static void deg_flush_updates_and_refresh(deg::Depsgraph *deg_graph) { /* Update the time on the cow scene. */ if (deg_graph->scene_cow) { - BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime); + BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->frame); } deg::deg_graph_flush_updates(deg_graph); @@ -63,10 +63,12 @@ void DEG_evaluate_on_refresh(Depsgraph *graph) { deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); const Scene *scene = DEG_get_input_scene(graph); - const float ctime = BKE_scene_frame_get(scene); + const float frame = BKE_scene_frame_get(scene); + const float ctime = BKE_scene_ctime_get(scene); - if (ctime != deg_graph->ctime) { + if (deg_graph->frame != frame || ctime != deg_graph->ctime) { deg_graph->tag_time_source(); + deg_graph->frame = frame; deg_graph->ctime = ctime; } @@ -74,10 +76,13 @@ void DEG_evaluate_on_refresh(Depsgraph *graph) } /* Frame-change happened for root scene that graph belongs to. */ -void DEG_evaluate_on_framechange(Depsgraph *graph, float ctime) +void DEG_evaluate_on_framechange(Depsgraph *graph, float frame) { deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); + const Scene *scene = DEG_get_input_scene(graph); + deg_graph->tag_time_source(); - deg_graph->ctime = ctime; + deg_graph->frame = frame; + deg_graph->ctime = BKE_scene_frame_to_ctime(scene, frame); deg_flush_updates_and_refresh(deg_graph); } diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index b00cae87311..e879e8d0f23 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -117,7 +117,7 @@ void depsgraph_select_tag_to_component_opcode(const ID *id, } else if (is_selectable_data_id_type(id_type)) { *component_type = NodeType::BATCH_CACHE; - *operation_code = OperationCode::GEOMETRY_SELECT_UPDATE; + *operation_code = OperationCode::BATCH_UPDATE_SELECT; } else { *component_type = NodeType::COPY_ON_WRITE; @@ -168,6 +168,11 @@ void depsgraph_tag_to_component_opcode(const ID *id, break; case ID_RECALC_GEOMETRY: depsgraph_geometry_tag_to_component(id, component_type); + *operation_code = OperationCode::GEOMETRY_EVAL_INIT; + break; + case ID_RECALC_GEOMETRY_DEFORM: + depsgraph_geometry_tag_to_component(id, component_type); + *operation_code = OperationCode::GEOMETRY_EVAL_DEFORM; break; case ID_RECALC_ANIMATION: *component_type = NodeType::ANIMATION; @@ -708,6 +713,8 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag) return "GEOMETRY"; case ID_RECALC_GEOMETRY_ALL_MODES: return "GEOMETRY_ALL_MODES"; + case ID_RECALC_GEOMETRY_DEFORM: + return "GEOMETRY_DEFORM"; case ID_RECALC_ANIMATION: return "ANIMATION"; case ID_RECALC_PSYS_REDO: diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 1b24e2b7ad2..2cbb0b52e34 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -144,7 +144,10 @@ inline void flush_handle_component_node(IDNode *id_node, * special component where we don't want all operations to be tagged. * * TODO(sergey): Make this a more generic solution. */ - if (!ELEM(comp_node->type, NodeType::PARTICLE_SETTINGS, NodeType::PARTICLE_SYSTEM)) { + if (!ELEM(comp_node->type, + NodeType::PARTICLE_SETTINGS, + NodeType::PARTICLE_SYSTEM, + NodeType::BATCH_CACHE)) { for (OperationNode *op : comp_node->operations) { op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; } diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index 7e57467f905..62a3d65d1f4 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -98,6 +98,8 @@ const char *operationCodeAsString(OperationCode opcode) /* Geometry. */ case OperationCode::GEOMETRY_EVAL_INIT: return "GEOMETRY_EVAL_INIT"; + case OperationCode::GEOMETRY_EVAL_DEFORM: + return "GEOMETRY_EVAL_DEFORM"; case OperationCode::GEOMETRY_EVAL: return "GEOMETRY_EVAL"; case OperationCode::GEOMETRY_EVAL_DONE: @@ -160,8 +162,12 @@ const char *operationCodeAsString(OperationCode opcode) case OperationCode::FILE_CACHE_UPDATE: return "FILE_CACHE_UPDATE"; /* Batch cache. */ - case OperationCode::GEOMETRY_SELECT_UPDATE: - return "GEOMETRY_SELECT_UPDATE"; + case OperationCode::BATCH_UPDATE_SELECT: + return "BATCH_UPDATE_SELECT"; + case OperationCode::BATCH_UPDATE_DEFORM: + return "BATCH_UPDATE_DEFORM"; + case OperationCode::BATCH_UPDATE_ALL: + return "BATCH_UPDATE_ALL"; /* Masks. */ case OperationCode::MASK_ANIMATION: return "MASK_ANIMATION"; diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h index a17186da941..b0130d03c69 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.h +++ b/source/blender/depsgraph/intern/node/deg_node_operation.h @@ -100,7 +100,11 @@ enum class OperationCode { /* Initialize evaluation of the geometry. Is an entry operation of geometry * component. */ GEOMETRY_EVAL_INIT, - /* Evaluate the whole geometry, including modifiers. */ + /* Evaluate the geometry, including modifiers, and update only batches that + * are affected by deform operations. */ + GEOMETRY_EVAL_DEFORM, + /* Evaluate the geometry, including modifiers, but don't update the batch + * cache. */ GEOMETRY_EVAL, /* Evaluation of geometry is completely done. */ GEOMETRY_EVAL_DONE, @@ -178,7 +182,9 @@ enum class OperationCode { WORLD_UPDATE, /* Batch caches. -------------------------------------------------------- */ - GEOMETRY_SELECT_UPDATE, + BATCH_UPDATE_SELECT, + BATCH_UPDATE_DEFORM, + BATCH_UPDATE_ALL, /* Masks. --------------------------------------------------------------- */ MASK_ANIMATION, diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 1227f4db8e4..ad154704d2c 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -51,14 +51,14 @@ set(INC set(SRC intern/draw_cache.c + intern/draw_cache_extract_mesh.cc intern/draw_cache_extract_mesh_extractors.c intern/draw_cache_extract_mesh_render_data.c - intern/draw_cache_extract_mesh.cc intern/mesh_extractors/extract_mesh_ibo_edituv.cc intern/mesh_extractors/extract_mesh_ibo_fdots.cc + intern/mesh_extractors/extract_mesh_ibo_lines.cc intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc - intern/mesh_extractors/extract_mesh_ibo_lines.cc intern/mesh_extractors/extract_mesh_ibo_points.cc intern/mesh_extractors/extract_mesh_ibo_tris.cc intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc @@ -205,8 +205,8 @@ set(SRC intern/draw_manager_profiling.h intern/draw_manager_testing.h intern/draw_manager_text.h - intern/draw_view.h intern/draw_shader.h + intern/draw_view.h intern/smaa_textures.h engines/basic/basic_engine.h engines/eevee/eevee_engine.h @@ -515,6 +515,8 @@ if(WITH_GTESTS) set(TEST_SRC tests/draw_testing.cc tests/shaders_test.cc + + tests/draw_testing.hh ) set(TEST_INC "../../../intern/ghost/" diff --git a/source/blender/draw/engines/image/image_engine.c b/source/blender/draw/engines/image/image_engine.c index 2522a445d8e..b6fd73e76d1 100644 --- a/source/blender/draw/engines/image/image_engine.c +++ b/source/blender/draw/engines/image/image_engine.c @@ -31,6 +31,7 @@ #include "DNA_camera_types.h" #include "DNA_screen_types.h" +#include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "ED_image.h" @@ -222,19 +223,30 @@ static void image_cache_image(IMAGE_Data *vedata, Image *image, ImageUser *iuser copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f); } else if ((sima_flag & SI_SHOW_R) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING; + draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f); } else if ((sima_flag & SI_SHOW_G) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING; + draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f); } else if ((sima_flag & SI_SHOW_B) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING; + draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f); } else /* RGB */ { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + if (IMB_alpha_affects_rgb(ibuf)) { + draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } } } if (space_type == SPACE_NODE) { @@ -248,19 +260,30 @@ static void image_cache_image(IMAGE_Data *vedata, Image *image, ImageUser *iuser copy_v4_fl4(shuffle, 0.0f, 0.0f, 0.0f, 1.0f); } else if ((snode->flag & SNODE_SHOW_R) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING; + draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f); } else if ((snode->flag & SNODE_SHOW_G) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING; + draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f); } else if ((snode->flag & SNODE_SHOW_B) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING; + draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f); } else /* RGB */ { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + if (IMB_alpha_affects_rgb(ibuf)) { + draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } } } diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index ec5d43683d1..1da682ff01b 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -37,6 +37,7 @@ #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_deform.h" #include "BKE_modifier.h" #include "DEG_depsgraph_query.h" @@ -1293,10 +1294,9 @@ static void draw_axes(ArmatureDrawContext *ctx, const bArmature *arm) { float final_col[4]; - const float *col = (ctx->const_color) ? - ctx->const_color : - (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? G_draw.block.colorTextHi : - G_draw.block.colorText; + const float *col = (ctx->const_color) ? ctx->const_color : + (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? G_draw.block.colorTextHi : + G_draw.block.colorText; copy_v4_v4(final_col, col); /* Mix with axes color. */ final_col[3] = (ctx->const_color) ? 1.0 : (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? 0.1 : 0.65; @@ -2040,7 +2040,8 @@ static void draw_armature_pose(ArmatureDrawContext *ctx) const Object *obact_orig = DEG_get_original_object(draw_ctx->obact); - LISTBASE_FOREACH (bDeformGroup *, dg, &obact_orig->defbase) { + const ListBase *defbase = BKE_object_defgroup_list(obact_orig); + LISTBASE_FOREACH (const bDeformGroup *, dg, defbase) { if (dg->flag & DG_LOCK_WEIGHT) { pchan = BKE_pose_channel_find_name(ob->pose, dg->name); diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c index 7639911286f..a7ed6c777e8 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c +++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c @@ -26,6 +26,7 @@ #include "DNA_mesh_types.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "draw_cache_impl.h" diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c index 01ab47ac1de..c2b130163e8 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_uv.c +++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c @@ -24,6 +24,7 @@ #include "draw_cache_impl.h" #include "draw_manager_text.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_image.h" #include "BKE_layer.h" diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 5c83047b18f..a2e8dc20907 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -3274,8 +3274,8 @@ GPUBatch *DRW_cache_lattice_wire_get(Object *ob, bool use_weight) Lattice *lt = ob->data; int actdef = -1; - if (use_weight && ob->defbase.first && lt->editlatt->latt->dvert) { - actdef = ob->actdef - 1; + if (use_weight && !BLI_listbase_is_empty(<->vertex_group_names) && lt->editlatt->latt->dvert) { + actdef = lt->vertex_group_active_index - 1; } return DRW_lattice_batch_cache_get_all_edges(lt, use_weight, actdef); diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index be61b0a9baf..a0694a08f0b 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -36,7 +36,7 @@ typedef struct DRW_MeshWeightState { short flags; char alert_mode; - /* Set of all selected bones for Multipaint. */ + /* Set of all selected bones for Multi-paint. */ bool *defgroup_sel; /* [defgroup_len] */ int defgroup_sel_count; diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_private.h b/source/blender/draw/intern/draw_cache_extract_mesh_private.h index 2424b0f9fee..5f670bdc5ec 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_private.h +++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h @@ -30,6 +30,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "draw_cache_extract.h" diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index 7fe543db01f..336ccd40d5c 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -844,8 +844,8 @@ static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, in int vert_len = GPU_vertbuf_get_vertex_len(cache->vbo); gpEditIterData iter; - iter.vgindex = ob->actdef - 1; - if (!BLI_findlink(&ob->defbase, iter.vgindex)) { + iter.vgindex = gpd->vertex_group_active_index - 1; + if (!BLI_findlink(&gpd->vertex_group_names, iter.vgindex)) { iter.vgindex = -1; } diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 41047191efe..0c002ff09f2 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -544,8 +544,8 @@ static void drw_mesh_weight_state_extract(Object *ob, /* Extract complete vertex weight group selection state and mode flags. */ memset(wstate, 0, sizeof(*wstate)); - wstate->defgroup_active = ob->actdef - 1; - wstate->defgroup_len = BLI_listbase_count(&ob->defbase); + wstate->defgroup_active = me->vertex_group_active_index - 1; + wstate->defgroup_len = BLI_listbase_count(&me->vertex_group_names); wstate->alert_mode = ts->weightuser; @@ -821,6 +821,17 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) mesh_batch_cache_discard_shaded_tri(cache); mesh_batch_cache_discard_uvedit(cache); break; + case BKE_MESH_BATCH_DIRTY_DEFORM: + FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { + GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor); + GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.lnor); + GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_pos); + GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_nor); + GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.tris); + } + batch_map = MDEPS_CREATE_MAP(vbo.pos_nor, vbo.lnor, vbo.fdots_pos, vbo.fdots_nor, ibo.tris); + mesh_batch_cache_discard_batch(cache, batch_map); + break; case BKE_MESH_BATCH_DIRTY_UVEDIT_ALL: mesh_batch_cache_discard_uvedit(cache); break; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 62742d082ca..6f5e041fa79 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1645,7 +1645,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, drw_engines_draw_scene(); - /* Fix 3D view being "laggy" on macos and win+nvidia. (See T56996, T61474) */ + /* Fix 3D view "lagging" on APPLE and WIN32+NVIDIA. (See T56996, T61474) */ GPU_flush(); DRW_stats_reset(); diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 76b6ce54d29..8f8c1c067d4 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -1283,6 +1283,9 @@ static void split_groups_action_temp(bAction *act, bActionGroup *tgrp) else { group_fcurves_last->next->prev = group_fcurves_first->prev; } + + /* Clear links pointing outside the per-group list. */ + group_fcurves_first->prev = group_fcurves_last->next = NULL; } /* Initialize memory for temp-group */ @@ -1337,24 +1340,12 @@ static void join_groups_action_temp(bAction *act) if (agrp->flag & AGRP_TEMP) { LISTBASE_FOREACH (FCurve *, fcu, &agrp->channels) { fcu->grp = NULL; - if (fcu == agrp->channels.last) { - break; - } } BLI_remlink(&act->groups, agrp); break; } } - - /* BLI_movelisttolist() doesn't touch first->prev and last->next pointers in its "dst" list. - * Ensure that after the reshuffling the list is properly terminated. */ - if (!BLI_listbase_is_empty(&act->curves)) { - FCurve *act_fcurves_first = act->curves.first; - act_fcurves_first->prev = NULL; - FCurve *act_fcurves_last = act->curves.last; - act_fcurves_last->next = NULL; - } } /* Change the order of anim-channels within action diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 16eb2f6b6f2..bfaa76b3bf9 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -80,7 +80,7 @@ FCurve *verify_driver_fcurve(ID *id, /* init animdata if none available yet */ adt = BKE_animdata_from_id(id); if (adt == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) { - adt = BKE_animdata_add_id(id); + adt = BKE_animdata_ensure_id(id); } if (adt == NULL) { /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */ diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 864d97c9ea9..0a499232ba9 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -142,7 +142,7 @@ bAction *ED_id_action_ensure(Main *bmain, ID *id) /* init animdata if none available yet */ adt = BKE_animdata_from_id(id); if (adt == NULL) { - adt = BKE_animdata_add_id(id); + adt = BKE_animdata_ensure_id(id); } if (adt == NULL) { /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */ diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c index 034378399b9..6af033f3cf2 100644 --- a/source/blender/editors/animation/time_scrub_ui.c +++ b/source/blender/editors/animation/time_scrub_ui.c @@ -109,7 +109,7 @@ static void draw_current_frame(const Scene *scene, 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, BKE_scene_frame_get(scene)); + const float subframe_x = UI_view2d_view_to_region_x(v2d, BKE_scene_ctime_get(scene)); GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index fc9191967f8..ec5c665402b 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -478,7 +478,7 @@ void ED_object_vgroup_calc_from_armature(ReportList *reports, bArmature *arm = par->data; if (mode == ARM_GROUPS_NAME) { - const int defbase_tot = BLI_listbase_count(&ob->defbase); + const int defbase_tot = BKE_object_defgroup_count(ob); int defbase_add; /* Traverse the bone list, trying to create empty vertex * groups corresponding to the bone. diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c index 725945f8edc..832e75b2a8b 100644 --- a/source/blender/editors/armature/editarmature_undo.c +++ b/source/blender/editors/armature/editarmature_undo.c @@ -206,7 +206,7 @@ static void armature_undosys_step_decode(struct bContext *C, } undoarm_to_editarm(&elem->data, arm); arm->needs_flush_to_id = 1; - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + DEG_id_tag_update(&arm->id, ID_RECALC_GEOMETRY); } /* The first element is always active */ diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c index 88f6398567d..210411c6eb5 100644 --- a/source/blender/editors/curve/editcurve_undo.c +++ b/source/blender/editors/curve/editcurve_undo.c @@ -267,7 +267,7 @@ static void curve_undosys_step_decode(struct bContext *C, } undocurve_to_editcurve(bmain, &elem->data, obedit->data, &obedit->shapenr); cu->editnurb->needs_flush_to_id = 1; - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY); } /* The first element is always active */ diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index b61506d9346..6eaf8971eb0 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -379,7 +379,7 @@ static void font_undosys_step_decode(struct bContext *C, Curve *cu = obedit->data; undofont_to_editfont(&us->data, cu); - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY); ED_undo_object_set_active_or_warn( CTX_data_scene(C), CTX_data_view_layer(C), obedit, us_p->name, &LOG); diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c index d8734c4ae6b..8d60ef3ed12 100644 --- a/source/blender/editors/gpencil/gpencil_add_monkey.c +++ b/source/blender/editors/gpencil/gpencil_add_monkey.c @@ -39,6 +39,32 @@ #include "ED_gpencil.h" +/** + * Populate stroke with point data from data buffers. + * \param gps: Grease pencil stroke + * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values. + * \param totpoints: Total of points + * \param mat: 4x4 transform matrix to transform points into the right coordinate space. + */ +void ED_gpencil_stroke_init_data(bGPDstroke *gps, + const float *array, + const int totpoints, + const float mat[4][4]) +{ + for (int i = 0; i < totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + const int x = GP_PRIM_DATABUF_SIZE * i; + + pt->x = array[x]; + pt->y = array[x + 1]; + pt->z = array[x + 2]; + mul_m4_v3(mat, &pt->x); + + pt->pressure = array[x + 3]; + pt->strength = array[x + 4]; + } +} + /* Definition of the most important info from a color */ typedef struct ColorTemplate { const char *name; @@ -847,115 +873,115 @@ void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4]) /* generate strokes */ gps = BKE_gpencil_stroke_add(frameFills, color_Skin, 270, 75, false); - BKE_gpencil_stroke_add_points(gps, data0, 270, mat); + ED_gpencil_stroke_init_data(gps, data0, 270, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 33, 60, false); - BKE_gpencil_stroke_add_points(gps, data1, 33, mat); + ED_gpencil_stroke_init_data(gps, data1, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 60, false); - BKE_gpencil_stroke_add_points(gps, data2, 18, mat); + ED_gpencil_stroke_init_data(gps, data2, 18, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 64, 60, false); - BKE_gpencil_stroke_add_points(gps, data3, 64, mat); + ED_gpencil_stroke_init_data(gps, data3, 64, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 33, 60, false); - BKE_gpencil_stroke_add_points(gps, data4, 33, mat); + ED_gpencil_stroke_init_data(gps, data4, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 64, 60, false); - BKE_gpencil_stroke_add_points(gps, data5, 64, mat); + ED_gpencil_stroke_init_data(gps, data5, 64, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 33, 60, false); - BKE_gpencil_stroke_add_points(gps, data6, 33, mat); + ED_gpencil_stroke_init_data(gps, data6, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 18, 40, false); - BKE_gpencil_stroke_add_points(gps, data7, 18, mat); + ED_gpencil_stroke_init_data(gps, data7, 18, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Eyes, 49, 60, false); - BKE_gpencil_stroke_add_points(gps, data8, 49, mat); + ED_gpencil_stroke_init_data(gps, data8, 49, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 33, 60, false); - BKE_gpencil_stroke_add_points(gps, data9, 33, mat); + ED_gpencil_stroke_init_data(gps, data9, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Eyes, 49, 60, false); - BKE_gpencil_stroke_add_points(gps, data10, 49, mat); + ED_gpencil_stroke_init_data(gps, data10, 49, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 40, false); - BKE_gpencil_stroke_add_points(gps, data11, 18, mat); + ED_gpencil_stroke_init_data(gps, data11, 18, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 40, false); - BKE_gpencil_stroke_add_points(gps, data12, 18, mat); + ED_gpencil_stroke_init_data(gps, data12, 18, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); - BKE_gpencil_stroke_add_points(gps, data13, 33, mat); + ED_gpencil_stroke_init_data(gps, data13, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); - BKE_gpencil_stroke_add_points(gps, data14, 33, mat); + ED_gpencil_stroke_init_data(gps, data14, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 65, 60, false); - BKE_gpencil_stroke_add_points(gps, data15, 65, mat); + ED_gpencil_stroke_init_data(gps, data15, 65, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 34, 60, false); - BKE_gpencil_stroke_add_points(gps, data16, 34, mat); + ED_gpencil_stroke_init_data(gps, data16, 34, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); - BKE_gpencil_stroke_add_points(gps, data17, 33, mat); + ED_gpencil_stroke_init_data(gps, data17, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 40, false); - BKE_gpencil_stroke_add_points(gps, data18, 33, mat); + ED_gpencil_stroke_init_data(gps, data18, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 34, 40, false); - BKE_gpencil_stroke_add_points(gps, data19, 34, mat); + ED_gpencil_stroke_init_data(gps, data19, 34, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); - BKE_gpencil_stroke_add_points(gps, data20, 33, mat); + ED_gpencil_stroke_init_data(gps, data20, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 64, 60, false); - BKE_gpencil_stroke_add_points(gps, data21, 64, mat); + ED_gpencil_stroke_init_data(gps, data21, 64, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Pupils, 26, 60, false); - BKE_gpencil_stroke_add_points(gps, data22, 26, mat); + ED_gpencil_stroke_init_data(gps, data22, 26, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Pupils, 26, 60, false); - BKE_gpencil_stroke_add_points(gps, data23, 26, mat); + ED_gpencil_stroke_init_data(gps, data23, 26, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); - BKE_gpencil_stroke_add_points(gps, data24, 33, mat); + ED_gpencil_stroke_init_data(gps, data24, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 18, 40, false); - BKE_gpencil_stroke_add_points(gps, data25, 18, mat); + ED_gpencil_stroke_init_data(gps, data25, 18, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 18, 40, false); - BKE_gpencil_stroke_add_points(gps, data26, 18, mat); + ED_gpencil_stroke_init_data(gps, data26, 18, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); - BKE_gpencil_stroke_add_points(gps, data27, 33, mat); + ED_gpencil_stroke_init_data(gps, data27, 33, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); /* update depsgraph */ diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c index e95496b51ee..73c4e64dd9a 100644 --- a/source/blender/editors/gpencil/gpencil_add_stroke.c +++ b/source/blender/editors/gpencil/gpencil_add_stroke.c @@ -235,7 +235,7 @@ void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4]) /* generate stroke */ gps = BKE_gpencil_stroke_add(frame_lines, color_black, 175, 75, false); - BKE_gpencil_stroke_add_points(gps, data0, 175, mat); + ED_gpencil_stroke_init_data(gps, data0, 175, mat); BKE_gpencil_stroke_geometry_update(gpd, gps); /* update depsgraph */ diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c index 24fb0873a86..c800851bb08 100644 --- a/source/blender/editors/gpencil/gpencil_armature.c +++ b/source/blender/editors/gpencil/gpencil_armature.c @@ -384,7 +384,7 @@ static void gpencil_add_verts_to_dgroups( /* loop groups and assign weight */ for (j = 0; j < numbones; j++) { - int def_nr = BLI_findindex(&ob->defbase, dgrouplist[j]); + int def_nr = BLI_findindex(&gpd->vertex_group_names, dgrouplist[j]); if (def_nr < 0) { continue; } @@ -454,7 +454,7 @@ static void gpencil_object_vgroup_calc_from_armature(const bContext *C, bArmature *arm = ob_arm->data; /* always create groups */ - const int defbase_tot = BLI_listbase_count(&ob->defbase); + const int defbase_tot = BKE_object_defgroup_count(ob); int defbase_add; /* Traverse the bone list, trying to create empty vertex * groups corresponding to the bone. diff --git a/source/blender/editors/gpencil/gpencil_bake_animation.c b/source/blender/editors/gpencil/gpencil_bake_animation.c index 1a5e2950e09..2d299230124 100644 --- a/source/blender/editors/gpencil/gpencil_bake_animation.c +++ b/source/blender/editors/gpencil/gpencil_bake_animation.c @@ -38,6 +38,7 @@ #include "BKE_duplilist.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" +#include "BKE_gpencil_modifier.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" @@ -303,8 +304,12 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op float matrix[4][4]; BKE_gpencil_layer_transform_matrix_get(depsgraph, elem->ob, gpl_src, matrix); + /* Apply time modifier. */ + int remap_cfra = BKE_gpencil_time_modifier_cfra( + depsgraph, scene, elem->ob, gpl_src, CFRA, false); /* Duplicate frame. */ - bGPDframe *gpf_src = BKE_gpencil_layer_frame_get(gpl_src, CFRA, GP_GETFRAME_USE_PREV); + bGPDframe *gpf_src = BKE_gpencil_layer_frame_get( + gpl_src, remap_cfra, GP_GETFRAME_USE_PREV); if (gpf_src == NULL) { continue; } diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index e272f46d13d..b1e57079d28 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -2165,7 +2165,9 @@ static bool gpencil_vertex_group_poll(bContext *C) Object *ob = CTX_data_active_object(C); if ((ob) && (ob->type == OB_GPENCIL)) { - if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) { + const bGPdata *gpd = (const bGPdata *)ob->data; + if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && + !BLI_listbase_is_empty(&gpd->vertex_group_names)) { if (ELEM(ob->mode, OB_MODE_EDIT_GPENCIL, OB_MODE_SCULPT_GPENCIL)) { return true; } @@ -2180,7 +2182,9 @@ static bool gpencil_vertex_group_weight_poll(bContext *C) Object *ob = CTX_data_active_object(C); if ((ob) && (ob->type == OB_GPENCIL)) { - if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) { + const bGPdata *gpd = (const bGPdata *)ob->data; + if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && + !BLI_listbase_is_empty(&gpd->vertex_group_names)) { if (ob->mode == OB_MODE_WEIGHT_GPENCIL) { return true; } @@ -2333,6 +2337,7 @@ static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); + bGPdata *gpd = ob->data; /* sanity checks */ if (ELEM(NULL, ts, ob, ob->data)) { @@ -2340,8 +2345,9 @@ static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *op) } MDeformVert *dvert; - const int def_nr = ob->actdef - 1; - bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr); + const int def_nr = gpd->vertex_group_active_index - 1; + + bDeformGroup *defgroup = BLI_findlink(&gpd->vertex_group_names, def_nr); if (defgroup == NULL) { return OPERATOR_CANCELLED; } @@ -2373,7 +2379,6 @@ static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* notifiers */ - bGPdata *gpd = ob->data; DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); @@ -2403,14 +2408,15 @@ static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op) ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); + bGPdata *gpd = ob->data; /* sanity checks */ if (ELEM(NULL, ts, ob, ob->data)) { return OPERATOR_CANCELLED; } - const int def_nr = ob->actdef - 1; - bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr); + const int def_nr = gpd->vertex_group_active_index - 1; + bDeformGroup *defgroup = BLI_findlink(&gpd->vertex_group_names, def_nr); if (defgroup == NULL) { return OPERATOR_CANCELLED; } @@ -2470,7 +2476,6 @@ static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* notifiers */ - bGPdata *gpd = ob->data; DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); @@ -2500,6 +2505,7 @@ static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); + bGPdata *gpd = ob->data; /* sanity checks */ if (ELEM(NULL, ts, ob, ob->data)) { @@ -2508,8 +2514,8 @@ static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op) MDeformVert *dvert = NULL; MDeformWeight *dw = NULL; - const int def_nr = ob->actdef - 1; - bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr); + const int def_nr = gpd->vertex_group_active_index - 1; + bDeformGroup *defgroup = BLI_findlink(&gpd->vertex_group_names, def_nr); if (defgroup == NULL) { return OPERATOR_CANCELLED; } @@ -2548,7 +2554,6 @@ static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* notifiers */ - bGPdata *gpd = ob->data; DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); @@ -2576,6 +2581,7 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op) ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); bool lock_active = RNA_boolean_get(op->ptr, "lock_active"); + bGPdata *gpd = ob->data; /* sanity checks */ if (ELEM(NULL, ts, ob, ob->data)) { @@ -2585,8 +2591,8 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op) bDeformGroup *defgroup = NULL; MDeformVert *dvert = NULL; MDeformWeight *dw = NULL; - const int def_nr = ob->actdef - 1; - const int defbase_tot = BLI_listbase_count(&ob->defbase); + const int def_nr = gpd->vertex_group_active_index - 1; + const int defbase_tot = BLI_listbase_count(&gpd->vertex_group_names); if (defbase_tot == 0) { return OPERATOR_CANCELLED; } @@ -2603,7 +2609,7 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op) for (int i = 0; i < gps->totpoints; i++) { dvert = &gps->dvert[i]; for (int v = 0; v < defbase_tot; v++) { - defgroup = BLI_findlink(&ob->defbase, v); + defgroup = BLI_findlink(&gpd->vertex_group_names, v); /* skip NULL or locked groups */ if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) { continue; @@ -2629,7 +2635,7 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op) dvert = &gps->dvert[i]; for (int v = 0; v < defbase_tot; v++) { - defgroup = BLI_findlink(&ob->defbase, v); + defgroup = BLI_findlink(&gpd->vertex_group_names, v); /* skip NULL or locked groups */ if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) { continue; @@ -2653,7 +2659,6 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* notifiers */ - bGPdata *gpd = ob->data; DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); @@ -2769,7 +2774,6 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *ob_active = CTX_data_active_object(C); - bGPdata *gpd_dst = NULL; bool ok = false; /* Ensure we're in right mode and that the active object is correct */ @@ -2807,7 +2811,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - gpd_dst = ob_active->data; + bGPdata *gpd_dst = ob_active->data; Object *ob_dst = ob_active; /* loop and join all data */ @@ -2828,11 +2832,11 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) /* copy vertex groups to the base one's */ int old_idx = 0; - LISTBASE_FOREACH (bDeformGroup *, dg, &ob_iter->defbase) { + LISTBASE_FOREACH (bDeformGroup *, dg, &gpd_src->vertex_group_names) { bDeformGroup *vgroup = MEM_dupallocN(dg); - int idx = BLI_listbase_count(&ob_active->defbase); + int idx = BLI_listbase_count(&gpd_dst->vertex_group_names); BKE_object_defgroup_unique_name(vgroup, ob_active); - BLI_addtail(&ob_active->defbase, vgroup); + BLI_addtail(&gpd_dst->vertex_group_names, vgroup); /* update vertex groups in strokes in original data */ LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd->layers) { LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_src->frames) { @@ -2852,8 +2856,9 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) } old_idx++; } - if (ob_active->defbase.first && ob_active->actdef == 0) { - ob_active->actdef = 1; + if (!BLI_listbase_is_empty(&gpd_dst->vertex_group_names) && + gpd_dst->vertex_group_active_index == 0) { + gpd_dst->vertex_group_active_index = 1; } /* add missing materials reading source materials and checking in destination object */ diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 091ff2c16b0..67e1bd5294b 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1522,8 +1522,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) pt = gps->points; point2D = (tGPspoint *)tgpf->sbuffer; - const int def_nr = tgpf->ob->actdef - 1; - const bool have_weight = (bool)BLI_findlink(&tgpf->ob->defbase, def_nr); + const int def_nr = tgpf->gpd->vertex_group_active_index - 1; + const bool have_weight = (bool)BLI_findlink(&tgpf->gpd->vertex_group_names, def_nr); if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) { BKE_gpencil_dvert_ensure(gps); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 67d4b7726b5..d6f6dbb2b10 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -938,8 +938,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) Depsgraph *depsgraph = p->depsgraph; Object *obact = (Object *)p->ownerPtr.data; RegionView3D *rv3d = p->region->regiondata; - const int def_nr = obact->actdef - 1; - const bool have_weight = (bool)BLI_findlink(&obact->defbase, def_nr); + const int def_nr = gpd->vertex_group_active_index - 1; + const bool have_weight = (bool)BLI_findlink(&gpd->vertex_group_names, def_nr); const char align_flag = ts->gpencil_v3d_align; const bool is_depth = (bool)(align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)); const bool is_lock_axis_view = (bool)(ts->gp_sculpt.lock_axis == 0); diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index a2b4e5dee64..78eaab01b1a 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -1315,8 +1315,9 @@ static void gpencil_primitive_interaction_end(bContext *C, Brush *brush = tgpi->brush; BrushGpencilSettings *brush_settings = brush->gpencil_settings; - const int def_nr = tgpi->ob->actdef - 1; - const bool have_weight = (bool)BLI_findlink(&tgpi->ob->defbase, def_nr); + const int def_nr = tgpi->gpd->vertex_group_active_index - 1; + const ListBase *defbase = BKE_object_defgroup_list(tgpi->ob); + const bool have_weight = (bool)BLI_findlink(defbase, def_nr); /* return to normal cursor and header status */ ED_workspace_status_text(C, NULL); diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index efd0f86df03..462462cf341 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -1177,8 +1177,8 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op) gso->object = ob; if (ob) { invert_m4_m4(gso->inv_mat, ob->obmat); - gso->vrgroup = ob->actdef - 1; - if (!BLI_findlink(&ob->defbase, gso->vrgroup)) { + gso->vrgroup = gso->gpd->vertex_group_active_index - 1; + if (!BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup)) { gso->vrgroup = -1; } /* Check if some modifier can transform the stroke. */ diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index e6488cfe454..ba3d3b584d7 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -1600,8 +1600,8 @@ void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight) { bGPdata *gpd = (bGPdata *)ob->data; const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - const int def_nr = ob->actdef - 1; - if (!BLI_findlink(&ob->defbase, def_nr)) { + const int def_nr = gpd->vertex_group_active_index - 1; + if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) { return; } @@ -1654,8 +1654,8 @@ void ED_gpencil_vgroup_remove(bContext *C, Object *ob) { bGPdata *gpd = (bGPdata *)ob->data; const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - const int def_nr = ob->actdef - 1; - if (!BLI_findlink(&ob->defbase, def_nr)) { + const int def_nr = gpd->vertex_group_active_index - 1; + if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) { return; } @@ -1707,8 +1707,8 @@ void ED_gpencil_vgroup_select(bContext *C, Object *ob) { bGPdata *gpd = (bGPdata *)ob->data; const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - const int def_nr = ob->actdef - 1; - if (!BLI_findlink(&ob->defbase, def_nr)) { + const int def_nr = gpd->vertex_group_active_index - 1; + if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) { return; } @@ -1762,8 +1762,8 @@ void ED_gpencil_vgroup_deselect(bContext *C, Object *ob) { bGPdata *gpd = (bGPdata *)ob->data; const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - const int def_nr = ob->actdef - 1; - if (!BLI_findlink(&ob->defbase, def_nr)) { + const int def_nr = gpd->vertex_group_active_index - 1; + if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) { return; } diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c index 6d953a4d8cf..d14322e12b5 100644 --- a/source/blender/editors/gpencil/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil/gpencil_weight_paint.c @@ -252,7 +252,7 @@ static bool brush_draw_apply(tGP_BrushWeightpaintData *gso, } } else { - bDeformGroup *defgroup = BLI_findlink(&gso->object->defbase, gso->vrgroup); + bDeformGroup *defgroup = BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup); if (defgroup->flag & DG_LOCK_WEIGHT) { return false; } @@ -308,8 +308,8 @@ static bool gpencil_weightpaint_brush_init(bContext *C, wmOperator *op) gso->scene = scene; gso->object = ob; if (ob) { - gso->vrgroup = ob->actdef - 1; - if (!BLI_findlink(&ob->defbase, gso->vrgroup)) { + gso->vrgroup = gso->gpd->vertex_group_active_index - 1; + if (!BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup)) { gso->vrgroup = -1; } } diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 59b5a1abaa6..8a8d91a570c 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -251,6 +251,13 @@ void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y); /* ----------- Add Primitive Utilities -------------- */ +/* Number of values defining each point in the built-in data buffers for primitives. */ +#define GP_PRIM_DATABUF_SIZE 5 +void ED_gpencil_stroke_init_data(struct bGPDstroke *gps, + const float *array, + const int totpoints, + const float mat[4][4]); + void ED_gpencil_create_blank(struct bContext *C, struct Object *ob, float mat[4][4]); void ED_gpencil_create_monkey(struct bContext *C, struct Object *ob, float mat[4][4]); void ED_gpencil_create_stroke(struct bContext *C, struct Object *ob, float mat[4][4]); diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 0493832c06f..673f629d6ef 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -468,7 +468,7 @@ bool fcurve_is_changed(struct PointerRNA ptr, * Checks whether a keyframe exists for the given ID-block one the given frame. * - It is recommended to call this method over the other keyframe-checkers directly, * in case some detail of the implementation changes... - * - frame: the value of this is quite often result of #BKE_scene_frame_get() + * - frame: the value of this is quite often result of #BKE_scene_ctime_get() */ bool id_frame_has_keyframe(struct ID *id, float frame, short filter); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 667540b8f63..2b73194afb2 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -86,7 +86,7 @@ void EDBM_mesh_clear(struct BMEditMesh *em); void EDBM_selectmode_to_scene(struct bContext *C); void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index); -void EDBM_mesh_free(struct BMEditMesh *em); +void EDBM_mesh_free_data(struct BMEditMesh *em); void EDBM_mesh_load_ex(struct Main *bmain, struct Object *ob, bool free_data); void EDBM_mesh_load(struct Main *bmain, struct Object *ob); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 6901176a587..802c175492f 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -58,6 +58,7 @@ struct bNodeTree; struct bScreen; struct rctf; struct rcti; +struct uiBlockInteraction_Handle; struct uiButSearch; struct uiFontStyle; struct uiList; @@ -514,6 +515,54 @@ typedef int (*uiButPushedStateFunc)(struct uiBut *but, const void *arg); typedef void (*uiBlockHandleFunc)(struct bContext *C, void *arg, int event); +/* -------------------------------------------------------------------- */ +/** \name Custom Interaction + * + * Sometimes it's useful to create data that remains available + * while the user interacts with a button. + * + * A common case is dragging a number button or slider + * however this could be used in other cases too. + * \{ */ + +struct uiBlockInteraction_Params { + /** + * When true, this interaction is not modal + * (user clicking on a number button arrows or pasting a value for example). + */ + bool is_click; + /** + * Array of unique event ID's (values from #uiBut.retval). + * There may be more than one for multi-button editing (see #UI_BUT_DRAG_MULTI). + */ + int *unique_retval_ids; + uint unique_retval_ids_len; +}; + +/** Returns 'user_data', freed by #uiBlockInteractionEndFn. */ +typedef void *(*uiBlockInteractionBeginFn)(struct bContext *C, + const struct uiBlockInteraction_Params *params, + void *arg1); +typedef void (*uiBlockInteractionEndFn)(struct bContext *C, + const struct uiBlockInteraction_Params *params, + void *arg1, + void *user_data); +typedef void (*uiBlockInteractionUpdateFn)(struct bContext *C, + const struct uiBlockInteraction_Params *params, + void *arg1, + void *user_data); + +typedef struct uiBlockInteraction_CallbackData { + uiBlockInteractionBeginFn begin_fn; + uiBlockInteractionEndFn end_fn; + uiBlockInteractionUpdateFn update_fn; + void *arg1; +} uiBlockInteraction_CallbackData; + +void UI_block_interaction_set(uiBlock *block, uiBlockInteraction_CallbackData *callbacks); + +/** \} */ + /* Menu Callbacks */ typedef void (*uiMenuCreateFunc)(struct bContext *C, struct uiLayout *layout, void *arg1); diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index de0d5a4a3d7..2a7611eabb1 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -560,7 +560,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0; /* Set the (button_pointer, button_prop) - * and pointer data for Python access to the hovered ui element. */ + * and pointer data for Python access to the hovered UI element. */ uiLayoutSetContextFromBut(layout, but); /* Keyframes */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 743f646d4df..0e45970a165 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -35,10 +35,12 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "BLI_array_utils.h" #include "BLI_linklist.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rect.h" +#include "BLI_sort_utils.h" #include "BLI_string.h" #include "BLI_string_cursor_utf8.h" #include "BLI_string_utf8.h" @@ -170,6 +172,20 @@ static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but static void ui_textedit_string_set(uiBut *but, struct uiHandleButtonData *data, const char *str); static void button_tooltip_timer_reset(bContext *C, uiBut *but); +static void ui_block_interaction_begin_ensure(bContext *C, + uiBlock *block, + struct uiHandleButtonData *data, + const bool is_click); +static struct uiBlockInteraction_Handle *ui_block_interaction_begin(struct bContext *C, + uiBlock *block, + const bool is_click); +static void ui_block_interaction_end(struct bContext *C, + uiBlockInteraction_CallbackData *callbacks, + struct uiBlockInteraction_Handle *interaction); +static void ui_block_interaction_update(struct bContext *C, + uiBlockInteraction_CallbackData *callbacks, + struct uiBlockInteraction_Handle *interaction); + #ifdef USE_KEYNAV_LIMIT static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event); static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEvent *event); @@ -225,6 +241,19 @@ typedef enum uiMenuScrollType { MENU_SCROLL_BOTTOM, } uiMenuScrollType; +typedef struct uiBlockInteraction_Handle { + struct uiBlockInteraction_Params params; + void *user_data; + /** + * This is shared between #uiHandleButtonData and #uiAfterFunc, + * the last user runs the end callback and frees the data. + * + * This is needed as the order of freeing changes depending on + * accepting/canceling the operation. + */ + int user_count; +} uiBlockInteraction_Handle; + #ifdef USE_ALLSELECT /* Unfortunately there's no good way handle more generally: @@ -430,6 +459,8 @@ typedef struct uiHandleButtonData { uiSelectContextStore select_others; #endif + struct uiBlockInteraction_Handle *custom_interaction_handle; + /* Text field undo. */ struct uiUndoStack_Text *undo_stack_text; @@ -471,6 +502,9 @@ typedef struct uiAfterFunc { void *search_arg; uiFreeArgFunc search_arg_free_fn; + uiBlockInteraction_CallbackData custom_interaction_callbacks; + uiBlockInteraction_Handle *custom_interaction_handle; + bContextStore *context; char undostr[BKE_UNDO_STR_MAX]; @@ -769,72 +803,95 @@ static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but) (block->handle && block->handle->popup_op)); } +/** + * These functions are postponed and only executed after all other + * handling is done, i.e. menus are closed, in order to avoid conflicts + * with these functions removing the buttons we are working with. + */ static void ui_apply_but_func(bContext *C, uiBut *but) { uiBlock *block = but->block; + if (!ui_afterfunc_check(block, but)) { + return; + } - /* these functions are postponed and only executed after all other - * handling is done, i.e. menus are closed, in order to avoid conflicts - * with these functions removing the buttons we are working with */ - - if (ui_afterfunc_check(block, but)) { - uiAfterFunc *after = ui_afterfunc_new(); + uiAfterFunc *after = ui_afterfunc_new(); - if (but->func && ELEM(but, but->func_arg1, but->func_arg2)) { - /* exception, this will crash due to removed button otherwise */ - but->func(C, but->func_arg1, but->func_arg2); - } - else { - after->func = but->func; - } + if (but->func && ELEM(but, but->func_arg1, but->func_arg2)) { + /* exception, this will crash due to removed button otherwise */ + but->func(C, but->func_arg1, but->func_arg2); + } + else { + after->func = but->func; + } - after->func_arg1 = but->func_arg1; - after->func_arg2 = but->func_arg2; + after->func_arg1 = but->func_arg1; + after->func_arg2 = but->func_arg2; - after->funcN = but->funcN; - after->func_argN = (but->func_argN) ? MEM_dupallocN(but->func_argN) : NULL; + after->funcN = but->funcN; + after->func_argN = (but->func_argN) ? MEM_dupallocN(but->func_argN) : NULL; - after->rename_func = but->rename_func; - after->rename_arg1 = but->rename_arg1; - after->rename_orig = but->rename_orig; /* needs free! */ + after->rename_func = but->rename_func; + after->rename_arg1 = but->rename_arg1; + after->rename_orig = but->rename_orig; /* needs free! */ - after->handle_func = block->handle_func; - after->handle_func_arg = block->handle_func_arg; - after->retval = but->retval; + after->handle_func = block->handle_func; + after->handle_func_arg = block->handle_func_arg; + after->retval = but->retval; - if (but->type == UI_BTYPE_BUT_MENU) { - after->butm_func = block->butm_func; - after->butm_func_arg = block->butm_func_arg; - after->a2 = but->a2; - } + if (but->type == UI_BTYPE_BUT_MENU) { + after->butm_func = block->butm_func; + after->butm_func_arg = block->butm_func_arg; + after->a2 = but->a2; + } - if (block->handle) { - after->popup_op = block->handle->popup_op; - } + if (block->handle) { + after->popup_op = block->handle->popup_op; + } - after->optype = but->optype; - after->opcontext = but->opcontext; - after->opptr = but->opptr; + after->optype = but->optype; + after->opcontext = but->opcontext; + after->opptr = but->opptr; - after->rnapoin = but->rnapoin; - after->rnaprop = but->rnaprop; + after->rnapoin = but->rnapoin; + after->rnaprop = but->rnaprop; - if (but->type == UI_BTYPE_SEARCH_MENU) { - uiButSearch *search_but = (uiButSearch *)but; - after->search_arg_free_fn = search_but->arg_free_fn; - after->search_arg = search_but->arg; - search_but->arg_free_fn = NULL; - search_but->arg = NULL; - } + if (but->type == UI_BTYPE_SEARCH_MENU) { + uiButSearch *search_but = (uiButSearch *)but; + after->search_arg_free_fn = search_but->arg_free_fn; + after->search_arg = search_but->arg; + search_but->arg_free_fn = NULL; + search_but->arg = NULL; + } - if (but->context) { - after->context = CTX_store_copy(but->context); + if (but->active != NULL) { + uiHandleButtonData *data = but->active; + if (data->custom_interaction_handle != NULL) { + after->custom_interaction_callbacks = block->custom_interaction_callbacks; + after->custom_interaction_handle = data->custom_interaction_handle; + + /* Ensure this callback runs once and last. */ + uiAfterFunc *after_prev = after->prev; + if (after_prev && + (after_prev->custom_interaction_handle == data->custom_interaction_handle)) { + after_prev->custom_interaction_handle = NULL; + memset(&after_prev->custom_interaction_callbacks, + 0x0, + sizeof(after_prev->custom_interaction_callbacks)); + } + else { + after->custom_interaction_handle->user_count++; + } } + } - but->optype = NULL; - but->opcontext = 0; - but->opptr = NULL; + if (but->context) { + after->context = CTX_store_copy(but->context); } + + but->optype = NULL; + but->opcontext = 0; + but->opptr = NULL; } /* typically call ui_apply_but_undo(), ui_apply_but_autokey() */ @@ -997,6 +1054,18 @@ static void ui_apply_but_funcs_after(bContext *C) after.search_arg_free_fn(after.search_arg); } + if (after.custom_interaction_handle != NULL) { + after.custom_interaction_handle->user_count--; + BLI_assert(after.custom_interaction_handle->user_count >= 0); + if (after.custom_interaction_handle->user_count == 0) { + ui_block_interaction_update( + C, &after.custom_interaction_callbacks, after.custom_interaction_handle); + ui_block_interaction_end( + C, &after.custom_interaction_callbacks, after.custom_interaction_handle); + } + after.custom_interaction_handle = NULL; + } + ui_afterfunc_update_preferences_dirty(&after); if (after.undostr[0]) { @@ -2283,6 +2352,11 @@ static void ui_apply_but( uiButCurveProfile *but_profile = (uiButCurveProfile *)but; but_profile->edit_profile = editprofile; } + + if (data->custom_interaction_handle != NULL) { + ui_block_interaction_update( + C, &block->custom_interaction_callbacks, data->custom_interaction_handle); + } } /** \} */ @@ -4852,6 +4926,8 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but, return changed; } + ui_block_interaction_begin_ensure(but->block->evil_C, but->block, data, false); + if (ui_but_is_cursor_warp(but)) { const float softmin = but->softmin; const float softmax = but->softmax; @@ -5362,6 +5438,8 @@ static bool ui_numedit_but_SLI(uiBut *but, return changed; } + ui_block_interaction_begin_ensure(but->block->evil_C, but->block, data, false); + const PropertyScaleType scale_type = ui_but_scale_type(but); softmin = but->softmin; @@ -8239,6 +8317,16 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s but->flag &= ~UI_SELECT; } + if (state == BUTTON_STATE_TEXT_EDITING) { + ui_block_interaction_begin_ensure(C, but->block, data, true); + } + else if (state == BUTTON_STATE_EXIT) { + if (data->state == BUTTON_STATE_NUM_EDITING) { + /* This happens on pasting values for example. */ + ui_block_interaction_begin_ensure(C, but->block, data, true); + } + } + data->state = state; if (state != BUTTON_STATE_EXIT) { @@ -8467,6 +8555,21 @@ static void button_activate_exit( ED_region_tag_redraw_no_rebuild(data->region); ED_region_tag_refresh_ui(data->region); + if ((but->flag & UI_BUT_DRAG_MULTI) == 0) { + if (data->custom_interaction_handle != NULL) { + /* Should only set when the button is modal. */ + BLI_assert(but->active != NULL); + data->custom_interaction_handle->user_count--; + + BLI_assert(data->custom_interaction_handle->user_count >= 0); + if (data->custom_interaction_handle->user_count == 0) { + ui_block_interaction_end( + C, &but->block->custom_interaction_callbacks, data->custom_interaction_handle); + } + data->custom_interaction_handle = NULL; + } + } + /* clean up button */ if (but->active) { MEM_freeN(but->active); @@ -11314,3 +11417,100 @@ bool UI_but_active_drop_color(bContext *C) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name UI Block Interaction API + * \{ */ + +void UI_block_interaction_set(uiBlock *block, uiBlockInteraction_CallbackData *callbacks) +{ + block->custom_interaction_callbacks = *callbacks; +} + +static uiBlockInteraction_Handle *ui_block_interaction_begin(bContext *C, + uiBlock *block, + const bool is_click) +{ + BLI_assert(block->custom_interaction_callbacks.begin_fn != NULL); + uiBlockInteraction_Handle *interaction = MEM_callocN(sizeof(*interaction), __func__); + + int unique_retval_ids_len = 0; + LISTBASE_FOREACH (uiBut *, but, &block->buttons) { + if (but->active || (but->flag & UI_BUT_DRAG_MULTI)) { + unique_retval_ids_len++; + } + } + + int *unique_retval_ids = MEM_mallocN(sizeof(*unique_retval_ids) * unique_retval_ids_len, + __func__); + unique_retval_ids_len = 0; + LISTBASE_FOREACH (uiBut *, but, &block->buttons) { + if (but->active || (but->flag & UI_BUT_DRAG_MULTI)) { + unique_retval_ids[unique_retval_ids_len++] = but->retval; + } + } + + if (unique_retval_ids_len > 1) { + qsort(unique_retval_ids, unique_retval_ids_len, sizeof(int), BLI_sortutil_cmp_int); + unique_retval_ids_len = BLI_array_deduplicate_ordered(unique_retval_ids, + unique_retval_ids_len); + unique_retval_ids = MEM_reallocN(unique_retval_ids, + sizeof(*unique_retval_ids) * unique_retval_ids_len); + } + + interaction->params.is_click = is_click; + interaction->params.unique_retval_ids = unique_retval_ids; + interaction->params.unique_retval_ids_len = unique_retval_ids_len; + + interaction->user_data = block->custom_interaction_callbacks.begin_fn( + C, &interaction->params, block->custom_interaction_callbacks.arg1); + return interaction; +} + +static void ui_block_interaction_end(bContext *C, + uiBlockInteraction_CallbackData *callbacks, + uiBlockInteraction_Handle *interaction) +{ + BLI_assert(callbacks->end_fn != NULL); + callbacks->end_fn(C, &interaction->params, callbacks->arg1, interaction->user_data); + MEM_freeN(interaction->params.unique_retval_ids); + MEM_freeN(interaction); +} + +static void ui_block_interaction_update(bContext *C, + uiBlockInteraction_CallbackData *callbacks, + uiBlockInteraction_Handle *interaction) +{ + BLI_assert(callbacks->update_fn != NULL); + callbacks->update_fn(C, &interaction->params, callbacks->arg1, interaction->user_data); +} + +/** + * \note #ui_block_interaction_begin cannot be called when setting the button state + * (e.g. #BUTTON_STATE_NUM_EDITING) for the following reasons. + * + * - Other buttons may still be activated using #UI_BUT_DRAG_MULTI + * which is necessary before gathering all the #uiBut.retval values to initialize + * #uiBlockInteraction_Params.unique_retval_ids. + * - When clicking on a number button it's not known if the event is a click or a drag. + * + * Instead, it must be called immediately before the drag action begins. + */ +static void ui_block_interaction_begin_ensure(bContext *C, + uiBlock *block, + uiHandleButtonData *data, + const bool is_click) +{ + if (data->custom_interaction_handle) { + return; + } + if (block->custom_interaction_callbacks.begin_fn == NULL) { + return; + } + + uiBlockInteraction_Handle *interaction = ui_block_interaction_begin(C, block, is_click); + interaction->user_count = 1; + data->custom_interaction_handle = interaction; +} + +/** \} */ diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index a05afb6e542..40a9c67c630 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -511,6 +511,9 @@ struct uiBlock { uiBlockHandleFunc handle_func; void *handle_func_arg; + /** Custom interaction data. */ + uiBlockInteraction_CallbackData custom_interaction_callbacks; + /** Custom extra event handling. */ int (*block_event_func)(const struct bContext *C, struct uiBlock *, const struct wmEvent *); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index abebc09ace2..8b9539f1d33 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1411,7 +1411,7 @@ BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout) } /** - * Create ui items for enum items in \a item_array. + * Create UI items for enum items in \a item_array. * * A version of #uiItemsFullEnumO that takes pre-calculated item array. */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index e3608684114..9c17486aea4 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2399,8 +2399,8 @@ static eAutoPropButsReturn template_operator_property_buts_draw_single( op->type->ui((bContext *)C, op); op->layout = NULL; - /* UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too. We could - * allow ot.ui callback to return this, but not needed right now. */ + /* #UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too. + * We could allow #wmOperatorType.ui callback to return this, but not needed right now. */ } else { wmWindowManager *wm = CTX_wm_manager(C); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 7b2e0fec1d0..72847fb2476 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1377,8 +1377,6 @@ static int ui_but_draw_menu_icon(const uiBut *but) static void widget_draw_icon( const uiBut *but, BIFIconID icon, float alpha, const rcti *rect, const uchar mono_color[4]) { - float xs = 0.0f, ys = 0.0f; - if (but->flag & UI_BUT_ICON_PREVIEW) { GPU_blend(GPU_BLEND_ALPHA); widget_draw_preview(icon, alpha, rect); @@ -1420,6 +1418,7 @@ static void widget_draw_icon( if (icon && icon != ICON_BLANK1) { const float ofs = 1.0f / aspect; + float xs, ys; if (but->drawflag & UI_BUT_ICON_LEFT) { /* special case - icon_only pie buttons */ diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c index e73a02840c9..e6f190f335b 100644 --- a/source/blender/editors/lattice/editlattice_select.c +++ b/source/blender/editors/lattice/editlattice_select.c @@ -514,7 +514,7 @@ static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op) BPoint *bp; int a, tot; - if (BLI_listbase_is_empty(&obedit->defbase) || lt->dvert == NULL) { + if (BLI_listbase_is_empty(<->vertex_group_names) || lt->dvert == NULL) { continue; } diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c index d92a81179cc..23eaf991fd3 100644 --- a/source/blender/editors/lattice/editlattice_undo.c +++ b/source/blender/editors/lattice/editlattice_undo.c @@ -240,7 +240,7 @@ static void lattice_undosys_step_decode(struct bContext *C, } undolatt_to_editlatt(&elem->data, lt->editlatt); lt->editlatt->needs_flush_to_id = 1; - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + DEG_id_tag_update(<->id, ID_RECALC_GEOMETRY); } /* The first element is always active */ diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index 942fe143787..09b17acf56d 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -30,6 +30,7 @@ #include "BKE_context.h" #include "BKE_curve.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index 993905462db..cccfc7e934c 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -126,7 +126,7 @@ static int geometry_extract_apply(bContext *C, .calc_face_normal = true, })); - BMEditMesh *em = BKE_editmesh_create(bm, false); + BMEditMesh *em = BKE_editmesh_create(bm); /* Generate the tags for deleting geometry in the extracted object. */ tag_fn(bm, params); @@ -206,7 +206,7 @@ static int geometry_extract_apply(bContext *C, }), mesh); - BKE_editmesh_free(em); + BKE_editmesh_free_data(em); MEM_freeN(em); if (new_mesh->totvert == 0) { diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index 593545ddcef..30a453a32ee 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -29,6 +29,7 @@ #include "DNA_windowmanager_types.h" #ifdef WITH_FREESTYLE +# include "BKE_customdata.h" # include "DNA_meshdata_types.h" #endif diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 6753c235a8d..830c9abb41e 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -35,6 +35,8 @@ #include "BLI_utildefines_stack.h" #include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_layer.h" #include "BKE_report.h" @@ -4739,10 +4741,11 @@ static bool edbm_select_ungrouped_poll(bContext *C) BMEditMesh *em = BKE_editmesh_from_object(obedit); const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + const ListBase *defbase = BKE_object_defgroup_list(obedit); if ((em->selectmode & SCE_SELECT_VERTEX) == 0) { CTX_wm_operator_poll_msg_set(C, "Must be in vertex selection mode"); } - else if (BLI_listbase_is_empty(&obedit->defbase) || cd_dvert_offset == -1) { + else if (BLI_listbase_is_empty(defbase) || cd_dvert_offset == -1) { CTX_wm_operator_poll_msg_set(C, "No weights/vertex groups on object"); } else { diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index ff4db96061f..c452f7a7487 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -29,6 +29,8 @@ #include "BLI_math.h" #include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_layer.h" #include "BKE_material.h" @@ -1041,7 +1043,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) if (cd_dvert_offset == -1) { continue; } - defbase_len = BLI_listbase_count(&ob->defbase); + defbase_len = BKE_object_defgroup_count(ob); if (defbase_len == 0) { continue; } @@ -1090,8 +1092,10 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) /* We store the names of the vertex groups, so we can select * vertex groups with the same name in different objects. */ + const ListBase *defbase = BKE_object_defgroup_list(ob); + int i = 0; - LISTBASE_FOREACH (bDeformGroup *, dg, &ob->defbase) { + LISTBASE_FOREACH (bDeformGroup *, dg, defbase) { if (BLI_BITMAP_TEST(defbase_selected, i)) { BLI_gset_add(gset, dg->name); } @@ -1128,7 +1132,8 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) if (cd_dvert_offset == -1) { continue; } - defbase_len = BLI_listbase_count(&ob->defbase); + const ListBase *defbase = BKE_object_defgroup_list(ob); + defbase_len = BLI_listbase_count(defbase); if (defbase_len == 0) { continue; } @@ -1141,7 +1146,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) GSetIterator gs_iter; GSET_ITER (gs_iter, gset) { const char *name = BLI_gsetIterator_getKey(&gs_iter); - int vgroup_id = BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)); + int vgroup_id = BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name)); if (vgroup_id != -1) { BLI_BITMAP_ENABLE(defbase_selected, vgroup_id); found_any = true; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 627d67a5254..41a9f426798 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -44,6 +44,7 @@ #include "BLI_string.h" #include "BKE_context.h" +#include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_key.h" @@ -5739,7 +5740,7 @@ static int edbm_decimate_exec(bContext *C, wmOperator *op) float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__); { const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); - const int defbase_act = obedit->actdef - 1; + const int defbase_act = BKE_object_defgroup_active_index_get(obedit) - 1; if (use_vertex_group && (cd_dvert_offset == -1)) { BKE_report(op->reports, RPT_WARNING, "No active vertex group"); diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 112de68b52c..fc9e1aa8b1a 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -33,6 +33,7 @@ #include "BLI_listbase.h" #include "BKE_context.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_key.h" #include "BKE_layer.h" @@ -671,7 +672,7 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key * em->bm->shapenr = um->shapenr; - EDBM_mesh_free(em); + EDBM_mesh_free_data(em); bm = BM_mesh_create(&allocsize, &((struct BMeshCreateParams){ @@ -681,13 +682,21 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key * BM_mesh_bm_from_me(bm, &um->me, (&(struct BMeshFromMeshParams){ - .calc_face_normal = true, + /* Handled with tessellation. */ + .calc_face_normal = false, .active_shapekey = um->shapenr, })); - em_tmp = BKE_editmesh_create(bm, true); + em_tmp = BKE_editmesh_create(bm); *em = *em_tmp; + /* Calculate face normals and tessellation at once since it's multi-threaded. + * The vertex normals are stored in the undo-mesh, so this doesn't need to be updated. */ + BKE_editmesh_looptri_calc_ex(em, + &(const struct BMeshCalcTessellation_Params){ + .face_normals = true, + }); + em->selectmode = um->selectmode; bm->selectmode = um->selectmode; @@ -865,7 +874,7 @@ static void mesh_undosys_step_decode(struct bContext *C, BMEditMesh *em = me->edit_mesh; undomesh_to_editmesh(&elem->data, obedit, em, me->key); em->needs_flush_to_id = 1; - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY); } /* The first element is always active */ diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 4f416c94f62..85c646d689c 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -305,17 +305,13 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index) if (me->edit_mesh) { /* this happens when switching shape keys */ - EDBM_mesh_free(me->edit_mesh); + EDBM_mesh_free_data(me->edit_mesh); MEM_freeN(me->edit_mesh); } - /* currently executing operators re-tessellates, so we can avoid doing here - * but at some point it may need to be added back. */ -#if 0 - me->edit_mesh = BKE_editmesh_create(bm, true); -#else - me->edit_mesh = BKE_editmesh_create(bm, false); -#endif + /* Executing operators re-tessellates, + * so we can avoid doing here but at some point it may need to be added back. */ + me->edit_mesh = BKE_editmesh_create(bm); me->edit_mesh->selectmode = me->edit_mesh->bm->selectmode = select_mode; me->edit_mesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0; @@ -326,7 +322,8 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index) /** * \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates). - * Most callers should run #DEG_id_tag_update on \a ob->data, see: T46738, T46913 + * Most callers should run #DEG_id_tag_update on `ob->data`, see: T46738, T46913. + * This ensures #BKE_object_free_derived_caches runs on all objects that use this mesh. */ void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data) { @@ -346,25 +343,6 @@ void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data) .calc_object_remap = true, .update_shapekey_indices = !free_data, })); - - /* Free derived mesh. usually this would happen through depsgraph but there - * are exceptions like file save that will not cause this, and we want to - * avoid ending up with an invalid derived mesh then. - * - * Do it for all objects which shares the same mesh datablock, since their - * derived meshes might also be referencing data which was just freed, - * - * Annoying enough, but currently seems most efficient way to avoid access - * of freed data on scene update, especially in cases when there are dependency - * cycles. - */ -#if 0 - for (Object *other_object = bmain->objects.first; other_object != NULL; other_object = other_object->id.next) { - if (other_object->data == ob->data) { - BKE_object_free_derived_caches(other_object); - } - } -#endif } void EDBM_mesh_clear(BMEditMesh *em) @@ -372,8 +350,8 @@ void EDBM_mesh_clear(BMEditMesh *em) /* clear bmesh */ BM_mesh_clear(em->bm); - /* free derived meshes */ - BKE_editmesh_free_derivedmesh(em); + /* Free evaluated meshes & cache. */ + BKE_editmesh_free_derived_caches(em); /* free tessellation data */ em->tottri = 0; @@ -389,9 +367,9 @@ void EDBM_mesh_load(Main *bmain, Object *ob) } /** - * Should only be called on the active editmesh, otherwise call #BKE_editmesh_free + * Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data. */ -void EDBM_mesh_free(BMEditMesh *em) +void EDBM_mesh_free_data(BMEditMesh *em) { /* These tables aren't used yet, so it's not strictly necessary * to 'end' them but if someone tries to start using them, @@ -399,7 +377,7 @@ void EDBM_mesh_free(BMEditMesh *em) ED_mesh_mirror_spatial_table_end(NULL); ED_mesh_mirror_topo_table_end(NULL); - BKE_editmesh_free(em); + BKE_editmesh_free_data(em); } /** \} */ @@ -1471,8 +1449,8 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params) BM_lnorspace_invalidate(em->bm, false); em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET; } - /* don't keep stale derivedMesh data around, see: T38872. */ - BKE_editmesh_free_derivedmesh(em); + /* Don't keep stale evaluated mesh data around, see: T38872. */ + BKE_editmesh_free_derived_caches(em); #ifdef DEBUG { diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 2b78d83a9f5..73b3fb9724e 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -34,6 +34,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_mesh.h" #include "BKE_report.h" diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index ca68c47cf8e..27fb21e1dfb 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -475,16 +475,17 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) me = ob_iter->data; /* Join this object's vertex groups to the base one's */ - for (dg = ob_iter->defbase.first; dg; dg = dg->next) { + for (dg = me->vertex_group_names.first; dg; dg = dg->next) { /* See if this group exists in the object (if it doesn't, add it to the end) */ if (!BKE_object_defgroup_find_name(ob, dg->name)) { odg = MEM_mallocN(sizeof(bDeformGroup), "join deformGroup"); memcpy(odg, dg, sizeof(bDeformGroup)); - BLI_addtail(&ob->defbase, odg); + BLI_addtail(&mesh_active->vertex_group_names, odg); } } - if (ob->defbase.first && ob->actdef == 0) { - ob->actdef = 1; + if (!BLI_listbase_is_empty(&mesh_active->vertex_group_names) && + me->vertex_group_active_index == 0) { + me->vertex_group_active_index = 1; } /* Join this object's face maps to the base one's. */ @@ -1473,19 +1474,21 @@ bool ED_mesh_pick_vert( MDeformVert *ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve) { - if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH && ob->defbase.first) { + if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH) { Mesh *me = ob->data; - BMesh *bm = me->edit_mesh->bm; - const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); + if (!BLI_listbase_is_empty(&me->vertex_group_names)) { + BMesh *bm = me->edit_mesh->bm; + const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); - if (cd_dvert_offset != -1) { - BMVert *eve = BM_mesh_active_vert_get(bm); + if (cd_dvert_offset != -1) { + BMVert *eve = BM_mesh_active_vert_get(bm); - if (eve) { - if (r_eve) { - *r_eve = eve; + if (eve) { + if (r_eve) { + *r_eve = eve; + } + return BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); } - return BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); } } } diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c index a8b471a7c92..f7b53b5513f 100644 --- a/source/blender/editors/metaball/editmball_undo.c +++ b/source/blender/editors/metaball/editmball_undo.c @@ -215,7 +215,7 @@ static void mball_undosys_step_decode(struct bContext *C, } undomball_to_editmball(&elem->data, mb); mb->needs_flush_to_id = 1; - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + DEG_id_tag_update(&mb->id, ID_RECALC_GEOMETRY); } /* The first element is always active */ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 6d22da2c2bc..8ae74fbfafa 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1845,7 +1845,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op) * ready to be moved around to re-time the sound and/or make new sound clips. */ { /* create new data for NLA hierarchy */ - AnimData *adt = BKE_animdata_add_id(&ob->id); + AnimData *adt = BKE_animdata_ensure_id(&ob->id); NlaTrack *nlt = BKE_nlatrack_add(adt, NULL, is_liboverride); NlaStrip *strip = BKE_nla_add_soundstrip(bmain, scene, ob->data); strip->start = CFRA; diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 742c7abb7ff..2109fe2a822 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -33,6 +33,7 @@ #include "BKE_context.h" #include "BKE_data_transfer.h" +#include "BKE_deform.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" #include "BKE_mesh_runtime.h" @@ -133,12 +134,13 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(bContext *C, } if (ob_src) { - bDeformGroup *dg; + const bDeformGroup *dg; int i; RNA_enum_item_add_separator(&item, &totitem); - for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) { + const ListBase *defbase = BKE_object_defgroup_list(ob_src); + for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) { tmp_item.value = i; tmp_item.identifier = tmp_item.name = dg->name; RNA_enum_item_add(&item, &totitem, &tmp_item); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 1cb6a5c8ff5..6108691b2f1 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -557,7 +557,7 @@ static bool ED_object_editmode_load_free_ex(Main *bmain, } if (free_data) { - EDBM_mesh_free(me->edit_mesh); + EDBM_mesh_free_data(me->edit_mesh); MEM_freeN(me->edit_mesh); me->edit_mesh = NULL; } diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index fcee2818b22..5065a2c00f0 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -105,14 +105,13 @@ static int return_editmesh_indexar(BMEditMesh *em, int *r_tot, int **r_indexar, static bool return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *r_name, float r_cent[3]) { - const int cd_dvert_offset = obedit->actdef ? + const int active_index = BKE_object_defgroup_active_index_get(obedit); + const int cd_dvert_offset = active_index ? CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT) : -1; - zero_v3(r_cent); - if (cd_dvert_offset != -1) { - const int defgrp_index = obedit->actdef - 1; + const int defgrp_index = active_index - 1; int totvert = 0; MDeformVert *dvert; @@ -129,7 +128,8 @@ static bool return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *r_name, } } if (totvert) { - bDeformGroup *dg = BLI_findlink(&obedit->defbase, defgrp_index); + const ListBase *defbase = BKE_object_defgroup_list(obedit); + bDeformGroup *dg = BLI_findlink(defbase, defgrp_index); BLI_strncpy(r_name, dg->name, sizeof(dg->name)); mul_v3_fl(r_cent, 1.0f / (float)totvert); return true; diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 5bf04e195fe..5a3a28b5a3f 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -247,7 +247,6 @@ void OBJECT_OT_vertex_group_assign_new(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_remove_from(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_select(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_deselect(struct wmOperatorType *ot); -void OBJECT_OT_vertex_group_copy_to_linked(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_copy_to_selected(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_copy(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_normalize(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index dc60d4df7d1..a438c760d3b 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -201,7 +201,6 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_vertex_group_remove_from); WM_operatortype_append(OBJECT_OT_vertex_group_select); WM_operatortype_append(OBJECT_OT_vertex_group_deselect); - WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_linked); WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_selected); WM_operatortype_append(OBJECT_OT_vertex_group_copy); WM_operatortype_append(OBJECT_OT_vertex_group_normalize); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 30f75e9a150..d7177eabcba 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2061,6 +2061,23 @@ static void single_object_action_users( FOREACH_OBJECT_FLAG_END; } +static void single_objectdata_action_users( + Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag) +{ + FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) { + if (!ID_IS_LINKED(ob) && ob->data != NULL) { + ID *id_obdata = (ID *)ob->data; + AnimData *adt = BKE_animdata_from_id(id_obdata); + ID *id_act = (ID *)adt->action; + if (id_act && id_act->us > 1) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + BKE_animdata_copy_id_action(bmain, id_obdata); + } + } + } + FOREACH_OBJECT_FLAG_END; +} + static void single_mat_users( Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag) { @@ -2643,6 +2660,10 @@ static int make_single_user_exec(bContext *C, wmOperator *op) single_object_action_users(bmain, scene, view_layer, v3d, flag); } + if (RNA_boolean_get(op->ptr, "obdata_animation")) { + single_objectdata_action_users(bmain, scene, view_layer, v3d, flag); + } + BKE_main_id_newptr_and_tag_clear(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); @@ -2684,8 +2705,16 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot) RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects"); RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data"); RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each data-block"); - RNA_def_boolean( - ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object"); + RNA_def_boolean(ot->srna, + "animation", + 0, + "Object Animation", + "Make object animation data local to each object"); + RNA_def_boolean(ot->srna, + "obdata_animation", + 0, + "Object Data Animation", + "Make object data (mesh, curve etc.) animation data local to each object"); } /** \} */ diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index e350653e178..4c4727f51ee 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -1152,51 +1152,53 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) for (int object_index = 0; object_index < num_objects; object_index++) { Object *ob = objects[object_index]; + if (ob->flag & OB_DONE) { + continue; + } - if ((ob->flag & OB_DONE) == 0) { - bool do_inverse_offset = false; - ob->flag |= OB_DONE; + bool do_inverse_offset = false; + ob->flag |= OB_DONE; - if (centermode == ORIGIN_TO_CURSOR) { - copy_v3_v3(cent, cursor); - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_v3(ob->imat, cent); - } + if (centermode == ORIGIN_TO_CURSOR) { + copy_v3_v3(cent, cursor); + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_v3(ob->imat, cent); + } - if (ob->data == NULL) { - /* special support for dupligroups */ - if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection && - (ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) { - if (ID_IS_LINKED(ob->instance_collection)) { - tot_lib_error++; + if (ob->data == NULL) { + /* special support for dupligroups */ + if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection && + (ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) { + if (ID_IS_LINKED(ob->instance_collection)) { + tot_lib_error++; + } + else { + if (centermode == ORIGIN_TO_CURSOR) { + /* done */ } else { - if (centermode == ORIGIN_TO_CURSOR) { - /* done */ - } - else { - float min[3], max[3]; - /* only bounds support */ - INIT_MINMAX(min, max); - BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true); - mid_v3_v3v3(cent, min, max); - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_v3(ob->imat, cent); - } + float min[3], max[3]; + /* only bounds support */ + INIT_MINMAX(min, max); + BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true); + mid_v3_v3v3(cent, min, max); + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_v3(ob->imat, cent); + } - add_v3_v3(ob->instance_collection->instance_offset, cent); + add_v3_v3(ob->instance_collection->instance_offset, cent); - tot_change++; - ob->instance_collection->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; - } + tot_change++; + ob->instance_collection->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; } } - else if (ID_IS_LINKED(ob->data)) { - tot_lib_error++; - } - - if (obedit == NULL && ob->type == OB_MESH) { + } + else if (ID_IS_LINKED(ob->data)) { + tot_lib_error++; + } + else if (ob->type == OB_MESH) { + if (obedit == NULL) { Mesh *me = ob->data; if (centermode == ORIGIN_TO_CURSOR) { @@ -1222,265 +1224,265 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) me->id.tag |= LIB_TAG_DOIT; do_inverse_offset = true; } - else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { - Curve *cu = ob->data; + } + else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { + Curve *cu = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { - /* done */ - } - else if (around == V3D_AROUND_CENTER_BOUNDS) { - BKE_curve_center_bounds(cu, cent); - } - else { /* #V3D_AROUND_CENTER_MEDIAN. */ - BKE_curve_center_median(cu, cent); - } + if (centermode == ORIGIN_TO_CURSOR) { + /* done */ + } + 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)) { - cent[2] = 0.0; - } + /* don't allow Z change if curve is 2D */ + if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) { + cent[2] = 0.0; + } - negate_v3_v3(cent_neg, cent); - BKE_curve_translate(cu, cent_neg, 1); + negate_v3_v3(cent_neg, cent); + BKE_curve_translate(cu, cent_neg, 1); - tot_change++; - cu->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; + tot_change++; + cu->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; - if (obedit) { - if (centermode == GEOMETRY_TO_ORIGIN) { - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); - } - break; + if (obedit) { + if (centermode == GEOMETRY_TO_ORIGIN) { + DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); } + break; } - else if (ob->type == OB_FONT) { - /* Get from bounding-box. */ + } + else if (ob->type == OB_FONT) { + /* Get from bounding-box. */ - Curve *cu = ob->data; + Curve *cu = ob->data; - if (ob->runtime.bb == NULL && (centermode != ORIGIN_TO_CURSOR)) { - /* Do nothing. */ + if (ob->runtime.bb == NULL && (centermode != ORIGIN_TO_CURSOR)) { + /* Do nothing. */ + } + else { + if (centermode == ORIGIN_TO_CURSOR) { + /* Done. */ } else { - if (centermode == ORIGIN_TO_CURSOR) { - /* Done. */ - } - else { - /* extra 0.5 is the height o above line */ - cent[0] = 0.5f * (ob->runtime.bb->vec[4][0] + ob->runtime.bb->vec[0][0]); - cent[1] = 0.5f * (ob->runtime.bb->vec[0][1] + ob->runtime.bb->vec[2][1]); - } + /* extra 0.5 is the height o above line */ + cent[0] = 0.5f * (ob->runtime.bb->vec[4][0] + ob->runtime.bb->vec[0][0]); + cent[1] = 0.5f * (ob->runtime.bb->vec[0][1] + ob->runtime.bb->vec[2][1]); + } - cent[2] = 0.0f; + cent[2] = 0.0f; - cu->xof = cu->xof - cent[0]; - cu->yof = cu->yof - cent[1]; + cu->xof = cu->xof - cent[0]; + cu->yof = cu->yof - cent[1]; - tot_change++; - cu->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; - } + tot_change++; + cu->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; } - else if (ob->type == OB_ARMATURE) { - bArmature *arm = ob->data; + } + else if (ob->type == OB_ARMATURE) { + bArmature *arm = ob->data; - if (ID_REAL_USERS(arm) > 1) { + if (ID_REAL_USERS(arm) > 1) { #if 0 BKE_report(op->reports, RPT_ERROR, "Cannot apply to a multi user armature"); return; #endif - tot_multiuser_arm_error++; - } - else { - /* Function to recenter armatures in editarmature.c - * Bone + object locations are handled there. - */ - ED_armature_origin_set(bmain, ob, cursor, centermode, around); + tot_multiuser_arm_error++; + } + else { + /* Function to recenter armatures in editarmature.c + * Bone + object locations are handled there. + */ + ED_armature_origin_set(bmain, ob, cursor, centermode, around); - tot_change++; - arm->id.tag |= LIB_TAG_DOIT; - /* do_inverse_offset = true; */ /* docenter_armature() handles this */ + tot_change++; + arm->id.tag |= LIB_TAG_DOIT; + /* do_inverse_offset = true; */ /* docenter_armature() handles this */ - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - BKE_object_transform_copy(ob_eval, ob); - BKE_armature_copy_bone_transforms(ob_eval->data, ob->data); - BKE_object_where_is_calc(depsgraph, scene, ob_eval); - BKE_pose_where_is(depsgraph, scene, ob_eval); /* needed for bone parents */ + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + BKE_object_transform_copy(ob_eval, ob); + BKE_armature_copy_bone_transforms(ob_eval->data, ob->data); + BKE_object_where_is_calc(depsgraph, scene, ob_eval); + BKE_pose_where_is(depsgraph, scene, ob_eval); /* needed for bone parents */ - ignore_parent_tx(bmain, depsgraph, scene, ob); + ignore_parent_tx(bmain, depsgraph, scene, ob); - if (obedit) { - break; - } + if (obedit) { + break; } } - else if (ob->type == OB_MBALL) { - MetaBall *mb = ob->data; + } + else if (ob->type == OB_MBALL) { + MetaBall *mb = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { - /* done */ - } - else if (around == V3D_AROUND_CENTER_BOUNDS) { - BKE_mball_center_bounds(mb, cent); - } - else { /* #V3D_AROUND_CENTER_MEDIAN. */ - BKE_mball_center_median(mb, cent); - } + if (centermode == ORIGIN_TO_CURSOR) { + /* done */ + } + 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); + negate_v3_v3(cent_neg, cent); + BKE_mball_translate(mb, cent_neg); - tot_change++; - mb->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; + tot_change++; + mb->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; - if (obedit) { - if (centermode == GEOMETRY_TO_ORIGIN) { - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); - } - break; + if (obedit) { + if (centermode == GEOMETRY_TO_ORIGIN) { + DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); } + break; } - else if (ob->type == OB_LATTICE) { - Lattice *lt = ob->data; + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { - /* done */ - } - else if (around == V3D_AROUND_CENTER_BOUNDS) { - BKE_lattice_center_bounds(lt, cent); - } - else { /* #V3D_AROUND_CENTER_MEDIAN. */ - BKE_lattice_center_median(lt, cent); - } + if (centermode == ORIGIN_TO_CURSOR) { + /* done */ + } + 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); + negate_v3_v3(cent_neg, cent); + BKE_lattice_translate(lt, cent_neg, 1); - tot_change++; - lt->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; - } - else if (ob->type == OB_GPENCIL) { - bGPdata *gpd = ob->data; - float gpcenter[3]; - if (gpd) { - if (centermode == ORIGIN_TO_GEOMETRY) { - zero_v3(gpcenter); - BKE_gpencil_centroid_3d(gpd, gpcenter); - add_v3_v3(gpcenter, ob->obmat[3]); - } - if (centermode == ORIGIN_TO_CURSOR) { - copy_v3_v3(gpcenter, cursor); - } - if (ELEM(centermode, ORIGIN_TO_GEOMETRY, ORIGIN_TO_CURSOR)) { - bGPDspoint *pt; - float imat[3][3], bmat[3][3]; - float offset_global[3]; - float offset_local[3]; - int i; - - sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]); - copy_m3_m4(bmat, obact->obmat); - invert_m3_m3(imat, bmat); - mul_m3_v3(imat, offset_global); - mul_v3_m3v3(offset_local, imat, offset_global); - - float diff_mat[4][4]; - float inverse_diff_mat[4][4]; - - /* recalculate all strokes - * (all layers are considered without evaluating lock attributes) */ - LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { - /* calculate difference matrix */ - BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); - /* undo matrix */ - invert_m4_m4(inverse_diff_mat, diff_mat); - LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { - LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - float mpt[3]; - mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x); - sub_v3_v3(mpt, offset_local); - mul_v3_m4v3(&pt->x, diff_mat, mpt); - } + tot_change++; + lt->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + } + else if (ob->type == OB_GPENCIL) { + bGPdata *gpd = ob->data; + float gpcenter[3]; + if (gpd) { + if (centermode == ORIGIN_TO_GEOMETRY) { + zero_v3(gpcenter); + BKE_gpencil_centroid_3d(gpd, gpcenter); + add_v3_v3(gpcenter, ob->obmat[3]); + } + if (centermode == ORIGIN_TO_CURSOR) { + copy_v3_v3(gpcenter, cursor); + } + if (ELEM(centermode, ORIGIN_TO_GEOMETRY, ORIGIN_TO_CURSOR)) { + bGPDspoint *pt; + float imat[3][3], bmat[3][3]; + float offset_global[3]; + float offset_local[3]; + int i; + + sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]); + copy_m3_m4(bmat, obact->obmat); + invert_m3_m3(imat, bmat); + mul_m3_v3(imat, offset_global); + mul_v3_m3v3(offset_local, imat, offset_global); + + float diff_mat[4][4]; + float inverse_diff_mat[4][4]; + + /* recalculate all strokes + * (all layers are considered without evaluating lock attributes) */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + /* calculate difference matrix */ + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); + /* undo matrix */ + invert_m4_m4(inverse_diff_mat, diff_mat); + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + float mpt[3]; + mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x); + sub_v3_v3(mpt, offset_local); + mul_v3_m4v3(&pt->x, diff_mat, mpt); } } } - tot_change++; - if (centermode == ORIGIN_TO_GEOMETRY) { - copy_v3_v3(ob->loc, gpcenter); - } - DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - - ob->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; } - else { - BKE_report(op->reports, - RPT_WARNING, - "Grease Pencil Object does not support this set origin option"); + tot_change++; + if (centermode == ORIGIN_TO_GEOMETRY) { + copy_v3_v3(ob->loc, gpcenter); } + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + + ob->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + } + else { + BKE_report(op->reports, + RPT_WARNING, + "Grease Pencil Object does not support this set origin option"); } } + } - /* offset other selected objects */ - if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) { - float obmat[4][4]; + /* offset other selected objects */ + if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) { + float obmat[4][4]; - /* was the object data modified - * NOTE: the functions above must set 'cent'. */ + /* was the object data modified + * NOTE: the functions above must set 'cent'. */ - /* convert the offset to parent space */ - BKE_object_to_mat4(ob, obmat); - mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */ + /* convert the offset to parent space */ + BKE_object_to_mat4(ob, obmat); + mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */ - add_v3_v3(ob->loc, centn); + add_v3_v3(ob->loc, centn); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - BKE_object_transform_copy(ob_eval, ob); - BKE_object_where_is_calc(depsgraph, scene, ob_eval); - if (ob->type == OB_ARMATURE) { - /* needed for bone parents */ - BKE_armature_copy_bone_transforms(ob_eval->data, ob->data); - BKE_pose_where_is(depsgraph, scene, ob_eval); - } - - ignore_parent_tx(bmain, depsgraph, scene, ob); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + BKE_object_transform_copy(ob_eval, ob); + BKE_object_where_is_calc(depsgraph, scene, ob_eval); + if (ob->type == OB_ARMATURE) { + /* needed for bone parents */ + BKE_armature_copy_bone_transforms(ob_eval->data, ob->data); + BKE_pose_where_is(depsgraph, scene, ob_eval); + } - /* other users? */ - // CTX_DATA_BEGIN (C, Object *, ob_other, selected_editable_objects) - //{ - - /* use existing context looper */ - for (int other_object_index = 0; other_object_index < num_objects; other_object_index++) { - Object *ob_other = objects[other_object_index]; - - if ((ob_other->flag & OB_DONE) == 0 && - ((ob->data && (ob->data == ob_other->data)) || - (ob->instance_collection == ob_other->instance_collection && - (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION))) { - ob_other->flag |= OB_DONE; - DEG_id_tag_update(&ob_other->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */ - add_v3_v3(ob_other->loc, centn); - - Object *ob_other_eval = DEG_get_evaluated_object(depsgraph, ob_other); - BKE_object_transform_copy(ob_other_eval, ob_other); - BKE_object_where_is_calc(depsgraph, scene, ob_other_eval); - if (ob_other->type == OB_ARMATURE) { - /* needed for bone parents */ - BKE_armature_copy_bone_transforms(ob_eval->data, ob->data); - BKE_pose_where_is(depsgraph, scene, ob_other_eval); - } - ignore_parent_tx(bmain, depsgraph, scene, ob_other); + ignore_parent_tx(bmain, depsgraph, scene, ob); + + /* other users? */ + // CTX_DATA_BEGIN (C, Object *, ob_other, selected_editable_objects) + //{ + + /* use existing context looper */ + for (int other_object_index = 0; other_object_index < num_objects; other_object_index++) { + Object *ob_other = objects[other_object_index]; + + if ((ob_other->flag & OB_DONE) == 0 && + ((ob->data && (ob->data == ob_other->data)) || + (ob->instance_collection == ob_other->instance_collection && + (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION))) { + ob_other->flag |= OB_DONE; + DEG_id_tag_update(&ob_other->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */ + add_v3_v3(ob_other->loc, centn); + + Object *ob_other_eval = DEG_get_evaluated_object(depsgraph, ob_other); + BKE_object_transform_copy(ob_other_eval, ob_other); + BKE_object_where_is_calc(depsgraph, scene, ob_other_eval); + if (ob_other->type == OB_ARMATURE) { + /* needed for bone parents */ + BKE_armature_copy_bone_transforms(ob_eval->data, ob->data); + BKE_pose_where_is(depsgraph, scene, ob_other_eval); } + ignore_parent_tx(bmain, depsgraph, scene, ob_other); } - // CTX_DATA_END; } + // CTX_DATA_END; } } MEM_freeN(objects); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 37075a29b92..4ea599fd30e 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -130,7 +130,7 @@ bool ED_vgroup_sync_from_pose(Object *ob) if (arm->act_bone) { int def_num = BKE_object_defgroup_name_index(ob, arm->act_bone->name); if (def_num != -1) { - ob->actdef = def_num + 1; + BKE_object_defgroup_active_index_set(ob, def_num + 1); return true; } } @@ -389,11 +389,16 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) int dvert_tot_from; int dvert_tot; int i; - int defbase_tot_from = BLI_listbase_count(&ob_from->defbase); - int defbase_tot = BLI_listbase_count(&ob->defbase); + ListBase *defbase_dst = BKE_object_defgroup_list_mutable(ob); + const ListBase *defbase_src = BKE_object_defgroup_list(ob_from); + + int defbase_tot_from = BLI_listbase_count(defbase_src); + int defbase_tot = BLI_listbase_count(defbase_dst); bool new_vgroup = false; - if (ob == ob_from) { + BLI_assert(ob != ob_from); + + if (ob->data == ob_from->data) { return true; } @@ -429,9 +434,9 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) } /* do the copy */ - BLI_freelistN(&ob->defbase); - BLI_duplicatelist(&ob->defbase, &ob_from->defbase); - ob->actdef = ob_from->actdef; + BLI_freelistN(defbase_dst); + BLI_duplicatelist(defbase_dst, defbase_src); + BKE_object_defgroup_active_index_set(ob, BKE_object_defgroup_active_index_get(ob_from)); if (defbase_tot_from < defbase_tot) { /* correct vgroup indices because the number of vgroups is being reduced. */ @@ -882,7 +887,8 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, /* add the vert to the deform group with the * specified assign mode */ - const int def_nr = BLI_findindex(&ob->defbase, dg); + const ListBase *defbase = BKE_object_defgroup_list(ob); + const int def_nr = BLI_findindex(defbase, dg); MDeformVert *dv = NULL; int tot; @@ -913,7 +919,8 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum) /* TODO(campbell): This is slow in a loop, better pass def_nr directly, * but leave for later. */ - const int def_nr = BLI_findindex(&ob->defbase, dg); + const ListBase *defbase = BKE_object_defgroup_list(ob); + const int def_nr = BLI_findindex(defbase, dg); if (def_nr != -1) { MDeformVert *dvert = NULL; @@ -989,7 +996,8 @@ static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum) float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum) { - const int def_nr = BLI_findindex(&ob->defbase, dg); + const ListBase *defbase = BKE_object_defgroup_list(ob); + const int def_nr = BLI_findindex(defbase, dg); if (def_nr == -1) { return -1; @@ -1000,9 +1008,9 @@ float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum) void ED_vgroup_select_by_name(Object *ob, const char *name) { - /* NOTE: ob->actdef==0 signals on painting to create a new one, + /* NOTE: actdef==0 signals on painting to create a new one, * if a bone in posemode is selected */ - ob->actdef = BKE_object_defgroup_name_index(ob, name) + 1; + BKE_object_defgroup_active_index_set(ob, BKE_object_defgroup_name_index(ob, name) + 1); } /** \} */ @@ -1014,9 +1022,10 @@ void ED_vgroup_select_by_name(Object *ob, const char *name) /* only in editmode */ static void vgroup_select_verts(Object *ob, int select) { - const int def_nr = ob->actdef - 1; + const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; - if (!BLI_findlink(&ob->defbase, def_nr)) { + const ListBase *defbase = BKE_object_defgroup_list(ob); + if (!BLI_findlink(defbase, def_nr)) { return; } @@ -1111,7 +1120,9 @@ static void vgroup_duplicate(Object *ob) MDeformVert **dvert_array = NULL; int i, idg, icdg, dvert_tot = 0; - dg = BLI_findlink(&ob->defbase, (ob->actdef - 1)); + ListBase *defbase = BKE_object_defgroup_list_mutable(ob); + + dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1); if (!dg) { return; } @@ -1127,11 +1138,11 @@ static void vgroup_duplicate(Object *ob) BLI_strncpy(cdg->name, name, sizeof(cdg->name)); BKE_object_defgroup_unique_name(cdg, ob); - BLI_addtail(&ob->defbase, cdg); + BLI_addtail(defbase, cdg); - idg = (ob->actdef - 1); - ob->actdef = BLI_listbase_count(&ob->defbase); - icdg = (ob->actdef - 1); + idg = BKE_object_defgroup_active_index_get(ob) - 1; + BKE_object_defgroup_active_index_set(ob, BLI_listbase_count(defbase)); + icdg = BKE_object_defgroup_active_index_get(ob) - 1; /* TODO(campbell): we might want to allow only copy selected verts here? */ ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); @@ -1157,11 +1168,12 @@ static bool vgroup_normalize(Object *ob) MDeformWeight *dw; MDeformVert *dv, **dvert_array = NULL; int dvert_tot = 0; - const int def_nr = ob->actdef - 1; + const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; const bool use_vert_sel = vertex_group_use_vert_sel(ob); - if (!BLI_findlink(&ob->defbase, def_nr)) { + const ListBase *defbase = BKE_object_defgroup_list(ob); + if (!BLI_findlink(defbase, def_nr)) { return false; } @@ -1639,7 +1651,7 @@ static bool vgroup_normalize_all(Object *ob, { MDeformVert *dv, **dvert_array = NULL; int i, dvert_tot = 0; - const int def_nr = ob->actdef - 1; + const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; const bool use_vert_sel = vertex_group_use_vert_sel(ob); @@ -1651,7 +1663,8 @@ static bool vgroup_normalize_all(Object *ob, ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { - const int defbase_tot = BLI_listbase_count(&ob->defbase); + const ListBase *defbase = BKE_object_defgroup_list(ob); + const int defbase_tot = BLI_listbase_count(defbase); bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot); bool changed = false; @@ -1742,7 +1755,7 @@ static const EnumPropertyItem vgroup_lock_mask[] = { static bool *vgroup_selected_get(Object *ob) { - int sel_count = 0, defbase_tot = BLI_listbase_count(&ob->defbase); + int sel_count = 0, defbase_tot = BKE_object_defgroup_count(ob); bool *mask; if (ob->mode & OB_MODE_WEIGHT_PAINT) { @@ -1759,8 +1772,9 @@ static bool *vgroup_selected_get(Object *ob) mask = MEM_callocN(defbase_tot * sizeof(bool), __func__); } - if (sel_count == 0 && ob->actdef >= 1 && ob->actdef <= defbase_tot) { - mask[ob->actdef - 1] = true; + const int actdef = BKE_object_defgroup_active_index_get(ob); + if (sel_count == 0 && actdef >= 1 && actdef <= defbase_tot) { + mask[actdef - 1] = true; } return mask; @@ -1775,11 +1789,12 @@ static void vgroup_lock_all(Object *ob, int action, int mask) if (mask != VGROUP_MASK_ALL) { selected = vgroup_selected_get(ob); } + const ListBase *defbase = BKE_object_defgroup_list(ob); if (action == VGROUP_TOGGLE) { action = VGROUP_LOCK; - for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) { + for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) { switch (mask) { case VGROUP_MASK_INVERT_UNSELECTED: case VGROUP_MASK_SELECTED: @@ -1802,7 +1817,7 @@ static void vgroup_lock_all(Object *ob, int action, int mask) } } - for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) { + for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) { switch (mask) { case VGROUP_MASK_SELECTED: if (!selected[i]) { @@ -2379,13 +2394,15 @@ void ED_vgroup_mirror(Object *ob, MDeformVert *dvert, *dvert_mirr; char sel, sel_mirr; int *flip_map = NULL, flip_map_len; - const int def_nr = ob->actdef - 1; + const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; int totmirr = 0, totfail = 0; *r_totmirr = *r_totfail = 0; + const ListBase *defbase = BKE_object_defgroup_list(ob); + if ((mirror_weights == false && flip_vgroups == false) || - (BLI_findlink(&ob->defbase, def_nr) == NULL)) { + (BLI_findlink(defbase, def_nr) == NULL)) { return; } @@ -2569,7 +2586,8 @@ cleanup: static void vgroup_delete_active(Object *ob) { - bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); + const ListBase *defbase = BKE_object_defgroup_list(ob); + bDeformGroup *dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1); if (!dg) { return; } @@ -2580,9 +2598,10 @@ static void vgroup_delete_active(Object *ob) /* only in editmode */ static void vgroup_assign_verts(Object *ob, const float weight) { - const int def_nr = ob->actdef - 1; + const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; - if (!BLI_findlink(&ob->defbase, def_nr)) { + const ListBase *defbase = BKE_object_defgroup_list(ob); + if (!BLI_findlink(defbase, def_nr)) { return; } @@ -2700,7 +2719,8 @@ static bool vertex_group_poll_ex(bContext *C, Object *ob) return false; } - if (BLI_listbase_is_empty(&ob->defbase)) { + const ListBase *defbase = BKE_object_defgroup_list(ob); + if (BLI_listbase_is_empty(defbase)) { CTX_wm_operator_poll_msg_set(C, "Object has no vertex groups"); return false; } @@ -2823,8 +2843,10 @@ static bool vertex_group_vert_select_unlocked_poll(bContext *C) return false; } - if (ob->actdef != 0) { - bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); + const int def_nr = BKE_object_defgroup_active_index_get(ob); + if (def_nr != 0) { + const ListBase *defbase = BKE_object_defgroup_list(ob); + const bDeformGroup *dg = BLI_findlink(defbase, def_nr - 1); if (dg) { return !(dg->flag & DG_LOCK_WEIGHT); } @@ -3025,8 +3047,8 @@ static int vertex_group_remove_from_exec(bContext *C, wmOperator *op) } } else { - bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); - + const ListBase *defbase = BKE_object_defgroup_list(ob); + bDeformGroup *dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1); if ((dg == NULL) || (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false)) { return OPERATOR_CANCELLED; } @@ -3860,55 +3882,6 @@ void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \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); - Object *ob_active = ED_object_context(C); - int retval = OPERATOR_CANCELLED; - - FOREACH_SCENE_OBJECT_BEGIN (scene, ob_iter) { - if (ob_iter->type == ob_active->type) { - if (ob_iter != ob_active && ob_iter->data == ob_active->data) { - BLI_freelistN(&ob_iter->defbase); - BLI_duplicatelist(&ob_iter->defbase, &ob_active->defbase); - ob_iter->actdef = ob_active->actdef; - - DEG_id_tag_update(&ob_iter->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob_iter->data); - - retval = OPERATOR_FINISHED; - } - } - } - FOREACH_SCENE_OBJECT_END; - - return retval; -} - -void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Copy Vertex Groups to Linked"; - ot->idname = "OBJECT_OT_vertex_group_copy_to_linked"; - ot->description = - "Replace vertex groups of all users of the same geometry data by vertex groups of active " - "object"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_copy_to_linked_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Vertex Group Copy to Selected Operator * \{ */ @@ -3972,7 +3945,7 @@ static int set_active_group_exec(bContext *C, wmOperator *op) int nr = RNA_enum_get(op->ptr, "group"); BLI_assert(nr + 1 >= 0); - ob->actdef = nr + 1; + BKE_object_defgroup_active_index_set(ob, nr + 1); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); @@ -3999,7 +3972,8 @@ static const EnumPropertyItem *vgroup_itemf(bContext *C, return DummyRNA_NULL_items; } - for (a = 0, def = ob->defbase.first; def; def = def->next, a++) { + const ListBase *defbase = BKE_object_defgroup_list(ob); + for (a = 0, def = defbase->first; def; def = def->next, a++) { tmp.value = a; tmp.icon = ICON_GROUP_VERTEX; tmp.identifier = def->name; @@ -4048,13 +4022,13 @@ void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot) * with the order of vgroups then call vgroup_do_remap after */ static char *vgroup_init_remap(Object *ob) { - bDeformGroup *def; - int defbase_tot = BLI_listbase_count(&ob->defbase); + const ListBase *defbase = BKE_object_defgroup_list(ob); + int defbase_tot = BLI_listbase_count(defbase); char *name_array = MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups"); char *name; name = name_array; - for (def = ob->defbase.first; def; def = def->next) { + for (const bDeformGroup *def = defbase->first; def; def = def->next) { BLI_strncpy(name, def->name, MAX_VGROUP_NAME); name += MAX_VGROUP_NAME; } @@ -4065,8 +4039,9 @@ static char *vgroup_init_remap(Object *ob) static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) { MDeformVert *dvert = NULL; - bDeformGroup *def; - int defbase_tot = BLI_listbase_count(&ob->defbase); + const bDeformGroup *def; + const ListBase *defbase = BKE_object_defgroup_list(ob); + int defbase_tot = BLI_listbase_count(defbase); /* Needs a dummy index at the start. */ int *sort_map_update = MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups"); @@ -4076,8 +4051,8 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) int i; name = name_array; - for (def = ob->defbase.first, i = 0; def; def = def->next, i++) { - sort_map[i] = BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)); + for (def = defbase->first, i = 0; def; def = def->next, i++) { + sort_map[i] = BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name)); name += MAX_VGROUP_NAME; BLI_assert(sort_map[i] != -1); @@ -4130,8 +4105,9 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) sort_map_update[0] = 0; BKE_object_defgroup_remap_update_users(ob, sort_map_update); - BLI_assert(sort_map_update[ob->actdef] >= 0); - ob->actdef = sort_map_update[ob->actdef]; + BLI_assert(sort_map_update[BKE_object_defgroup_active_index_get(ob)] >= 0); + BKE_object_defgroup_active_index_set(ob, + sort_map_update[BKE_object_defgroup_active_index_get(ob)]); MEM_freeN(sort_map_update); @@ -4159,6 +4135,7 @@ static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase) bonebase = &armature->bonebase; } } + ListBase *defbase = BKE_object_defgroup_list_mutable(ob); if (bonebase != NULL) { Bone *bone; @@ -4167,8 +4144,8 @@ static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase) vgroup_sort_bone_hierarchy(ob, &bone->childbase); if (dg != NULL) { - BLI_remlink(&ob->defbase, dg); - BLI_addhead(&ob->defbase, dg); + BLI_remlink(defbase, dg); + BLI_addhead(defbase, dg); } } } @@ -4189,10 +4166,12 @@ static int vertex_group_sort_exec(bContext *C, wmOperator *op) /* Init remapping. */ name_array = vgroup_init_remap(ob); + ListBase *defbase = BKE_object_defgroup_list_mutable(ob); + /* Sort vgroup names. */ switch (sort_type) { case SORT_TYPE_NAME: - BLI_listbase_sort(&ob->defbase, vgroup_sort_name); + BLI_listbase_sort(defbase, vgroup_sort_name); break; case SORT_TYPE_BONEHIERARCHY: vgroup_sort_bone_hierarchy(ob, NULL); @@ -4250,14 +4229,16 @@ static int vgroup_move_exec(bContext *C, wmOperator *op) int dir = RNA_enum_get(op->ptr, "direction"); int ret = OPERATOR_FINISHED; - def = BLI_findlink(&ob->defbase, ob->actdef - 1); + ListBase *defbase = BKE_object_defgroup_list_mutable(ob); + + def = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1); if (!def) { return OPERATOR_CANCELLED; } name_array = vgroup_init_remap(ob); - if (BLI_listbase_link_move(&ob->defbase, def, dir)) { + if (BLI_listbase_link_move(defbase, def, dir)) { ret = vgroup_do_remap(ob, name_array, op); if (ret != OPERATOR_CANCELLED) { @@ -4376,7 +4357,8 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) static bool check_vertex_group_accessible(wmOperator *op, Object *ob, int def_nr) { - bDeformGroup *dg = BLI_findlink(&ob->defbase, def_nr); + const ListBase *defbase = BKE_object_defgroup_list(ob); + bDeformGroup *dg = BLI_findlink(defbase, def_nr); if (!dg) { BKE_report(op->reports, RPT_ERROR, "Invalid vertex group index"); @@ -4498,7 +4480,7 @@ static int vertex_weight_set_active_exec(bContext *C, wmOperator *op) const int wg_index = RNA_int_get(op->ptr, "weight_group"); if (wg_index != -1) { - ob->actdef = wg_index + 1; + BKE_object_defgroup_active_index_set(ob, wg_index + 1); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); } diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 2484f382ed4..709e04d807d 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -752,7 +752,7 @@ static int vert_select_ungrouped_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); Mesh *me = ob->data; - if (BLI_listbase_is_empty(&ob->defbase) || (me->dvert == NULL)) { + if (BLI_listbase_is_empty(&me->vertex_group_names) || (me->dvert == NULL)) { BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 5c1cc6cadcf..9387b84f437 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1607,13 +1607,13 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo /* check if we are attempting to paint onto a locked vertex group, * and other options disallow it from doing anything useful */ bDeformGroup *dg; - dg = BLI_findlink(&ob->defbase, vgroup_index.active); + dg = BLI_findlink(&me->vertex_group_names, vgroup_index.active); if (dg->flag & DG_LOCK_WEIGHT) { BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting"); return false; } if (vgroup_index.mirror != -1) { - dg = BLI_findlink(&ob->defbase, vgroup_index.mirror); + dg = BLI_findlink(&me->vertex_group_names, vgroup_index.mirror); if (dg->flag & DG_LOCK_WEIGHT) { BKE_report(op->reports, RPT_WARNING, "Mirror group is locked, aborting"); return false; @@ -1622,7 +1622,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo } /* check that multipaint groups are unlocked */ - defbase_tot = BLI_listbase_count(&ob->defbase); + defbase_tot = BLI_listbase_count(&me->vertex_group_names); defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_tot_sel); if (ts->multipaint && defbase_tot_sel > 1) { @@ -1636,7 +1636,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo for (i = 0; i < defbase_tot; i++) { if (defbase_sel[i]) { - dg = BLI_findlink(&ob->defbase, i); + dg = BLI_findlink(&me->vertex_group_names, i); if (dg->flag & DG_LOCK_WEIGHT) { BKE_report(op->reports, RPT_WARNING, "Multipaint group is locked, aborting"); MEM_freeN(defbase_sel); @@ -2498,7 +2498,7 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) for (psys = ob->particlesystem.first; psys; psys = psys->next) { for (i = 0; i < PSYS_TOT_VG; i++) { - if (psys->vgroup[i] == ob->actdef) { + if (psys->vgroup[i] == BKE_object_defgroup_active_index_get(ob)) { psys->recalc |= ID_RECALC_PSYS_RESET; break; } diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c index 96d22fe4a21..9f023dd6e63 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c @@ -149,7 +149,7 @@ static bool vertex_paint_from_weight(Object *ob) /* TODO: respect selection. */ /* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway. */ mp = me->mpoly; - vgroup_active = ob->actdef - 1; + vgroup_active = me->vertex_group_active_index - 1; for (int i = 0; i < me->totpoly; i++, mp++) { MLoopCol *lcol = &me->mloopcol[mp->loopstart]; uint j = 0; diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c index 5e047283534..cb8dc838422 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -183,7 +183,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even ED_view3d_viewcontext_init(C, &vc, depsgraph); me = BKE_mesh_from_object(vc.obact); - if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) { + if (me && me->dvert && vc.v3d && vc.rv3d && (me->vertex_group_active_index != 0)) { const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; int v_idx_best = -1; uint index; @@ -213,9 +213,9 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even if (v_idx_best != -1) { /* should always be valid */ ToolSettings *ts = vc.scene->toolsettings; Brush *brush = BKE_paint_brush(&ts->wpaint->paint); - const int vgroup_active = vc.obact->actdef - 1; + const int vgroup_active = me->vertex_group_active_index - 1; float vgroup_weight = BKE_defvert_find_weight(&me->dvert[v_idx_best], vgroup_active); - const int defbase_tot = BLI_listbase_count(&vc.obact->defbase); + const int defbase_tot = BLI_listbase_count(&me->vertex_group_names); bool use_lock_relative = ts->wpaint_lock_relative; bool *defbase_locked = NULL, *defbase_unlocked = NULL; @@ -331,8 +331,8 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, ED_view3d_viewcontext_init(C, &vc, depsgraph); me = BKE_mesh_from_object(vc.obact); - if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) { - const int defbase_tot = BLI_listbase_count(&vc.obact->defbase); + if (me && me->dvert && vc.v3d && vc.rv3d && me->vertex_group_names.first) { + const int defbase_tot = BLI_listbase_count(&me->vertex_group_names); const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups"); bool found = false; @@ -372,7 +372,7 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, int totitem = 0; int i = 0; bDeformGroup *dg; - for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) { + for (dg = me->vertex_group_names.first; dg && i < defbase_tot; i++, dg = dg->next) { if (groups[i]) { item_tmp.identifier = item_tmp.name = dg->name; item_tmp.value = i; @@ -401,7 +401,7 @@ static int weight_sample_group_exec(bContext *C, wmOperator *op) ED_view3d_viewcontext_init(C, &vc, depsgraph); BLI_assert(type + 1 >= 0); - vc.obact->actdef = type + 1; + BKE_object_defgroup_active_index_set(vc.obact, type + 1); DEG_id_tag_update(&vc.obact->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact); @@ -458,7 +458,7 @@ static bool weight_paint_set(Object *ob, float paintweight) return false; } - vgroup_active = ob->actdef - 1; + vgroup_active = BKE_object_defgroup_active_index_get(ob) - 1; /* if mirror painting, find the other group */ if (ME_USING_MIRROR_X_VERTEX_GROUPS(me)) { @@ -815,7 +815,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) data.sco_start = sco_start; data.sco_end = sco_end; data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end); - data.def_nr = ob->actdef - 1; + data.def_nr = BKE_object_defgroup_active_index_get(ob) - 1; data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; data.vert_cache = vert_cache; data.vert_visit = NULL; @@ -863,7 +863,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) } if (scene->toolsettings->auto_normalize) { - const int vgroup_num = BLI_listbase_count(&ob->defbase); + const int vgroup_num = BLI_listbase_count(&me->vertex_group_names); bool *vgroup_validmap = BKE_object_defgroup_validmap_get(ob, vgroup_num); if (vgroup_validmap != NULL) { MDeformVert *dvert = me->dvert; diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c index d6a118bbd59..19ffa0c952d 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c @@ -79,8 +79,10 @@ bool ED_wpaint_ensure_data(bContext *C, WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); } + const ListBase *defbase = BKE_object_defgroup_list(ob); + /* this happens on a Bone select, when no vgroup existed yet */ - if (ob->actdef <= 0) { + if (me->vertex_group_active_index <= 0) { Object *modob; if ((modob = BKE_modifiers_is_deformed_by_armature(ob))) { Bone *actbone = ((bArmature *)modob->data)->act_bone; @@ -94,32 +96,33 @@ bool ED_wpaint_ensure_data(bContext *C, DEG_relations_tag_update(CTX_data_main(C)); } else { - int actdef = 1 + BLI_findindex(&ob->defbase, dg); + + int actdef = 1 + BLI_findindex(defbase, dg); BLI_assert(actdef >= 0); - ob->actdef = actdef; + me->vertex_group_active_index = actdef; } } } } } - if (BLI_listbase_is_empty(&ob->defbase)) { + if (BLI_listbase_is_empty(defbase)) { BKE_object_defgroup_add(ob); DEG_relations_tag_update(CTX_data_main(C)); } /* ensure we don't try paint onto an invalid group */ - if (ob->actdef <= 0) { + if (me->vertex_group_active_index <= 0) { BKE_report(reports, RPT_WARNING, "No active vertex group for painting, aborting"); return false; } if (vgroup_index) { - vgroup_index->active = ob->actdef - 1; + vgroup_index->active = me->vertex_group_active_index - 1; } if (flag & WPAINT_ENSURE_MIRROR) { if (ME_USING_MIRROR_X_VERTEX_GROUPS(me)) { - int mirror = ED_wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1); + int mirror = ED_wpaint_mirror_vgroup_ensure(ob, me->vertex_group_active_index - 1); if (vgroup_index) { vgroup_index->mirror = mirror; } @@ -133,7 +136,8 @@ bool ED_wpaint_ensure_data(bContext *C, /* mirror_vgroup is set to -1 when invalid */ int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) { - bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active); + const ListBase *defbase = BKE_object_defgroup_list(ob); + bDeformGroup *defgroup = BLI_findlink(defbase, vgroup_active); if (defgroup) { int mirrdef; @@ -143,7 +147,7 @@ int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) mirrdef = BKE_object_defgroup_name_index(ob, name_flip); if (mirrdef == -1) { if (BKE_object_defgroup_new(ob, name_flip)) { - mirrdef = BLI_listbase_count(&ob->defbase) - 1; + mirrdef = BLI_listbase_count(defbase) - 1; } } diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index fe7029c7457..f21c900941b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -1608,7 +1608,7 @@ void ED_sculpt_undosys_type(UndoType *ut) ut->step_decode = sculpt_undosys_step_decode; ut->step_free = sculpt_undosys_step_free; - ut->flags = 0; + ut->flags = UNDOTYPE_FLAG_DECODE_ACTIVE_STEP; ut->step_size = sizeof(SculptUndoStep); } diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index 9e69b0a72db..d69c7ab8d48 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -813,7 +813,7 @@ static int action_layer_next_exec(bContext *C, wmOperator *op) NlaTrack *act_track; Scene *scene = CTX_data_scene(C); - float ctime = BKE_scene_frame_get(scene); + float ctime = BKE_scene_ctime_get(scene); /* Get active track */ act_track = BKE_nlatrack_find_tweaked(adt); @@ -925,7 +925,7 @@ static int action_layer_prev_exec(bContext *C, wmOperator *op) NlaTrack *nlt; Scene *scene = CTX_data_scene(C); - float ctime = BKE_scene_frame_get(scene); + float ctime = BKE_scene_ctime_get(scene); /* Sanity Check */ if (adt == NULL) { diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 4d568017b4f..faa4b3cc9cc 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -523,6 +523,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) char orgname[FILE_MAX + 12]; char filename[FILE_MAX + 12]; wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); ARegion *region = CTX_wm_region(C); FileSelectParams *params = ED_fileselect_get_active_params(sfile); @@ -542,12 +543,16 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) else { /* If rename is successful, scroll to newly renamed entry. */ BLI_strncpy(params->renamefile, filename, sizeof(params->renamefile)); - file_params_invoke_rename_postscroll(wm, CTX_wm_window(C), sfile); + file_params_invoke_rename_postscroll(wm, win, sfile); } /* to make sure we show what is on disk */ ED_fileselect_clear(wm, sfile); } + else { + /* Renaming failed, reset the name for further renaming handling. */ + BLI_strncpy(params->renamefile, oldname, sizeof(params->renamefile)); + } ED_region_tag_redraw(region); } @@ -812,6 +817,8 @@ static void draw_details_columns(const FileSelectParams *params, void file_draw_list(const bContext *C, ARegion *region) { + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileLayout *layout = ED_fileselect_get_layout(sfile, region); @@ -882,12 +889,12 @@ void file_draw_list(const bContext *C, ARegion *region) // printf("%s: preview task: %d\n", __func__, previews_running); if (previews_running && !sfile->previews_timer) { sfile->previews_timer = WM_event_add_timer_notifier( - CTX_wm_manager(C), CTX_wm_window(C), NC_SPACE | ND_SPACE_FILE_PREVIEW, 0.01); + wm, win, NC_SPACE | ND_SPACE_FILE_PREVIEW, 0.01); } if (!previews_running && sfile->previews_timer) { /* Preview is not running, no need to keep generating update events! */ // printf("%s: Inactive preview task, sleeping!\n", __func__); - WM_event_remove_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), sfile->previews_timer); + WM_event_remove_timer_notifier(wm, win, sfile->previews_timer); sfile->previews_timer = NULL; } } @@ -998,8 +1005,19 @@ void file_draw_list(const bContext *C, ARegion *region) UI_but_flag_enable(but, UI_BUT_NO_UTF8); /* allow non utf8 names */ UI_but_flag_disable(but, UI_BUT_UNDO); if (false == UI_but_active_only(C, region, block, but)) { - file_selflag = filelist_entry_select_set( - sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL); + /* Note that this is the only place where we can also handle a cancelled renaming. */ + + file_params_rename_end(wm, win, sfile, file); + + /* After the rename button is removed, we need to make sure the view is redrawn once more, + * in case selection changed. Usually UI code would trigger that redraw, but the rename + * operator may have been called from a different region. + * Tagging regions for redrawing while drawing is rightfully prevented. However, this + * active button removing basically introduces handling logic to drawing code. So a + * notifier should be an acceptable workaround. */ + WM_event_add_notifier_ex(wm, win, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + + file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL); } } diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index b2182c45f2a..0bbed65671c 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -109,6 +109,7 @@ FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d, float file_string_width(const char *str); float file_font_pointsize(void); +void file_select_deselect_all(SpaceFile *sfile, uint flag); int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file); int autocomplete_directory(struct bContext *C, char *str, void *arg_v); int autocomplete_file(struct bContext *C, char *str, void *arg_v); @@ -120,6 +121,10 @@ void file_params_renamefile_clear(struct FileSelectParams *params); void file_params_invoke_rename_postscroll(struct wmWindowManager *wm, struct wmWindow *win, SpaceFile *sfile); +void file_params_rename_end(struct wmWindowManager *wm, + struct wmWindow *win, + SpaceFile *sfile, + struct FileDirEntry *rename_file); void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params); typedef void *onReloadFnData; diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index d91cc0f0b54..995383d9d0e 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -104,15 +104,6 @@ static FileSelection find_file_mouse_rect(SpaceFile *sfile, return sel; } -static void file_deselect_all(SpaceFile *sfile, uint flag) -{ - FileSelection sel; - sel.first = 0; - sel.last = filelist_files_ensure(sfile->files) - 1; - - filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL); -} - typedef enum FileSelect { FILE_SELECT_NOTHING = 0, FILE_SELECT_DIR = 1, @@ -444,7 +435,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) { int idx; - file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); + file_select_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); filelist_entries_select_index_range_set( sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); @@ -472,7 +463,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve params->highlight_file = -1; params->sel_first = params->sel_last = -1; fileselect_file_set(sfile, params->active_file); - file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); + file_select_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); } @@ -491,7 +482,7 @@ static int file_box_select_exec(bContext *C, wmOperator *op) const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); const bool select = (sel_op != SEL_OP_SUB); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - file_deselect_all(sfile, FILE_SEL_SELECTED); + file_select_deselect_all(sfile, FILE_SEL_SELECTED); } ED_fileselect_layout_isect_rect(sfile->layout, ®ion->v2d, &rect, &rect); @@ -573,7 +564,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) if ((idx >= 0) && (idx < numfiles)) { /* single select, deselect all selected first */ if (!extend) { - file_deselect_all(sfile, FILE_SEL_SELECTED); + file_select_deselect_all(sfile, FILE_SEL_SELECTED); } } } @@ -588,7 +579,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (ret == FILE_SELECT_NOTHING) { if (deselect_all) { - file_deselect_all(sfile, FILE_SEL_SELECTED); + file_select_deselect_all(sfile, FILE_SEL_SELECTED); } } else if (ret == FILE_SELECT_DIR) { @@ -721,7 +712,7 @@ static bool file_walk_select_selection_set(wmWindow *win, } else { /* deselect all first */ - file_deselect_all(sfile, FILE_SEL_SELECTED); + file_select_deselect_all(sfile, FILE_SEL_SELECTED); /* highlight file under mouse pos */ params->highlight_file = -1; @@ -2349,6 +2340,7 @@ static int file_directory_new_exec(bContext *C, wmOperator *op) /* If we don't enter the directory directly, remember file to jump into editing. */ if (do_diropen == false) { + BLI_assert(params->rename_id == NULL || !"File rename handling should immediately clear rename_id when done, because otherwise it will keep taking precedence over renamefile."); BLI_strncpy(params->renamefile, name, FILE_MAXFILE); rename_flag = FILE_PARAMS_RENAME_PENDING; } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index fe545aa5bf2..0e15538e03b 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2016,19 +2016,21 @@ FileDirEntry *filelist_file(struct FileList *filelist, int index) return filelist_file_ex(filelist, index, true); } -int filelist_file_findpath(struct FileList *filelist, const char *filename) +/** + * Find a file from a file name, or more precisely, its file-list relative path, inside the + * filtered items. \return The index of the found file or -1. + */ +int filelist_file_find_path(struct FileList *filelist, const char *filename) { - int fidx = -1; - if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) { - return fidx; + return -1; } /* XXX TODO: Cache could probably use a ghash on paths too? Not really urgent though. * This is only used to find again renamed entry, * annoying but looks hairy to get rid of it currently. */ - for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { + for (int fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; if (STREQ(entry->relpath, filename)) { return fidx; @@ -2039,6 +2041,26 @@ int filelist_file_findpath(struct FileList *filelist, const char *filename) } /** + * Find a file representing \a id. + * \return The index of the found file or -1. + */ +int filelist_file_find_id(const FileList *filelist, const ID *id) +{ + if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) { + return -1; + } + + for (int fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { + FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; + if (entry->local_data.id == id) { + return fidx; + } + } + + return -1; +} + +/** * Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET. */ ID *filelist_file_get_id(const FileDirEntry *file) @@ -2068,9 +2090,6 @@ void filelist_uid_unset(FileUID *r_uid) *r_uid = FILE_UID_UNSET; } -/** - * \warning The UID will only be valid for the current session. Use as runtime data only! - */ void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size) { /* Always keep it power of 2, in [256, 8192] range for now, diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index e6c4b8e1a07..0aace74e621 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -97,7 +97,8 @@ int filelist_needs_reading(struct FileList *filelist); FileDirEntry *filelist_file(struct FileList *filelist, int index); FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request); -int filelist_file_findpath(struct FileList *filelist, const char *file); +int filelist_file_find_path(struct FileList *filelist, const char *file); +int filelist_file_find_id(const struct FileList *filelist, const struct ID *id); struct ID *filelist_file_get_id(const struct FileDirEntry *file); bool filelist_uid_is_set(const FileUID uid); void filelist_uid_unset(FileUID *r_uid); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 4e59e4ba06e..b7accbf71e5 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -1086,6 +1086,15 @@ void ED_file_change_dir(bContext *C) ED_file_change_dir_ex(C, area); } +void file_select_deselect_all(SpaceFile *sfile, uint flag) +{ + FileSelection sel; + sel.first = 0; + sel.last = filelist_files_ensure(sfile->files) - 1; + + filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL); +} + int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file) { int match = 0; @@ -1237,7 +1246,7 @@ void file_params_smoothscroll_timer_clear(wmWindowManager *wm, wmWindow *win, Sp * Set the renaming-state to #FILE_PARAMS_RENAME_POSTSCROLL_PENDING and trigger the smooth-scroll * timer. To be used right after a file was renamed. * Note that the caller is responsible for setting the correct rename-file info - * (#FileSelectParams.renamefile or #FileSelectParams.renamefile_uuid). + * (#FileSelectParams.renamefile or #FileSelectParams.rename_id). */ void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile) { @@ -1252,12 +1261,40 @@ void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, Sp sfile->scroll_offset = 0; } +/** + * To be executed whenever renaming ends (successfully or not). + */ +void file_params_rename_end(wmWindowManager *wm, + wmWindow *win, + SpaceFile *sfile, + FileDirEntry *rename_file) +{ + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + + filelist_entry_select_set( + sfile->files, rename_file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL); + + /* Ensure smooth-scroll timer is active, even if not needed, because that way rename state is + * handled properly. */ + file_params_invoke_rename_postscroll(wm, win, sfile); + /* Also always activate the rename file, even if renaming was cancelled. */ + file_params_renamefile_activate(sfile, params); +} + void file_params_renamefile_clear(FileSelectParams *params) { params->renamefile[0] = '\0'; + params->rename_id = NULL; params->rename_flag = 0; } +static int file_params_find_renamed(const FileSelectParams *params, struct FileList *filelist) +{ + /* Find the file either through the local ID/asset it represents or its relative path. */ + return (params->rename_id != NULL) ? filelist_file_find_id(filelist, params->rename_id) : + filelist_file_find_path(filelist, params->renamefile); +} + /** * Helper used by both main update code, and smooth-scroll timer, * to try to enable rename editing from #FileSelectParams.renamefile name. @@ -1271,20 +1308,26 @@ void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params) return; } - BLI_assert(params->renamefile[0] != '\0'); + BLI_assert(params->renamefile[0] != '\0' || params->rename_id != NULL); - const int idx = filelist_file_findpath(sfile->files, params->renamefile); + const int idx = file_params_find_renamed(params, sfile->files); if (idx >= 0) { FileDirEntry *file = filelist_file(sfile->files, idx); BLI_assert(file != NULL); + params->active_file = idx; + filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + if ((params->rename_flag & FILE_PARAMS_RENAME_PENDING) != 0) { filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; } else if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_PENDING) != 0) { - filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL); - params->renamefile[0] = '\0'; + file_select_deselect_all(sfile, FILE_SEL_SELECTED); + filelist_entry_select_set( + sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED | FILE_SEL_HIGHLIGHTED, CHECK_ALL); + params->active_file = idx; + file_params_renamefile_clear(params); params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE; } } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 64b43ac74a5..05d484d8e2e 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -32,6 +32,7 @@ #include "BKE_appdir.h" #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_screen.h" #include "RNA_access.h" @@ -469,10 +470,19 @@ static void file_listener(const wmSpaceTypeListenerParams *listener_params) break; case NC_ID: { switch (wmn->action) { - case NA_RENAME: + case NA_RENAME: { + const ID *active_file_id = ED_fileselect_active_asset_get(sfile); + /* If a renamed ID is active in the file browser, update scrolling to keep it in view. */ + if (active_file_id && (wmn->reference == active_file_id)) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + params->rename_id = active_file_id; + file_params_invoke_rename_postscroll(G_MAIN->wm.first, listener_params->window, sfile); + } + /* Force list to update sorting (with a full reset for now). */ file_reset_filelist_showing_main_data(area, sfile); break; + } } break; } diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c index 082f66b57af..cc6effd0f71 100644 --- a/source/blender/editors/space_image/image_undo.c +++ b/source/blender/editors/space_image/image_undo.c @@ -1006,7 +1006,7 @@ void ED_image_undosys_type(UndoType *ut) * specific case, see `image_undosys_step_encode` code. We cannot specify * `UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE` though, as it can be called with a NULL context by * current code. */ - ut->flags = 0; + ut->flags = UNDOTYPE_FLAG_DECODE_ACTIVE_STEP; ut->step_size = sizeof(ImageUndoStep); } diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index aaf9852e212..94e53958524 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -564,12 +564,11 @@ void FILE_OT_find_missing_files(wmOperatorType *ot) /** \name Report Box Operator * \{ */ -/* Hard to decide whether to keep this as an operator, - * or turn it into a hardcoded ui control feature, - * handling TIMER events for all regions in interface_handlers.c +/* NOTE(matt): Hard to decide whether to keep this as an operator, + * or turn it into a hard_coded UI control feature, + * handling TIMER events for all regions in `interface_handlers.c`. * Not sure how good that is to be accessing UI data from - * inactive regions, so use this for now. --matt - */ + * inactive regions, so use this for now. */ #define INFO_TIMEOUT 5.0f #define ERROR_TIMEOUT 10.0f diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 51b897ce5a3..0498964c549 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -874,7 +874,7 @@ static int nlaedit_objects_add_exec(bContext *C, wmOperator *UNUSED(op)) /* operate on selected objects... */ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { /* ensure that object has AnimData... that's all */ - BKE_animdata_add_id(&ob->id); + BKE_animdata_ensure_id(&ob->id); } CTX_DATA_END; diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 6e234c5b2ce..80d3b43bf6b 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../compositor ../../depsgraph ../../draw + ../../functions ../../gpu ../../imbuf ../../makesdna @@ -39,7 +40,6 @@ set(INC set(SRC drawnode.cc node_add.cc - node_buttons.c node_draw.cc node_edit.cc node_geometry_attribute_search.cc @@ -78,4 +78,20 @@ if(WITH_OPENSUBDIV) add_definitions(-DWITH_OPENSUBDIV) endif() +if(WITH_TBB) + add_definitions(-DWITH_TBB) + if(WIN32) + # TBB includes Windows.h which will define min/max macros + # that will collide with the stl versions. + add_definitions(-DNOMINMAX) + endif() + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) + + list(APPEND LIB + ${TBB_LIBRARIES} + ) +endif() + blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c deleted file mode 100644 index a55cc21fb16..00000000000 --- a/source/blender/editors/space_node/node_buttons.c +++ /dev/null @@ -1,250 +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) 2009 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup spnode - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_node_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" - -#include "BLT_translation.h" - -#include "BKE_context.h" -#include "BKE_global.h" -#include "BKE_node.h" -#include "BKE_screen.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "RNA_access.h" - -#include "ED_screen.h" - -#include "UI_resources.h" - -#include "node_intern.h" /* own include */ - -/* ******************* node space & buttons ************** */ - -#if 0 -/* poll for active nodetree */ -static bool active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - return (snode && snode->nodetree); -} -#endif - -static bool node_sockets_poll(const bContext *C, PanelType *UNUSED(pt)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - return (snode && snode->nodetree && G.debug_value == 777); -} - -static void node_sockets_panel(const bContext *C, Panel *panel) -{ - SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */ - bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */ - bNode *node = nodeGetActive(ntree); - if (node == NULL) { - return; - } - - LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { - char name[UI_MAX_NAME_STR]; - BLI_snprintf(name, sizeof(name), "%s:", socket->name); - - uiLayout *split = uiLayoutSplit(panel->layout, 0.35f, false); - uiItemL(split, name, ICON_NONE); - uiTemplateNodeLink(split, (bContext *)C, ntree, node, socket); - } -} - -static bool node_tree_interface_poll(const bContext *C, PanelType *UNUSED(pt)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - return (snode && snode->edittree && - (snode->edittree->inputs.first || snode->edittree->outputs.first)); -} - -static bNodeSocket *node_tree_find_active_socket(bNodeTree *ntree, const eNodeSocketInOut in_out) -{ - ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs; - LISTBASE_FOREACH (bNodeSocket *, socket, sockets) { - if (socket->flag & SELECT) { - return socket; - } - } - return NULL; -} - -static void draw_socket_list(const bContext *C, - uiLayout *layout, - bNodeTree *ntree, - const eNodeSocketInOut in_out) -{ - PointerRNA tree_ptr; - RNA_id_pointer_create((ID *)ntree, &tree_ptr); - - uiLayout *split = uiLayoutRow(layout, false); - uiLayout *list_col = uiLayoutColumn(split, true); - uiTemplateList(list_col, - (bContext *)C, - "NODE_UL_interface_sockets", - (in_out == SOCK_IN) ? "inputs" : "outputs", - &tree_ptr, - (in_out == SOCK_IN) ? "inputs" : "outputs", - &tree_ptr, - (in_out == SOCK_IN) ? "active_input" : "active_output", - NULL, - 0, - 0, - 0, - 0, - false, - false); - PointerRNA opptr; - uiLayout *ops_col = uiLayoutColumn(split, false); - uiLayout *add_remove_col = uiLayoutColumn(ops_col, true); - wmOperatorType *ot = WM_operatortype_find("NODE_OT_tree_socket_add", false); - uiItemFullO_ptr(add_remove_col, ot, "", ICON_ADD, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); - RNA_enum_set(&opptr, "in_out", in_out); - ot = WM_operatortype_find("NODE_OT_tree_socket_remove", false); - uiItemFullO_ptr(add_remove_col, ot, "", ICON_REMOVE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); - RNA_enum_set(&opptr, "in_out", in_out); - - uiItemS(ops_col); - - uiLayout *up_down_col = uiLayoutColumn(ops_col, true); - ot = WM_operatortype_find("NODE_OT_tree_socket_move", false); - uiItemFullO_ptr(up_down_col, ot, "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); - RNA_enum_set(&opptr, "direction", 1); - RNA_enum_set(&opptr, "in_out", in_out); - uiItemFullO_ptr(up_down_col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); - RNA_enum_set(&opptr, "direction", 2); - RNA_enum_set(&opptr, "in_out", in_out); - - bNodeSocket *socket = node_tree_find_active_socket(ntree, in_out); - if (socket != NULL) { - PointerRNA socket_ptr; - RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, socket, &socket_ptr); - - { - /* Mimicking property split */ - uiLayoutSetPropSep(layout, false); - uiLayoutSetPropDecorate(layout, false); - uiLayout *layout_row = uiLayoutRow(layout, true); - uiLayout *layout_split = uiLayoutSplit(layout_row, 0.4f, true); - - uiLayout *label_column = uiLayoutColumn(layout_split, true); - uiLayoutSetAlignment(label_column, UI_LAYOUT_ALIGN_RIGHT); - /* Menu to change the socket type. */ - uiItemL(label_column, "Type", ICON_NONE); - - uiLayout *property_row = uiLayoutRow(layout_split, true); - - PointerRNA props_ptr; - uiItemMenuEnumFullO(property_row, - (bContext *)C, - "NODE_OT_tree_socket_change_type", - "socket_type", - nodeSocketTypeLabel(socket->typeinfo), - ICON_NONE, - &props_ptr); - RNA_enum_set(&props_ptr, "in_out", in_out); - } - - uiLayoutSetPropSep(layout, true); - uiLayoutSetPropDecorate(layout, false); - - uiItemR(layout, &socket_ptr, "name", 0, NULL, ICON_NONE); - - /* Display descriptions only for Geometry Nodes, since it's only used in the modifier panel. */ - if (ntree->type == NTREE_GEOMETRY) { - uiItemR(layout, &socket_ptr, "description", 0, NULL, ICON_NONE); - } - - if (socket->typeinfo->interface_draw) { - socket->typeinfo->interface_draw((bContext *)C, layout, &socket_ptr); - } - } -} - -static void node_tree_interface_inputs_panel(const bContext *C, Panel *panel) -{ - SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */ - bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */ - - draw_socket_list(C, panel->layout, ntree, SOCK_IN); -} - -static void node_tree_interface_outputs_panel(const bContext *C, Panel *panel) -{ - SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */ - bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */ - - draw_socket_list(C, panel->layout, ntree, SOCK_OUT); -} - -/* ******************* node buttons registration ************** */ - -void node_buttons_register(ARegionType *art) -{ - { - PanelType *pt = MEM_callocN(sizeof(PanelType), __func__); - strcpy(pt->idname, "NODE_PT_sockets"); - strcpy(pt->category, N_("Node")); - strcpy(pt->label, N_("Sockets")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = node_sockets_panel; - pt->poll = node_sockets_poll; - pt->flag |= PANEL_TYPE_DEFAULT_CLOSED; - BLI_addtail(&art->paneltypes, pt); - } - - { - PanelType *pt = MEM_callocN(sizeof(PanelType), __func__); - strcpy(pt->idname, "NODE_PT_node_tree_interface_inputs"); - strcpy(pt->category, N_("Group")); - strcpy(pt->label, N_("Inputs")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = node_tree_interface_inputs_panel; - pt->poll = node_tree_interface_poll; - BLI_addtail(&art->paneltypes, pt); - } - { - PanelType *pt = MEM_callocN(sizeof(PanelType), __func__); - strcpy(pt->idname, "NODE_PT_node_tree_interface_outputs"); - strcpy(pt->category, N_("Group")); - strcpy(pt->label, N_("Outputs")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = node_tree_interface_outputs_panel; - pt->poll = node_tree_interface_poll; - BLI_addtail(&art->paneltypes, pt); - } -} diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 8a341da0b5c..7eca5c0c933 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -45,10 +45,10 @@ #include "BLT_translation.h" #include "BKE_context.h" +#include "BKE_idtype.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" -#include "BKE_node_ui_storage.hh" #include "BKE_object.h" #include "DEG_depsgraph.h" @@ -76,6 +76,8 @@ #include "RNA_access.h" +#include "NOD_geometry_nodes_eval_log.hh" + #include "node_intern.h" /* own include */ #ifdef WITH_COMPOSITOR @@ -86,6 +88,9 @@ using blender::Map; using blender::Set; using blender::Span; using blender::Vector; +using blender::fn::CPPType; +using blender::fn::GPointer; +namespace geo_log = blender::nodes::geometry_nodes_eval_log; extern "C" { /* XXX interface.h */ @@ -822,6 +827,149 @@ void node_socket_color_get( } } +struct SocketTooltipData { + bNodeTree *ntree; + bNode *node; + bNodeSocket *socket; +}; + +static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log, + std::stringstream &ss) +{ + auto id_to_inspection_string = [&](ID *id) { + ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(GS(id->name)) + << ")"; + }; + + const GPointer value = value_log.value(); + if (value.is_type<int>()) { + ss << *value.get<int>() << TIP_(" (Integer)"); + } + else if (value.is_type<float>()) { + ss << *value.get<float>() << TIP_(" (Float)"); + } + else if (value.is_type<blender::float3>()) { + ss << *value.get<blender::float3>() << TIP_(" (Vector)"); + } + else if (value.is_type<bool>()) { + ss << (*value.get<bool>() ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)"); + } + else if (value.is_type<std::string>()) { + ss << *value.get<std::string>() << TIP_(" (String)"); + } + else if (value.is_type<Object *>()) { + id_to_inspection_string((ID *)*value.get<Object *>()); + } + else if (value.is_type<Material *>()) { + id_to_inspection_string((ID *)*value.get<Material *>()); + } + else if (value.is_type<Tex *>()) { + id_to_inspection_string((ID *)*value.get<Tex *>()); + } + else if (value.is_type<Collection *>()) { + id_to_inspection_string((ID *)*value.get<Collection *>()); + } +} + +static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log, + std::stringstream &ss) +{ + Span<GeometryComponentType> component_types = value_log.component_types(); + if (component_types.is_empty()) { + ss << TIP_("Empty Geometry"); + return; + } + + auto to_string = [](int value) { + char str[16]; + BLI_str_format_int_grouped(str, value); + return std::string(str); + }; + + ss << TIP_("Geometry:\n"); + for (GeometryComponentType type : component_types) { + const char *line_end = (type == component_types.last()) ? "" : ".\n"; + switch (type) { + case GEO_COMPONENT_TYPE_MESH: { + const geo_log::GeometryValueLog::MeshInfo &mesh_info = *value_log.mesh_info; + char line[256]; + BLI_snprintf(line, + sizeof(line), + TIP_("\u2022 Mesh: %s vertices, %s edges, %s faces"), + to_string(mesh_info.tot_verts).c_str(), + to_string(mesh_info.tot_edges).c_str(), + to_string(mesh_info.tot_faces).c_str()); + ss << line << line_end; + break; + } + case GEO_COMPONENT_TYPE_POINT_CLOUD: { + const geo_log::GeometryValueLog::PointCloudInfo &pointcloud_info = + *value_log.pointcloud_info; + char line[256]; + BLI_snprintf(line, + sizeof(line), + TIP_("\u2022 Point Cloud: %s points"), + to_string(pointcloud_info.tot_points).c_str()); + ss << line << line_end; + break; + } + case GEO_COMPONENT_TYPE_CURVE: { + const geo_log::GeometryValueLog::CurveInfo &curve_info = *value_log.curve_info; + char line[256]; + BLI_snprintf(line, + sizeof(line), + TIP_("\u2022 Curve: %s splines"), + to_string(curve_info.tot_splines).c_str()); + ss << line << line_end; + break; + } + case GEO_COMPONENT_TYPE_INSTANCES: { + const geo_log::GeometryValueLog::InstancesInfo &instances_info = *value_log.instances_info; + char line[256]; + BLI_snprintf(line, + sizeof(line), + TIP_("\u2022 Instances: %s"), + to_string(instances_info.tot_instances).c_str()); + ss << line << line_end; + break; + } + case GEO_COMPONENT_TYPE_VOLUME: { + ss << TIP_("\u2022 Volume") << line_end; + break; + } + } + } +} + +static std::optional<std::string> create_socket_inspection_string(bContext *C, + bNodeTree &UNUSED(ntree), + bNode &node, + bNodeSocket &socket) +{ + SpaceNode *snode = CTX_wm_space_node(C); + const geo_log::SocketLog *socket_log = geo_log::ModifierLog::find_socket_by_node_editor_context( + *snode, node, socket); + if (socket_log == nullptr) { + return {}; + } + const geo_log::ValueLog *value_log = socket_log->value(); + if (value_log == nullptr) { + return {}; + } + + std::stringstream ss; + if (const geo_log::GenericValueLog *generic_value_log = + dynamic_cast<const geo_log::GenericValueLog *>(value_log)) { + create_inspection_string_for_generic_value(*generic_value_log, ss); + } + else if (const geo_log::GeometryValueLog *geo_value_log = + dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) { + create_inspection_string_for_geometry(*geo_value_log, ss); + } + + return ss.str(); +} + static void node_socket_draw_nested(const bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, @@ -851,6 +999,55 @@ static void node_socket_draw_nested(const bContext *C, shape_id, size_id, outline_col_id); + + if (ntree->type != NTREE_GEOMETRY) { + /* Only geometry nodes has socket value tooltips currently. */ + return; + } + + bNode *node = (bNode *)node_ptr->data; + uiBlock *block = node->block; + + /* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible + * button on top of them for the tooltip. */ + const eUIEmbossType old_emboss = UI_block_emboss_get(block); + UI_block_emboss_set(block, UI_EMBOSS_NONE); + uiBut *but = uiDefIconBut(block, + UI_BTYPE_BUT, + 0, + ICON_NONE, + sock->locx - size / 2, + sock->locy - size / 2, + size, + size, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + + SocketTooltipData *data = (SocketTooltipData *)MEM_mallocN(sizeof(SocketTooltipData), __func__); + data->ntree = ntree; + data->node = (bNode *)node_ptr->data; + data->socket = sock; + + UI_but_func_tooltip_set( + but, + [](bContext *C, void *argN, const char *UNUSED(tip)) { + SocketTooltipData *data = (SocketTooltipData *)argN; + std::optional<std::string> str = create_socket_inspection_string( + C, *data->ntree, *data->node, *data->socket); + if (str.has_value()) { + return BLI_strdup(str->c_str()); + } + return BLI_strdup(TIP_("The socket value has not been computed yet")); + }, + data, + MEM_freeN); + /* Disable the button so that clicks on it are ignored the the link operator still works. */ + UI_but_flag_enable(but, UI_BUT_DISABLED); + UI_block_emboss_set(block, old_emboss); } /** @@ -1185,14 +1382,14 @@ void node_draw_sockets(const View2D *v2d, } } -static int node_error_type_to_icon(const NodeWarningType type) +static int node_error_type_to_icon(const geo_log::NodeWarningType type) { switch (type) { - case NodeWarningType::Error: + case geo_log::NodeWarningType::Error: return ICON_ERROR; - case NodeWarningType::Warning: + case geo_log::NodeWarningType::Warning: return ICON_ERROR; - case NodeWarningType::Info: + case geo_log::NodeWarningType::Info: return ICON_INFO; } @@ -1200,14 +1397,14 @@ static int node_error_type_to_icon(const NodeWarningType type) return ICON_ERROR; } -static uint8_t node_error_type_priority(const NodeWarningType type) +static uint8_t node_error_type_priority(const geo_log::NodeWarningType type) { switch (type) { - case NodeWarningType::Error: + case geo_log::NodeWarningType::Error: return 3; - case NodeWarningType::Warning: + case geo_log::NodeWarningType::Warning: return 2; - case NodeWarningType::Info: + case geo_log::NodeWarningType::Info: return 1; } @@ -1215,11 +1412,11 @@ static uint8_t node_error_type_priority(const NodeWarningType type) return 0; } -static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings) +static geo_log::NodeWarningType node_error_highest_priority(Span<geo_log::NodeWarning> warnings) { uint8_t highest_priority = 0; - NodeWarningType highest_priority_type = NodeWarningType::Info; - for (const NodeWarning &warning : warnings) { + geo_log::NodeWarningType highest_priority_type = geo_log::NodeWarningType::Info; + for (const geo_log::NodeWarning &warning : warnings) { const uint8_t priority = node_error_type_priority(warning.type); if (priority > highest_priority) { highest_priority = priority; @@ -1229,15 +1426,17 @@ static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings) return highest_priority_type; } +struct NodeErrorsTooltipData { + Span<geo_log::NodeWarning> warnings; +}; + static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char *UNUSED(tip)) { - const NodeUIStorage **storage_pointer_alloc = static_cast<const NodeUIStorage **>(argN); - const NodeUIStorage *node_ui_storage = *storage_pointer_alloc; - Span<NodeWarning> warnings = node_ui_storage->warnings; + NodeErrorsTooltipData &data = *(NodeErrorsTooltipData *)argN; std::string complete_string; - for (const NodeWarning &warning : warnings.drop_back(1)) { + for (const geo_log::NodeWarning &warning : data.warnings.drop_back(1)) { complete_string += warning.message; /* Adding the period is not ideal for multi-line messages, but it is consistent * with other tooltip implementations in Blender, so it is added here. */ @@ -1246,7 +1445,7 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char } /* Let the tooltip system automatically add the last period. */ - complete_string += warnings.last().message; + complete_string += data.warnings.last().message; return BLI_strdupn(complete_string.c_str(), complete_string.size()); } @@ -1254,20 +1453,26 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char #define NODE_HEADER_ICON_SIZE (0.8f * U.widget_unit) static void node_add_error_message_button( - const bContext *C, bNodeTree &ntree, bNode &node, const rctf &rect, float &icon_offset) + const bContext *C, bNodeTree &UNUSED(ntree), bNode &node, const rctf &rect, float &icon_offset) { - const NodeUIStorage *node_ui_storage = BKE_node_tree_ui_storage_get_from_context(C, ntree, node); - if (node_ui_storage == nullptr || node_ui_storage->warnings.is_empty()) { + SpaceNode *snode = CTX_wm_space_node(C); + const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(*snode, + node); + if (node_log == nullptr) { + return; + } + + Span<geo_log::NodeWarning> warnings = node_log->warnings(); + + if (warnings.is_empty()) { return; } - /* The UI API forces us to allocate memory for each error button, because the - * ownership of #UI_but_func_tooltip_set's argument is transferred to the button. */ - const NodeUIStorage **storage_pointer_alloc = (const NodeUIStorage **)MEM_mallocN( - sizeof(NodeUIStorage *), __func__); - *storage_pointer_alloc = node_ui_storage; + NodeErrorsTooltipData *tooltip_data = (NodeErrorsTooltipData *)MEM_mallocN( + sizeof(NodeErrorsTooltipData), __func__); + tooltip_data->warnings = warnings; - const NodeWarningType display_type = node_error_highest_priority(node_ui_storage->warnings); + const geo_log::NodeWarningType display_type = node_error_highest_priority(warnings); icon_offset -= NODE_HEADER_ICON_SIZE; UI_block_emboss_set(node.block, UI_EMBOSS_NONE); @@ -1285,7 +1490,7 @@ static void node_add_error_message_button( 0, 0, nullptr); - UI_but_func_tooltip_set(but, node_errors_tooltip_fn, storage_pointer_alloc, MEM_freeN); + UI_but_func_tooltip_set(but, node_errors_tooltip_fn, tooltip_data, MEM_freeN); UI_block_emboss_set(node.block, UI_EMBOSS); } diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 94080a7b616..a6901c21862 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -27,7 +27,6 @@ #include "DNA_space_types.h" #include "BKE_context.h" -#include "BKE_node_ui_storage.hh" #include "BKE_object.h" #include "RNA_access.h" @@ -40,17 +39,21 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "NOD_geometry_nodes_eval_log.hh" + #include "node_intern.h" using blender::IndexRange; using blender::Map; using blender::Set; using blender::StringRef; +namespace geo_log = blender::nodes::geometry_nodes_eval_log; +using geo_log::GeometryAttributeInfo; struct AttributeSearchData { - AvailableAttributeInfo &dummy_info_for_search; - const NodeUIStorage &ui_storage; - bNodeSocket &socket; + const bNodeTree *tree; + const bNode *node; + bNodeSocket *socket; }; /* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */ @@ -73,7 +76,7 @@ static StringRef attribute_domain_string(const AttributeDomain domain) /* Unicode arrow. */ #define MENU_SEP "\xe2\x96\xb6" -static bool attribute_search_item_add(uiSearchItems *items, const AvailableAttributeInfo &item) +static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttributeInfo &item) { const StringRef data_type_name = attribute_data_type_string(item.data_type); const StringRef domain_name = attribute_domain_string(item.domain); @@ -84,31 +87,47 @@ static bool attribute_search_item_add(uiSearchItems *items, const AvailableAttri items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0); } -static void attribute_search_update_fn(const bContext *UNUSED(C), - void *arg, - const char *str, - uiSearchItems *items, - const bool is_first) +static GeometryAttributeInfo &get_dummy_item_info() +{ + static GeometryAttributeInfo info; + return info; +} + +static void attribute_search_update_fn( + const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first) { AttributeSearchData *data = static_cast<AttributeSearchData *>(arg); - const Set<AvailableAttributeInfo> &attribute_hints = data->ui_storage.attribute_hints; + SpaceNode *snode = CTX_wm_space_node(C); + const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context( + *snode, *data->node); + if (node_log == nullptr) { + return; + } + blender::Vector<const GeometryAttributeInfo *> infos = node_log->lookup_available_attributes(); + + GeometryAttributeInfo &dummy_info = get_dummy_item_info(); /* Any string may be valid, so add the current search string along with the hints. */ if (str[0] != '\0') { - /* Note that the attribute domain and data type are dummies, since - * #AvailableAttributeInfo equality is only based on the string. */ - if (!attribute_hints.contains(AvailableAttributeInfo{str, ATTR_DOMAIN_AUTO, CD_PROP_BOOL})) { - data->dummy_info_for_search.name = std::string(str); - UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_ADD, 0, 0); + bool contained = false; + for (const GeometryAttributeInfo *attribute_info : infos) { + if (attribute_info->name == str) { + contained = true; + break; + } + } + if (!contained) { + dummy_info.name = str; + UI_search_item_add(items, str, &dummy_info, ICON_ADD, 0, 0); } } if (str[0] == '\0' && !is_first) { /* Allow clearing the text field when the string is empty, but not on the first pass, * or opening an attribute field for the first time would show this search item. */ - data->dummy_info_for_search.name = std::string(str); - UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_X, 0, 0); + dummy_info.name = str; + UI_search_item_add(items, str, &dummy_info, ICON_X, 0, 0); } /* Don't filter when the menu is first opened, but still run the search @@ -116,15 +135,15 @@ static void attribute_search_update_fn(const bContext *UNUSED(C), const char *string = is_first ? "" : str; StringSearch *search = BLI_string_search_new(); - for (const AvailableAttributeInfo &item : attribute_hints) { - BLI_string_search_add(search, item.name.c_str(), (void *)&item); + for (const GeometryAttributeInfo *item : infos) { + BLI_string_search_add(search, item->name.c_str(), (void *)item); } - AvailableAttributeInfo **filtered_items; + GeometryAttributeInfo **filtered_items; const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items); for (const int i : IndexRange(filtered_amount)) { - const AvailableAttributeInfo *item = filtered_items[i]; + const GeometryAttributeInfo *item = filtered_items[i]; if (!attribute_search_item_add(items, *item)) { break; } @@ -136,32 +155,25 @@ static void attribute_search_update_fn(const bContext *UNUSED(C), static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v) { + if (item_v == nullptr) { + return; + } AttributeSearchData *data = static_cast<AttributeSearchData *>(data_v); - AvailableAttributeInfo *item = static_cast<AvailableAttributeInfo *>(item_v); + GeometryAttributeInfo *item = (GeometryAttributeInfo *)item_v; - bNodeSocket &socket = data->socket; + bNodeSocket &socket = *data->socket; bNodeSocketValueString *value = static_cast<bNodeSocketValueString *>(socket.default_value); BLI_strncpy(value->value, item->name.c_str(), MAX_NAME); ED_undo_push(C, "Assign Attribute Name"); } -void node_geometry_add_attribute_search_button(const bContext *C, +void node_geometry_add_attribute_search_button(const bContext *UNUSED(C), const bNodeTree *node_tree, const bNode *node, PointerRNA *socket_ptr, uiLayout *layout) { - const NodeUIStorage *ui_storage = BKE_node_tree_ui_storage_get_from_context( - C, *node_tree, *node); - - if (ui_storage == nullptr) { - uiItemR(layout, socket_ptr, "default_value", 0, "", 0); - return; - } - - const NodeTreeUIStorage *tree_ui_storage = node_tree->ui_storage; - uiBlock *block = uiLayoutGetBlock(layout); uiBut *but = uiDefIconTextButR(block, UI_BTYPE_SEARCH_MENU, @@ -181,10 +193,8 @@ void node_geometry_add_attribute_search_button(const bContext *C, 0.0f, ""); - AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData, - {tree_ui_storage->dummy_info_for_search, - *ui_storage, - *static_cast<bNodeSocket *>(socket_ptr->data)}); + AttributeSearchData *data = OBJECT_GUARDED_NEW( + AttributeSearchData, {node_tree, node, (bNodeSocket *)socket_ptr->data}); UI_but_func_search_set_results_are_suggestions(but, true); UI_but_func_search_set_sep_string(but, MENU_SEP); diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index fe550242dbe..09e5a110a45 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -140,9 +140,6 @@ void node_to_view(const struct bNode *node, float x, float y, float *rx, float * void node_to_updated_rect(const struct bNode *node, rctf *r_rect); void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry); -/* node_buttons.c */ -void node_buttons_register(struct ARegionType *art); - /* node_toolbar.c */ void node_toolbar_register(struct ARegionType *art); diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index d7e16dd69f1..ff848a7bb95 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -651,6 +651,10 @@ static void node_main_region_init(wmWindowManager *wm, ARegion *region) lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW); WM_event_add_dropbox_handler(®ion->handlers, lb); + + /* The backdrop image gizmo needs to change together with the view. So always refresh gizmos on + * region size changes. */ + WM_gizmomap_tag_refresh(region->gizmo_map); } static void node_main_region_draw(const bContext *C, ARegion *region) @@ -1094,8 +1098,6 @@ void ED_spacetype_node(void) art->draw = node_buttons_region_draw; BLI_addhead(&st->regiontypes, art); - node_buttons_register(art); - /* regions: toolbar */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); art->regionid = RGN_TYPE_TOOLS; diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index d1fb36979b4..db37c8c1c8c 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -2964,7 +2964,8 @@ static void outliner_draw_iconrow(bContext *C, te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED); /* object hierarchy always, further constrained on level */ - if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) { + if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) || + ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL)) { /* active blocks get white circle */ if (tselem->type == TSE_SOME_ID) { if (te->idcode == ID_OB) { diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index f248711633e..35015356f0b 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -42,6 +42,7 @@ #include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_context.h" +#include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" #include "BKE_layer.h" @@ -450,7 +451,7 @@ static void tree_element_defgroup_activate(bContext *C, TreeElement *te, TreeSto /* id in tselem is object */ Object *ob = (Object *)tselem->id; BLI_assert(te->index + 1 >= 0); - ob->actdef = te->index + 1; + BKE_object_defgroup_active_index_set(ob, te->index + 1); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); @@ -830,7 +831,7 @@ static eOLDrawState tree_element_defgroup_state_get(const ViewLayer *view_layer, { const Object *ob = (const Object *)tselem->id; if (ob == OBACT(view_layer)) { - if (ob->actdef == te->index + 1) { + if (BKE_object_defgroup_active_index_get(ob) == te->index + 1) { return OL_DRAWSEL_NORMAL; } } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 334c901b6d3..c08707b7a6a 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1,4 +1,4 @@ -/* +/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -62,6 +62,7 @@ #include "BLT_translation.h" #include "BKE_armature.h" +#include "BKE_deform.h" #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -552,17 +553,20 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } /* vertex groups */ - if (!BLI_listbase_is_empty(&ob->defbase)) { - TreeElement *tenla = outliner_add_element( - space_outliner, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0); - tenla->name = IFACE_("Vertex Groups"); + if (ELEM(ob->type, OB_MESH, OB_GPENCIL, OB_LATTICE)) { + const ListBase *defbase = BKE_object_defgroup_list(ob); + if (!BLI_listbase_is_empty(defbase)) { + TreeElement *tenla = outliner_add_element( + space_outliner, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0); + tenla->name = IFACE_("Vertex Groups"); - int index; - LISTBASE_FOREACH_INDEX (bDeformGroup *, defgroup, &ob->defbase, index) { - TreeElement *ten = outliner_add_element( - space_outliner, &tenla->subtree, ob, tenla, TSE_DEFGROUP, index); - ten->name = defgroup->name; - ten->directdata = defgroup; + int index; + LISTBASE_FOREACH_INDEX (bDeformGroup *, defgroup, defbase, index) { + TreeElement *ten = outliner_add_element( + space_outliner, &tenla->subtree, ob, tenla, TSE_DEFGROUP, index); + ten->name = defgroup->name; + ten->directdata = defgroup; + } } } diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh index f089a149805..96af8258010 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.hh +++ b/source/blender/editors/space_outliner/tree/tree_display.hh @@ -86,7 +86,7 @@ class TreeDisplayViewLayer final : public AbstractTreeDisplay { ListBase buildTree(const TreeSourceData &source_data) override; private: - void add_view_layer(ListBase &, TreeElement &); + void add_view_layer(Scene &, ListBase &, TreeElement *); void add_layer_collections_recursive(ListBase &, ListBase &, TreeElement &); void add_layer_collection_objects(ListBase &, LayerCollection &, TreeElement &); void add_layer_collection_objects_children(TreeElement &); diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc index 3059f8bfe0c..a17bf174a74 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc @@ -150,27 +150,25 @@ TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar, } /* Create data-block list parent element on demand. */ - if (id != nullptr) { - TreeElement *ten; + TreeElement *ten; - if (filter_id_type) { - ten = tenlib; - } - else { - ten = outliner_add_element( - &space_outliner_, &tenlib->subtree, lbarray[a], nullptr, TSE_ID_BASE, 0); - ten->directdata = lbarray[a]; - ten->name = outliner_idcode_to_plural(GS(id->name)); - } + if (filter_id_type) { + ten = tenlib; + } + else { + ten = outliner_add_element( + &space_outliner_, &tenlib->subtree, lbarray[a], nullptr, TSE_ID_BASE, 0); + ten->directdata = lbarray[a]; + ten->name = outliner_idcode_to_plural(GS(id->name)); + } - for (ID *id : List<ID>(lbarray[a])) { - if (override_library_id_filter_poll(lib, id)) { - TreeElement *override_tree_element = outliner_add_element( - &space_outliner_, &ten->subtree, id, ten, TSE_LIBRARY_OVERRIDE_BASE, 0); + for (ID *id : List<ID>(lbarray[a])) { + if (override_library_id_filter_poll(lib, id)) { + TreeElement *override_tree_element = outliner_add_element( + &space_outliner_, &ten->subtree, id, ten, TSE_LIBRARY_OVERRIDE_BASE, 0); - if (BLI_listbase_is_empty(&override_tree_element->subtree)) { - outliner_free_tree_element(override_tree_element, &ten->subtree); - } + if (BLI_listbase_is_empty(&override_tree_element->subtree)) { + outliner_free_tree_element(override_tree_element, &ten->subtree); } } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index 402526bbe8d..c3d0aecd3cb 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -70,74 +70,69 @@ TreeDisplayViewLayer::TreeDisplayViewLayer(SpaceOutliner &space_outliner) ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data) { ListBase tree = {nullptr}; - Scene *scene = source_data.scene; show_objects_ = !(space_outliner_.filter & SO_FILTER_NO_OBJECT); - const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0; - for (auto *view_layer : ListBaseWrapper<ViewLayer>(scene->view_layers)) { + view_layer_ = view_layer; + if (space_outliner_.filter & SO_FILTER_NO_VIEW_LAYERS) { if (view_layer != source_data.view_layer) { continue; } - } - TreeElement &te_view_layer = *outliner_add_element( - &space_outliner_, &tree, scene, nullptr, TSE_R_LAYER, 0); - TREESTORE(&te_view_layer)->flag &= ~TSE_CLOSED; - te_view_layer.name = view_layer->name; - te_view_layer.directdata = view_layer; - view_layer_ = view_layer; - - if (space_outliner_.filter & SO_FILTER_NO_COLLECTION) { - /* Show objects in the view layer. */ - for (Base *base : List<Base>(view_layer_->object_bases)) { - TreeElement *te_object = outliner_add_element(&space_outliner_, - &te_view_layer.subtree, - base->object, - &te_view_layer, - TSE_SOME_ID, - 0); - te_object->directdata = base; - } - - if (show_children) { - outliner_make_object_parent_hierarchy(&tree); - } + add_view_layer(*scene, tree, (TreeElement *)nullptr); } else { - /* Show collections in the view layer. */ - TreeElement &ten = *outliner_add_element(&space_outliner_, - &te_view_layer.subtree, - source_data.scene, - &te_view_layer, - TSE_VIEW_COLLECTION_BASE, - 0); - ten.name = IFACE_("Scene Collection"); - TREESTORE(&ten)->flag &= ~TSE_CLOSED; - - add_view_layer(ten.subtree, ten); - if (show_children) { - add_layer_collection_objects_children(ten); - } + TreeElement &te_view_layer = *outliner_add_element( + &space_outliner_, &tree, scene, nullptr, TSE_R_LAYER, 0); + TREESTORE(&te_view_layer)->flag &= ~TSE_CLOSED; + te_view_layer.name = view_layer->name; + te_view_layer.directdata = view_layer; + + add_view_layer(*scene, te_view_layer.subtree, &te_view_layer); } } return tree; } -void TreeDisplayViewLayer::add_view_layer(ListBase &tree, TreeElement &parent) +void TreeDisplayViewLayer::add_view_layer(Scene &scene, ListBase &tree, TreeElement *parent) { - /* First layer collection is for master collection, don't show it. */ - LayerCollection *lc = static_cast<LayerCollection *>(view_layer_->layer_collections.first); - if (lc == nullptr) { - return; + const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0; + + if (space_outliner_.filter & SO_FILTER_NO_COLLECTION) { + /* Show objects in the view layer. */ + for (Base *base : List<Base>(view_layer_->object_bases)) { + TreeElement *te_object = outliner_add_element( + &space_outliner_, &tree, base->object, parent, TSE_SOME_ID, 0); + te_object->directdata = base; + } + + if (show_children) { + outliner_make_object_parent_hierarchy(&tree); + } } + else { + /* Show collections in the view layer. */ + TreeElement &ten = *outliner_add_element( + &space_outliner_, &tree, &scene, parent, TSE_VIEW_COLLECTION_BASE, 0); + ten.name = IFACE_("Scene Collection"); + TREESTORE(&ten)->flag &= ~TSE_CLOSED; + + /* First layer collection is for master collection, don't show it. */ + LayerCollection *lc = static_cast<LayerCollection *>(view_layer_->layer_collections.first); + if (lc == nullptr) { + return; + } - add_layer_collections_recursive(tree, lc->layer_collections, parent); - if (show_objects_) { - add_layer_collection_objects(tree, *lc, parent); + add_layer_collections_recursive(ten.subtree, lc->layer_collections, ten); + if (show_objects_) { + add_layer_collection_objects(ten.subtree, *lc, ten); + } + if (show_children) { + add_layer_collection_objects_children(ten); + } } } diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index ac31e0e7c37..1239286d4da 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -260,7 +260,7 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm RNA_PROP_BEGIN (op->ptr, itemptr, prop) { char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0); BLI_strncpy(load_data->name, filename, sizeof(load_data->name)); - BLI_snprintf(load_data->path, sizeof(load_data->path), "%s%s", directory, filename); + BLI_join_dirfile(load_data->path, sizeof(load_data->path), directory, filename); MEM_freeN(filename); break; } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 82283b03fc8..8371a634a78 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2479,13 +2479,14 @@ void draw_timeline_seq_display(const bContext *C, ARegion *region) const SpaceSeq *sseq = CTX_wm_space_seq(C); View2D *v2d = ®ion->v2d; - UI_view2d_view_ortho(v2d); - draw_cache_view(C); - - if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) { - draw_overlap_frame_indicator(scene, v2d); + if (scene->ed != NULL) { + UI_view2d_view_ortho(v2d); + draw_cache_view(C); + if (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) { + draw_overlap_frame_indicator(scene, v2d); + } + UI_view2d_view_restore(C); } - UI_view2d_view_restore(C); 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 45c6931364d..75cf8542f67 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2414,6 +2414,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) (LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_FREE_NO_MAIN)); seqbase_clipboard_frame = scene->r.cfra; + SEQ_clipboard_active_seq_name_store(scene); /* Remove anything that references the current scene. */ LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) { @@ -2504,6 +2505,10 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) BLI_movelisttolist(ed->seqbasep, &nseqbase); for (iseq = iseq_first; iseq; iseq = iseq->next) { + if (SEQ_clipboard_pasted_seq_was_active(iseq)) { + SEQ_select_active_set(scene, iseq); + } + /* Make sure, that pasted strips have unique names. */ SEQ_ensure_unique_name(iseq, scene); /* Translate after name has been changed, otherwise this will affect animdata of original diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c index 8cc8b4a007b..5d857f62b47 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.c +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -624,8 +624,6 @@ static void vectorscope_put_cross(uchar r, uchar g, uchar b, char *tgt, int w, i { float rgb[3], yuv[3]; char *p; - int x = 0; - int y = 0; rgb[0] = (float)r / 255.0f; rgb[1] = (float)g / 255.0f; @@ -638,8 +636,8 @@ static void vectorscope_put_cross(uchar r, uchar g, uchar b, char *tgt, int w, i r = 255; } - for (y = -size; y <= size; y++) { - for (x = -size; x <= size; x++) { + for (int y = -size; y <= size; y++) { + for (int x = -size; x <= size; x++) { char *q = p + 4 * (y * w + x); q[0] = r; q[1] = g; diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt index 1ea6593588a..e903feeec1b 100644 --- a/source/blender/editors/space_spreadsheet/CMakeLists.txt +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -27,6 +27,7 @@ set(INC ../../gpu ../../makesdna ../../makesrna + ../../nodes ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc @@ -34,8 +35,8 @@ set(INC set(SRC space_spreadsheet.cc - spreadsheet_context.cc spreadsheet_column.cc + spreadsheet_context.cc spreadsheet_data_source.cc spreadsheet_data_source_geometry.cc spreadsheet_dataset_draw.cc @@ -46,10 +47,10 @@ set(SRC spreadsheet_row_filter.cc spreadsheet_row_filter_ui.cc - spreadsheet_context.hh spreadsheet_cell_value.hh spreadsheet_column.hh spreadsheet_column_values.hh + spreadsheet_context.hh spreadsheet_data_source.hh spreadsheet_data_source_geometry.hh spreadsheet_dataset_draw.hh diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index f730f199ca4..e38c70afd0f 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -31,11 +31,15 @@ #include "ED_spreadsheet.h" +#include "NOD_geometry_nodes_eval_log.hh" + #include "bmesh.h" #include "spreadsheet_data_source_geometry.hh" #include "spreadsheet_intern.hh" +namespace geo_log = blender::nodes::geometry_nodes_eval_log; + namespace blender::ed::spreadsheet { void GeometryDataSource::foreach_default_column_ids( @@ -410,7 +414,6 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread Mesh *mesh = (Mesh *)object_orig->data; mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); } - mesh_component.copy_vertex_group_names_from_object(*object_orig); } else if (object_orig->type == OB_POINTCLOUD) { PointCloud *pointcloud = (PointCloud *)object_orig->data; @@ -428,7 +431,6 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread BKE_mesh_wrapper_ensure_mdata(mesh); MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); - mesh_component.copy_vertex_group_names_from_object(*object_eval); } else { if (BLI_listbase_count(&sspreadsheet->context_path) == 1) { @@ -438,13 +440,18 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread } } else { - if (object_eval->runtime.geometry_set_previews != nullptr) { - GHash *ghash = (GHash *)object_eval->runtime.geometry_set_previews; - const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet); - GeometrySet *geometry_set_preview = (GeometrySet *)BLI_ghash_lookup_default( - ghash, POINTER_FROM_UINT(key), nullptr); - if (geometry_set_preview != nullptr) { - geometry_set = *geometry_set_preview; + const geo_log::NodeLog *node_log = + geo_log::ModifierLog::find_node_by_spreadsheet_editor_context(*sspreadsheet); + if (node_log != nullptr) { + for (const geo_log::SocketLog &input_log : node_log->input_logs()) { + if (const geo_log::GeometryValueLog *geo_value_log = + dynamic_cast<const geo_log::GeometryValueLog *>(input_log.value())) { + const GeometrySet *full_geometry = geo_value_log->full_geometry(); + if (full_geometry != nullptr) { + geometry_set = *full_geometry; + break; + } + } } } } diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c index f55db8c3cc9..80af7d8c9f6 100644 --- a/source/blender/editors/space_text/text_undo.c +++ b/source/blender/editors/space_text/text_undo.c @@ -265,7 +265,7 @@ void ED_text_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = text_undosys_foreach_ID_ref; - ut->flags = UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE; + ut->flags = UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE | UNDOTYPE_FLAG_DECODE_ACTIVE_STEP; ut->step_size = sizeof(TextUndoStep); } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 60e1c780b9e..3428a738dde 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -39,6 +39,8 @@ #include "BLT_translation.h" +#include "BLI_array_utils.h" +#include "BLI_bitmap.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -112,10 +114,94 @@ typedef struct { float ob_dims[3]; /* Floats only (treated as an array). */ TransformMedian ve_median, median; + bool tag_for_update; } TransformProperties; #define TRANSFORM_MEDIAN_ARRAY_LEN (sizeof(TransformMedian) / sizeof(float)) +static TransformProperties *v3d_transform_props_ensure(View3D *v3d); + +/* -------------------------------------------------------------------- */ +/** \name Edit Mesh Partial Updates + * \{ */ + +static void *editmesh_partial_update_begin_fn(struct bContext *UNUSED(C), + const struct uiBlockInteraction_Params *params, + void *arg1) +{ + const int retval_test = B_TRANSFORM_PANEL_MEDIAN; + if (BLI_array_findindex( + params->unique_retval_ids, params->unique_retval_ids_len, &retval_test) == -1) { + return NULL; + } + + BMEditMesh *em = arg1; + + int verts_mask_count = 0; + BMIter iter; + BMVert *eve; + int i; + + BLI_bitmap *verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__); + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + continue; + } + BLI_BITMAP_ENABLE(verts_mask, i); + verts_mask_count += 1; + } + + BMPartialUpdate *bmpinfo = BM_mesh_partial_create_from_verts_group_single( + em->bm, + &(BMPartialUpdate_Params){ + .do_tessellate = true, + .do_normals = true, + }, + verts_mask, + verts_mask_count); + + MEM_freeN(verts_mask); + + return bmpinfo; +} + +static void editmesh_partial_update_end_fn(struct bContext *UNUSED(C), + const struct uiBlockInteraction_Params *UNUSED(params), + void *UNUSED(arg1), + void *user_data) +{ + BMPartialUpdate *bmpinfo = user_data; + if (bmpinfo == NULL) { + return; + } + BM_mesh_partial_destroy(bmpinfo); +} + +static void editmesh_partial_update_update_fn( + struct bContext *C, + const struct uiBlockInteraction_Params *UNUSED(params), + void *arg1, + void *user_data) +{ + BMPartialUpdate *bmpinfo = user_data; + if (bmpinfo == NULL) { + return; + } + + View3D *v3d = CTX_wm_view3d(C); + TransformProperties *tfp = v3d_transform_props_ensure(v3d); + if (tfp->tag_for_update == false) { + return; + } + tfp->tag_for_update = false; + + BMEditMesh *em = arg1; + + BKE_editmesh_looptri_and_normals_calc_with_partial(em, bmpinfo); +} + +/** \} */ + /* Helper function to compute a median changed value, * when the value should be clamped in [0.0, 1.0]. * Returns either 0.0, 1.0 (both can be applied directly), a positive scale factor @@ -840,6 +926,20 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float } UI_block_align_end(block); + + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + if (em != NULL) { + UI_block_interaction_set(block, + &(uiBlockInteraction_CallbackData){ + .begin_fn = editmesh_partial_update_begin_fn, + .end_fn = editmesh_partial_update_end_fn, + .update_fn = editmesh_partial_update_update_fn, + .arg1 = em, + }); + } + } } else { /* apply */ memcpy(&ve_median_basis, &tfp->ve_median, sizeof(tfp->ve_median)); @@ -927,9 +1027,8 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float } if (apply_vcos) { - /* TODO: use the #BKE_editmesh_looptri_and_normals_calc_with_partial - * This requires begin/end states for UI interaction (which currently aren't supported). */ - BKE_editmesh_looptri_and_normals_calc(em); + /* Tell the update callback to run. */ + tfp->tag_for_update = true; } /* Edges */ @@ -1152,7 +1251,7 @@ static void do_view3d_vgroup_buttons(bContext *C, void *UNUSED(arg), int event) ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = view_layer->basact->object; ED_vgroup_vert_active_mirror(ob, event - B_VGRP_PNL_EDIT_SINGLE); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); } @@ -1211,7 +1310,9 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel) vgroup_validmap = BKE_object_defgroup_subset_from_select_type( ob, subset_type, &vgroup_tot, &subset_count); - for (i = 0, dg = ob->defbase.first; dg; i++, dg = dg->next) { + const ListBase *defbase = BKE_object_defgroup_list(ob); + + for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) { bool locked = (dg->flag & DG_LOCK_WEIGHT) != 0; if (vgroup_validmap[i]) { MDeformWeight *dw = BKE_defvert_find_index(dv, i); @@ -1237,7 +1338,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel) but_ptr = UI_but_operator_ptr_get(but); RNA_int_set(but_ptr, "weight_group", i); UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); - if (ob->actdef != i + 1) { + if (BKE_object_defgroup_active_index_get(ob) != i + 1) { UI_but_flag_enable(but, UI_BUT_INACTIVE); } xco += x; @@ -1464,7 +1565,7 @@ static void v3d_posearmature_buts(uiLayout *layout, Object *ob) /* XXX: RNA buts show data in native types (i.e. quats, 4-component axis/angle, etc.) * but old-school UI shows in eulers always. Do we want to be able to still display in Eulers? - * Maybe needs RNA/ui options to display rotations as different types... */ + * Maybe needs RNA/UI options to display rotations as different types. */ v3d_transform_butsR(col, &pchanptr); } @@ -1568,7 +1669,7 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event case B_TRANSFORM_PANEL_MEDIAN: if (ob) { v3d_editvertex_buts(NULL, v3d, ob, 1.0); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY); } break; case B_TRANSFORM_PANEL_DIMS: diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index ea9d9a8c010..c97ba7ba7e9 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1404,7 +1404,7 @@ static void draw_selected_name( /* color depends on whether there is a keyframe */ if (id_frame_has_keyframe( - (ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) { + (ID *)ob, /* BKE_scene_ctime_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) { UI_FontThemeColor(font_id, TH_TIME_KEYFRAME); } else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) { diff --git a/source/blender/editors/space_view3d/view3d_navigate_fly.c b/source/blender/editors/space_view3d/view3d_navigate_fly.c index e2fa0fdc6a5..5752837c40f 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_fly.c +++ b/source/blender/editors/space_view3d/view3d_navigate_fly.c @@ -122,7 +122,7 @@ void fly_modal_keymap(wmKeyConfig *keyconf) {FLY_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""}, {FLY_MODAL_AXIS_LOCK_X, "AXIS_LOCK_X", 0, "X Axis Correction", "X axis correction (toggle)"}, - {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "X Axis Correction", "Z axis correction (toggle)"}, + {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "Z Axis Correction", "Z axis correction (toggle)"}, {FLY_MODAL_PRECISION_ENABLE, "PRECISION_ENABLE", 0, "Precision", ""}, {FLY_MODAL_PRECISION_DISABLE, "PRECISION_DISABLE", 0, "Precision (Off)", ""}, diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c index 435d74aa591..09936b41a74 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_walk.c +++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c @@ -98,9 +98,10 @@ enum { WALK_MODAL_JUMP, WALK_MODAL_JUMP_STOP, WALK_MODAL_TELEPORT, - WALK_MODAL_TOGGLE, + WALK_MODAL_GRAVITY_TOGGLE, WALK_MODAL_ACCELERATE, WALK_MODAL_DECELERATE, + WALK_MODAL_AXIS_LOCK_Z, }; enum { @@ -129,6 +130,18 @@ typedef enum eWalkGravityState { WALK_GRAVITY_STATE_ON, } eWalkGravityState; +/* Relative view axis z axis locking. */ +typedef enum eWalkLockState { + /* Disabled. */ + WALK_AXISLOCK_STATE_OFF = 0, + + /* Moving. */ + WALK_AXISLOCK_STATE_ACTIVE = 2, + + /* Done moving, it cannot be activated again. */ + WALK_AXISLOCK_STATE_DONE = 3, +} eWalkLockState; + /* Called in transform_ops.c, on each regeneration of key-maps. */ void walk_modal_keymap(wmKeyConfig *keyconf) { @@ -164,7 +177,9 @@ void walk_modal_keymap(wmKeyConfig *keyconf) {WALK_MODAL_JUMP, "JUMP", 0, "Jump", "Jump when in walk mode"}, {WALK_MODAL_JUMP_STOP, "JUMP_STOP", 0, "Jump (Off)", "Stop pushing jump"}, - {WALK_MODAL_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"}, + {WALK_MODAL_GRAVITY_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"}, + + {WALK_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "Z Axis Correction", "Z axis correction"}, {0, NULL, 0, NULL, NULL}, }; @@ -292,6 +307,10 @@ typedef struct WalkInfo { /** To use for fast/slow speeds. */ float speed_factor; + eWalkLockState zlock; + /** Nicer dynamics. */ + float zlock_momentum; + struct SnapObjectContext *snap_context; struct View3DCameraControl *v3d_camera_control; @@ -540,6 +559,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->jump_height = U.walk_navigation.jump_height; walk->speed = U.walk_navigation.walk_speed; walk->speed_factor = U.walk_navigation.walk_speed_factor; + walk->zlock = WALK_AXISLOCK_STATE_OFF; walk->gravity_state = WALK_GRAVITY_STATE_OFF; @@ -708,8 +728,6 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event) walk->is_cursor_absolute = true; copy_v2_v2_int(walk->prev_mval, event->mval); copy_v2_v2_int(walk->center_mval, event->mval); - /* Without this we can't turn 180d with the default speed of 1.0. */ - walk->mouse_speed *= 4.0f; } #endif /* USE_TABLET_SUPPORT */ @@ -941,7 +959,7 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event) #undef JUMP_TIME_MAX #undef JUMP_SPEED_MIN - case WALK_MODAL_TOGGLE: + case WALK_MODAL_GRAVITY_TOGGLE: if (walk->navigation_mode == WALK_MODE_GRAVITY) { walk_navigation_mode_set(walk, WALK_MODE_FREE); } @@ -949,6 +967,13 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event) walk_navigation_mode_set(walk, WALK_MODE_GRAVITY); } break; + + case WALK_MODAL_AXIS_LOCK_Z: + if (walk->zlock != WALK_AXISLOCK_STATE_DONE) { + walk->zlock = WALK_AXISLOCK_STATE_ACTIVE; + walk->zlock_momentum = 0.0f; + } + break; } } } @@ -982,12 +1007,14 @@ static float getVelocityZeroTime(const float gravity, const float velocity) static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) { -#define WALK_ROTATE_RELATIVE_FAC 2.2f /* More is faster, relative to region size. */ -#define WALK_ROTATE_CONSTANT_FAC DEG2RAD(0.15f) /* More is faster, radians per-pixel. */ +#define WALK_ROTATE_TABLET_FAC 8.8f /* Higher is faster, relative to region size. */ +#define WALK_ROTATE_CONSTANT_FAC DEG2RAD(0.15f) /* Higher is faster, radians per-pixel. */ #define WALK_TOP_LIMIT DEG2RADF(85.0f) #define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f) #define WALK_MOVE_SPEED base_speed #define WALK_BOOST_FACTOR ((void)0, walk->speed_factor) +#define WALK_ZUP_CORRECT_FAC 0.1f /* Amount to correct per step. */ +#define WALK_ZUP_CORRECT_ACCEL 0.05f /* Increase upright momentum each step. */ RegionView3D *rv3d = walk->rv3d; ARegion *region = walk->region; @@ -1022,20 +1049,25 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) /* Should we redraw? */ if ((walk->active_directions) || moffset[0] || moffset[1] || - walk->teleport.state == WALK_TELEPORT_STATE_ON || - walk->gravity_state != WALK_GRAVITY_STATE_OFF || is_confirm) { + walk->zlock == WALK_AXISLOCK_STATE_ACTIVE || + walk->gravity_state != WALK_GRAVITY_STATE_OFF || + walk->teleport.state == WALK_TELEPORT_STATE_ON || is_confirm) { float dvec_tmp[3]; /* time how fast it takes for us to redraw, * this is so simple scenes don't walk too fast */ double time_current; float time_redraw; + float time_redraw_clamped; #ifdef NDOF_WALK_DRAW_TOOMUCH walk->redraw = 1; #endif time_current = PIL_check_seconds_timer(); time_redraw = (float)(time_current - walk->time_lastdraw); + /* Clamp redraw time to avoid jitter in roll correction. */ + time_redraw_clamped = min_ff(0.05f, time_redraw); + walk->time_lastdraw = time_current; /* base speed in m/s */ @@ -1064,7 +1096,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) #ifdef USE_TABLET_SUPPORT if (walk->is_cursor_absolute) { y /= region->winy; - y *= WALK_ROTATE_RELATIVE_FAC; + y *= WALK_ROTATE_TABLET_FAC; } else #endif @@ -1113,7 +1145,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) #ifdef USE_TABLET_SUPPORT if (walk->is_cursor_absolute) { x /= region->winx; - x *= WALK_ROTATE_RELATIVE_FAC; + x *= WALK_ROTATE_TABLET_FAC; } else #endif @@ -1128,6 +1160,32 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) axis_angle_to_quat_single(tmp_quat, 'Z', x); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); } + + if (walk->zlock == WALK_AXISLOCK_STATE_ACTIVE) { + float upvec[3]; + copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); + mul_m3_v3(mat, upvec); + + /* Make sure we have some z rolling. */ + if (fabsf(upvec[2]) > 0.00001f) { + float roll = upvec[2] * 5.0f; + /* Rotate the view about this axis. */ + copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f); + mul_m3_v3(mat, upvec); + /* Rotate about the relative up vec. */ + axis_angle_to_quat(tmp_quat, + upvec, + roll * time_redraw_clamped * walk->zlock_momentum * + WALK_ZUP_CORRECT_FAC); + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); + + walk->zlock_momentum += WALK_ZUP_CORRECT_ACCEL; + } + else { + /* Lock fixed, don't need to check it ever again. */ + walk->zlock = WALK_AXISLOCK_STATE_DONE; + } + } } /* WASD - 'move' translation code */ @@ -1318,7 +1376,8 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) add_v3_v3(rv3d->ofs, dvec_tmp); if (rv3d->persp == RV3D_CAMOB) { - walk->need_rotation_keyframe |= (moffset[0] || moffset[1]); + walk->need_rotation_keyframe |= (moffset[0] || moffset[1] || + walk->zlock == WALK_AXISLOCK_STATE_ACTIVE); walk->need_translation_keyframe |= (len_squared_v3(dvec_tmp) > FLT_EPSILON); walkMoveCamera( C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm); @@ -1333,7 +1392,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) } return OPERATOR_FINISHED; -#undef WALK_ROTATE_RELATIVE_FAC +#undef WALK_ROTATE_TABLET_FAC #undef WALK_TOP_LIMIT #undef WALK_BOTTOM_LIMIT #undef WALK_MOVE_SPEED diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index a19e92f229a..4482e5897ca 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -511,47 +511,47 @@ static int snap_selected_to_location(bContext *C, for (int ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob = objects[ob_index]; + if (ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) { + continue; + } - if ((ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) == 0) { - - float cursor_parent[3]; /* parent-relative */ - - if (use_offset) { - add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global); - } - else { - copy_v3_v3(cursor_parent, snap_target_global); - } + float cursor_parent[3]; /* parent-relative */ - sub_v3_v3(cursor_parent, ob->obmat[3]); + if (use_offset) { + add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global); + } + else { + copy_v3_v3(cursor_parent, snap_target_global); + } - if (ob->parent) { - float originmat[3][3], parentmat[4][4]; - /* Use the evaluated object here because sometimes - * `ob->parent->runtime.curve_cache` is required. */ - BKE_scene_graph_evaluated_ensure(depsgraph, bmain); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + sub_v3_v3(cursor_parent, ob->obmat[3]); - BKE_object_get_parent_matrix(ob_eval, ob_eval->parent, parentmat); - mul_m3_m4m4(originmat, parentmat, ob->parentinv); - invert_m3_m3(imat, originmat); - mul_m3_v3(imat, cursor_parent); - } - if ((ob->protectflag & OB_LOCK_LOCX) == 0) { - ob->loc[0] += cursor_parent[0]; - } - if ((ob->protectflag & OB_LOCK_LOCY) == 0) { - ob->loc[1] += cursor_parent[1]; - } - if ((ob->protectflag & OB_LOCK_LOCZ) == 0) { - ob->loc[2] += cursor_parent[2]; - } + if (ob->parent) { + float originmat[3][3], parentmat[4][4]; + /* Use the evaluated object here because sometimes + * `ob->parent->runtime.curve_cache` is required. */ + BKE_scene_graph_evaluated_ensure(depsgraph, bmain); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + + BKE_object_get_parent_matrix(ob_eval, ob_eval->parent, parentmat); + mul_m3_m4m4(originmat, parentmat, ob->parentinv); + invert_m3_m3(imat, originmat); + mul_m3_v3(imat, cursor_parent); + } + if ((ob->protectflag & OB_LOCK_LOCX) == 0) { + ob->loc[0] += cursor_parent[0]; + } + if ((ob->protectflag & OB_LOCK_LOCY) == 0) { + ob->loc[1] += cursor_parent[1]; + } + if ((ob->protectflag & OB_LOCK_LOCZ) == 0) { + ob->loc[2] += cursor_parent[2]; + } - /* auto-keyframing */ - ED_autokeyframe_object(C, scene, ob, ks); + /* auto-keyframing */ + ED_autokeyframe_object(C, scene, ob, ks); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); } if (objects) { diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index c1ee6edfef6..383f9870714 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -2067,6 +2067,27 @@ static void tc_mesh_transdata_mirror_apply(TransDataContainer *tc) } } +static bool tc_mesh_is_deform_only_update(TransInfo *t, TransDataContainer *tc) +{ + if (tc->custom.type.data && + ((struct TransCustomDataMesh *)tc->custom.type.data)->cd_layer_correct) { + return false; + } + + Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(t->depsgraph, (ID *)tc->obedit->data); + Mesh *mesh_eval_cage = me_eval->edit_mesh->mesh_eval_cage; + Mesh *mesh_eval_final = me_eval->edit_mesh->mesh_eval_final; + if (mesh_eval_cage && !mesh_eval_cage->runtime.is_original) { + return false; + } + if (mesh_eval_final && mesh_eval_final != mesh_eval_cage && + !mesh_eval_final->runtime.is_original) { + return false; + } + + return me_eval->runtime.deformed_only; +} + void recalcData_mesh(TransInfo *t) { bool is_canceling = t->state == TRANS_CANCEL; @@ -2094,7 +2115,10 @@ void recalcData_mesh(TransInfo *t) tc_mesh_partial_types_calc(t, &partial_state); FOREACH_TRANS_DATA_CONTAINER (t, tc) { - DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); + const bool is_deform_only = tc_mesh_is_deform_only_update(t, tc); + + DEG_id_tag_update(tc->obedit->data, + is_deform_only ? ID_RECALC_GEOMETRY_DEFORM : ID_RECALC_GEOMETRY); tc_mesh_partial_update(t, tc, &partial_state); } diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c index 3b1191a3401..2db3e259153 100644 --- a/source/blender/editors/transform/transform_convert_mesh_edge.c +++ b/source/blender/editors/transform/transform_convert_mesh_edge.c @@ -28,6 +28,7 @@ #include "BLI_math.h" #include "BKE_context.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_mesh.h" diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c index d91a2a8be4b..61397b6ef4b 100644 --- a/source/blender/editors/transform/transform_convert_mesh_uv.c +++ b/source/blender/editors/transform/transform_convert_mesh_uv.c @@ -30,6 +30,7 @@ #include "BLI_math.h" #include "BKE_context.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_mesh_mapping.h" diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index c217478bd04..ee6cb391fdc 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -153,7 +153,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) if (t->mode != TFM_DUMMY && ob->rigidbody_object) { float rot[3][3], scale[3]; - float ctime = BKE_scene_frame_get(scene); + float ctime = BKE_scene_ctime_get(scene); /* only use rigid body transform if simulation is running, * avoids problems with initial setup of rigid bodies */ @@ -978,7 +978,7 @@ void special_aftertrans_update__object(bContext *C, TransInfo *t) /* restore rigid body transform */ if (ob->rigidbody_object && canceled) { - float ctime = BKE_scene_frame_get(t->scene); + float ctime = BKE_scene_ctime_get(t->scene); if (BKE_rigidbody_check_sim_running(t->scene->rigidbody_world, ctime)) { BKE_rigidbody_aftertrans_update(ob, td->ext->oloc, diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c index fe853440c96..a8f7fc43b5e 100644 --- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c @@ -129,7 +129,7 @@ static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2])) transform_convert_sequencer_channel_clamp(t, values_final); if (t->con.mode & CON_APPLY) { - t->con.applyVec(t, NULL, NULL, t->values, values_final); + t->con.applyVec(t, NULL, NULL, values_final, values_final); } } diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c index d9395e5e960..d0b730383d5 100644 --- a/source/blender/editors/transform/transform_snap_sequencer.c +++ b/source/blender/editors/transform/transform_snap_sequencer.c @@ -236,6 +236,11 @@ void transform_snap_sequencer_data_free(TransSeqSnapData *data) bool transform_snap_sequencer_calc(TransInfo *t) { + /* Prevent snapping when constrained to Y axis. */ + if (t->con.mode & CON_APPLY && t->con.mode & CON_AXIS1) { + return false; + } + const TransSeqSnapData *snap_data = t->tsnap.seq_context; int best_dist = MAXFRAME, best_target_frame = 0, best_source_frame = 0; diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c index 93948b5ae1b..56bcbc63de1 100644 --- a/source/blender/editors/uvedit/uvedit_islands.c +++ b/source/blender/editors/uvedit/uvedit_islands.c @@ -36,6 +36,7 @@ #include "BLI_math.h" #include "BLI_rect.h" +#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "DEG_depsgraph.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index 9593a1364e7..fcc44aab583 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -205,11 +205,18 @@ static void bakeModifier(Main *UNUSED(bmain), } if (!gpd->runtime.lineart_cache) { + /* Only calculate for this modifier, thus no need to get maximum values from all line art + * modifiers in the stack. */ + lmd->edge_types_override = lmd->edge_types; + lmd->level_end_override = lmd->level_end; + MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache); MOD_lineart_destroy_render_data(lmd); } generate_strokes_actual(md, depsgraph, ob, gpl, gpf); + + MOD_lineart_clear_cache(&gpd->runtime.lineart_cache); } static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams)) @@ -331,7 +338,7 @@ static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel) PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr); const bool is_baked = RNA_boolean_get(ptr, "is_baked"); - const bool use_cache = RNA_boolean_get(ptr, "use_cached_result"); + const bool use_cache = RNA_boolean_get(ptr, "use_cache"); const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data); uiLayoutSetEnabled(layout, !is_baked); diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 3f722f33946..9899d889c56 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1696,7 +1696,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu } if (rb->remove_doubles) { - BMEditMesh *em = BKE_editmesh_create(bm, false); + BMEditMesh *em = BKE_editmesh_create(bm); BMOperator findop, weldop; /* See bmesh_opdefines.c and bmesh_operators.c for op names and argument formatting. */ @@ -4217,9 +4217,6 @@ static void lineart_gpencil_generate(LineartCache *cache, /* (!orig_col && !orig_ob) means the whole scene is selected. */ - float mat[4][4]; - unit_m4(mat); - int enabled_types = cache->rb_edge_types; bool invert_input = modifier_flags & LRT_GPENCIL_INVERT_SOURCE_VGROUP; bool match_output = modifier_flags & LRT_GPENCIL_MATCH_OUTPUT_VGROUP; @@ -4271,29 +4268,20 @@ static void lineart_gpencil_generate(LineartCache *cache, /* Preserved: If we ever do asynchronous generation, this picked flag should be set here. */ // ec->picked = 1; - int array_idx = 0; - int count = MOD_lineart_chain_count(ec); + const int count = MOD_lineart_chain_count(ec); bGPDstroke *gps = BKE_gpencil_stroke_add(gpf, color_idx, count, thickness, false); - float *stroke_data = MEM_callocN(sizeof(float) * count * GP_PRIM_DATABUF_SIZE, - "line art add stroke"); - - LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) { - stroke_data[array_idx] = eci->gpos[0]; - stroke_data[array_idx + 1] = eci->gpos[1]; - stroke_data[array_idx + 2] = eci->gpos[2]; - mul_m4_v3(gp_obmat_inverse, &stroke_data[array_idx]); - stroke_data[array_idx + 3] = 1; /* thickness. */ - stroke_data[array_idx + 4] = opacity; /* hardness?. */ - array_idx += 5; + int i; + LISTBASE_FOREACH_INDEX (LineartEdgeChainItem *, eci, &ec->chain, i) { + bGPDspoint *point = &gps->points[i]; + mul_v3_m4v3(&point->x, gp_obmat_inverse, eci->gpos); + point->pressure = 1.0f; + point->strength = opacity; } - BKE_gpencil_stroke_add_points(gps, stroke_data, count, mat); BKE_gpencil_dvert_ensure(gps); gps->mat_nr = max_ii(material_nr, 0); - MEM_freeN(stroke_data); - if (source_vgname && vgname) { Object *eval_ob = DEG_get_evaluated_object(depsgraph, ec->object_ref); int gpdg = -1; @@ -4302,7 +4290,7 @@ static void lineart_gpencil_generate(LineartCache *cache, int dindex = 0; Mesh *me = (Mesh *)eval_ob->data; if (me->dvert) { - LISTBASE_FOREACH (bDeformGroup *, db, &eval_ob->defbase) { + LISTBASE_FOREACH (bDeformGroup *, db, &me->vertex_group_names) { if ((!source_vgname) || strstr(db->name, source_vgname) == db->name) { if (match_output) { gpdg = BKE_object_defgroup_name_index(gpencil_object, db->name); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index abb7330d292..b7dc3210c41 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -82,8 +82,8 @@ set(SRC intern/gpu_select_sample_query.cc intern/gpu_shader.cc intern/gpu_shader_builtin.c - intern/gpu_shader_log.cc intern/gpu_shader_interface.cc + intern/gpu_shader_log.cc intern/gpu_state.cc intern/gpu_texture.cc intern/gpu_uniform_buffer.cc @@ -103,8 +103,8 @@ set(SRC opengl/gl_index_buffer.cc opengl/gl_query.cc opengl/gl_shader.cc - opengl/gl_shader_log.cc opengl/gl_shader_interface.cc + opengl/gl_shader_log.cc opengl/gl_state.cc opengl/gl_texture.cc opengl/gl_uniform_buffer.cc diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c index ad72f373d12..70bb70ec4fa 100644 --- a/source/blender/imbuf/intern/bmp.c +++ b/source/blender/imbuf/intern/bmp.c @@ -395,9 +395,8 @@ bool imb_savebmp(ImBuf *ibuf, const char *filepath, int UNUSED(flags)) } } } - if (ofile) { - fflush(ofile); - fclose(ofile); - } + + fflush(ofile); + fclose(ofile); return 1; } diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp index 6f0d422dbe2..e61ed47adee 100644 --- a/source/blender/io/collada/ControllerExporter.cpp +++ b/source/blender/io/collada/ControllerExporter.cpp @@ -29,6 +29,7 @@ #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_deform.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_lib_id.h" @@ -194,9 +195,9 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) add_bind_shape_mat(ob); - std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id); - std::string inv_bind_mat_source_id = add_inv_bind_mats_source( - ob_arm, &ob->defbase, controller_id); + const ListBase *defbase = BKE_object_defgroup_list(ob); + std::string joints_source_id = add_joints_source(ob_arm, defbase, controller_id); + std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, defbase, controller_id); std::list<int> vcounts; std::list<int> joints; @@ -207,9 +208,9 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) /* def group index -> joint index */ std::vector<int> joint_index_by_def_index; - bDeformGroup *def; + const bDeformGroup *def; - for (def = (bDeformGroup *)ob->defbase.first, i = 0, j = 0; def; def = def->next, i++) { + for (def = (const bDeformGroup *)defbase->first, i = 0, j = 0; def; def = def->next, i++) { if (is_bone_defgroup(ob_arm, def)) { joint_index_by_def_index.push_back(j++); } @@ -269,7 +270,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) } std::string weights_source_id = add_weights_source(me, controller_id, weights); - add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id); + add_joints_element(defbase, joints_source_id, inv_bind_mat_source_id); add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints); BKE_id_free(nullptr, me); @@ -392,7 +393,7 @@ void ControllerExporter::add_weight_extras(Key *key) } } -void ControllerExporter::add_joints_element(ListBase *defbase, +void ControllerExporter::add_joints_element(const ListBase *defbase, const std::string &joints_source_id, const std::string &inv_bind_mat_source_id) { @@ -431,7 +432,7 @@ void ControllerExporter::add_bind_shape_mat(Object *ob) } std::string ControllerExporter::add_joints_source(Object *ob_arm, - ListBase *defbase, + const ListBase *defbase, const std::string &controller_id) { std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX; @@ -468,7 +469,7 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm, } std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, - ListBase *defbase, + const ListBase *defbase, const std::string &controller_id) { std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX; @@ -568,13 +569,13 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, return source_id; } -Bone *ControllerExporter::get_bone_from_defgroup(Object *ob_arm, bDeformGroup *def) +Bone *ControllerExporter::get_bone_from_defgroup(Object *ob_arm, const bDeformGroup *def) { bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, def->name); return pchan ? pchan->bone : nullptr; } -bool ControllerExporter::is_bone_defgroup(Object *ob_arm, bDeformGroup *def) +bool ControllerExporter::is_bone_defgroup(Object *ob_arm, const bDeformGroup *def) { return get_bone_from_defgroup(ob_arm, def) != nullptr; } diff --git a/source/blender/io/collada/ControllerExporter.h b/source/blender/io/collada/ControllerExporter.h index 6a377a4119e..0aec9e8d179 100644 --- a/source/blender/io/collada/ControllerExporter.h +++ b/source/blender/io/collada/ControllerExporter.h @@ -97,7 +97,7 @@ class ControllerExporter : public COLLADASW::LibraryControllers, void export_morph_controller(Object *ob, Key *key); - void add_joints_element(ListBase *defbase, + void add_joints_element(const ListBase *defbase, const std::string &joints_source_id, const std::string &inv_bind_mat_source_id); @@ -110,16 +110,16 @@ class ControllerExporter : public COLLADASW::LibraryControllers, void add_weight_extras(Key *key); std::string add_joints_source(Object *ob_arm, - ListBase *defbase, + const ListBase *defbase, const std::string &controller_id); std::string add_inv_bind_mats_source(Object *ob_arm, - ListBase *defbase, + const ListBase *defbase, const std::string &controller_id); - Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup *def); + Bone *get_bone_from_defgroup(Object *ob_arm, const bDeformGroup *def); - bool is_bone_defgroup(Object *ob_arm, bDeformGroup *def); + bool is_bone_defgroup(Object *ob_arm, const bDeformGroup *def); std::string add_weights_source(Mesh *me, const std::string &controller_id, diff --git a/source/blender/io/collada/SkinInfo.cpp b/source/blender/io/collada/SkinInfo.cpp index c2f17174d75..f0e1c5e4c26 100644 --- a/source/blender/io/collada/SkinInfo.cpp +++ b/source/blender/io/collada/SkinInfo.cpp @@ -36,6 +36,7 @@ #include "DNA_scene_types.h" #include "BKE_action.h" +#include "BKE_deform.h" #include "BKE_object.h" #include "BKE_object_deform.h" @@ -289,7 +290,8 @@ void SkinInfo::link_armature(bContext *C, /* -1 means "weight towards the bind shape", we just don't assign it to any group */ if (joint != -1) { - bDeformGroup *def = (bDeformGroup *)BLI_findlink(&ob->defbase, joint); + const ListBase *defbase = BKE_object_defgroup_list(ob); + bDeformGroup *def = (bDeformGroup *)BLI_findlink(defbase, joint); ED_vgroup_vert_add(ob, def, vertex, weights[joint_weight], WEIGHT_REPLACE); } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index c9d652ad03d..43969bf0768 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -621,9 +621,9 @@ typedef enum IDRecalcFlag { * When a collection gets tagged with this flag, all objects depending on the geometry and * transforms on any of the objects in the collection are updated. */ ID_RECALC_GEOMETRY = (1 << 1), - - /* ** Animation or time changed and animation is to be re-evaluated. ** */ - ID_RECALC_ANIMATION = (1 << 2), + /* Same as #ID_RECALC_GEOMETRY, but instead of tagging the batch cache as `dirty_all`, just tags + what matches the deform cache. */ + ID_RECALC_GEOMETRY_DEFORM = (1 << 2), /* ** Particle system changed. ** */ /* Only do pathcache etc. */ @@ -683,6 +683,9 @@ typedef enum IDRecalcFlag { * have to be copied on every update. */ ID_RECALC_PARAMETERS = (1 << 21), + /* ** Animation or time changed and animation is to be re-evaluated. ** */ + ID_RECALC_ANIMATION = (1 << 22), + /* Input has changed and datablock is to be reload from disk. * Applies to movie clips to inform that copy-on-written version is to be refreshed for the new * input file or for color space changes. */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index c573de6b54e..0952c45e81f 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -666,6 +666,9 @@ typedef struct bGPdata { /** List of bGPDpalette's - Deprecated (2.78 - 2.79 only). */ ListBase palettes DNA_DEPRECATED; + /** List of bDeformGroup names and flag only. */ + ListBase vertex_group_names; + /* 3D Viewport/Appearance Settings */ /** Factor to define pixel size conversion. */ float pixfactor; @@ -715,7 +718,8 @@ typedef struct bGPdata { /** Stroke selection last index. Used to generate a unique selection index. */ int select_last_index; - char _pad3[4]; + + int vertex_group_active_index; bGPgrid grid; diff --git a/source/blender/makesdna/DNA_lattice_types.h b/source/blender/makesdna/DNA_lattice_types.h index 48eb8d90702..361893db893 100644 --- a/source/blender/makesdna/DNA_lattice_types.h +++ b/source/blender/makesdna/DNA_lattice_types.h @@ -72,6 +72,11 @@ typedef struct Lattice { struct MDeformVert *dvert; /** Multiply the influence, MAX_VGROUP_NAME. */ char vgroup[64]; + /** List of bDeformGroup names and flag only. */ + ListBase vertex_group_names; + int vertex_group_active_index; + + char _pad0[4]; struct EditLatt *editlatt; void *batch_cache; diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 2f089b28048..2a569c8db50 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -166,6 +166,8 @@ typedef struct Mesh { struct MEdge *medge; /** Deform-group vertices. */ struct MDeformVert *dvert; + /** List of bDeformGroup names and flag only. */ + ListBase vertex_group_names; /* array of colors for the tessellated faces, must be number of tessellated * faces * 4 in length */ @@ -189,7 +191,7 @@ typedef struct Mesh { /* END BMESH ONLY */ int attributes_active_index; - int _pad3; + int vertex_group_active_index; /* the last selected vertex/edge/face are used for the active face however * this means the active face must always be selected, this is to keep track @@ -279,9 +281,9 @@ enum { /* We can't have both flags enabled at once, * flags defined in DNA_scene_types.h */ #define ME_EDIT_PAINT_SEL_MODE(_me) \ - (((_me)->editflag & ME_EDIT_PAINT_FACE_SEL) ? \ - SCE_SELECT_FACE : \ - ((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : 0) + (((_me)->editflag & ME_EDIT_PAINT_FACE_SEL) ? SCE_SELECT_FACE : \ + ((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : \ + 0) /* me->flag */ enum { diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 08a38f0652c..1c765d19ce2 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -2256,6 +2256,10 @@ typedef struct NodesModifierData { ModifierData modifier; struct bNodeTree *node_group; struct NodesModifierSettings settings; + + /* Contains logged information from the last evaluation. This can be used to help the user to + * debug a node tree. */ + void *runtime_eval_log; } NodesModifierData; typedef struct MeshToVolumeModifierData { diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 9af77949fe2..1f75006bd07 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -37,7 +37,6 @@ struct Collection; struct ID; struct Image; struct ListBase; -struct NodeTreeUIStorage; struct bGPdata; struct bNodeInstanceHash; struct bNodeLink; @@ -516,8 +515,6 @@ typedef struct bNodeTree { int (*test_break)(void *); void (*update_draw)(void *); void *tbh, *prh, *sdh, *udh; - - struct NodeTreeUIStorage *ui_storage; } bNodeTree; /* ntree->type, index */ @@ -1373,6 +1370,11 @@ typedef struct NodeGeometryCurvePrimitiveCircle { uint8_t mode; } NodeGeometryCurvePrimitiveCircle; +typedef struct NodeGeometryCurvePrimitiveQuad { + /* GeometryNodeCurvePrimitiveQuadMode. */ + uint8_t mode; +} NodeGeometryCurvePrimitiveQuad; + typedef struct NodeGeometryCurveResample { /* GeometryNodeCurveResampleMode. */ uint8_t mode; @@ -1928,6 +1930,14 @@ typedef enum GeometryNodeCurvePrimitiveLineMode { GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION = 1 } GeometryNodeCurvePrimitiveLineMode; +typedef enum GeometryNodeCurvePrimitiveQuadMode { + GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE = 0, + GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM = 1, + GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID = 2, + GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE = 3, + GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS = 4, +} GeometryNodeCurvePrimitiveQuadMode; + typedef enum GeometryNodeCurvePrimitiveBezierSegmentMode { GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION = 0, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_OFFSET = 1, diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 262d650c1ef..dd31e85647d 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -172,12 +172,6 @@ typedef struct Object_Runtime { struct GeometrySet *geometry_set_eval; /** - * A GHash that contains geometry sets for intermediate stages of evaluation. The keys are just a - * hash and are not owned by the map. The geometry sets are owned. - */ - void *geometry_set_previews; - - /** * Mesh structure created during object evaluation. * It has deformation only modifiers applied on it. */ @@ -278,8 +272,7 @@ typedef struct Object { ListBase constraintChannels DNA_DEPRECATED; /* XXX deprecated... old animation system */ ListBase effect DNA_DEPRECATED; /* XXX deprecated... keep for readfile */ - /** List of bDeformGroup (vertex groups) names and flag only. */ - ListBase defbase; + ListBase defbase DNA_DEPRECATED; /* Only for versioning, moved to object data. */ /** List of ModifierData structures. */ ListBase modifiers; /** List of GpencilModifierData structures. */ @@ -381,7 +374,7 @@ typedef struct Object { /** Custom index, for renderpasses. */ short index; /** Current deformation group, NOTE: index starts at 1. */ - unsigned short actdef; + unsigned short actdef DNA_DEPRECATED; /** Current face map, NOTE: index starts at 1. */ unsigned short actfmap; char _pad2[2]; diff --git a/source/blender/makesdna/DNA_pointcache_types.h b/source/blender/makesdna/DNA_pointcache_types.h index 669c8500677..7de0bb29c46 100644 --- a/source/blender/makesdna/DNA_pointcache_types.h +++ b/source/blender/makesdna/DNA_pointcache_types.h @@ -131,32 +131,34 @@ typedef struct PointCache { void (*free_edit)(struct PTCacheEdit *edit); } PointCache; -/* pointcache->flag */ -#define PTCACHE_BAKED (1 << 0) -#define PTCACHE_OUTDATED (1 << 1) -#define PTCACHE_SIMULATION_VALID (1 << 2) -#define PTCACHE_BAKING (1 << 3) -//#define PTCACHE_BAKE_EDIT (1 << 4) -//#define PTCACHE_BAKE_EDIT_ACTIVE (1 << 5) -#define PTCACHE_DISK_CACHE (1 << 6) -///* removed since 2.64 - T30974, could be added back in a more useful way */ -//#define PTCACHE_QUICK_CACHE (1 << 7) -#define PTCACHE_FRAMES_SKIPPED (1 << 8) -#define PTCACHE_EXTERNAL (1 << 9) -#define PTCACHE_READ_INFO (1 << 10) -/** Don't use the filename of the blend-file the data is linked from (write a local cache). */ -#define PTCACHE_IGNORE_LIBPATH (1 << 11) -/** - * High resolution cache is saved for smoke for backwards compatibility, - * so set this flag to know it's a "fake" cache. - */ -#define PTCACHE_FAKE_SMOKE (1 << 12) -#define PTCACHE_IGNORE_CLEAR (1 << 13) +enum { + /* pointcache->flag */ + PTCACHE_BAKED = 1 << 0, + PTCACHE_OUTDATED = 1 << 1, + PTCACHE_SIMULATION_VALID = 1 << 2, + PTCACHE_BAKING = 1 << 3, + // PTCACHE_BAKE_EDIT = 1 << 4, + // PTCACHE_BAKE_EDIT_ACTIVE = 1 << 5, + PTCACHE_DISK_CACHE = 1 << 6, + /* removed since 2.64 - T30974, could be added back in a more useful way */ + // PTCACHE_QUICK_CACHE = 1 << 7, + PTCACHE_FRAMES_SKIPPED = 1 << 8, + PTCACHE_EXTERNAL = 1 << 9, + PTCACHE_READ_INFO = 1 << 10, + /** Don't use the filename of the blend-file the data is linked from (write a local cache). */ + PTCACHE_IGNORE_LIBPATH = 1 << 11, + /** + * High resolution cache is saved for smoke for backwards compatibility, + * so set this flag to know it's a "fake" cache. + */ + PTCACHE_FAKE_SMOKE = 1 << 12, + PTCACHE_IGNORE_CLEAR = 1 << 13, -#define PTCACHE_FLAG_INFO_DIRTY (1 << 14) + PTCACHE_FLAG_INFO_DIRTY = 1 << 14, -/* PTCACHE_OUTDATED + PTCACHE_FRAMES_SKIPPED */ -#define PTCACHE_REDO_NEEDED 258 + PTCACHE_REDO_NEEDED = PTCACHE_OUTDATED | PTCACHE_FRAMES_SKIPPED, + PTCACHE_FLAGS_COPY = PTCACHE_DISK_CACHE | PTCACHE_EXTERNAL | PTCACHE_IGNORE_LIBPATH, +}; #define PTCACHE_COMPRESS_NO 0 #define PTCACHE_COMPRESS_LZO 1 diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 557343f79cd..73a44ec16bb 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -727,6 +727,12 @@ typedef struct FileSelectParams { char renamefile[256]; short rename_flag; + char _pad[4]; + /** An ID that was just renamed. Used to identify a renamed asset file over re-reads, similar to + * `renamefile` but for local IDs (takes precedence). Don't keep this stored across handlers! + * Would break on undo. */ + const ID *rename_id; + void *_pad3; /** List of filetypes to filter (FILE_MAXFILE). */ char filter_glob[256]; @@ -734,7 +740,6 @@ typedef struct FileSelectParams { /** Text items name must match to be shown. */ char filter_search[64]; /** Same as filter, but for ID types (aka library groups). */ - int _pad0; uint64_t filter_id; /** Active file used for keyboard navigation. */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 782d0924d21..299f96a4c46 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -811,6 +811,7 @@ void RNA_struct_py_type_set(StructRNA *srna, void *py_type); void *RNA_struct_blender_type_get(StructRNA *srna); void RNA_struct_blender_type_set(StructRNA *srna, void *blender_type); +struct IDProperty **RNA_struct_idprops_p(PointerRNA *ptr); struct IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create); bool RNA_struct_idprops_check(StructRNA *srna); bool RNA_struct_idprops_register_check(const StructRNA *type); diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 499b5538ad8..38b00afdc8f 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -493,9 +493,10 @@ StructRNA *rna_ID_refine(PointerRNA *ptr) return ID_code_to_RNA_type(GS(id->name)); } -IDProperty *rna_ID_idprops(PointerRNA *ptr, bool create) +IDProperty **rna_ID_idprops(PointerRNA *ptr) { - return IDP_GetProperties(ptr->data, create); + ID *id = (ID *)ptr->data; + return &id->properties; } void rna_ID_fake_user_set(PointerRNA *ptr, bool value) @@ -510,9 +511,9 @@ void rna_ID_fake_user_set(PointerRNA *ptr, bool value) } } -IDProperty *rna_PropertyGroup_idprops(PointerRNA *ptr, bool UNUSED(create)) +IDProperty **rna_PropertyGroup_idprops(PointerRNA *ptr) { - return ptr->data; + return (IDProperty **)&ptr->data; } void rna_PropertyGroup_unregister(Main *UNUSED(bmain), StructRNA *type) @@ -772,7 +773,7 @@ static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, bool clear_pro static AnimData *rna_ID_animation_data_create(ID *id, Main *bmain) { - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); DEG_relations_tag_update(bmain); return adt; } @@ -1162,12 +1163,12 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img); } -static IDProperty *rna_IDPropertyWrapPtr_idprops(PointerRNA *ptr, bool UNUSED(create)) +static IDProperty **rna_IDPropertyWrapPtr_idprops(PointerRNA *ptr) { if (ptr == NULL) { return NULL; } - return ptr->data; + return (IDProperty **)&ptr->data; } static void rna_Library_version_get(PointerRNA *ptr, int *value) diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index a0a84bf4fc9..eb347987f87 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -369,15 +369,32 @@ static bool rna_idproperty_ui_set_default(PointerRNA *ptr, return true; } -IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create) +IDProperty **RNA_struct_idprops_p(PointerRNA *ptr) { StructRNA *type = ptr->type; + if (type == NULL) { + return NULL; + } + if (type->idproperties == NULL) { + return NULL; + } - if (type && type->idproperties) { - return type->idproperties(ptr, create); + return type->idproperties(ptr); +} + +IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create) +{ + IDProperty **property_ptr = RNA_struct_idprops_p(ptr); + if (property_ptr == NULL) { + return NULL; } - return NULL; + if (create && *property_ptr == NULL) { + IDPropertyTemplate val = {0}; + *property_ptr = IDP_New(IDP_GROUP, &val, __func__); + } + + return *property_ptr; } bool RNA_struct_idprops_check(StructRNA *srna) @@ -2026,11 +2043,9 @@ bool RNA_property_enum_item_from_value( bool RNA_property_enum_item_from_value_gettexted( bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, EnumPropertyItem *r_item) { - bool result; + const bool result = RNA_property_enum_item_from_value(C, ptr, prop, value, r_item); - result = RNA_property_enum_item_from_value(C, ptr, prop, value, r_item); - - if (!(prop->flag & PROP_ENUM_NO_TRANSLATE)) { + if (result && !(prop->flag & PROP_ENUM_NO_TRANSLATE)) { if (BLT_translate_iface()) { r_item->name = BLT_pgettext(prop->translation_context, r_item->name); } diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 816fc68195f..c4d35140423 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -422,7 +422,9 @@ static int rna_property_override_diff(Main *bmain, bool override_changed = false; eRNAOverrideMatch diff_flags = flags; - if (!RNA_property_overridable_get(&prop_a->ptr, prop_a->rawprop)) { + if (!RNA_property_overridable_get(&prop_a->ptr, prop_a->rawprop) || + (!ELEM(RNA_property_type(prop_a->rawprop), PROP_POINTER, PROP_COLLECTION) && + !RNA_property_editable_flag(&prop_a->ptr, prop_a->rawprop))) { diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE; } const int diff = override_diff(bmain, diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 7114e21beff..49d02524e43 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -260,28 +260,16 @@ static char *rna_Bone_path(PointerRNA *ptr) return BLI_sprintfN("bones[\"%s\"]", name_esc); } -static IDProperty *rna_Bone_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_Bone_idprops(PointerRNA *ptr) { Bone *bone = ptr->data; - - if (create && !bone->prop) { - IDPropertyTemplate val = {0}; - bone->prop = IDP_New(IDP_GROUP, &val, "RNA_Bone ID properties"); - } - - return bone->prop; + return &bone->prop; } -static IDProperty *rna_EditBone_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_EditBone_idprops(PointerRNA *ptr) { EditBone *ebone = ptr->data; - - if (create && !ebone->prop) { - IDPropertyTemplate val = {0}; - ebone->prop = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties"); - } - - return ebone->prop; + return &ebone->prop; } static void rna_bone_layer_set(int *layer, const bool *values) diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c index 1af53e95cc9..55f680c736d 100644 --- a/source/blender/makesrna/intern/rna_asset.c +++ b/source/blender/makesrna/intern/rna_asset.c @@ -75,16 +75,10 @@ static void rna_AssetMetaData_tag_remove(AssetMetaData *asset_data, RNA_POINTER_INVALIDATE(tag_ptr); } -static IDProperty *rna_AssetMetaData_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_AssetMetaData_idprops(PointerRNA *ptr) { AssetMetaData *asset_data = ptr->data; - - if (create && !asset_data->properties) { - IDPropertyTemplate val = {0}; - asset_data->properties = IDP_New(IDP_GROUP, &val, "RNA_AssetMetaData group"); - } - - return asset_data->properties; + return &asset_data->properties; } static void rna_AssetMetaData_description_get(PointerRNA *ptr, char *value) diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c index 0dfd7d74c25..a9d5ef089bb 100644 --- a/source/blender/makesrna/intern/rna_dynamicpaint.c +++ b/source/blender/makesrna/intern/rna_dynamicpaint.c @@ -342,8 +342,8 @@ static void rna_def_canvas_surface(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; - /* Effect type - * Only used by ui to view per effect settings */ + /* Effect type + * Only used by UI to view per effect settings. */ static const EnumPropertyItem prop_dynamicpaint_effecttype[] = { {1, "SPREAD", 0, "Spread", ""}, {2, "DRIP", 0, "Drip", ""}, @@ -351,7 +351,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; - /* Displacemap file format */ + /* Displace-map file format. */ static const EnumPropertyItem prop_dynamicpaint_image_fileformat[] = { {MOD_DPAINT_IMGFORMAT_PNG, "PNG", 0, "PNG", ""}, # ifdef WITH_OPENEXR @@ -360,7 +360,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; - /* Displacemap type */ + /* Displace-map type. */ static const EnumPropertyItem prop_dynamicpaint_displace_type[] = { {MOD_DPAINT_DISP_DISPLACE, "DISPLACE", 0, "Displacement", ""}, {MOD_DPAINT_DISP_DEPTH, "DEPTH", 0, "Depth", ""}, diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index bfe9d4bb77c..f15368bcc77 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -276,10 +276,10 @@ void rna_ID_name_get(struct PointerRNA *ptr, char *value); int rna_ID_name_length(struct PointerRNA *ptr); void rna_ID_name_set(struct PointerRNA *ptr, const char *value); struct StructRNA *rna_ID_refine(struct PointerRNA *ptr); -struct IDProperty *rna_ID_idprops(struct PointerRNA *ptr, bool create); +struct IDProperty **rna_ID_idprops(struct PointerRNA *ptr); void rna_ID_fake_user_set(struct PointerRNA *ptr, bool value); void **rna_ID_instance(PointerRNA *ptr); -struct IDProperty *rna_PropertyGroup_idprops(struct PointerRNA *ptr, bool create); +struct IDProperty **rna_PropertyGroup_idprops(struct PointerRNA *ptr); void rna_PropertyGroup_unregister(struct Main *bmain, struct StructRNA *type); struct StructRNA *rna_PropertyGroup_register(struct Main *bmain, struct ReportList *reports, diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index ee60b199d64..479306e8c06 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -54,7 +54,7 @@ typedef void (*ContextPropUpdateFunc)(struct bContext *C, typedef void (*ContextUpdateFunc)(struct bContext *C, struct PointerRNA *ptr); typedef int (*EditableFunc)(struct PointerRNA *ptr, const char **r_info); typedef int (*ItemEditableFunc)(struct PointerRNA *ptr, int index); -typedef struct IDProperty *(*IDPropertiesFunc)(struct PointerRNA *ptr, bool create); +typedef struct IDProperty **(*IDPropertiesFunc)(struct PointerRNA *ptr); typedef struct StructRNA *(*StructRefineFunc)(struct PointerRNA *ptr); typedef char *(*StructPathFunc)(struct PointerRNA *ptr); @@ -559,7 +559,7 @@ struct StructRNA { */ StructInstanceFunc instance; - /* callback to get id properties */ + /** Return the location of the struct's pointer to the root group IDProperty. */ IDPropertiesFunc idproperties; /* functions of this struct */ diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index b4253ab9236..0414afe1514 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -119,16 +119,10 @@ static char *rna_ViewLayer_path(PointerRNA *ptr) return BLI_sprintfN("view_layers[\"%s\"]", name_esc); } -static IDProperty *rna_ViewLayer_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_ViewLayer_idprops(PointerRNA *ptr) { ViewLayer *view_layer = (ViewLayer *)ptr->data; - - if (create && !view_layer->id_properties) { - IDPropertyTemplate val = {0}; - view_layer->id_properties = IDP_New(IDP_GROUP, &val, "ViewLayer ID properties"); - } - - return view_layer->id_properties; + return &view_layer->id_properties; } static bool rna_LayerCollection_visible_get(LayerCollection *layer_collection, bContext *C) diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 3fba8cdb035..9835d664a55 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -249,7 +249,7 @@ void RNA_api_mesh(StructRNA *srna) func = RNA_def_function(srna, "split_faces", "rna_Mesh_split_faces"); RNA_def_function_ui_description(func, "Split faces based on the edge angle"); RNA_def_boolean( - func, "free_loop_normals", 1, "Free Loop Notmals", "Free loop normals custom data layer"); + func, "free_loop_normals", 1, "Free Loop Normals", "Free loop normals custom data layer"); func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents"); RNA_def_function_flag(func, FUNC_USE_REPORTS); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 7def9bdb636..e64eaf8c363 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -602,6 +602,7 @@ const EnumPropertyItem rna_enum_axis_flag_xyz_items[] = { # include "BKE_cachefile.h" # include "BKE_context.h" +# include "BKE_deform.h" # include "BKE_mesh_runtime.h" # include "BKE_modifier.h" # include "BKE_object.h" @@ -1250,12 +1251,13 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf( # endif if (ob_src) { - bDeformGroup *dg; + const bDeformGroup *dg; int i; RNA_enum_item_add_separator(&item, &totitem); - for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) { + const ListBase *defbase = BKE_object_defgroup_list(ob_src); + for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) { tmp_item.value = i; tmp_item.identifier = tmp_item.name = dg->name; RNA_enum_item_add(&item, &totitem, &tmp_item); @@ -1349,12 +1351,13 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf( Object *ob_dst = CTX_data_active_object(C); /* XXX Is this OK? */ if (ob_dst) { - bDeformGroup *dg; + const bDeformGroup *dg; int i; RNA_enum_item_add_separator(&item, &totitem); - for (i = 0, dg = ob_dst->defbase.first; dg; i++, dg = dg->next) { + const ListBase *defbase = BKE_object_defgroup_list(ob_dst); + for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) { tmp_item.value = i; tmp_item.identifier = tmp_item.name = dg->name; RNA_enum_item_add(&item, &totitem, &tmp_item); @@ -1618,15 +1621,11 @@ static void rna_NodesModifier_node_group_update(Main *bmain, Scene *scene, Point MOD_nodes_update_interface(object, nmd); } -static IDProperty *rna_NodesModifier_properties(PointerRNA *ptr, bool create) +static IDProperty **rna_NodesModifier_properties(PointerRNA *ptr) { NodesModifierData *nmd = ptr->data; NodesModifierSettings *settings = &nmd->settings; - if (create && settings->properties == NULL) { - IDPropertyTemplate val = {0}; - settings->properties = IDP_New(IDP_GROUP, &val, "Nodes Modifier Settings"); - } - return settings->properties; + return &settings->properties; } #else diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 978ea13f92f..582bc40a142 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -2366,16 +2366,10 @@ static StructRNA *rna_FunctionNode_register(Main *bmain, return nt->rna_ext.srna; } -static IDProperty *rna_Node_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_Node_idprops(PointerRNA *ptr) { bNode *node = ptr->data; - - if (create && !node->prop) { - IDPropertyTemplate val = {0}; - node->prop = IDP_New(IDP_GROUP, &val, "RNA_Node ID properties"); - } - - return node->prop; + return &node->prop; } static void rna_Node_parent_set(PointerRNA *ptr, @@ -2834,16 +2828,10 @@ static char *rna_NodeSocket_path(PointerRNA *ptr) } } -static IDProperty *rna_NodeSocket_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_NodeSocket_idprops(PointerRNA *ptr) { bNodeSocket *sock = ptr->data; - - if (create && !sock->prop) { - IDPropertyTemplate val = {0}; - sock->prop = IDP_New(IDP_GROUP, &val, "RNA_NodeSocket ID properties"); - } - - return sock->prop; + return &sock->prop; } static PointerRNA rna_NodeSocket_node_get(PointerRNA *ptr) @@ -3150,16 +3138,10 @@ static char *rna_NodeSocketInterface_path(PointerRNA *ptr) return NULL; } -static IDProperty *rna_NodeSocketInterface_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_NodeSocketInterface_idprops(PointerRNA *ptr) { bNodeSocket *sock = ptr->data; - - if (create && !sock->prop) { - IDPropertyTemplate val = {0}; - sock->prop = IDP_New(IDP_GROUP, &val, "RNA_NodeSocketInterface ID properties"); - } - - return sock->prop; + return &sock->prop; } static void rna_NodeSocketInterface_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) @@ -3205,7 +3187,7 @@ static void rna_NodeSocketInterfaceStandard_draw(ID *id, struct uiLayout *layout) { PointerRNA ptr; - RNA_pointer_create(id, &RNA_NodeSocket, sock, &ptr); + RNA_pointer_create(id, &RNA_NodeSocketInterface, sock, &ptr); sock->typeinfo->interface_draw(C, layout, &ptr); } @@ -3215,7 +3197,7 @@ static void rna_NodeSocketInterfaceStandard_draw_color(ID *id, float r_color[4]) { PointerRNA ptr; - RNA_pointer_create(id, &RNA_NodeSocket, sock, &ptr); + RNA_pointer_create(id, &RNA_NodeSocketInterface, sock, &ptr); sock->typeinfo->interface_draw_color(C, &ptr, r_color); } @@ -9947,6 +9929,45 @@ static void def_geo_switch(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_geo_curve_primitive_quadrilateral(StructRNA *srna) +{ + PropertyRNA *prop; + + static EnumPropertyItem mode_items[] = { + {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE, + "RECTANGLE", + 0, + "Rectangle", + "Create a rectangle"}, + {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM, + "PARALLELOGRAM", + 0, + "Parallelogram", + "Create a parallelogram"}, + {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID, + "TRAPEZOID", + 0, + "Trapezoid", + "Create a trapezoid"}, + {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE, "KITE", 0, "Kite", "Create a Kite / Dart"}, + {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS, + "POINTS", + 0, + "Points", + "Create a quadrilateral from four points"}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_struct_sdna_from(srna, "NodeGeometryCurvePrimitiveQuad", "storage"); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, mode_items); + RNA_def_property_enum_default(prop, GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE); + RNA_def_property_ui_text(prop, "Mode", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + static void def_geo_curve_resample(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 7c012922c2c..e110459eeea 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -790,9 +790,27 @@ static void rna_Object_dup_collection_set(PointerRNA *ptr, } } +static void rna_Object_vertex_groups_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->data; + if (!BKE_object_supports_vertex_groups(ob)) { + iter->valid = 0; + return; + } + + ListBase *defbase = BKE_object_defgroup_list_mutable(ob); + iter->valid = defbase != NULL; + + rna_iterator_listbase_begin(iter, defbase, NULL); +} + static void rna_VertexGroup_name_set(PointerRNA *ptr, const char *value) { Object *ob = (Object *)ptr->owner_id; + if (!BKE_object_supports_vertex_groups(ob)) { + return; + } + bDeformGroup *dg = (bDeformGroup *)ptr->data; BLI_strncpy_utf8(dg->name, value, sizeof(dg->name)); BKE_object_defgroup_unique_name(dg, ob); @@ -801,15 +819,25 @@ static void rna_VertexGroup_name_set(PointerRNA *ptr, const char *value) static int rna_VertexGroup_index_get(PointerRNA *ptr) { Object *ob = (Object *)ptr->owner_id; + if (!BKE_object_supports_vertex_groups(ob)) { + return -1; + } - return BLI_findindex(&ob->defbase, ptr->data); + const ListBase *defbase = BKE_object_defgroup_list(ob); + return BLI_findindex(defbase, ptr->data); } static PointerRNA rna_Object_active_vertex_group_get(PointerRNA *ptr) { Object *ob = (Object *)ptr->owner_id; + if (!BKE_object_supports_vertex_groups(ob)) { + return PointerRNA_NULL; + } + + const ListBase *defbase = BKE_object_defgroup_list(ob); + return rna_pointer_inherit_refine( - ptr, &RNA_VertexGroup, BLI_findlink(&ob->defbase, ob->actdef - 1)); + ptr, &RNA_VertexGroup, BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1)); } static void rna_Object_active_vertex_group_set(PointerRNA *ptr, @@ -817,7 +845,13 @@ static void rna_Object_active_vertex_group_set(PointerRNA *ptr, struct ReportList *reports) { Object *ob = (Object *)ptr->owner_id; - int index = BLI_findindex(&ob->defbase, value.data); + if (!BKE_object_supports_vertex_groups(ob)) { + return; + } + + const ListBase *defbase = BKE_object_defgroup_list(ob); + + int index = BLI_findindex(defbase, value.data); if (index == -1) { BKE_reportf(reports, RPT_ERROR, @@ -827,19 +861,27 @@ static void rna_Object_active_vertex_group_set(PointerRNA *ptr, return; } - ob->actdef = index + 1; + BKE_object_defgroup_active_index_set(ob, index + 1); } static int rna_Object_active_vertex_group_index_get(PointerRNA *ptr) { Object *ob = (Object *)ptr->owner_id; - return ob->actdef - 1; + if (!BKE_object_supports_vertex_groups(ob)) { + return -1; + } + + return BKE_object_defgroup_active_index_get(ob) - 1; } static void rna_Object_active_vertex_group_index_set(PointerRNA *ptr, int value) { Object *ob = (Object *)ptr->owner_id; - ob->actdef = value + 1; + if (!BKE_object_supports_vertex_groups(ob)) { + return; + } + + BKE_object_defgroup_active_index_set(ob, value + 1); } static void rna_Object_active_vertex_group_index_range( @@ -848,15 +890,24 @@ static void rna_Object_active_vertex_group_index_range( Object *ob = (Object *)ptr->owner_id; *min = 0; - *max = max_ii(0, BLI_listbase_count(&ob->defbase) - 1); + if (!BKE_object_supports_vertex_groups(ob)) { + *max = 0; + return; + } + const ListBase *defbase = BKE_object_defgroup_list(ob); + *max = max_ii(0, BLI_listbase_count(defbase) - 1); } void rna_object_vgroup_name_index_get(PointerRNA *ptr, char *value, int index) { Object *ob = (Object *)ptr->owner_id; - bDeformGroup *dg; + if (!BKE_object_supports_vertex_groups(ob)) { + value[0] = '\0'; + return; + } - dg = BLI_findlink(&ob->defbase, index - 1); + const ListBase *defbase = BKE_object_defgroup_list(ob); + const bDeformGroup *dg = BLI_findlink(defbase, index - 1); if (dg) { BLI_strncpy(value, dg->name, sizeof(dg->name)); @@ -869,21 +920,34 @@ void rna_object_vgroup_name_index_get(PointerRNA *ptr, char *value, int index) int rna_object_vgroup_name_index_length(PointerRNA *ptr, int index) { Object *ob = (Object *)ptr->owner_id; - bDeformGroup *dg; + if (!BKE_object_supports_vertex_groups(ob)) { + return 0; + } - dg = BLI_findlink(&ob->defbase, index - 1); + const ListBase *defbase = BKE_object_defgroup_list(ob); + bDeformGroup *dg = BLI_findlink(defbase, index - 1); return (dg) ? strlen(dg->name) : 0; } void rna_object_vgroup_name_index_set(PointerRNA *ptr, const char *value, short *index) { Object *ob = (Object *)ptr->owner_id; + if (!BKE_object_supports_vertex_groups(ob)) { + *index = -1; + return; + } + *index = BKE_object_defgroup_name_index(ob, value) + 1; } void rna_object_vgroup_name_set(PointerRNA *ptr, const char *value, char *result, int maxlen) { Object *ob = (Object *)ptr->owner_id; + if (!BKE_object_supports_vertex_groups(ob)) { + result[0] = '\0'; + return; + } + bDeformGroup *dg = BKE_object_defgroup_find_name(ob, value); if (dg) { /* No need for BLI_strncpy_utf8, since this matches an existing group. */ @@ -1960,7 +2024,9 @@ static void rna_Object_vgroup_remove(Object *ob, PointerRNA *defgroup_ptr) { bDeformGroup *defgroup = defgroup_ptr->data; - if (BLI_findindex(&ob->defbase, defgroup) == -1) { + ListBase *defbase = BKE_object_defgroup_list_mutable(ob); + + if (BLI_findindex(defbase, defgroup) == -1) { BKE_reportf(reports, RPT_ERROR, "DeformGroup '%s' not in object '%s'", @@ -2687,7 +2753,6 @@ static void rna_def_object_vertex_groups(BlenderRNA *brna, PropertyRNA *cprop) prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_int_sdna(prop, NULL, "actdef"); RNA_def_property_int_funcs(prop, "rna_Object_active_vertex_group_index_get", "rna_Object_active_vertex_group_index_set", @@ -3274,7 +3339,15 @@ static void rna_def_object(BlenderRNA *brna) /* vertex groups */ prop = RNA_def_property(srna, "vertex_groups", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "defbase", NULL); + RNA_def_property_collection_funcs(prop, + "rna_Object_vertex_groups_begin", + "rna_iterator_listbase_next", + "rna_iterator_listbase_end", + "rna_iterator_listbase_get", + NULL, + NULL, + NULL, + 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"); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 8edb80f68c5..de4cfb2b61a 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -1430,9 +1430,10 @@ static void psys_vg_name_get__internal(PointerRNA *ptr, char *value, int index) { Object *ob = (Object *)ptr->owner_id; ParticleSystem *psys = (ParticleSystem *)ptr->data; + const ListBase *defbase = BKE_object_defgroup_list(ob); if (psys->vgroup[index] > 0) { - bDeformGroup *defGroup = BLI_findlink(&ob->defbase, psys->vgroup[index] - 1); + bDeformGroup *defGroup = BLI_findlink(defbase, psys->vgroup[index] - 1); if (defGroup) { strcpy(value, defGroup->name); @@ -1448,7 +1449,8 @@ static int psys_vg_name_len__internal(PointerRNA *ptr, int index) ParticleSystem *psys = (ParticleSystem *)ptr->data; if (psys->vgroup[index] > 0) { - bDeformGroup *defGroup = BLI_findlink(&ob->defbase, psys->vgroup[index] - 1); + const ListBase *defbase = BKE_object_defgroup_list(ob); + bDeformGroup *defGroup = BLI_findlink(defbase, psys->vgroup[index] - 1); if (defGroup) { return strlen(defGroup->name); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index bb4939a010b..ee509fa92d4 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -224,16 +224,10 @@ static void rna_BoneGroup_name_set(PointerRNA *ptr, const char *value) sizeof(agrp->name)); } -static IDProperty *rna_PoseBone_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_PoseBone_idprops(PointerRNA *ptr) { bPoseChannel *pchan = ptr->data; - - if (create && !pchan->prop) { - IDPropertyTemplate val = {0}; - pchan->prop = IDP_New(IDP_GROUP, &val, "RNA_PoseBone group"); - } - - return pchan->prop; + return &pchan->prop; } static void rna_Pose_ik_solver_set(struct PointerRNA *ptr, int value) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 0c46450759d..b1f0b0d760f 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -199,7 +199,10 @@ static void rna_SequenceEditor_sequences_all_begin(CollectionPropertyIterator *i bli_iter->data = MEM_callocN(sizeof(SeqIterator), __func__); iter->internal.custom = bli_iter; - SEQ_iterator_ensure(all_strips, bli_iter->data, (Sequence **)&bli_iter->current); + if (!SEQ_iterator_ensure(all_strips, bli_iter->data, (Sequence **)&bli_iter->current)) { + SEQ_collection_free(all_strips); + } + iter->valid = bli_iter->current != NULL; } @@ -220,7 +223,9 @@ static void rna_SequenceEditor_sequences_all_end(CollectionPropertyIterator *ite { BLI_Iterator *bli_iter = iter->internal.custom; SeqIterator *seq_iter = bli_iter->data; - SEQ_collection_free(seq_iter->collection); + if (seq_iter->collection != NULL) { + SEQ_collection_free(seq_iter->collection); + } MEM_freeN(seq_iter); MEM_freeN(bli_iter); } @@ -729,16 +734,10 @@ static char *rna_Sequence_path(PointerRNA *ptr) } } -static IDProperty *rna_Sequence_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_Sequence_idprops(PointerRNA *ptr) { Sequence *seq = ptr->data; - - if (create && !seq->prop) { - IDPropertyTemplate val = {0}; - seq->prop = IDP_New(IDP_GROUP, &val, "Sequence ID properties"); - } - - return seq->prop; + return &seq->prop; } static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main *bmain) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 56deb873611..7366934695e 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1041,16 +1041,10 @@ static bool rna_RegionView3D_is_orthographic_side_view_get(PointerRNA *ptr) return RV3D_VIEW_IS_AXIS(rv3d->view); } -static IDProperty *rna_View3DShading_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_View3DShading_idprops(PointerRNA *ptr) { View3DShading *shading = ptr->data; - - if (create && !shading->prop) { - IDPropertyTemplate val = {0}; - shading->prop = IDP_New(IDP_GROUP, &val, "View3DShading ID properties"); - } - - return shading->prop; + return &shading->prop; } static void rna_3DViewShading_type_update(Main *bmain, Scene *scene, PointerRNA *ptr) @@ -2106,7 +2100,7 @@ static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr) switch (saction->mode) { case SACTCONT_ACTION: /* TODO: context selector could help decide this with more control? */ - adt = BKE_animdata_add_id(&obact->id); + adt = BKE_animdata_ensure_id(&obact->id); id = &obact->id; break; case SACTCONT_SHAPEKEY: { @@ -2114,7 +2108,7 @@ static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr) if (key == NULL) { return; } - adt = BKE_animdata_add_id(&key->id); + adt = BKE_animdata_ensure_id(&key->id); id = &key->id; break; } diff --git a/source/blender/makesrna/intern/rna_timeline.c b/source/blender/makesrna/intern/rna_timeline.c index c0bd9fd92a2..223e6389942 100644 --- a/source/blender/makesrna/intern/rna_timeline.c +++ b/source/blender/makesrna/intern/rna_timeline.c @@ -33,16 +33,10 @@ # include "BKE_idprop.h" # include "WM_api.h" -static IDProperty *rna_TimelineMarker_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_TimelineMarker_idprops(PointerRNA *ptr) { TimeMarker *marker = ptr->data; - - if (create && marker->prop == NULL) { - IDPropertyTemplate val = {0}; - marker->prop = IDP_New(IDP_GROUP, &val, "Marker ID properties"); - } - - return marker->prop; + return &marker->prop; } static void rna_TimelineMarker_update(Main *UNUSED(bmain), diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 98bed5a7891..d4ae5f1ecfc 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -452,15 +452,10 @@ static unsigned int rna_UIList_filter_const_FILTER_ITEM_get(PointerRNA *UNUSED(p return UILST_FLT_ITEM; } -static IDProperty *rna_UIList_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_UIList_idprops(PointerRNA *ptr) { uiList *ui_list = (uiList *)ptr->data; - if (create && !ui_list->properties) { - IDPropertyTemplate val = {0}; - ui_list->properties = IDP_New(IDP_GROUP, &val, "RNA_UIList IDproperties group"); - } - - return ui_list->properties; + return &ui_list->properties; } static void uilist_draw_item(uiList *ui_list, diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 81f6bcc5805..fd1c0b7951a 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -809,14 +809,9 @@ static const EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C } # endif -static IDProperty *rna_AddonPref_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_AddonPref_idprops(PointerRNA *ptr) { - if (create && !ptr->data) { - IDPropertyTemplate val = {0}; - ptr->data = IDP_New(IDP_GROUP, &val, "RNA_AddonPreferences group"); - } - - return ptr->data; + return (IDProperty **)&ptr->data; } static PointerRNA rna_Addon_preferences_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index a563541b968..afbde26e59e 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -568,14 +568,9 @@ static StructRNA *rna_OperatorProperties_refine(PointerRNA *ptr) } } -static IDProperty *rna_OperatorProperties_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_OperatorProperties_idprops(PointerRNA *ptr) { - if (create && !ptr->data) { - IDPropertyTemplate val = {0}; - ptr->data = IDP_New(IDP_GROUP, &val, "RNA_OperatorProperties group"); - } - - return ptr->data; + return (IDProperty **)&ptr->data; } static void rna_Operator_name_get(PointerRNA *ptr, char *value) @@ -1120,13 +1115,9 @@ static PointerRNA rna_wmKeyConfig_preferences_get(PointerRNA *ptr) } } -static IDProperty *rna_wmKeyConfigPref_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_wmKeyConfigPref_idprops(PointerRNA *ptr) { - if (create && !ptr->data) { - IDPropertyTemplate val = {0}; - ptr->data = IDP_New(IDP_GROUP, &val, "RNA_KeyConfigPreferences group"); - } - return ptr->data; + return (IDProperty **)&ptr->data; } static void rna_wmKeyConfigPref_unregister(Main *UNUSED(bmain), StructRNA *type) diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c index 98920bbd518..076a77d4fb5 100644 --- a/source/blender/makesrna/intern/rna_wm_gizmo.c +++ b/source/blender/makesrna/intern/rna_wm_gizmo.c @@ -293,14 +293,9 @@ static StructRNA *rna_GizmoProperties_refine(PointerRNA *ptr) } } -static IDProperty *rna_GizmoProperties_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_GizmoProperties_idprops(PointerRNA *ptr) { - if (create && !ptr->data) { - IDPropertyTemplate val = {0}; - ptr->data = IDP_New(IDP_GROUP, &val, "RNA_GizmoProperties group"); - } - - return ptr->data; + return (IDProperty **)&ptr->data; } static PointerRNA rna_Gizmo_properties_get(PointerRNA *ptr) @@ -585,14 +580,9 @@ static StructRNA *rna_GizmoGroupProperties_refine(PointerRNA *ptr) } } -static IDProperty *rna_GizmoGroupProperties_idprops(PointerRNA *ptr, bool create) +static IDProperty **rna_GizmoGroupProperties_idprops(PointerRNA *ptr) { - if (create && !ptr->data) { - IDPropertyTemplate val = {0}; - ptr->data = IDP_New(IDP_GROUP, &val, "RNA_GizmoGroupProperties group"); - } - - return ptr->data; + return (IDProperty **)&ptr->data; } static wmGizmo *rna_GizmoGroup_gizmo_new(wmGizmoGroup *gzgroup, diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 649d36e3d57..828b8b79664 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -37,6 +37,7 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_context.h" +#include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" @@ -122,7 +123,8 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte /* If neither vertex groups nor envelopes are used, the modifier has no bone dependencies. */ if ((amd->deformflag & ARM_DEF_VGROUP) != 0) { /* Enumerate groups that match existing bones. */ - LISTBASE_FOREACH (bDeformGroup *, dg, &ctx->object->defbase) { + const ListBase *defbase = BKE_object_defgroup_list(ctx->object); + LISTBASE_FOREACH (bDeformGroup *, dg, defbase) { if (BKE_pose_channel_find_name(amd->object->pose, dg->name) != NULL) { /* Can't check BONE_NO_DEFORM because it can be animated. */ DEG_add_bone_relation( diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index 4b9b24e4e47..bdb791dc8e7 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -109,7 +109,7 @@ static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *u { BooleanModifierData *bmd = (BooleanModifierData *)md; - walk(userData, ob, (ID **)&bmd->collection, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&bmd->collection, IDWALK_CB_USER); walk(userData, ob, (ID **)&bmd->object, IDWALK_CB_NOP); } diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index c38e5126f6b..52f21e3d3d0 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -101,7 +101,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct range_vn_i(faceMap, numPoly_src, 0); struct Scene *scene = DEG_get_input_scene(ctx->depsgraph); - frac = (BKE_scene_frame_get(scene) - bmd->start) / bmd->length; + frac = (BKE_scene_ctime_get(scene) - bmd->start) / bmd->length; CLAMP(frac, 0.0f, 1.0f); if (bmd->flag & MOD_BUILD_FLAG_REVERSE) { frac = 1.0f - frac; diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 40d027f3044..4487adcfdda 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -206,6 +206,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla tclmd->point_cache->step = clmd->point_cache->step; tclmd->point_cache->startframe = clmd->point_cache->startframe; tclmd->point_cache->endframe = clmd->point_cache->endframe; + tclmd->point_cache->flag |= (clmd->point_cache->flag & PTCACHE_FLAGS_COPY); } } diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index 20dbb299767..aae6d257766 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -167,7 +167,7 @@ static void deformVertsEM(ModifierData *md, int defgrp_index = -1; if (ctx->object->type == OB_MESH && cmd->name[0] != '\0') { - defgrp_index = BKE_object_defgroup_name_index(ctx->object, cmd->name); + defgrp_index = BKE_id_defgroup_name_index(&mesh->id, cmd->name); if (defgrp_index != -1) { use_dverts = true; } diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 545e23221ec..bf197dca7e5 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -919,7 +919,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, EdgeHashIterator *ehi; float *vertco = NULL, imat[4][4]; float rot[4]; - float cfra; + float ctime; /* float timestep; */ const int *facepa = emd->facepa; int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0; @@ -940,7 +940,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, /* timestep = psys_get_timestep(&sim); */ - cfra = BKE_scene_frame_get(scene); + ctime = BKE_scene_ctime_get(scene); /* hash table for vertice <-> particle relations */ vertpahash = BLI_edgehash_new(__func__); @@ -962,7 +962,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, /* do mindex + totvert to ensure the vertex index to be the first * with BLI_edgehashIterator_getKey */ - if (pa == NULL || cfra < pa->time) { + if (pa == NULL || ctime < pa->time) { mindex = totvert + totpart; } else { @@ -1022,7 +1022,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, psys_get_birth_coords(&sim, pa, &birth, 0, 0); - state.time = cfra; + state.time = ctime; psys_get_particle_state(&sim, ed_v2, &state, 1); vertco = explode->mvert[v].co; @@ -1076,7 +1076,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, orig_v4 = source.v4; /* Same as above in the first loop over mesh's faces. */ - if (pa == NULL || cfra < pa->time) { + if (pa == NULL || ctime < pa->time) { mindex = totvert + totpart; } else { @@ -1096,7 +1096,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, /* override uv channel for particle age */ if (mtface) { - float age = (pa != NULL) ? (cfra - pa->time) / pa->lifetime : 0.0f; + float age = (pa != NULL) ? (ctime - pa->time) / pa->lifetime : 0.0f; /* Clamp to this range to avoid flipping to the other side of the coordinates. */ CLAMP(age, 0.001f, 0.999f); diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index a77f6cfe8ba..9aa8e3dd7c8 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -119,7 +119,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte /* A vertex will be in the mask if a selected bone influences it more than a certain threshold. */ static void compute_vertex_mask__armature_mode(MDeformVert *dvert, - Object *ob, + Mesh *mesh, Object *armature_ob, float threshold, MutableSpan<bool> r_vertex_mask) @@ -127,7 +127,7 @@ static void compute_vertex_mask__armature_mode(MDeformVert *dvert, /* Element i is true if there is a selected bone that uses vertex group i. */ Vector<bool> selected_bone_uses_group; - for (bDeformGroup *def : ListBaseWrapper<bDeformGroup>(ob->defbase)) { + LISTBASE_FOREACH (bDeformGroup *, def, &mesh->vertex_group_names) { bPoseChannel *pchan = BKE_pose_channel_find_name(armature_ob->pose, def->name); bool bone_for_group_exists = pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED); selected_bone_uses_group.append(bone_for_group_exists); @@ -325,10 +325,9 @@ void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, * 2. Find edges and polygons only using those vertices. * 3. Create a new mesh that only uses the found vertices, edges and polygons. */ -static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) +static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh) { MaskModifierData *mmd = reinterpret_cast<MaskModifierData *>(md); - Object *ob = ctx->object; const bool invert_mask = mmd->flag & MOD_MASK_INV; /* Return empty or input mesh when there are no vertex groups. */ @@ -339,7 +338,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* Quick test to see if we can return early. */ if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || (mesh->totvert == 0) || - BLI_listbase_is_empty(&ob->defbase)) { + BLI_listbase_is_empty(&mesh->vertex_group_names)) { return mesh; } @@ -348,15 +347,15 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * Object *armature_ob = mmd->ob_arm; /* Return input mesh if there is no armature with bones. */ - if (ELEM(NULL, armature_ob, armature_ob->pose, ob->defbase.first)) { + if (ELEM(NULL, armature_ob, armature_ob->pose)) { return mesh; } vertex_mask = Array<bool>(mesh->totvert); - compute_vertex_mask__armature_mode(dvert, ob, armature_ob, mmd->threshold, vertex_mask); + compute_vertex_mask__armature_mode(dvert, mesh, armature_ob, mmd->threshold, vertex_mask); } else { - int defgrp_index = BKE_object_defgroup_name_index(ob, mmd->vgroup); + int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, mmd->vgroup); /* Return input mesh if the vertex group does not exist. */ if (defgrp_index == -1) { diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c index 6ec3277ee7a..e0507320628 100644 --- a/source/blender/modifiers/intern/MOD_meshcache.c +++ b/source/blender/modifiers/intern/MOD_meshcache.c @@ -104,20 +104,20 @@ static void meshcache_do(MeshCacheModifierData *mcmd, /* -------------------------------------------------------------------- */ /* Interpret Time (the reading functions also do some of this ) */ if (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA) { - const float cfra = BKE_scene_frame_get(scene); + const float ctime = BKE_scene_ctime_get(scene); switch (mcmd->time_mode) { case MOD_MESHCACHE_TIME_FRAME: { - time = cfra; + time = ctime; break; } case MOD_MESHCACHE_TIME_SECONDS: { - time = cfra / fps; + time = ctime / fps; break; } case MOD_MESHCACHE_TIME_FACTOR: default: { - time = cfra / fps; + time = ctime / fps; break; } } diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 76eec76acb4..87fce26c45e 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -48,6 +48,7 @@ #include "DNA_space_types.h" #include "DNA_windowmanager_types.h" +#include "BKE_attribute_math.hh" #include "BKE_customdata.h" #include "BKE_geometry_set_instances.hh" #include "BKE_global.h" @@ -56,7 +57,6 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_modifier.h" -#include "BKE_node_ui_storage.hh" #include "BKE_object.h" #include "BKE_pointcloud.h" #include "BKE_screen.h" @@ -83,8 +83,10 @@ #include "NOD_derived_node_tree.hh" #include "NOD_geometry.h" +#include "NOD_geometry_nodes_eval_log.hh" #include "NOD_node_tree_multi_function.hh" +using blender::destruct_ptr; using blender::float3; using blender::FunctionRef; using blender::IndexRange; @@ -97,6 +99,7 @@ using blender::Vector; using blender::fn::GMutablePointer; using blender::fn::GPointer; using blender::nodes::GeoNodeExecParams; +using blender::threading::EnumerableThreadSpecific; using namespace blender::fn::multi_function_types; using namespace blender::nodes::derived_node_tree_types; @@ -734,19 +737,6 @@ static void initialize_group_input(NodesModifierData &nmd, property_type->init_cpp_value(*property, r_value); } -static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> trees, - const Object &object, - const ModifierData &modifier) -{ - const NodeTreeEvaluationContext context = {object, modifier}; - - for (const blender::nodes::NodeTreeRef *tree : trees) { - bNodeTree *btree_cow = tree->btree(); - bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow); - BKE_nodetree_ui_storage_free_for_context(*btree_original, context); - } -} - static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain) { wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; @@ -766,8 +756,6 @@ static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain) return spreadsheets; } -using PreviewSocketMap = blender::MultiValueMap<DSocket, uint64_t>; - static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet, NodesModifierData *nmd, const ModifierEvalContext *ctx, @@ -821,19 +809,10 @@ static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspre } const NodeTreeRef &tree_ref = context->tree(); - for (const NodeRef *node_ref : tree_ref.nodes()) { + for (const NodeRef *node_ref : tree_ref.nodes_by_type("GeometryNodeViewer")) { if (node_ref->name() == last_context->node_name) { const DNode viewer_node{context, node_ref}; - DSocket socket_to_view; - viewer_node.input(0).foreach_origin_socket( - [&](const DSocket socket) { socket_to_view = socket; }); - if (!socket_to_view) { - return {}; - } - bNodeSocket *bsocket = socket_to_view->bsocket(); - if (bsocket->type == SOCK_GEOMETRY && bsocket->flag != SOCK_MULTI_INPUT) { - return socket_to_view; - } + return viewer_node.input(0); } } return {}; @@ -842,7 +821,7 @@ static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspre static void find_sockets_to_preview(NodesModifierData *nmd, const ModifierEvalContext *ctx, const DerivedNodeTree &tree, - PreviewSocketMap &r_sockets_to_preview) + Set<DSocket> &r_sockets_to_preview) { Main *bmain = DEG_get_bmain(ctx->depsgraph); @@ -852,51 +831,16 @@ static void find_sockets_to_preview(NodesModifierData *nmd, for (SpaceSpreadsheet *sspreadsheet : spreadsheets) { const DSocket socket = try_get_socket_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree); if (socket) { - const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet); - r_sockets_to_preview.add_non_duplicates(socket, key); + r_sockets_to_preview.add(socket); } } } -static void log_preview_socket_value(const Span<GPointer> values, - Object *object, - Span<uint64_t> keys) +static void clear_runtime_data(NodesModifierData *nmd) { - GeometrySet geometry_set = *(const GeometrySet *)values[0].get(); - geometry_set.ensure_owns_direct_data(); - for (uint64_t key : keys) { - BKE_object_preview_geometry_set_add(object, key, new GeometrySet(geometry_set)); - } -} - -static void log_ui_hints(const DSocket socket, - const Span<GPointer> values, - Object *self_object, - NodesModifierData *nmd) -{ - const DNode node = socket.node(); - if (node->is_reroute_node() || socket->typeinfo()->type != SOCK_GEOMETRY) { - return; - } - bNodeTree *btree_cow = node->btree(); - bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow); - const NodeTreeEvaluationContext context{*self_object, nmd->modifier}; - for (const GPointer &data : values) { - if (data.type() == &CPPType::get<GeometrySet>()) { - const GeometrySet &geometry_set = *(const GeometrySet *)data.get(); - blender::bke::geometry_set_instances_attribute_foreach( - geometry_set, - [&](StringRefNull attribute_name, const AttributeMetaData &meta_data) { - BKE_nodetree_attribute_hint_add(*btree_original, - context, - *node->bnode(), - attribute_name, - meta_data.domain, - meta_data.data_type); - return true; - }, - 8); - } + if (nmd->runtime_eval_log != nullptr) { + delete (geo_log::ModifierLog *)nmd->runtime_eval_log; + nmd->runtime_eval_log = nullptr; } } @@ -952,32 +896,32 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, Vector<DInputSocket> group_outputs; group_outputs.append({root_context, &socket_to_compute}); - PreviewSocketMap preview_sockets; - find_sockets_to_preview(nmd, ctx, tree, preview_sockets); - - auto log_socket_value = [&](const DSocket socket, const Span<GPointer> values) { - if (!logging_enabled(ctx)) { - return; - } - Span<uint64_t> keys = preview_sockets.lookup(socket); - if (!keys.is_empty()) { - log_preview_socket_value(values, ctx->object, keys); - } - log_ui_hints(socket, values, ctx->object, nmd); - }; + std::optional<geo_log::GeoLogger> geo_logger; blender::modifiers::geometry_nodes::GeometryNodesEvaluationParams eval_params; + + if (logging_enabled(ctx)) { + Set<DSocket> preview_sockets; + find_sockets_to_preview(nmd, ctx, tree, preview_sockets); + eval_params.force_compute_sockets.extend(preview_sockets.begin(), preview_sockets.end()); + geo_logger.emplace(std::move(preview_sockets)); + } + eval_params.input_values = group_inputs; eval_params.output_sockets = group_outputs; - eval_params.force_compute_sockets.extend(preview_sockets.keys().begin(), - preview_sockets.keys().end()); eval_params.mf_by_node = &mf_by_node; eval_params.modifier_ = nmd; eval_params.depsgraph = ctx->depsgraph; eval_params.self_object = ctx->object; - eval_params.log_socket_value_fn = log_socket_value; + eval_params.geo_logger = geo_logger.has_value() ? &*geo_logger : nullptr; blender::modifiers::geometry_nodes::evaluate_geometry_nodes(eval_params); + if (geo_logger.has_value()) { + NodesModifierData *nmd_orig = (NodesModifierData *)BKE_modifier_get_original(&nmd->modifier); + clear_runtime_data(nmd_orig); + nmd_orig->runtime_eval_log = new geo_log::ModifierLog(*geo_logger); + } + BLI_assert(eval_params.r_output_values.size() == 1); GMutablePointer result = eval_params.r_output_values[0]; return result.relocate_out<GeometrySet>(); @@ -1067,10 +1011,6 @@ static void modifyGeometry(ModifierData *md, return; } - if (logging_enabled(ctx)) { - reset_tree_ui_storage(tree.used_node_tree_refs(), *ctx->object, *md); - } - geometry_set = compute_geometry( tree, input_nodes, *group_outputs[0], std::move(geometry_set), nmd, ctx); } @@ -1078,13 +1018,14 @@ static void modifyGeometry(ModifierData *md, static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { GeometrySet geometry_set = GeometrySet::create_with_mesh(mesh, GeometryOwnershipType::Editable); - geometry_set.get_component_for_write<MeshComponent>().copy_vertex_group_names_from_object( - *ctx->object); + modifyGeometry(md, ctx, geometry_set); - /* This function is only called when applying modifiers. In this case it makes sense to realize - * instances, otherwise in some cases there might be no results when applying the modifier. */ - geometry_set = blender::bke::geometry_set_realize_mesh_for_modifier(geometry_set); + if (ctx->flag & MOD_APPLY_TO_BASE_MESH) { + /* In this case it makes sense to realize instances, otherwise in some cases there might be no + * results when applying the modifier. */ + geometry_set = blender::bke::geometry_set_realize_mesh_for_modifier(geometry_set); + } Mesh *new_mesh = geometry_set.get_component_for_write<MeshComponent>().release(); if (new_mesh == nullptr) { @@ -1215,6 +1156,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md) NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md); BLO_read_data_address(reader, &nmd->settings.properties); IDP_BlendDataRead(reader, &nmd->settings.properties); + nmd->runtime_eval_log = nullptr; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) @@ -1224,6 +1166,8 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla BKE_modifier_copydata_generic(md, target, flag); + tnmd->runtime_eval_log = nullptr; + if (nmd->settings.properties != nullptr) { tnmd->settings.properties = IDP_CopyProperty_ex(nmd->settings.properties, flag); } @@ -1236,6 +1180,8 @@ static void freeData(ModifierData *md) IDP_FreeProperty_ex(nmd->settings.properties, false); nmd->settings.properties = nullptr; } + + clear_runtime_data(nmd); } static void requiredDataMask(Object *UNUSED(ob), diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 205bfa34465..18cc1ce6c86 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -558,11 +558,11 @@ class GeometryNodesEvaluator { for (auto &&item : params_.input_values.items()) { const DOutputSocket socket = item.key; GMutablePointer value = item.value; - this->log_socket_value(socket, value); const DNode node = socket.node(); if (!node_states_.contains_as(node)) { /* The socket is not connected to any output. */ + this->log_socket_value({socket}, value); value.destruct(); continue; } @@ -780,7 +780,6 @@ class GeometryNodesEvaluator { /* Checks if all the linked sockets have been provided already. */ if (multi_value.items.size() == multi_value.expected_size) { input_state.was_ready_for_execution = true; - this->log_socket_value(socket, input_state, multi_value.items); } else if (is_required) { /* The input is required but is not fully provided yet. Therefore the node cannot be @@ -792,7 +791,6 @@ class GeometryNodesEvaluator { SingleInputValue &single_value = *input_state.value.single; if (single_value.value != nullptr) { input_state.was_ready_for_execution = true; - this->log_socket_value(socket, GPointer{input_state.type, single_value.value}); } else if (is_required) { /* The input is required but has not been provided yet. Therefore the node cannot be @@ -1170,6 +1168,9 @@ class GeometryNodesEvaluator { { BLI_assert(value_to_forward.get() != nullptr); + Vector<DSocket> sockets_to_log_to; + sockets_to_log_to.append(from_socket); + Vector<DInputSocket> to_sockets; auto handle_target_socket_fn = [&, this](const DInputSocket to_socket) { if (this->should_forward_to_socket(to_socket)) { @@ -1177,9 +1178,7 @@ class GeometryNodesEvaluator { } }; auto handle_skipped_socket_fn = [&, this](const DSocket socket) { - /* Log socket value on intermediate sockets to support e.g. attribute search or spreadsheet - * breadcrumbs on group nodes. */ - this->log_socket_value(socket, value_to_forward); + sockets_to_log_to.append(socket); }; from_socket.foreach_target_socket(handle_target_socket_fn, handle_skipped_socket_fn); @@ -1192,11 +1191,18 @@ class GeometryNodesEvaluator { if (from_type == to_type) { /* All target sockets that do not need a conversion will be handled afterwards. */ to_sockets_same_type.append(to_socket); + /* Multi input socket values are logged once all values are available. */ + if (!to_socket->is_multi_input_socket()) { + sockets_to_log_to.append(to_socket); + } continue; } this->forward_to_socket_with_different_type( allocator, value_to_forward, from_socket, to_socket, to_type); } + + this->log_socket_value(sockets_to_log_to, value_to_forward); + this->forward_to_sockets_with_same_type( allocator, to_sockets_same_type, value_to_forward, from_socket); } @@ -1227,6 +1233,7 @@ class GeometryNodesEvaluator { /* Allocate a buffer for the converted value. */ void *buffer = allocator.allocate(to_type.size(), to_type.alignment()); + GMutablePointer value{to_type, buffer}; if (conversions_.is_convertible(from_type, to_type)) { /* Do the conversion if possible. */ @@ -1236,7 +1243,11 @@ class GeometryNodesEvaluator { /* Cannot convert, use default value instead. */ to_type.copy_construct(to_type.default_value(), buffer); } - this->add_value_to_input_socket(to_socket, from_socket, {to_type, buffer}); + /* Multi input socket values are logged once all values are available. */ + if (!to_socket->is_multi_input_socket()) { + this->log_socket_value({to_socket}, value); + } + this->add_value_to_input_socket(to_socket, from_socket, value); } void forward_to_sockets_with_same_type(LinearAllocator<> &allocator, @@ -1284,6 +1295,10 @@ class GeometryNodesEvaluator { /* Add a new value to the multi-input. */ MultiInputValue &multi_value = *input_state.value.multi; multi_value.items.append({origin, value.get()}); + + if (multi_value.expected_size == multi_value.items.size()) { + this->log_socket_value({socket}, input_state, multi_value.items); + } } else { /* Assign the value to the input. */ @@ -1314,10 +1329,14 @@ class GeometryNodesEvaluator { if (input_socket->is_multi_input_socket()) { MultiInputValue &multi_value = *input_state.value.multi; multi_value.items.append({origin_socket, value.get()}); + if (multi_value.expected_size == multi_value.items.size()) { + this->log_socket_value({input_socket}, input_state, multi_value.items); + } } else { SingleInputValue &single_value = *input_state.value.single; single_value.value = value.get(); + this->log_socket_value({input_socket}, value); } } @@ -1370,29 +1389,27 @@ class GeometryNodesEvaluator { return *node_states_.lookup_key_as(node).state; } - void log_socket_value(const DSocket socket, Span<GPointer> values) + void log_socket_value(DSocket socket, InputState &input_state, Span<MultiInputValueItem> values) { - if (params_.log_socket_value_fn) { - params_.log_socket_value_fn(socket, values); + if (params_.geo_logger == nullptr) { + return; } - } - void log_socket_value(const DSocket socket, - InputState &input_state, - Span<MultiInputValueItem> values) - { Vector<GPointer, 16> value_pointers; value_pointers.reserve(values.size()); const CPPType &type = *input_state.type; for (const MultiInputValueItem &item : values) { value_pointers.append({type, item.value}); } - this->log_socket_value(socket, value_pointers); + params_.geo_logger->local().log_multi_value_socket(socket, value_pointers); } - void log_socket_value(const DSocket socket, GPointer value) + void log_socket_value(Span<DSocket> sockets, GPointer value) { - this->log_socket_value(socket, Span<GPointer>(&value, 1)); + if (params_.geo_logger == nullptr) { + return; + } + params_.geo_logger->local().log_value_for_sockets(sockets, value); } /* In most cases when `NodeState` is accessed, the node has to be locked first to avoid race @@ -1431,6 +1448,7 @@ NodeParamsProvider::NodeParamsProvider(GeometryNodesEvaluator &evaluator, this->self_object = evaluator.params_.self_object; this->modifier = &evaluator.params_.modifier_->modifier; this->depsgraph = evaluator.params_.depsgraph; + this->logger = evaluator.params_.geo_logger; } bool NodeParamsProvider::can_get_input(StringRef identifier) const @@ -1530,8 +1548,6 @@ void NodeParamsProvider::set_output(StringRef identifier, GMutablePointer value) const DOutputSocket socket = this->dnode.output_by_identifier(identifier); BLI_assert(socket); - evaluator_.log_socket_value(socket, value); - OutputState &output_state = node_state_.outputs[socket->index()]; BLI_assert(!output_state.has_been_computed); evaluator_.forward_output(socket, value); diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh index 58eb6a4cd0b..f4ee6242dcb 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh @@ -19,20 +19,21 @@ #include "BLI_map.hh" #include "NOD_derived_node_tree.hh" +#include "NOD_geometry_nodes_eval_log.hh" #include "NOD_node_tree_multi_function.hh" #include "FN_generic_pointer.hh" #include "DNA_modifier_types.h" +namespace geo_log = blender::nodes::geometry_nodes_eval_log; + namespace blender::modifiers::geometry_nodes { using namespace nodes::derived_node_tree_types; using fn::GMutablePointer; using fn::GPointer; -using LogSocketValueFn = std::function<void(DSocket, Span<GPointer>)>; - struct GeometryNodesEvaluationParams { blender::LinearAllocator<> allocator; @@ -48,7 +49,7 @@ struct GeometryNodesEvaluationParams { const NodesModifierData *modifier_; Depsgraph *depsgraph; Object *self_object; - LogSocketValueFn log_socket_value_fn; + geo_log::GeoLogger *geo_logger; Vector<GMutablePointer> r_output_values; }; diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index 38cce5e6a50..ef70f3fe6f4 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -120,7 +120,6 @@ static void deformVerts(ModifierData *md, Mesh *mesh_src = mesh; ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; ParticleSystem *psys = NULL; - /* float cfra = BKE_scene_frame_get(md->scene); */ /* UNUSED */ if (ctx->object->particlesystem.first) { psys = psmd->psys; diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index a5bd41c23e4..e97190b1878 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -242,9 +242,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex MDeformVert *dvert; const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0; int defgrp_index; - const int shell_defgrp_index = BKE_object_defgroup_name_index(ctx->object, - smd->shell_defgrp_name); - const int rim_defgrp_index = BKE_object_defgroup_name_index(ctx->object, smd->rim_defgrp_name); + const int shell_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->shell_defgrp_name); + const int rim_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->rim_defgrp_name); /* array size is doubled in case of using a shell */ const uint stride = do_shell ? 2 : 1; @@ -1028,14 +1027,13 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex if (do_rim) { uint i; - /* bugger, need to re-calculate the normals for the new edge faces. + /* NOTE(campbell): Unfortunately re-calculate the normals for the new edge faces is necessary. * This could be done in many ways, but probably the quickest way * is to calculate the average normals for side faces only. * Then blend them with the normals of the edge verts. * - * at the moment its easiest to allocate an entire array for every vertex, - * even though we only need edge verts - campbell - */ + * At the moment its easiest to allocate an entire array for every vertex, + * even though we only need edge verts. */ #define SOLIDIFY_SIDE_NORMALS diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index 1a7daa10e0f..b872f04b60f 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -181,9 +181,8 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, MDeformVert *dvert; const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0; int defgrp_index; - const int shell_defgrp_index = BKE_object_defgroup_name_index(ctx->object, - smd->shell_defgrp_name); - const int rim_defgrp_index = BKE_object_defgroup_name_index(ctx->object, smd->rim_defgrp_name); + const int shell_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->shell_defgrp_name); + const int rim_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->rim_defgrp_name); MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index); diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 9aed4fbfc5f..5b97d0eb259 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -254,15 +254,22 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, void MOD_get_vgroup( Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index) { - *defgrp_index = BKE_object_defgroup_name_index(ob, name); - *dvert = NULL; - - if (*defgrp_index != -1) { - if (ob->type == OB_LATTICE) { + if (mesh) { + *defgrp_index = BKE_id_defgroup_name_index(&mesh->id, name); + if (*defgrp_index != -1) { + *dvert = mesh->dvert; + } + else { + *dvert = NULL; + } + } + else { + *defgrp_index = BKE_object_defgroup_name_index(ob, name); + if (*defgrp_index != -1 && ob->type == OB_LATTICE) { *dvert = BKE_lattice_deform_verts_get(ob); } - else if (mesh) { - *dvert = mesh->dvert; + else { + *dvert = NULL; } } } diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index c5e2ecb9660..696c4c855c7 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -230,7 +230,7 @@ void weightvg_do_mask(const ModifierEvalContext *ctx, MEM_freeN(tex_co); } - else if ((ref_didx = BKE_object_defgroup_name_index(ob, defgrp_name)) != -1) { + else if ((ref_didx = BKE_id_defgroup_name_index(&mesh->id, defgrp_name)) != -1) { MDeformVert *dvert = NULL; /* Check whether we want to set vgroup weights from a constant weight factor or a vertex diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index b5f72c88800..093fa118ee0 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -194,12 +194,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* Check if we can just return the original mesh. * Must have verts and therefore verts assigned to vgroups to do anything useful! */ - if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) { + if ((numVerts == 0) || BLI_listbase_is_empty(&mesh->vertex_group_names)) { return mesh; } /* Get vgroup idx from its name. */ - const int defgrp_index = BKE_object_defgroup_name_index(ctx->object, wmd->defgrp_name); + const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name); if (defgrp_index == -1) { return mesh; } diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index a71a2f3b480..7aae089fa18 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -245,19 +245,19 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* Check if we can just return the original mesh. * Must have verts and therefore verts assigned to vgroups to do anything useful! */ - if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) { + if ((numVerts == 0) || BLI_listbase_is_empty(&mesh->vertex_group_names)) { return mesh; } /* Get vgroup idx from its name. */ - const int defgrp_index = BKE_object_defgroup_name_index(ctx->object, wmd->defgrp_name_a); + const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name_a); if (defgrp_index == -1) { return mesh; } /* Get second vgroup idx from its name, if given. */ int defgrp_index_other = -1; if (wmd->defgrp_name_b[0] != '\0') { - defgrp_index_other = BKE_object_defgroup_name_index(ctx->object, wmd->defgrp_name_b); + defgrp_index_other = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name_b); if (defgrp_index_other == -1) { return mesh; } diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index b0d2f52f78c..6e78774269a 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -468,7 +468,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* Check if we can just return the original mesh. * Must have verts and therefore verts assigned to vgroups to do anything useful! */ - if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) { + if ((numVerts == 0) || BLI_listbase_is_empty(&mesh->vertex_group_names)) { return mesh; } @@ -479,11 +479,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } /* Get vgroup idx from its name. */ - defgrp_index = BKE_object_defgroup_name_index(ob, wmd->defgrp_name); + defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name); if (defgrp_index == -1) { return mesh; } - const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT); /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */ /* As this modifier never add vertices to vgroup, just return. */ diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c index 1590f342666..fe2d699aea8 100644 --- a/source/blender/modifiers/intern/MOD_weld.c +++ b/source/blender/modifiers/intern/MOD_weld.c @@ -1573,11 +1573,12 @@ struct WeldVertexCluster { uint merged_verts; }; -static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContext *ctx, Mesh *mesh) +static Mesh *weldModifier_doWeld(WeldModifierData *wmd, + const ModifierEvalContext *UNUSED(ctx), + Mesh *mesh) { Mesh *result = mesh; - Object *ob = ctx->object; BLI_bitmap *v_mask = NULL; int v_mask_act = 0; @@ -1590,7 +1591,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex totvert = mesh->totvert; /* Vertex Group. */ - const int defgrp_index = BKE_object_defgroup_name_index(ob, wmd->defgrp_name); + const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name); if (defgrp_index != -1) { MDeformVert *dvert, *dv; dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index 16bf1f7d763..e188a61e975 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -76,7 +76,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh * Mesh *result; BMesh *bm; - const int defgrp_index = BKE_object_defgroup_name_index(ob, wmd->defgrp_name); + const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name); bm = BKE_mesh_to_bmesh_ex(mesh, &(struct BMeshCreateParams){0}, diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index a7640d6cacd..09085ac8799 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -165,11 +165,12 @@ set(SRC geometry/nodes/node_geo_common.cc geometry/nodes/node_geo_convex_hull.cc geometry/nodes/node_geo_curve_endpoints.cc - geometry/nodes/node_geo_curve_length.cc + geometry/nodes/node_geo_curve_length.cc geometry/nodes/node_geo_curve_primitive_bezier_segment.cc geometry/nodes/node_geo_curve_primitive_circle.cc geometry/nodes/node_geo_curve_primitive_line.cc geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc + geometry/nodes/node_geo_curve_primitive_quadrilateral.cc geometry/nodes/node_geo_curve_primitive_spiral.cc geometry/nodes/node_geo_curve_primitive_star.cc geometry/nodes/node_geo_curve_sample.cc @@ -338,6 +339,7 @@ set(SRC texture/node_texture_util.c intern/derived_node_tree.cc + intern/geometry_nodes_eval_log.cc intern/math_functions.cc intern/node_common.c intern/node_exec.cc @@ -361,6 +363,7 @@ set(SRC NOD_function.h NOD_geometry.h NOD_geometry_exec.hh + NOD_geometry_nodes_eval_log.hh NOD_math_functions.hh NOD_node_tree_multi_function.hh NOD_node_tree_ref.hh @@ -421,6 +424,11 @@ if(WITH_TBB) ${TBB_INCLUDE_DIRS} ) add_definitions(-DWITH_TBB) + if(WIN32) + # TBB includes Windows.h which will define min/max macros + # that will collide with the stl versions. + add_definitions(-DNOMINMAX) + endif() endif() if(WITH_IMAGE_OPENEXR) diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 9346a3ae5a8..8a2b77118e5 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -57,6 +57,7 @@ void register_node_type_geo_curve_primitive_bezier_segment(void); void register_node_type_geo_curve_primitive_circle(void); void register_node_type_geo_curve_primitive_line(void); void register_node_type_geo_curve_primitive_quadratic_bezier(void); +void register_node_type_geo_curve_primitive_quadrilateral(void); void register_node_type_geo_curve_primitive_spiral(void); void register_node_type_geo_curve_primitive_star(void); void register_node_type_geo_curve_sample(void); diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 23474201daa..d6a23051c0b 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -21,11 +21,11 @@ #include "BKE_attribute_access.hh" #include "BKE_geometry_set.hh" #include "BKE_geometry_set_instances.hh" -#include "BKE_node_ui_storage.hh" #include "DNA_node_types.h" #include "NOD_derived_node_tree.hh" +#include "NOD_geometry_nodes_eval_log.hh" struct Depsgraph; struct ModifierData; @@ -52,10 +52,11 @@ using fn::GVMutableArray; using fn::GVMutableArray_GSpan; using fn::GVMutableArray_Typed; using fn::GVMutableArrayPtr; +using geometry_nodes_eval_log::NodeWarningType; /** - * This class exists to separate the memory management details of the geometry nodes evaluator from - * the node execution functions and related utilities. + * This class exists to separate the memory management details of the geometry nodes evaluator + * from the node execution functions and related utilities. */ class GeoNodeExecParamsProvider { public: @@ -63,6 +64,7 @@ class GeoNodeExecParamsProvider { const Object *self_object = nullptr; const ModifierData *modifier = nullptr; Depsgraph *depsgraph = nullptr; + geometry_nodes_eval_log::GeoLogger *logger = nullptr; /** * Returns true when the node is allowed to get/extract the input value. The identifier is diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh new file mode 100644 index 00000000000..b85862a0176 --- /dev/null +++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh @@ -0,0 +1,309 @@ +/* + * 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 + +/** + * Many geometry nodes related UI features need access to data produced during evaluation. Not only + * is the final output required but also the intermediate results. Those features include + * attribute search, node warnings, socket inspection and the viewer node. + * + * This file provides the framework for logging data during evaluation and accessing the data after + * evaluation. + * + * During logging every thread gets its own local logger to avoid too much locking (logging + * generally happens for every socket). After geometry nodes evaluation is done, the thread-local + * logging information is combined and post-processed to make it easier for the UI to lookup. + * necessary information. + */ + +#include "BLI_enumerable_thread_specific.hh" +#include "BLI_linear_allocator.hh" +#include "BLI_map.hh" + +#include "BKE_geometry_set.hh" + +#include "FN_generic_pointer.hh" + +#include "NOD_derived_node_tree.hh" + +struct SpaceNode; +struct SpaceSpreadsheet; + +namespace blender::nodes::geometry_nodes_eval_log { + +using fn::GMutablePointer; +using fn::GPointer; + +/** Contains information about a value that has been computed during geometry nodes evaluation. */ +class ValueLog { + public: + virtual ~ValueLog() = default; +}; + +/** Contains an owned copy of a value of a generic type. */ +class GenericValueLog : public ValueLog { + private: + GMutablePointer data_; + + public: + GenericValueLog(GMutablePointer data) : data_(data) + { + } + + ~GenericValueLog() + { + data_.destruct(); + } + + GPointer value() const + { + return data_; + } +}; + +struct GeometryAttributeInfo { + std::string name; + AttributeDomain domain; + CustomDataType data_type; +}; + +/** Contains information about a geometry set. In most cases this does not store the entire + * geometry set as this would require too much memory. */ +class GeometryValueLog : public ValueLog { + private: + Vector<GeometryAttributeInfo> attributes_; + Vector<GeometryComponentType> component_types_; + std::unique_ptr<GeometrySet> full_geometry_; + + public: + struct MeshInfo { + int tot_verts, tot_edges, tot_faces; + }; + struct CurveInfo { + int tot_splines; + }; + struct PointCloudInfo { + int tot_points; + }; + struct InstancesInfo { + int tot_instances; + }; + + std::optional<MeshInfo> mesh_info; + std::optional<CurveInfo> curve_info; + std::optional<PointCloudInfo> pointcloud_info; + std::optional<InstancesInfo> instances_info; + + GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry); + + Span<GeometryAttributeInfo> attributes() const + { + return attributes_; + } + + Span<GeometryComponentType> component_types() const + { + return component_types_; + } + + const GeometrySet *full_geometry() const + { + return full_geometry_.get(); + } +}; + +enum class NodeWarningType { + Error, + Warning, + Info, +}; + +struct NodeWarning { + NodeWarningType type; + std::string message; +}; + +struct NodeWithWarning { + DNode node; + NodeWarning warning; +}; + +/** The same value can be referenced by multiple sockets when they are linked. */ +struct ValueOfSockets { + Span<DSocket> sockets; + destruct_ptr<ValueLog> value; +}; + +class GeoLogger; +class ModifierLog; + +/** Every thread has its own local logger to avoid having to communicate between threads during + * evaluation. After evaluation the individual logs are combined. */ +class LocalGeoLogger { + private: + /* Back pointer to the owner of this local logger. */ + GeoLogger *main_logger_; + /* Allocator for the many small allocations during logging. This is in a `unique_ptr` so that + * ownership can be transferred later on. */ + std::unique_ptr<LinearAllocator<>> allocator_; + Vector<ValueOfSockets> values_; + Vector<NodeWithWarning> node_warnings_; + + friend ModifierLog; + + public: + LocalGeoLogger(GeoLogger &main_logger) : main_logger_(&main_logger) + { + this->allocator_ = std::make_unique<LinearAllocator<>>(); + } + + void log_value_for_sockets(Span<DSocket> sockets, GPointer value); + void log_multi_value_socket(DSocket socket, Span<GPointer> values); + void log_node_warning(DNode node, NodeWarningType type, std::string message); +}; + +/** The root logger class. */ +class GeoLogger { + private: + /** The entire geometry of sockets in this set should be cached, because e.g. the spreadsheet + * displays the data. We don't log the entire geometry at all places, because that would require + * way too much memory. */ + Set<DSocket> log_full_geometry_sockets_; + threading::EnumerableThreadSpecific<LocalGeoLogger> threadlocals_; + + friend LocalGeoLogger; + + public: + GeoLogger(Set<DSocket> log_full_geometry_sockets) + : log_full_geometry_sockets_(std::move(log_full_geometry_sockets)), + threadlocals_([this]() { return LocalGeoLogger(*this); }) + { + } + + LocalGeoLogger &local() + { + return threadlocals_.local(); + } + + auto begin() + { + return threadlocals_.begin(); + } + + auto end() + { + return threadlocals_.end(); + } +}; + +/** Contains information that has been logged for one specific socket. */ +class SocketLog { + private: + ValueLog *value_ = nullptr; + + friend ModifierLog; + + public: + const ValueLog *value() const + { + return value_; + } +}; + +/** Contains information that has been logged for one specific node. */ +class NodeLog { + private: + Vector<SocketLog> input_logs_; + Vector<SocketLog> output_logs_; + Vector<NodeWarning, 0> warnings_; + + friend ModifierLog; + + public: + const SocketLog *lookup_socket_log(eNodeSocketInOut in_out, int index) const; + const SocketLog *lookup_socket_log(const bNode &node, const bNodeSocket &socket) const; + + Span<SocketLog> input_logs() const + { + return input_logs_; + } + + Span<SocketLog> output_logs() const + { + return output_logs_; + } + + Span<NodeWarning> warnings() const + { + return warnings_; + } + + Vector<const GeometryAttributeInfo *> lookup_available_attributes() const; +}; + +/** Contains information that has been logged for one specific tree. */ +class TreeLog { + private: + Map<std::string, destruct_ptr<NodeLog>> node_logs_; + Map<std::string, destruct_ptr<TreeLog>> child_logs_; + + friend ModifierLog; + + public: + const NodeLog *lookup_node_log(StringRef node_name) const; + const NodeLog *lookup_node_log(const bNode &node) const; + const TreeLog *lookup_child_log(StringRef node_name) const; +}; + +/** Contains information about an entire geometry nodes evaluation. */ +class ModifierLog { + private: + LinearAllocator<> allocator_; + /* Allocators of the individual loggers. */ + Vector<std::unique_ptr<LinearAllocator<>>> logger_allocators_; + destruct_ptr<TreeLog> root_tree_logs_; + Vector<destruct_ptr<ValueLog>> logged_values_; + + public: + ModifierLog(GeoLogger &logger); + + const TreeLog &root_tree() const + { + return *root_tree_logs_; + } + + /* Utilities to find logged information for a specific context. */ + static const ModifierLog *find_root_by_node_editor_context(const SpaceNode &snode); + static const TreeLog *find_tree_by_node_editor_context(const SpaceNode &snode); + static const NodeLog *find_node_by_node_editor_context(const SpaceNode &snode, + const bNode &node); + static const SocketLog *find_socket_by_node_editor_context(const SpaceNode &snode, + const bNode &node, + const bNodeSocket &socket); + static const NodeLog *find_node_by_spreadsheet_editor_context( + const SpaceSpreadsheet &sspreadsheet); + + private: + using LogByTreeContext = Map<const DTreeContext *, TreeLog *>; + + TreeLog &lookup_or_add_tree_log(LogByTreeContext &log_by_tree_context, + const DTreeContext &tree_context); + NodeLog &lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node); + SocketLog &lookup_or_add_socket_log(LogByTreeContext &log_by_tree_context, DSocket socket); +}; + +} // namespace blender::nodes::geometry_nodes_eval_log diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 854a27b01d8..c24763baa1e 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -210,7 +210,7 @@ DefNode(CompositorNode, CMP_NODE_MASK_ELLIPSE, def_cmp_ellipsemask, "ELLIPS DefNode(CompositorNode, CMP_NODE_BOKEHIMAGE, def_cmp_bokehimage, "BOKEHIMAGE", BokehImage, "Bokeh Image", "" ) DefNode(CompositorNode, CMP_NODE_BOKEHBLUR, def_cmp_bokehblur, "BOKEHBLUR", BokehBlur, "Bokeh Blur", "" ) DefNode(CompositorNode, CMP_NODE_SWITCH, def_cmp_switch, "SWITCH", Switch, "Switch", "" ) -DefNode(CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "View Switch", "" ) +DefNode(CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "Switch View", "" ) DefNode(CompositorNode, CMP_NODE_COLORCORRECTION,def_cmp_colorcorrection,"COLORCORRECTION",ColorCorrection, "Color Correction", "" ) DefNode(CompositorNode, CMP_NODE_MASK, def_cmp_mask, "MASK", Mask, "Mask", "" ) DefNode(CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYINGSCREEN", KeyingScreen, "Keying Screen", "" ) @@ -295,6 +295,7 @@ DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Cu DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "") +DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_primitive_quadrilateral, "CURVE_PRIMITIVE_QUADRILATERAL", CurvePrimitiveQuadrilateral, "Quadrilateral", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, 0, "CURVE_PRIMITIVE_QUADRATIC_BEZIER", CurveQuadraticBezier, "Quadratic Bezier", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "") diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc index 1b9e9af3e2d..ae947b7aeed 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc @@ -83,9 +83,10 @@ static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3) } static std::unique_ptr<CurveEval> create_point_circle_curve( - const float3 p1, const float3 p2, const float3 p3, const int resolution, float center_out[3]) + const float3 p1, const float3 p2, const float3 p3, const int resolution, float3 &r_center) { if (colinear_f3_f3_f3(p1, p2, p3)) { + r_center = float3(0); return nullptr; } @@ -118,6 +119,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve( /* If the 3 planes do not intersect at one point, just return empty geometry. */ if (!isect_plane_plane_plane_v3(plane_1, plane_2, plane_3, center)) { + r_center = float3(0); return nullptr; } @@ -141,7 +143,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve( curve->add_spline(std::move(spline)); curve->attributes.reallocate(curve->splines().size()); - copy_v3_v3(center_out, center); + r_center = center; return curve; } @@ -179,18 +181,13 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params) std::unique_ptr<CurveEval> curve; if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS) { - float center_point[3]; + float3 center_point; curve = create_point_circle_curve(params.extract_input<float3>("Point 1"), params.extract_input<float3>("Point 2"), params.extract_input<float3>("Point 3"), std::max(params.extract_input<int>("Resolution"), 3), center_point); - if (curve) { - params.set_output("Center", float3(center_point)); - } - else { - params.set_output("Center", float3(0, 0, 0)); - } + params.set_output("Center", center_point); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS) { curve = create_radius_circle_curve(std::max(params.extract_input<int>("Resolution"), 3), diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc index 04a7fc7e5df..419a7af1ba0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc @@ -95,7 +95,7 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start spline->resize(2); MutableSpan<float3> positions = spline->positions(); positions[0] = start; - positions[1] = direction.normalized() * length; + positions[1] = direction.normalized() * length + start; spline->radii().fill(1.0f); spline->tilts().fill(0.0f); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc new file mode 100644 index 00000000000..5f3f159c305 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc @@ -0,0 +1,241 @@ +/* + * 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 "BKE_spline.hh" +#include "UI_interface.h" +#include "UI_resources.h" +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_curve_primitive_quadrilateral_in[] = { + {SOCK_FLOAT, N_("Width"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Height"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Bottom Width"), 4.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Top Width"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Offset"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Bottom Height"), 3.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Top Height"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_VECTOR, N_("Point 1"), -1.0f, 1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_VECTOR, N_("Point 2"), 1.0f, 1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_VECTOR, N_("Point 3"), 1.0f, -1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_VECTOR, N_("Point 4"), -1.0f, -1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_curve_primitive_quadrilateral_out[] = { + {SOCK_GEOMETRY, N_("Curve")}, + {-1, ""}, +}; + +static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); +} + +static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN( + sizeof(NodeGeometryCurvePrimitiveQuad), __func__); + data->mode = GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE; + node->storage = data; +} + +namespace blender::nodes { + +static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage; + GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>( + node_storage.mode); + + bNodeSocket *width = ((bNodeSocket *)node->inputs.first); + bNodeSocket *height = width->next; + bNodeSocket *bottom = height->next; + bNodeSocket *top = bottom->next; + bNodeSocket *offset = top->next; + bNodeSocket *bottom_height = offset->next; + bNodeSocket *top_height = bottom_height->next; + bNodeSocket *p1 = top_height->next; + bNodeSocket *p2 = p1->next; + bNodeSocket *p3 = p2->next; + bNodeSocket *p4 = p3->next; + + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { + nodeSetSocketAvailability(sock, false); + } + + if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) { + nodeSetSocketAvailability(width, true); + nodeSetSocketAvailability(height, true); + } + else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) { + nodeSetSocketAvailability(width, true); + nodeSetSocketAvailability(height, true); + nodeSetSocketAvailability(offset, true); + } + else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) { + nodeSetSocketAvailability(bottom, true); + nodeSetSocketAvailability(top, true); + nodeSetSocketAvailability(offset, true); + nodeSetSocketAvailability(height, true); + } + else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) { + nodeSetSocketAvailability(width, true); + nodeSetSocketAvailability(bottom_height, true); + nodeSetSocketAvailability(top_height, true); + } + else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) { + nodeSetSocketAvailability(p1, true); + nodeSetSocketAvailability(p2, true); + nodeSetSocketAvailability(p3, true); + nodeSetSocketAvailability(p4, true); + } +} + +static void create_rectangle_curve(MutableSpan<float3> positions, + const float height, + const float width) +{ + positions[0] = float3(width / 2.0f, -height / 2.0f, 0.0f); + positions[1] = float3(-width / 2.0f, -height / 2.0f, 0.0f); + positions[2] = float3(-width / 2.0f, height / 2.0f, 0.0f); + positions[3] = float3(width / 2.0f, height / 2.0f, 0.0f); +} + +static void create_points_curve(MutableSpan<float3> positions, + const float3 &p1, + const float3 &p2, + const float3 &p3, + const float3 &p4) +{ + positions[0] = p1; + positions[1] = p2; + positions[2] = p3; + positions[3] = p4; +} + +static void create_parallelogram_curve(MutableSpan<float3> positions, + const float height, + const float width, + const float offset) +{ + positions[0] = float3(width / 2.0f - offset / 2.0f, -height / 2.0f, 0.0f); + positions[1] = float3(-width / 2.0f - offset / 2.0f, -height / 2.0f, 0.0f); + positions[2] = float3(-width / 2.0f + offset / 2.0f, height / 2.0f, 0.0f); + positions[3] = float3(width / 2.0f + offset / 2.0f, height / 2.0f, 0.0f); +} +static void create_trapezoid_curve(MutableSpan<float3> positions, + const float bottom, + const float top, + const float offset, + const float height) +{ + positions[0] = float3(bottom / 2.0f, -height / 2.0f, 0.0f); + positions[1] = float3(-bottom / 2.0f, -height / 2.0f, 0.0f); + positions[2] = float3(-top / 2.0f + offset, height / 2.0f, 0.0f); + positions[3] = float3(top / 2.0f + offset, height / 2.0f, 0.0f); +} + +static void create_kite_curve(MutableSpan<float3> positions, + const float width, + const float bottom_height, + const float top_height) +{ + positions[0] = float3(-width / 2.0f, 0, 0); + positions[1] = float3(0, top_height, 0); + positions[2] = float3(width / 2, 0, 0); + positions[3] = float3(0, -bottom_height, 0); +} + +static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params) +{ + const NodeGeometryCurvePrimitiveQuad &node_storage = + *(NodeGeometryCurvePrimitiveQuad *)(params.node()).storage; + const GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>( + node_storage.mode); + + std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>(); + std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>(); + spline->resize(4); + spline->radii().fill(1.0f); + spline->tilts().fill(0.0f); + spline->set_cyclic(true); + MutableSpan<float3> positions = spline->positions(); + + switch (mode) { + case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE: + create_rectangle_curve(positions, + std::max(params.extract_input<float>("Height"), 0.0f), + std::max(params.extract_input<float>("Width"), 0.0f)); + break; + + case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM: + create_parallelogram_curve(positions, + std::max(params.extract_input<float>("Height"), 0.0f), + std::max(params.extract_input<float>("Width"), 0.0f), + params.extract_input<float>("Offset")); + break; + case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID: + create_trapezoid_curve(positions, + std::max(params.extract_input<float>("Bottom Width"), 0.0f), + std::max(params.extract_input<float>("Top Width"), 0.0f), + params.extract_input<float>("Offset"), + std::max(params.extract_input<float>("Height"), 0.0f)); + break; + case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE: + create_kite_curve(positions, + std::max(params.extract_input<float>("Width"), 0.0f), + std::max(params.extract_input<float>("Bottom Height"), 0.0f), + params.extract_input<float>("Top Height")); + break; + case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS: + create_points_curve(positions, + params.extract_input<float3>("Point 1"), + params.extract_input<float3>("Point 2"), + params.extract_input<float3>("Point 3"), + params.extract_input<float3>("Point 4")); + break; + default: + params.set_output("Curve", GeometrySet()); + return; + } + + curve->add_spline(std::move(spline)); + curve->attributes.reallocate(curve->splines().size()); + params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); +} + +} // namespace blender::nodes + +void register_node_type_geo_curve_primitive_quadrilateral() +{ + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, + geo_node_curve_primitive_quadrilateral_in, + geo_node_curve_primitive_quadrilateral_out); + ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadrilateral_exec; + ntype.draw_buttons = geo_node_curve_primitive_quadrilateral_layout; + node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_update); + node_type_init(&ntype, geo_node_curve_primitive_quadrilateral_init); + node_type_storage(&ntype, + "NodeGeometryCurvePrimitiveQuad", + node_free_standard_storage, + node_copy_standard_storage); + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc index 3de2604cd0a..7908c26e2dc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc @@ -116,38 +116,6 @@ static void subdivide_attribute(Span<T> src, } /** - * De Casteljau Bezier subdivision. - * - * <pre> - * handle_prev handle_next - * O----------------O - * / \ - * / x---O---x \ - * / new_* \ - * / \ - * O O - * point_prev point_next - * </pre> - */ -static void calculate_new_bezier_point(const float3 &point_prev, - float3 &handle_prev, - float3 &new_left_handle, - float3 &new_position, - float3 &new_right_handle, - float3 &handle_next, - const float3 &point_next, - const float parameter) -{ - const float3 center_point = float3::interpolate(handle_prev, handle_next, parameter); - - handle_prev = float3::interpolate(point_prev, handle_prev, parameter); - handle_next = float3::interpolate(handle_next, point_next, parameter); - new_left_handle = float3::interpolate(handle_prev, center_point, parameter); - new_right_handle = float3::interpolate(center_point, handle_next, parameter); - new_position = float3::interpolate(new_left_handle, new_right_handle, parameter); -} - -/** * In order to generate a Bezier spline with the same shape as the input spline, apply the * De Casteljau algorithm iteratively for the provided number of cuts, constantly updating the * previous result point's right handle and the left handle at the end of the segment. @@ -171,6 +139,10 @@ static void subdivide_bezier_segment(const BezierSpline &src, { const bool is_last_cyclic_segment = index == (src.size() - 1); const int next_index = is_last_cyclic_segment ? 0 : index + 1; + + /* The first point in the segment is always copied. */ + dst_positions[offset] = src_positions[index]; + if (src.segment_is_vector(index)) { if (is_last_cyclic_segment) { dst_type_left.first() = BezierSpline::HandleType::Vector; @@ -178,7 +150,6 @@ static void subdivide_bezier_segment(const BezierSpline &src, dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Vector); dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Vector); - dst_positions[offset] = src_positions[index]; const float factor_delta = 1.0f / result_size; for (const int cut : IndexRange(result_size)) { const float factor = cut * factor_delta; @@ -194,21 +165,38 @@ static void subdivide_bezier_segment(const BezierSpline &src, dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Free); const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_size; - dst_positions[offset] = src_positions[index]; - dst_handles_right[offset] = src_handles_right[index]; - dst_handles_left[i_segment_last] = src_handles_left[next_index]; + + /* Create a Bezier segment to update iteratively for every subdivision + * and references to the meaningful values for ease of use. */ + BezierSpline temp; + temp.resize(2); + float3 &segment_start = temp.positions().first(); + float3 &segment_end = temp.positions().last(); + float3 &handle_prev = temp.handle_positions_right().first(); + float3 &handle_next = temp.handle_positions_left().last(); + segment_start = src_positions[index]; + segment_end = src_positions[next_index]; + handle_prev = src_handles_right[index]; + handle_next = src_handles_left[next_index]; for (const int cut : IndexRange(result_size - 1)) { const float parameter = 1.0f / (result_size - cut); - calculate_new_bezier_point(dst_positions[offset + cut], - dst_handles_right[offset + cut], - dst_handles_left[offset + cut + 1], - dst_positions[offset + cut + 1], - dst_handles_right[offset + cut + 1], - dst_handles_left[i_segment_last], - src_positions[next_index], - parameter); + const BezierSpline::InsertResult insert = temp.calculate_segment_insertion(0, 1, parameter); + + /* Copy relevant temporary data to the result. */ + dst_handles_right[offset + cut] = insert.handle_prev; + dst_handles_left[offset + cut + 1] = insert.left_handle; + dst_positions[offset + cut + 1] = insert.position; + + /* Update the segment to prepare it for the next subdivision. */ + segment_start = insert.position; + handle_prev = insert.right_handle; + handle_next = insert.handle_next; } + + /* Copy the handles for the last segment from the temporary spline. */ + dst_handles_right[offset + result_size - 1] = handle_prev; + dst_handles_left[i_segment_last] = handle_next; } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index b1da2dcd3c4..8c697275f88 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -627,7 +627,7 @@ static void delete_mesh_selection(MeshComponent &component, mesh_out = nullptr; break; } - component.replace_mesh_but_keep_vertex_group_names(mesh_out); + component.replace(mesh_out); } static void geo_node_delete_geometry_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc index 7492582c8cf..245d7800621 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc @@ -91,7 +91,7 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params) BKE_mesh_calc_normals(mesh_out); MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); - mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_out); + mesh_component.replace(mesh_out); BKE_subdiv_free(subdiv); diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 20ffcdb516d..f0f032ed8f4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -96,7 +96,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) BKE_mesh_calc_normals(mesh_out); MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); - mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_out); + mesh_component.replace(mesh_out); // BKE_subdiv_stats_print(&subdiv->stats); BKE_subdiv_free(subdiv); diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc new file mode 100644 index 00000000000..3024cc51cad --- /dev/null +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -0,0 +1,361 @@ +/* + * 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 "NOD_geometry_nodes_eval_log.hh" + +#include "BKE_geometry_set_instances.hh" + +#include "DNA_modifier_types.h" +#include "DNA_space_types.h" + +namespace blender::nodes::geometry_nodes_eval_log { + +using fn::CPPType; + +ModifierLog::ModifierLog(GeoLogger &logger) +{ + root_tree_logs_ = allocator_.construct<TreeLog>(); + + LogByTreeContext log_by_tree_context; + + /* Combine all the local loggers that have been used by separate threads. */ + for (LocalGeoLogger &local_logger : logger) { + /* Take ownership of the allocator. */ + logger_allocators_.append(std::move(local_logger.allocator_)); + + for (ValueOfSockets &value_of_sockets : local_logger.values_) { + ValueLog *value_log = value_of_sockets.value.get(); + + /* Take centralized ownership of the logged value. It might be referenced by multiple + * sockets. */ + logged_values_.append(std::move(value_of_sockets.value)); + + for (const DSocket &socket : value_of_sockets.sockets) { + SocketLog &socket_log = this->lookup_or_add_socket_log(log_by_tree_context, socket); + socket_log.value_ = value_log; + } + } + + for (NodeWithWarning &node_with_warning : local_logger.node_warnings_) { + NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, + node_with_warning.node); + node_log.warnings_.append(node_with_warning.warning); + } + } +} + +TreeLog &ModifierLog::lookup_or_add_tree_log(LogByTreeContext &log_by_tree_context, + const DTreeContext &tree_context) +{ + TreeLog *tree_log = log_by_tree_context.lookup_default(&tree_context, nullptr); + if (tree_log != nullptr) { + return *tree_log; + } + + const DTreeContext *parent_context = tree_context.parent_context(); + if (parent_context == nullptr) { + return *root_tree_logs_.get(); + } + TreeLog &parent_log = this->lookup_or_add_tree_log(log_by_tree_context, *parent_context); + destruct_ptr<TreeLog> owned_tree_log = allocator_.construct<TreeLog>(); + tree_log = owned_tree_log.get(); + log_by_tree_context.add_new(&tree_context, tree_log); + parent_log.child_logs_.add_new(tree_context.parent_node()->name(), std::move(owned_tree_log)); + return *tree_log; +} + +NodeLog &ModifierLog::lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node) +{ + TreeLog &tree_log = this->lookup_or_add_tree_log(log_by_tree_context, *node.context()); + NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name(), [&]() { + destruct_ptr<NodeLog> node_log = allocator_.construct<NodeLog>(); + node_log->input_logs_.resize(node->inputs().size()); + node_log->output_logs_.resize(node->outputs().size()); + return node_log; + }); + return node_log; +} + +SocketLog &ModifierLog::lookup_or_add_socket_log(LogByTreeContext &log_by_tree_context, + DSocket socket) +{ + NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, socket.node()); + MutableSpan<SocketLog> socket_logs = socket->is_input() ? node_log.input_logs_ : + node_log.output_logs_; + SocketLog &socket_log = socket_logs[socket->index()]; + return socket_log; +} + +const NodeLog *TreeLog::lookup_node_log(StringRef node_name) const +{ + const destruct_ptr<NodeLog> *node_log = node_logs_.lookup_ptr_as(node_name); + if (node_log == nullptr) { + return nullptr; + } + return node_log->get(); +} + +const NodeLog *TreeLog::lookup_node_log(const bNode &node) const +{ + return this->lookup_node_log(node.name); +} + +const TreeLog *TreeLog::lookup_child_log(StringRef node_name) const +{ + const destruct_ptr<TreeLog> *tree_log = child_logs_.lookup_ptr_as(node_name); + if (tree_log == nullptr) { + return nullptr; + } + return tree_log->get(); +} + +const SocketLog *NodeLog::lookup_socket_log(eNodeSocketInOut in_out, int index) const +{ + BLI_assert(index >= 0); + Span<SocketLog> socket_logs = (in_out == SOCK_IN) ? input_logs_ : output_logs_; + if (index >= socket_logs.size()) { + return nullptr; + } + return &socket_logs[index]; +} + +const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket &socket) const +{ + ListBase sockets = socket.in_out == SOCK_IN ? node.inputs : node.outputs; + int index = BLI_findindex(&sockets, &socket); + return this->lookup_socket_log((eNodeSocketInOut)socket.in_out, index); +} + +GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry) +{ + bke::geometry_set_instances_attribute_foreach( + geometry_set, + [&](StringRefNull attribute_name, const AttributeMetaData &meta_data) { + this->attributes_.append({attribute_name, meta_data.domain, meta_data.data_type}); + return true; + }, + 8); + for (const GeometryComponent *component : geometry_set.get_components_for_read()) { + component_types_.append(component->type()); + switch (component->type()) { + case GEO_COMPONENT_TYPE_MESH: { + const MeshComponent &mesh_component = *(const MeshComponent *)component; + MeshInfo &info = this->mesh_info.emplace(); + info.tot_verts = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT); + info.tot_edges = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE); + info.tot_faces = mesh_component.attribute_domain_size(ATTR_DOMAIN_FACE); + break; + } + case GEO_COMPONENT_TYPE_CURVE: { + const CurveComponent &curve_component = *(const CurveComponent *)component; + CurveInfo &info = this->curve_info.emplace(); + info.tot_splines = curve_component.attribute_domain_size(ATTR_DOMAIN_CURVE); + break; + } + case GEO_COMPONENT_TYPE_POINT_CLOUD: { + const PointCloudComponent &pointcloud_component = *(const PointCloudComponent *)component; + PointCloudInfo &info = this->pointcloud_info.emplace(); + info.tot_points = pointcloud_component.attribute_domain_size(ATTR_DOMAIN_POINT); + break; + } + case GEO_COMPONENT_TYPE_INSTANCES: { + const InstancesComponent &instances_component = *(const InstancesComponent *)component; + InstancesInfo &info = this->instances_info.emplace(); + info.tot_instances = instances_component.instances_amount(); + break; + } + case GEO_COMPONENT_TYPE_VOLUME: { + break; + } + } + } + if (log_full_geometry) { + full_geometry_ = std::make_unique<GeometrySet>(geometry_set); + full_geometry_->ensure_owns_direct_data(); + } +} + +Vector<const GeometryAttributeInfo *> NodeLog::lookup_available_attributes() const +{ + Vector<const GeometryAttributeInfo *> attributes; + Set<StringRef> names; + for (const SocketLog &socket_log : input_logs_) { + const ValueLog *value_log = socket_log.value(); + if (const GeometryValueLog *geo_value_log = dynamic_cast<const GeometryValueLog *>( + value_log)) { + for (const GeometryAttributeInfo &attribute : geo_value_log->attributes()) { + if (names.add(attribute.name)) { + attributes.append(&attribute); + } + } + } + } + return attributes; +} + +const ModifierLog *ModifierLog::find_root_by_node_editor_context(const SpaceNode &snode) +{ + if (snode.id == nullptr) { + return nullptr; + } + if (GS(snode.id->name) != ID_OB) { + return nullptr; + } + Object *object = (Object *)snode.id; + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + if (md->type == eModifierType_Nodes) { + NodesModifierData *nmd = (NodesModifierData *)md; + if (nmd->node_group == snode.nodetree) { + return (ModifierLog *)nmd->runtime_eval_log; + } + } + } + return nullptr; +} + +const TreeLog *ModifierLog::find_tree_by_node_editor_context(const SpaceNode &snode) +{ + const ModifierLog *eval_log = ModifierLog::find_root_by_node_editor_context(snode); + if (eval_log == nullptr) { + return nullptr; + } + Vector<bNodeTreePath *> tree_path_vec = snode.treepath; + if (tree_path_vec.is_empty()) { + return nullptr; + } + TreeLog *current = eval_log->root_tree_logs_.get(); + for (bNodeTreePath *path : tree_path_vec.as_span().drop_front(1)) { + destruct_ptr<TreeLog> *tree_log = current->child_logs_.lookup_ptr_as(path->node_name); + if (tree_log == nullptr) { + return nullptr; + } + current = tree_log->get(); + } + return current; +} + +const NodeLog *ModifierLog::find_node_by_node_editor_context(const SpaceNode &snode, + const bNode &node) +{ + const TreeLog *tree_log = ModifierLog::find_tree_by_node_editor_context(snode); + if (tree_log == nullptr) { + return nullptr; + } + return tree_log->lookup_node_log(node); +} + +const SocketLog *ModifierLog::find_socket_by_node_editor_context(const SpaceNode &snode, + const bNode &node, + const bNodeSocket &socket) +{ + const NodeLog *node_log = ModifierLog::find_node_by_node_editor_context(snode, node); + if (node_log == nullptr) { + return nullptr; + } + return node_log->lookup_socket_log(node, socket); +} + +const NodeLog *ModifierLog::find_node_by_spreadsheet_editor_context( + const SpaceSpreadsheet &sspreadsheet) +{ + Vector<SpreadsheetContext *> context_path = sspreadsheet.context_path; + if (context_path.size() <= 2) { + return nullptr; + } + if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) { + return nullptr; + } + if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) { + return nullptr; + } + for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) { + if (context->type != SPREADSHEET_CONTEXT_NODE) { + return nullptr; + } + } + Span<SpreadsheetContextNode *> node_contexts = + context_path.as_span().drop_front(2).cast<SpreadsheetContextNode *>(); + + Object *object = ((SpreadsheetContextObject *)context_path[0])->object; + StringRefNull modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name; + if (object == nullptr) { + return nullptr; + } + + const ModifierLog *eval_log = nullptr; + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + if (md->type == eModifierType_Nodes) { + if (md->name == modifier_name) { + NodesModifierData *nmd = (NodesModifierData *)md; + eval_log = (const ModifierLog *)nmd->runtime_eval_log; + break; + } + } + } + if (eval_log == nullptr) { + return nullptr; + } + + const TreeLog *tree_log = &eval_log->root_tree(); + for (SpreadsheetContextNode *context : node_contexts.drop_back(1)) { + tree_log = tree_log->lookup_child_log(context->node_name); + if (tree_log == nullptr) { + return nullptr; + } + } + const NodeLog *node_log = tree_log->lookup_node_log(node_contexts.last()->node_name); + return node_log; +} + +void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value) +{ + const CPPType &type = *value.type(); + Span<DSocket> copied_sockets = allocator_->construct_array_copy(sockets); + if (type.is<GeometrySet>()) { + bool log_full_geometry = false; + for (const DSocket &socket : sockets) { + if (main_logger_->log_full_geometry_sockets_.contains(socket)) { + log_full_geometry = true; + break; + } + } + + const GeometrySet &geometry_set = *value.get<GeometrySet>(); + destruct_ptr<GeometryValueLog> value_log = allocator_->construct<GeometryValueLog>( + geometry_set, log_full_geometry); + values_.append({copied_sockets, std::move(value_log)}); + } + else { + void *buffer = allocator_->allocate(type.size(), type.alignment()); + type.copy_construct(value.get(), buffer); + destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>( + GMutablePointer{type, buffer}); + values_.append({copied_sockets, std::move(value_log)}); + } +} + +void LocalGeoLogger::log_multi_value_socket(DSocket socket, Span<GPointer> values) +{ + /* Doesn't have to be logged currently. */ + UNUSED_VARS(socket, values); +} + +void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::string message) +{ + node_warnings_.append({node, {type, std::move(message)}}); +} + +} // namespace blender::nodes::geometry_nodes_eval_log diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index 17a13f2d1b0..bfd1ad02d36 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -16,8 +16,6 @@ #include "DNA_modifier_types.h" -#include "BKE_node_ui_storage.hh" - #include "DEG_depsgraph_query.h" #include "NOD_geometry_exec.hh" @@ -26,21 +24,17 @@ #include "node_geometry_util.hh" +using blender::nodes::geometry_nodes_eval_log::LocalGeoLogger; + namespace blender::nodes { void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const { - bNodeTree *btree_cow = provider_->dnode->btree(); - BLI_assert(btree_cow != nullptr); - if (btree_cow == nullptr) { + if (provider_->logger == nullptr) { return; } - bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow); - - const NodeTreeEvaluationContext context(*provider_->self_object, *provider_->modifier); - - BKE_nodetree_error_message_add( - *btree_original, context, *provider_->dnode->bnode(), type, std::move(message)); + LocalGeoLogger &local_logger = provider_->logger->local(); + local_logger.log_node_warning(provider_->dnode, type, std::move(message)); } const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index bed4d60382d..9ce9d6fc273 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -461,7 +461,7 @@ bool NodeTreeRef::has_undefined_nodes_or_sockets() const return true; } } - return true; + return false; } std::string NodeTreeRef::to_dot() const diff --git a/source/blender/python/gpu/gpu_py_uniformbuffer.c b/source/blender/python/gpu/gpu_py_uniformbuffer.c index edcec486398..cfef20e2e4d 100644 --- a/source/blender/python/gpu/gpu_py_uniformbuffer.c +++ b/source/blender/python/gpu/gpu_py_uniformbuffer.c @@ -104,7 +104,7 @@ static PyObject *pygpu_uniformbuffer__tp_new(PyTypeObject *UNUSED(self), } PyDoc_STRVAR(pygpu_uniformbuffer_update_doc, - ".. method::update(data)\n" + ".. method:: update(data)\n" "\n" " Update the data of the uniform buffer object.\n"); static PyObject *pygpu_uniformbuffer_update(BPyGPUUniformBuf *self, PyObject *obj) diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index e6479df2fa8..a8ab54ac3bb 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -4253,6 +4253,56 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA *self) return ret; } +PyDoc_STRVAR(pyrna_struct_id_properties_ensure_doc, + ".. method:: id_properties_ensure()\n" + " :return: the parent group for an RNA struct's custom IDProperties.\n" + " :rtype: :class:`bpy.types.IDPropertyGroup`\n"); +static PyObject *pyrna_struct_id_properties_ensure(BPy_StructRNA *self) +{ + PYRNA_STRUCT_CHECK_OBJ(self); + + if (RNA_struct_idprops_check(self->ptr.type) == 0) { + PyErr_SetString(PyExc_TypeError, "This type doesn't support IDProperties"); + return NULL; + } + + IDProperty *idprops = RNA_struct_idprops(&self->ptr, true); + + /* This is a paranoid check that theoretically might not be necessary. + * It allows the possibility that some structs can't ensure IDProperties. */ + if (idprops == NULL) { + return Py_None; + } + + BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type); + group->owner_id = self->ptr.owner_id; + group->prop = idprops; + group->parent = NULL; + return (PyObject *)group; +} + +PyDoc_STRVAR(pyrna_struct_id_properties_clear_doc, + ".. method:: id_properties_clear()\n" + " :return: Remove the parent group for an RNA struct's custom IDProperties.\n"); +static PyObject *pyrna_struct_id_properties_clear(BPy_StructRNA *self) +{ + PYRNA_STRUCT_CHECK_OBJ(self); + + if (RNA_struct_idprops_check(self->ptr.type) == 0) { + PyErr_SetString(PyExc_TypeError, "This type doesn't support IDProperties"); + return NULL; + } + + IDProperty **idprops = RNA_struct_idprops_p(&self->ptr); + + if (*idprops) { + IDP_FreeProperty(*idprops); + *idprops = NULL; + } + + Py_RETURN_NONE; +} + /* ---------------getattr-------------------------------------------- */ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname) { @@ -5743,6 +5793,14 @@ static struct PyMethodDef pyrna_struct_methods[] = { METH_VARARGS | METH_CLASS, pyrna_struct_bl_rna_get_subclass_doc}, {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL}, + {"id_properties_ensure", + (PyCFunction)pyrna_struct_id_properties_ensure, + METH_NOARGS, + pyrna_struct_id_properties_ensure_doc}, + {"id_properties_clear", + (PyCFunction)pyrna_struct_id_properties_clear, + METH_NOARGS, + pyrna_struct_id_properties_clear_doc}, /* experimental */ /* unused for now */ diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index ac061c3dd60..66044311321 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -130,7 +130,7 @@ static int foreach_libblock_id_user_map_callback(LibraryIDLinkCallbackData *cb_d } PyDoc_STRVAR(bpy_user_map_doc, - ".. method:: user_map([subset=(id1, id2, ...)], key_types={..}, value_types={..})\n" + ".. method:: user_map(subset, key_types, value_types)\n" "\n" " Returns a mapping of all ID data-blocks in current ``bpy.data`` to a set of all " "datablocks using them.\n" @@ -277,7 +277,7 @@ error: } PyDoc_STRVAR(bpy_batch_remove_doc, - ".. method:: batch_remove(ids=(id1, id2, ...))\n" + ".. method:: batch_remove(ids)\n" "\n" " Remove (delete) several IDs at once.\n" "\n" diff --git a/source/blender/python/intern/bpy_utils_previews.c b/source/blender/python/intern/bpy_utils_previews.c index 7a826d99a3d..6a46d2a1a96 100644 --- a/source/blender/python/intern/bpy_utils_previews.c +++ b/source/blender/python/intern/bpy_utils_previews.c @@ -59,7 +59,6 @@ PyDoc_STRVAR( " :type name: string\n" " :return: The Preview matching given name, or a new empty one.\n" " :rtype: :class:`bpy.types.ImagePreview`\n" - " :rtype: :class:`bpy.types.ImagePreview`\n" /* This is only true when accessed via 'bpy.utils.previews.ImagePreviewCollection.load', * however this is the public API, allow this minor difference to the internal version here. */ " :raises KeyError: if ``name`` already exists."); diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index 4ad0264582f..c2223b023ad 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -149,7 +149,7 @@ static PyObject *C_Vector_Fill(PyObject *cls, PyObject *args) } PyDoc_STRVAR(C_Vector_Range_doc, - ".. classmethod:: Range(start=0, stop, step=1)\n" + ".. classmethod:: Range(start, stop, step=1)\n" "\n" " Create a filled with a range of values.\n" "\n" diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c index fd65bb12044..d5653f87c2b 100644 --- a/source/blender/render/intern/bake.c +++ b/source/blender/render/intern/bake.c @@ -340,10 +340,10 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData, float co_high[3], dir_high[3]; hits[i].index = -1; - /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */ + /* TODO: we should use FLT_MAX here, but sweep-sphere code isn't prepared for that. */ hits[i].dist = BVH_RAYCAST_DIST_MAX; - /* transform the ray from the world space to the highpoly space */ + /* Transform the ray from the world space to the `highpoly` space. */ mul_v3_m4v3(co_high, highpoly[i].imat, co); /* rotates */ @@ -555,10 +555,10 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low, TriTessFace *tris_cage = NULL; TriTessFace **tris_high; - /* assume all lowpoly tessfaces can be quads */ + /* Assume all low-poly tessfaces can be quads. */ tris_high = MEM_callocN(sizeof(TriTessFace *) * tot_highpoly, "MVerts Highpoly Mesh Array"); - /* assume all highpoly tessfaces are triangles */ + /* Assume all high-poly tessfaces are triangles. */ me_highpoly = MEM_mallocN(sizeof(Mesh *) * tot_highpoly, "Highpoly Derived Meshes"); treeData = MEM_callocN(sizeof(BVHTreeFromMesh) * tot_highpoly, "Highpoly BVH Trees"); @@ -583,7 +583,7 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low, BKE_mesh_runtime_looptri_ensure(me_highpoly[i]); if (me_highpoly[i]->runtime.looptris.len != 0) { - /* Create a BVH-tree for each highpoly object. */ + /* Create a BVH-tree for each `highpoly` object. */ BKE_bvhtree_from_mesh_get(&treeData[i], me_highpoly[i], BVHTREE_FROM_LOOPTRI, 2); if (treeData[i].tree == NULL) { diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c index 86ed88d37ab..657cd1f606b 100644 --- a/source/blender/render/intern/engine.c +++ b/source/blender/render/intern/engine.c @@ -679,7 +679,7 @@ static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer) DRW_render_context_enable(engine->re); } - DEG_evaluate_on_framechange(depsgraph, CFRA); + DEG_evaluate_on_framechange(depsgraph, BKE_scene_frame_get(scene)); if (use_gpu_context) { DRW_render_context_disable(engine->re); diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c index bc03158f036..6329901b4ce 100644 --- a/source/blender/render/intern/pipeline.c +++ b/source/blender/render/intern/pipeline.c @@ -1828,7 +1828,7 @@ void RE_SetReports(Render *re, ReportList *reports) static void render_update_depsgraph(Render *re) { Scene *scene = re->scene; - DEG_evaluate_on_framechange(re->pipeline_depsgraph, CFRA); + DEG_evaluate_on_framechange(re->pipeline_depsgraph, BKE_scene_frame_get(scene)); BKE_scene_update_sound(re->pipeline_depsgraph, re->main); } @@ -2410,7 +2410,7 @@ void RE_RenderAnim(Render *re, * -sergey- */ { - float ctime = BKE_scene_frame_get(scene); + float ctime = BKE_scene_ctime_get(scene); AnimData *adt = BKE_animdata_from_id(&scene->id); const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( re->pipeline_depsgraph, ctime); diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c index c0ff00d4f59..31d5bf67f28 100644 --- a/source/blender/render/intern/texture_pointdensity.c +++ b/source/blender/render/intern/texture_pointdensity.c @@ -169,7 +169,7 @@ static void pointdensity_cache_psys( ParticleCacheKey *cache; ParticleSimulationData sim = {NULL}; ParticleData *pa = NULL; - float cfra = BKE_scene_frame_get(scene); + float cfra = BKE_scene_ctime_get(scene); int i /*, Childexists*/ /* UNUSED */; int total_particles; int data_used; @@ -347,9 +347,9 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd, if (!mdef) { return; } - mdef_index = BKE_object_defgroup_name_index(ob, pd->vertex_attribute_name); + mdef_index = BKE_id_defgroup_name_index(&mesh->id, pd->vertex_attribute_name); if (mdef_index < 0) { - mdef_index = ob->actdef - 1; + mdef_index = BKE_object_defgroup_active_index_get(ob) - 1; } if (mdef_index < 0) { return; @@ -782,7 +782,7 @@ static void particle_system_minmax(Depsgraph *depsgraph, float max[3]) { const float size[3] = {radius, radius, radius}; - const float cfra = BKE_scene_frame_get(scene); + const float cfra = BKE_scene_ctime_get(scene); ParticleSettings *part = psys->part; ParticleSimulationData sim = {NULL}; ParticleData *pa = NULL; diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt index 9340cfbf03d..e324bc8b407 100644 --- a/source/blender/sequencer/CMakeLists.txt +++ b/source/blender/sequencer/CMakeLists.txt @@ -77,9 +77,9 @@ set(SRC intern/proxy_job.c intern/render.c intern/render.h + intern/sequence_lookup.c intern/sequencer.c intern/sequencer.h - intern/sequence_lookup.c intern/sound.c intern/strip_add.c intern/strip_edit.c diff --git a/source/blender/sequencer/SEQ_clipboard.h b/source/blender/sequencer/SEQ_clipboard.h index 4b2bf69a8ac..ea7f01e6ae3 100644 --- a/source/blender/sequencer/SEQ_clipboard.h +++ b/source/blender/sequencer/SEQ_clipboard.h @@ -29,12 +29,16 @@ extern "C" { struct ListBase; struct Main; +struct Scene; +struct Sequence; extern struct ListBase seqbase_clipboard; extern int seqbase_clipboard_frame; void SEQ_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase); void SEQ_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain); void SEQ_clipboard_free(void); +void SEQ_clipboard_active_seq_name_store(struct Scene *scene); +bool SEQ_clipboard_pasted_seq_was_active(struct Sequence *pasted_seq); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c index e3f82dd4bb0..9e702a4e60b 100644 --- a/source/blender/sequencer/intern/clipboard.c +++ b/source/blender/sequencer/intern/clipboard.c @@ -24,6 +24,8 @@ * \ingroup bke */ +#include <string.h> + #include "MEM_guardedalloc.h" #include "DNA_scene_types.h" @@ -31,6 +33,7 @@ #include "DNA_sound_types.h" #include "BLI_listbase.h" +#include "BLI_string.h" #include "BKE_main.h" #include "BKE_movieclip.h" @@ -38,6 +41,7 @@ #include "BKE_sound.h" #include "SEQ_clipboard.h" +#include "SEQ_select.h" #include "sequencer.h" @@ -55,6 +59,7 @@ ListBase seqbase_clipboard; int seqbase_clipboard_frame; +static char seq_clipboard_active_seq_name[SEQ_NAME_MAXSTR]; void seq_clipboard_pointers_free(struct ListBase *seqbase); @@ -177,3 +182,26 @@ void SEQ_clipboard_pointers_restore(ListBase *seqbase, Main *bmain) SEQ_clipboard_pointers_restore(&seq->seqbase, bmain); } } + +void SEQ_clipboard_active_seq_name_store(Scene *scene) +{ + Sequence *active_seq = SEQ_select_active_get(scene); + if (active_seq != NULL) { + STRNCPY(seq_clipboard_active_seq_name, active_seq->name); + } + else { + seq_clipboard_active_seq_name[0] = '\0'; + } +} + +/** + * Check if strip was active when it was copied. User should restrict this check to pasted strips + * before ensuring original name, because strip name comparison is used to check. + * + * \param pasted_seq: Strip that is pasted(duplicated) from clipboard + * \return true if strip was active, false otherwise + */ +bool SEQ_clipboard_pasted_seq_was_active(Sequence *pasted_seq) +{ + return STREQ(pasted_seq->name, seq_clipboard_active_seq_name); +} |