diff options
Diffstat (limited to 'source/blender/blenkernel')
54 files changed, 851 insertions, 283 deletions
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index b92d0d4326b..108993d91c0 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -351,8 +351,9 @@ class AttributeAccessor { /** * The data that actually owns the attributes, for example, a pointer to a #Mesh or #PointCloud * Most commonly this is a pointer to a #Mesh or #PointCloud. - * Under some circumstances this can be null. In that case most methods can't be used. Just e.g. - * the #domain_size method works and returns 0 for every domain. + * Under some circumstances this can be null. In that case most methods can't be used. Allowed + * methods are #domain_size, #for_all and #is_builtin. We could potentially make these methods + * accessible without #AttributeAccessor and then #owner_ could always be non-null. * * \note This class cannot modify the owner's attributes, but the pointer is still non-const, so * this class can be a base class for the mutable version. @@ -509,7 +510,10 @@ class AttributeAccessor { */ bool for_all(const AttributeForeachCallback fn) const { - return fn_->for_all(owner_, fn); + if (owner_ != nullptr) { + return fn_->for_all(owner_, fn); + } + return true; } /** @@ -662,6 +666,22 @@ class MutableAttributeAccessor : public AttributeAccessor { void remove_anonymous(); }; +struct AttributeTransferData { + /* Expect that if an attribute exists, it is stored as a contiguous array internally anyway. */ + GVArraySpan src; + AttributeMetaData meta_data; + bke::GSpanAttributeWriter dst; +}; +/** + * Retrieve attribute arrays and writers for attributes that should be transferred between + * data-blocks of the same type. + */ +Vector<AttributeTransferData> retrieve_attributes_for_transfer( + const bke::AttributeAccessor &src_attributes, + bke::MutableAttributeAccessor &dst_attributes, + eAttrDomainMask domain_mask, + const Set<std::string> &skip = {}); + bool allow_procedural_attribute_access(StringRef attribute_name); extern const char *no_procedural_access_message; diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index fb97e52f6da..68c90a45031 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -385,8 +385,6 @@ class CurvesGeometry : public ::CurvesGeometry { void calculate_bezier_auto_handles(); - void update_customdata_pointers(); - void remove_points(IndexMask points_to_delete); void remove_curves(IndexMask curves_to_delete); @@ -735,6 +733,12 @@ Curves *curves_new_nomain(CurvesGeometry curves); */ Curves *curves_new_nomain_single(int points_num, CurveType type); +/** + * Copy data from #src to #dst, except the geometry data in #CurvesGeometry. Typically used to + * copy high-level parameters when a geometry-altering operation creates a new curves data-block. + */ +void curves_copy_parameters(const Curves &src, Curves &dst); + std::array<int, CURVE_TYPES_NUM> calculate_type_counts(const VArray<int8_t> &types); /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh index f223e173ea9..0fbd33002e1 100644 --- a/source/blender/blenkernel/BKE_curves_utils.hh +++ b/source/blender/blenkernel/BKE_curves_utils.hh @@ -56,6 +56,13 @@ void fill_points(const CurvesGeometry &curves, } /** + * Copy only the information on the point domain, but not the offsets or any point attributes, + * meant for operations that change the number of points but not the number of curves. + * \warning The returned curves have invalid offsets! + */ +bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves); + +/** * Copy the size of every curve in #curve_ranges to the corresponding index in #counts. */ void fill_curve_counts(const bke::CurvesGeometry &curves, diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 10d9ce3364d..c5788c07336 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -463,23 +463,39 @@ bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt, struct BezTriple *next, float *r_pdelta); +/** + * Delete a keyframe from an F-curve at a specific index. + */ +void BKE_fcurve_delete_key(struct FCurve *fcu, int index); + +/** + * Delete selected keyframes from an F-curve. + */ +bool BKE_fcurve_delete_keys_selected(struct FCurve *fcu); + +/** + * Delete all keyframes from an F-curve. + */ +void BKE_fcurve_delete_keys_all(struct FCurve *fcu); + /* -------- Curve Sanity -------- */ /** * This function recalculates the handles of an F-Curve. Acts based on selection with `SELECT` - * flag. To use a different flag, use #calchandles_fcurve_ex(). + * flag. To use a different flag, use #BKE_fcurve_handles_recalc_ex(). * * If the BezTriples have been rearranged, sort them first before using this. */ -void calchandles_fcurve(struct FCurve *fcu); +void BKE_fcurve_handles_recalc(struct FCurve *fcu); /** - * Variant of #calchandles_fcurve() that allows calculating based on a different select flag. + * Variant of #BKE_fcurve_handles_recalc() that allows calculating based on a different select + * flag. * * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. * Usually `SELECT`, but may want to use a different one at times * (if caller does not operate on selection). */ -void calchandles_fcurve_ex(struct FCurve *fcu, eBezTriple_Flag handle_sel_flag); +void BKE_fcurve_handles_recalc_ex(struct FCurve *fcu, eBezTriple_Flag handle_sel_flag); /** * Update handles, making sure the handle-types are valid (e.g. correctly deduced from an "Auto" * type), and recalculating their position vectors. diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 6ec1285af0c..4e622a5708f 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -97,7 +97,7 @@ int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, const struct ImageForm */ int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, - struct ImageFormatData *imf, + const struct ImageFormatData *imf, bool save_copy); /** diff --git a/source/blender/blenkernel/BKE_image_save.h b/source/blender/blenkernel/BKE_image_save.h index 673a7dffb82..e17136174eb 100644 --- a/source/blender/blenkernel/BKE_image_save.h +++ b/source/blender/blenkernel/BKE_image_save.h @@ -48,14 +48,14 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts, struct ImageUser *iuser, const bool guess_path, const bool save_as_render); -void BKE_image_save_options_update(struct ImageSaveOptions *opts, struct Image *ima); +void BKE_image_save_options_update(struct ImageSaveOptions *opts, const struct Image *ima); void BKE_image_save_options_free(struct ImageSaveOptions *opts); bool BKE_image_save(struct ReportList *reports, struct Main *bmain, struct Image *ima, struct ImageUser *iuser, - struct ImageSaveOptions *opts); + const struct ImageSaveOptions *opts); /* Render saving. */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 366083fee7f..6c61068b1c2 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -85,10 +85,18 @@ struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, * Add original index (#CD_ORIGINDEX) layers if they don't already exist. This is meant to be used * when creating an evaluated mesh from an original edit mode mesh, to allow mapping from the * evaluated vertices to the originals. + * + * The mesh is expected to of a `ME_WRAPPER_TYPE_MDATA` wrapper type. This is asserted. */ void BKE_mesh_ensure_default_orig_index_customdata(struct Mesh *mesh); /** + * Same as #BKE_mesh_ensure_default_orig_index_customdata but does not perform any checks: they + * must be done by the caller. + */ +void BKE_mesh_ensure_default_orig_index_customdata_no_check(struct Mesh *mesh); + +/** * Find the index of the loop in 'poly' which references vertex, * returns -1 if not found */ @@ -986,7 +994,7 @@ void BKE_mesh_strip_loose_edges(struct Mesh *me); /** * If the mesh is from a very old blender version, - * convert mface->edcode to edge drawflags + * convert #MFace.edcode to edge #ME_EDGEDRAW. */ void BKE_mesh_calc_edges_legacy(struct Mesh *me, bool use_old); void BKE_mesh_calc_edges_loose(struct Mesh *mesh); @@ -1002,8 +1010,8 @@ void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool selec void BKE_mesh_calc_edges_tessface(struct Mesh *mesh); /* In DerivedMesh.cc */ -void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval, - const struct CustomData_MeshMasks *cd_mask_finalize); +void BKE_mesh_wrapper_deferred_finalize_mdata(struct Mesh *me_eval, + const struct CustomData_MeshMasks *cd_mask_finalize); /* **** Depsgraph evaluation **** */ diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index 163acf062e0..c58bcbea242 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -69,8 +69,6 @@ typedef struct UvElementMap { int *islandIndices; } UvElementMap; -#define INVALID_ISLAND ((unsigned int)-1) - /* Connectivity data */ typedef struct MeshElemMap { int *indices; diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 866b0353d07..46d609f9aa3 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -446,10 +446,22 @@ bool BKE_modifier_is_enabled(const struct Scene *scene, */ bool BKE_modifier_is_nonlocal_in_liboverride(const struct Object *ob, const struct ModifierData *md); + +/* Set modifier execution error. + * The message will be shown in the interface and will be logged as an error to the console. */ void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4); + +/* Set modifier execution warning, which does not prevent the modifier from being applied but which + * might need an attention. The message will only be shown in the interface, but will not appear in + * the logs. */ +void BKE_modifier_set_warning(const struct Object *ob, + struct ModifierData *md, + const char *format, + ...) ATTR_PRINTF_FORMAT(3, 4); + bool BKE_modifier_is_preview(struct ModifierData *md); void BKE_modifiers_foreach_ID_link(struct Object *ob, IDWalkFunc walk, void *userData); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index b7962ade312..ea43fba1a85 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -314,6 +314,10 @@ typedef struct bNodeType { /* Execute a geometry node. */ NodeGeometryExecFunction geometry_node_execute; + /** + * If true, the geometry nodes evaluator can call the execute function multiple times to improve + * performance by specifying required data in one call and using it for calculations in another. + */ bool geometry_node_execute_supports_laziness; /* Declares which sockets the node has. */ diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index ffe80ff47b6..162459d2005 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -200,6 +200,11 @@ bool BKE_paint_select_vert_test(struct Object *ob); * (when we don't care if its face or vert) */ bool BKE_paint_select_elem_test(struct Object *ob); +/** + * Checks if face/vertex hiding is always applied in the current mode. + * Returns true in vertex/weight paint. + */ +bool BKE_paint_always_hide_test(struct Object *ob); /* Partial visibility. */ diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h index 6dbba11a56d..ee90fea6506 100644 --- a/source/blender/blenkernel/BKE_pointcloud.h +++ b/source/blender/blenkernel/BKE_pointcloud.h @@ -29,7 +29,6 @@ struct PointCloud *BKE_pointcloud_new_nomain(int totpoint); struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob); bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]); -void BKE_pointcloud_update_customdata_pointers(struct PointCloud *pointcloud); bool BKE_pointcloud_customdata_required(const struct PointCloud *pointcloud, const char *name); /* Dependency Graph */ diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index a6402a1e8a1..61fc883fe7f 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -251,6 +251,10 @@ bool BKE_scene_check_rigidbody_active(const struct Scene *scene); int BKE_scene_num_threads(const struct Scene *scene); int BKE_render_num_threads(const struct RenderData *r); +void BKE_render_resolution(const struct RenderData *r, + const bool use_crop, + int *r_width, + int *r_height); int BKE_render_preview_pixel_size(const struct RenderData *r); /**********************************/ diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h index cb0f2ac7e32..e4a7f813a8b 100644 --- a/source/blender/blenkernel/BKE_subdiv_eval.h +++ b/source/blender/blenkernel/BKE_subdiv_eval.h @@ -20,7 +20,7 @@ struct Subdiv; typedef enum eSubdivEvaluatorType { SUBDIV_EVALUATOR_TYPE_CPU, - SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, + SUBDIV_EVALUATOR_TYPE_GPU, } eSubdivEvaluatorType; /* Returns true if evaluator is ready for use. */ diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h index 3f92d6fa117..736f7548bb4 100644 --- a/source/blender/blenkernel/BKE_writeffmpeg.h +++ b/source/blender/blenkernel/BKE_writeffmpeg.h @@ -68,7 +68,7 @@ void BKE_ffmpeg_filepath_get(char *string, const char *suffix); void BKE_ffmpeg_preset_set(struct RenderData *rd, int preset); -void BKE_ffmpeg_image_type_verify(struct RenderData *rd, struct ImageFormatData *imf); +void BKE_ffmpeg_image_type_verify(struct RenderData *rd, const struct ImageFormatData *imf); bool BKE_ffmpeg_alpha_channel_is_supported(const struct RenderData *rd); void *BKE_ffmpeg_context_create(void); diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index c2ea01bcadf..a29d8726f21 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -84,6 +84,8 @@ static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER; static void mesh_init_origspace(Mesh *mesh); static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, const CustomData_MeshMasks *final_datamask); +static void editbmesh_calc_modifier_final_normals_or_defer( + Mesh *mesh_final, const CustomData_MeshMasks *final_datamask); /* -------------------------------------------------------------------- */ @@ -663,8 +665,8 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval) mesh_eval->edit_mesh = mesh_input->edit_mesh; } -void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval, - const CustomData_MeshMasks *cd_mask_finalize) +void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *me_eval, + const CustomData_MeshMasks *cd_mask_finalize) { if (me_eval->runtime.wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) { editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize); @@ -1286,12 +1288,6 @@ bool editbmesh_modifier_is_enabled(const Scene *scene, static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, const CustomData_MeshMasks *final_datamask) { - if (mesh_final->runtime.wrapper_type != ME_WRAPPER_TYPE_MDATA) { - /* Generated at draw time. */ - mesh_final->runtime.wrapper_type_finalize = (1 << mesh_final->runtime.wrapper_type); - return; - } - const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 || (final_datamask->lmask & CD_MASK_NORMAL) != 0); @@ -1319,6 +1315,18 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, } } +static void editbmesh_calc_modifier_final_normals_or_defer( + Mesh *mesh_final, const CustomData_MeshMasks *final_datamask) +{ + if (mesh_final->runtime.wrapper_type != ME_WRAPPER_TYPE_MDATA) { + /* Generated at draw time. */ + mesh_final->runtime.wrapper_type_finalize = (1 << mesh_final->runtime.wrapper_type); + return; + } + + editbmesh_calc_modifier_final_normals(mesh_final, final_datamask); +} + static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, const Scene *scene, Object *ob, @@ -1598,9 +1606,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } /* Compute normals. */ - editbmesh_calc_modifier_final_normals(mesh_final, &final_datamask); + editbmesh_calc_modifier_final_normals_or_defer(mesh_final, &final_datamask); if (mesh_cage && (mesh_cage != mesh_final)) { - editbmesh_calc_modifier_final_normals(mesh_cage, &final_datamask); + editbmesh_calc_modifier_final_normals_or_defer(mesh_cage, &final_datamask); } /* Return final mesh. */ diff --git a/source/blender/blenkernel/intern/action_mirror.c b/source/blender/blenkernel/intern/action_mirror.c index 7ef561c8216..0663538f3bb 100644 --- a/source/blender/blenkernel/intern/action_mirror.c +++ b/source/blender/blenkernel/intern/action_mirror.c @@ -363,7 +363,7 @@ static void action_flip_pchan(Object *ob_arm, /* Recalculate handles. */ for (int i = 0; i < fcurve_array_len; i++) { - calchandles_fcurve_ex(fcurve_array[i], 0); + BKE_fcurve_handles_recalc_ex(fcurve_array[i], 0); } MEM_freeN((void *)keyed_frames); diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index ac1ee19927c..a834b77d65e 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -1011,6 +1011,37 @@ GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span return {}; } +Vector<AttributeTransferData> retrieve_attributes_for_transfer( + const bke::AttributeAccessor &src_attributes, + bke::MutableAttributeAccessor &dst_attributes, + const eAttrDomainMask domain_mask, + const Set<std::string> &skip) +{ + Vector<AttributeTransferData> attributes; + src_attributes.for_all( + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) { + if (!(ATTR_DOMAIN_AS_MASK(meta_data.domain) & domain_mask)) { + return true; + } + if (id.is_named() && skip.contains(id.name())) { + return true; + } + if (!id.should_be_kept()) { + return true; + } + + GVArray src = src_attributes.lookup(id, meta_data.domain); + BLI_assert(src); + bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span( + id, meta_data.domain, meta_data.data_type); + BLI_assert(dst); + attributes.append({std::move(src), meta_data, std::move(dst)}); + + return true; + }); + return attributes; +} + } // namespace blender::bke /** \} */ diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index ffa63f9792f..99733c8edb3 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -444,7 +444,8 @@ static void brush_defaults(Brush *brush) const Brush *brush_def = DNA_struct_default_get(Brush); -#define FROM_DEFAULT(member) memcpy(&brush->member, &brush_def->member, sizeof(brush->member)) +#define FROM_DEFAULT(member) \ + memcpy((void *)&brush->member, (void *)&brush_def->member, sizeof(brush->member)) #define FROM_DEFAULT_PTR(member) memcpy(brush->member, brush_def->member, sizeof(brush->member)) FROM_DEFAULT(blend); @@ -586,15 +587,15 @@ bool BKE_brush_delete(Main *bmain, Brush *brush) return true; } -/* grease pencil cumapping->preset */ -typedef enum eGPCurveMappingPreset { +/** Local grease pencil curve mapping preset. */ +using eGPCurveMappingPreset = enum eGPCurveMappingPreset { GPCURVE_PRESET_PENCIL = 0, GPCURVE_PRESET_INK = 1, GPCURVE_PRESET_INKNOISE = 2, GPCURVE_PRESET_MARKER = 3, GPCURVE_PRESET_CHISEL_SENSIVITY = 4, GPCURVE_PRESET_CHISEL_STRENGTH = 5, -} eGPCurveMappingPreset; +}; static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset) { diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc index 35c2039634a..03dd5c89b70 100644 --- a/source/blender/blenkernel/intern/bvhutils.cc +++ b/source/blender/blenkernel/intern/bvhutils.cc @@ -19,6 +19,7 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BKE_attribute.hh" #include "BKE_bvhutils.h" #include "BKE_editmesh.h" #include "BKE_mesh.h" @@ -1430,13 +1431,17 @@ BVHTree *BKE_bvhtree_from_pointcloud_get(BVHTreeFromPointCloud *data, return nullptr; } - for (int i = 0; i < pointcloud->totpoint; i++) { - BLI_bvhtree_insert(tree, i, pointcloud->co[i], 1); + blender::bke::AttributeAccessor attributes = blender::bke::pointcloud_attributes(*pointcloud); + blender::VArraySpan<blender::float3> positions = attributes.lookup_or_default<blender::float3>( + "position", ATTR_DOMAIN_POINT, blender::float3(0)); + + for (const int i : positions.index_range()) { + BLI_bvhtree_insert(tree, i, positions[i], 1); } BLI_assert(BLI_bvhtree_get_len(tree) == pointcloud->totpoint); bvhtree_balance(tree, false); - data->coords = pointcloud->co; + data->coords = (const float(*)[3])positions.data(); data->tree = tree; data->nearest_callback = nullptr; diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index fbe03ac365c..9aea3b2768f 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -25,6 +25,7 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_action.h" #include "BKE_anim_data.h" #include "BKE_camera.h" #include "BKE_idtype.h" @@ -221,7 +222,16 @@ float BKE_camera_object_dof_distance(const Object *ob) if (cam->dof.focus_object) { float view_dir[3], dof_dir[3]; normalize_v3_v3(view_dir, ob->obmat[2]); - sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof.focus_object->obmat[3]); + bPoseChannel *pchan = BKE_pose_channel_find_name(cam->dof.focus_object->pose, + cam->dof.focus_subtarget); + if (pchan) { + float posemat[4][4]; + mul_m4_m4m4(posemat, cam->dof.focus_object->obmat, pchan->pose_mat); + sub_v3_v3v3(dof_dir, ob->obmat[3], posemat[3]); + } + else { + sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof.focus_object->obmat[3]); + } return fabsf(dot_v3v3(view_dir, dof_dir)); } return cam->dof.focus_distance; @@ -559,6 +569,11 @@ void BKE_camera_view_frame(const Scene *scene, const Camera *camera, float r_vec #define CAMERA_VIEWFRAME_NUM_PLANES 4 +#define Y_MIN 0 +#define Y_MAX 1 +#define Z_MIN 2 +#define Z_MAX 3 + typedef struct CameraViewFrameData { float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][4]; /* 4 planes normalized */ float dist_vals[CAMERA_VIEWFRAME_NUM_PLANES]; /* distance (signed) */ @@ -622,15 +637,13 @@ static void camera_frame_fit_data_init(const Scene *scene, invert_m4(camera_rotmat_transposed_inversed); /* Extract frustum planes from projection matrix. */ - planes_from_projmat( - params->winmat, - /* left right top bottom near far */ - data->plane_tx[2], - data->plane_tx[0], - data->plane_tx[3], - data->plane_tx[1], - NULL, - NULL); + planes_from_projmat(params->winmat, + data->plane_tx[Y_MIN], + data->plane_tx[Y_MAX], + data->plane_tx[Z_MIN], + data->plane_tx[Z_MAX], + NULL, + NULL); /* Rotate planes and get normals from them */ for (uint i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { @@ -670,21 +683,21 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params, const float *cam_axis_y = data->camera_rotmat[1]; const float *cam_axis_z = data->camera_rotmat[2]; const float *dists = data->dist_vals; - float scale_diff; + const float dist_span_y = dists[Y_MIN] + dists[Y_MAX]; + const float dist_span_z = dists[Z_MIN] + dists[Z_MAX]; + const float dist_mid_y = (dists[Y_MIN] - dists[Y_MAX]) * 0.5f; + const float dist_mid_z = (dists[Z_MIN] - dists[Z_MAX]) * 0.5f; + const float scale_diff = (dist_span_z < dist_span_y) ? + (dist_span_z * (BLI_rctf_size_x(¶ms->viewplane) / + BLI_rctf_size_y(¶ms->viewplane))) : + (dist_span_y * (BLI_rctf_size_y(¶ms->viewplane) / + BLI_rctf_size_x(¶ms->viewplane))); - if ((dists[0] + dists[2]) > (dists[1] + dists[3])) { - scale_diff = (dists[1] + dists[3]) * - (BLI_rctf_size_x(¶ms->viewplane) / BLI_rctf_size_y(¶ms->viewplane)); - } - else { - scale_diff = (dists[0] + dists[2]) * - (BLI_rctf_size_y(¶ms->viewplane) / BLI_rctf_size_x(¶ms->viewplane)); - } *r_scale = params->ortho_scale - scale_diff; zero_v3(r_co); - madd_v3_v3fl(r_co, cam_axis_x, (dists[2] - dists[0]) * 0.5f + params->shiftx * scale_diff); - madd_v3_v3fl(r_co, cam_axis_y, (dists[1] - dists[3]) * 0.5f + params->shifty * scale_diff); + madd_v3_v3fl(r_co, cam_axis_x, dist_mid_y + (params->shiftx * scale_diff)); + madd_v3_v3fl(r_co, cam_axis_y, dist_mid_z + (params->shifty * scale_diff)); madd_v3_v3fl(r_co, cam_axis_z, -(data->z_range[0] - 1.0f - params->clip_start)); } else { @@ -700,36 +713,37 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params, plane_from_point_normal_v3(plane_tx[i], co, data->plane_tx[i]); } - if ((!isect_plane_plane_v3(plane_tx[0], plane_tx[2], plane_isect_1, plane_isect_1_no)) || - (!isect_plane_plane_v3(plane_tx[1], plane_tx[3], plane_isect_2, plane_isect_2_no))) { + if ((!isect_plane_plane_v3( + plane_tx[Y_MIN], plane_tx[Y_MAX], plane_isect_1, plane_isect_1_no)) || + (!isect_plane_plane_v3( + plane_tx[Z_MIN], plane_tx[Z_MAX], plane_isect_2, plane_isect_2_no))) { return false; } add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no); add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no); - if (isect_line_line_v3(plane_isect_1, - plane_isect_1_other, - plane_isect_2, - plane_isect_2_other, - plane_isect_pt_1, - plane_isect_pt_2) == 0) { + if (!isect_line_line_v3(plane_isect_1, + plane_isect_1_other, + plane_isect_2, + plane_isect_2_other, + plane_isect_pt_1, + plane_isect_pt_2)) { return false; } float cam_plane_no[3]; float plane_isect_delta[3]; - float plane_isect_delta_len; - float shift_fac = BKE_camera_sensor_size( - params->sensor_fit, params->sensor_x, params->sensor_y) / - params->lens; + const float shift_fac = BKE_camera_sensor_size( + params->sensor_fit, params->sensor_x, params->sensor_y) / + params->lens; /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */ negate_v3_v3(cam_plane_no, data->camera_rotmat[2]); sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1); - plane_isect_delta_len = len_v3(plane_isect_delta); + const float plane_isect_delta_len = len_v3(plane_isect_delta); if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) { copy_v3_v3(r_co, plane_isect_pt_1); @@ -755,6 +769,11 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params, return true; } +#undef Y_MIN +#undef Y_MAX +#undef Z_MIN +#undef Z_MAX + bool BKE_camera_view_frame_fit_to_scene(Depsgraph *depsgraph, const Scene *scene, Object *camera_ob, diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 78791b55b4d..5684a2e5b07 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -53,8 +53,6 @@ using blender::Vector; static const char *ATTR_POSITION = "position"; -static void update_custom_data_pointers(Curves &curves); - static void curves_init_data(ID *id) { Curves *curves = (Curves *)id; @@ -97,8 +95,6 @@ static void curves_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, dst.runtime->type_counts = src.runtime->type_counts; - dst.update_customdata_pointers(); - curves_dst->batch_cache = nullptr; } @@ -170,7 +166,6 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id) /* Geometry */ CustomData_blend_read(reader, &curves->geometry.point_data, curves->geometry.point_num); CustomData_blend_read(reader, &curves->geometry.curve_data, curves->geometry.curve_num); - update_custom_data_pointers(*curves); BLO_read_int32_array(reader, curves->geometry.curve_num + 1, &curves->geometry.curve_offsets); @@ -233,11 +228,6 @@ IDTypeInfo IDType_ID_CV = { /*lib_override_apply_post */ nullptr, }; -static void update_custom_data_pointers(Curves &curves) -{ - blender::bke::CurvesGeometry::wrap(curves.geometry).update_customdata_pointers(); -} - void *BKE_curves_add(Main *bmain, const char *name) { Curves *curves = static_cast<Curves *>(BKE_id_new(bmain, ID_CV, name)); @@ -388,6 +378,23 @@ Curves *curves_new_nomain(CurvesGeometry curves) return curves_id; } +void curves_copy_parameters(const Curves &src, Curves &dst) +{ + dst.flag = src.flag; + dst.attributes_active_index = src.attributes_active_index; + MEM_SAFE_FREE(dst.mat); + dst.mat = static_cast<Material **>(MEM_malloc_arrayN(src.totcol, sizeof(Material *), __func__)); + dst.totcol = src.totcol; + MutableSpan(dst.mat, dst.totcol).copy_from(Span(src.mat, src.totcol)); + dst.symmetry = src.symmetry; + dst.selection_domain = src.selection_domain; + dst.surface = src.surface; + MEM_SAFE_FREE(dst.surface_uv_map); + if (src.surface_uv_map != nullptr) { + dst.surface_uv_map = BLI_strdup(src.surface_uv_map); + } +} + CurvesSurfaceTransforms::CurvesSurfaceTransforms(const Object &curves_ob, const Object *surface_ob) { this->curves_to_world = curves_ob.obmat; diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 8d955a46275..7fc660cfbfc 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -68,8 +68,6 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num) #endif this->offsets_for_write().first() = 0; - this->update_customdata_pointers(); - this->runtime = MEM_new<CurvesGeometryRuntime>(__func__); /* Fill the type counts with the default so they're in a valid state. */ this->runtime->type_counts[CURVE_TYPE_CATMULL_ROM] = curve_num; @@ -95,8 +93,6 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src) /* Though type counts are a cache, they must be copied because they are calculated eagerly. */ dst.runtime->type_counts = src.runtime->type_counts; - - dst.update_customdata_pointers(); } CurvesGeometry::CurvesGeometry(const CurvesGeometry &other) @@ -130,9 +126,6 @@ static void move_curves_geometry(CurvesGeometry &dst, CurvesGeometry &src) MEM_SAFE_FREE(src.curve_offsets); std::swap(dst.runtime, src.runtime); - - src.update_customdata_pointers(); - dst.update_customdata_pointers(); } CurvesGeometry::CurvesGeometry(CurvesGeometry &&other) @@ -306,13 +299,11 @@ void CurvesGeometry::update_curve_types() Span<float3> CurvesGeometry::positions() const { - return {(const float3 *)this->position, this->point_num}; + return get_span_attribute<float3>(*this, ATTR_DOMAIN_POINT, ATTR_POSITION); } MutableSpan<float3> CurvesGeometry::positions_for_write() { - this->position = (float(*)[3])CustomData_duplicate_referenced_layer_named( - &this->point_data, CD_PROP_FLOAT3, ATTR_POSITION.c_str(), this->point_num); - return {(float3 *)this->position, this->point_num}; + return get_mutable_attribute<float3>(*this, ATTR_DOMAIN_POINT, ATTR_POSITION); } Span<int> CurvesGeometry::offsets() const @@ -961,7 +952,6 @@ void CurvesGeometry::resize(const int points_num, const int curves_num) this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1)); } this->tag_topology_changed(); - this->update_customdata_pointers(); } void CurvesGeometry::tag_positions_changed() @@ -1060,10 +1050,11 @@ void CurvesGeometry::transform(const float4x4 &matrix) static std::optional<bounds::MinMaxResult<float3>> curves_bounds(const CurvesGeometry &curves) { - Span<float3> positions = curves.positions(); - if (curves.radius) { - Span<float> radii{curves.radius, curves.points_num()}; - return bounds::min_max_with_radii(positions, radii); + const Span<float3> positions = curves.positions(); + const VArray<float> radii = curves.attributes().lookup_or_default<float>( + ATTR_RADIUS, ATTR_DOMAIN_POINT, 0.0f); + if (!(radii.is_single() && radii.get_internal_single() == 0.0f)) { + return bounds::min_max_with_radii(positions, radii.get_internal_span()); } return bounds::min_max(positions); } @@ -1079,16 +1070,6 @@ bool CurvesGeometry::bounds_min_max(float3 &min, float3 &max) const return true; } -void CurvesGeometry::update_customdata_pointers() -{ - this->position = (float(*)[3])CustomData_get_layer_named( - &this->point_data, CD_PROP_FLOAT3, ATTR_POSITION.c_str()); - this->radius = (float *)CustomData_get_layer_named( - &this->point_data, CD_PROP_FLOAT, ATTR_RADIUS.c_str()); - this->curve_type = (int8_t *)CustomData_get_layer_named( - &this->point_data, CD_PROP_INT8, ATTR_CURVE_TYPE.c_str()); -} - static void *ensure_customdata_layer(CustomData &custom_data, const StringRefNull name, const eCustomDataType data_type, @@ -1497,7 +1478,6 @@ void CurvesGeometry::remove_attributes_based_on_types() if (!this->has_curve_with_type({CURVE_TYPE_BEZIER, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_NURBS})) { CustomData_free_layer_named(&this->curve_data, ATTR_RESOLUTION.c_str(), curves_num); } - this->update_customdata_pointers(); } /** \} */ diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc index f7db60ee588..d98832e796c 100644 --- a/source/blender/blenkernel/intern/curves_utils.cc +++ b/source/blender/blenkernel/intern/curves_utils.cc @@ -84,6 +84,18 @@ void fill_points(const CurvesGeometry &curves, }); } +bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves) +{ + bke::CurvesGeometry dst_curves(0, src_curves.curves_num()); + CustomData_copy(&src_curves.curve_data, + &dst_curves.curve_data, + CD_MASK_ALL, + CD_DUPLICATE, + src_curves.curves_num()); + dst_curves.runtime->type_counts = src_curves.runtime->type_counts; + return dst_curves; +} + IndexMask indices_for_type(const VArray<int8_t> &types, const std::array<int, CURVE_TYPES_NUM> &type_counts, const CurveType type, diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 0203620df84..972ff377519 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1146,7 +1146,7 @@ void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end) MEM_SAFE_FREE(fcu->fpt); /* Not strictly needed since we use linear interpolation, but better be consistent here. */ - calchandles_fcurve(fcu); + BKE_fcurve_handles_recalc(fcu); } /* ***************************** F-Curve Sanity ********************************* */ @@ -1216,7 +1216,7 @@ static BezTriple *cycle_offset_triple( return out; } -void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag) +void BKE_fcurve_handles_recalc_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag) { BezTriple *bezt, *prev, *next; int a = fcu->totvert; @@ -1299,9 +1299,9 @@ void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag) } } -void calchandles_fcurve(FCurve *fcu) +void BKE_fcurve_handles_recalc(FCurve *fcu) { - calchandles_fcurve_ex(fcu, SELECT); + BKE_fcurve_handles_recalc_ex(fcu, SELECT); } void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle) @@ -1320,7 +1320,7 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha } /* Recalculate handles. */ - calchandles_fcurve_ex(fcu, sel_flag); + BKE_fcurve_handles_recalc_ex(fcu, sel_flag); } void sort_time_fcurve(FCurve *fcu) @@ -1590,6 +1590,12 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b) } } +static void fcurve_bezt_free(FCurve *fcu) +{ + MEM_SAFE_FREE(fcu->bezt); + fcu->totvert = 0; +} + bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, @@ -1651,6 +1657,69 @@ bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt, return true; } +void BKE_fcurve_delete_key(FCurve *fcu, int index) +{ + /* sanity check */ + if (fcu == NULL) { + return; + } + + /* verify the index: + * 1) cannot be greater than the number of available keyframes + * 2) negative indices are for specifying a value from the end of the array + */ + if (abs(index) >= fcu->totvert) { + return; + } + if (index < 0) { + index += fcu->totvert; + } + + /* Delete this keyframe */ + memmove( + &fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1)); + fcu->totvert--; + + /* Free the array of BezTriples if there are not keyframes */ + if (fcu->totvert == 0) { + fcurve_bezt_free(fcu); + } +} + +bool BKE_fcurve_delete_keys_selected(FCurve *fcu) +{ + bool changed = false; + + if (fcu->bezt == NULL) { /* ignore baked curves */ + return false; + } + + /* Delete selected BezTriples */ + for (int i = 0; i < fcu->totvert; i++) { + if (fcu->bezt[i].f2 & SELECT) { + if (i == fcu->active_keyframe_index) { + BKE_fcurve_active_keyframe_set(fcu, NULL); + } + memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1)); + fcu->totvert--; + i--; + changed = true; + } + } + + /* Free the array of BezTriples if there are not keyframes */ + if (fcu->totvert == 0) { + fcurve_bezt_free(fcu); + } + + return changed; +} + +void BKE_fcurve_delete_keys_all(FCurve *fcu) +{ + fcurve_bezt_free(fcu); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index 1bb7c49d616..e4c7572b9e4 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -1127,7 +1127,7 @@ FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu) /* update the fcurve if the Cycles modifier is added */ if ((owner_fcu) && (type == FMODIFIER_TYPE_CYCLES)) { - calchandles_fcurve(owner_fcu); + BKE_fcurve_handles_recalc(owner_fcu); } /* return modifier for further editing */ @@ -1215,7 +1215,7 @@ bool remove_fmodifier(ListBase *modifiers, FModifier *fcm) /* update the fcurve if the Cycles modifier is removed */ if (update_fcu) { - calchandles_fcurve(update_fcu); + BKE_fcurve_handles_recalc(update_fcu); } return true; diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index 0d899ec7b06..22f105af0f1 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -1452,7 +1452,8 @@ std::optional<blender::bke::AttributeAccessor> CurveComponentLegacy::attributes( std::optional<blender::bke::MutableAttributeAccessor> CurveComponentLegacy::attributes_for_write() { - return blender::bke::MutableAttributeAccessor(curve_, + CurveEval *curve = this->get_for_write(); + return blender::bke::MutableAttributeAccessor(curve, blender::bke::get_curve_accessor_functions_ref()); } diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index 34c17bedc2c..2714c78e381 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -358,10 +358,7 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner); return curves.curves_num(); }, - [](void *owner) { - CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner); - curves.update_customdata_pointers(); - }}; + [](void * /*owner*/) {}}; static CustomDataAccessInfo point_access = { [](void *owner) -> CustomData * { CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner); @@ -375,10 +372,7 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner); return curves.points_num(); }, - [](void *owner) { - CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner); - curves.update_customdata_pointers(); - }}; + [](void * /*owner*/) {}}; static BuiltinCustomDataLayerProvider position("position", ATTR_DOMAIN_POINT, @@ -644,6 +638,7 @@ std::optional<blender::bke::AttributeAccessor> CurveComponent::attributes() cons std::optional<blender::bke::MutableAttributeAccessor> CurveComponent::attributes_for_write() { - return blender::bke::MutableAttributeAccessor(curves_ ? &curves_->geometry : nullptr, + Curves *curves = this->get_for_write(); + return blender::bke::MutableAttributeAccessor(curves ? &curves->geometry : nullptr, blender::bke::get_curves_accessor_functions_ref()); } diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index cb36b9b19f7..436868ba375 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -298,12 +298,14 @@ static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, const MPoly &poly = mesh.mpoly[poly_index]; /* For every edge, mix values from the two adjacent corners (the current and next corner). */ - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const int loop_index_next = (loop_index + 1) % poly.totloop; - const MLoop &loop = mesh.mloop[loop_index]; + for (const int i : IndexRange(poly.totloop)) { + const int next_i = (i + 1) % poly.totloop; + const int loop_i = poly.loopstart + i; + const int next_loop_i = poly.loopstart + next_i; + const MLoop &loop = mesh.mloop[loop_i]; const int edge_index = loop.e; - mixer.mix_in(edge_index, old_values[loop_index]); - mixer.mix_in(edge_index, old_values[loop_index_next]); + mixer.mix_in(edge_index, old_values[loop_i]); + mixer.mix_in(edge_index, old_values[next_loop_i]); } } @@ -325,13 +327,16 @@ void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, for (const int poly_index : IndexRange(mesh.totpoly)) { const MPoly &poly = mesh.mpoly[poly_index]; - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const int loop_index_next = (loop_index == poly.totloop) ? poly.loopstart : (loop_index + 1); - const MLoop &loop = mesh.mloop[loop_index]; + for (const int i : IndexRange(poly.totloop)) { + const int next_i = (i + 1) % poly.totloop; + const int loop_i = poly.loopstart + i; + const int next_loop_i = poly.loopstart + next_i; + const MLoop &loop = mesh.mloop[loop_i]; const int edge_index = loop.e; + loose_edges[edge_index] = false; - if (!old_values[loop_index] || !old_values[loop_index_next]) { + if (!old_values[loop_i] || !old_values[next_loop_i]) { r_values[edge_index] = false; } } @@ -1324,7 +1329,8 @@ std::optional<blender::bke::AttributeAccessor> MeshComponent::attributes() const std::optional<blender::bke::MutableAttributeAccessor> MeshComponent::attributes_for_write() { - return blender::bke::MutableAttributeAccessor(mesh_, + Mesh *mesh = this->get_for_write(); + return blender::bke::MutableAttributeAccessor(mesh, blender::bke::get_mesh_accessor_functions_ref()); } diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index b439a9ba7f8..4953da8a5ee 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -111,10 +111,7 @@ namespace blender::bke { */ static ComponentAttributeProviders create_attribute_providers_for_point_cloud() { - static auto update_custom_data_pointers = [](void *owner) { - PointCloud *pointcloud = static_cast<PointCloud *>(owner); - BKE_pointcloud_update_customdata_pointers(pointcloud); - }; + static auto update_custom_data_pointers = [](void * /*owner*/) {}; static CustomDataAccessInfo point_access = { [](void *owner) -> CustomData * { PointCloud *pointcloud = static_cast<PointCloud *>(owner); @@ -226,8 +223,9 @@ std::optional<blender::bke::AttributeAccessor> PointCloudComponent::attributes() std::optional<blender::bke::MutableAttributeAccessor> PointCloudComponent::attributes_for_write() { + PointCloud *pointcloud = this->get_for_write(); return blender::bke::MutableAttributeAccessor( - pointcloud_, blender::bke::get_pointcloud_accessor_functions_ref()); + pointcloud, blender::bke::get_pointcloud_accessor_functions_ref()); } /** \} */ diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c index e55143d6852..923582dff4c 100644 --- a/source/blender/blenkernel/intern/idtype.c +++ b/source/blender/blenkernel/intern/idtype.c @@ -209,7 +209,11 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode) case ID_##_id: \ return FILTER_ID_##_id - switch (idcode) { +#define CASE_IDFILTER_NONE(_id) \ + case ID_##_id: \ + return 0 + + switch ((ID_Type)idcode) { CASE_IDFILTER(AC); CASE_IDFILTER(AR); CASE_IDFILTER(BR); @@ -220,7 +224,11 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode) CASE_IDFILTER(GR); CASE_IDFILTER(CV); CASE_IDFILTER(IM); + CASE_IDFILTER_NONE(IP); + CASE_IDFILTER(KE); CASE_IDFILTER(LA); + CASE_IDFILTER(LI); + CASE_IDFILTER(LP); CASE_IDFILTER(LS); CASE_IDFILTER(LT); CASE_IDFILTER(MA); @@ -234,22 +242,25 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode) CASE_IDFILTER(PAL); CASE_IDFILTER(PC); CASE_IDFILTER(PT); - CASE_IDFILTER(LP); CASE_IDFILTER(SCE); + CASE_IDFILTER(SCR); CASE_IDFILTER(SIM); - CASE_IDFILTER(SPK); CASE_IDFILTER(SO); + CASE_IDFILTER(SPK); CASE_IDFILTER(TE); CASE_IDFILTER(TXT); CASE_IDFILTER(VF); CASE_IDFILTER(VO); + CASE_IDFILTER(WM); CASE_IDFILTER(WO); CASE_IDFILTER(WS); - default: - return 0; } + BLI_assert_unreachable(); + return 0; + #undef CASE_IDFILTER +#undef CASE_IDFILTER_NONE } short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter) @@ -258,6 +269,8 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter) case FILTER_ID_##_id: \ return ID_##_id +#define CASE_IDFILTER_NONE(_id) (void)0 + switch (idfilter) { CASE_IDFILTER(AC); CASE_IDFILTER(AR); @@ -269,7 +282,11 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter) CASE_IDFILTER(GR); CASE_IDFILTER(CV); CASE_IDFILTER(IM); + CASE_IDFILTER_NONE(IP); + CASE_IDFILTER(KE); CASE_IDFILTER(LA); + CASE_IDFILTER(LI); + CASE_IDFILTER(LP); CASE_IDFILTER(LS); CASE_IDFILTER(LT); CASE_IDFILTER(MA); @@ -283,21 +300,25 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter) CASE_IDFILTER(PAL); CASE_IDFILTER(PC); CASE_IDFILTER(PT); - CASE_IDFILTER(LP); CASE_IDFILTER(SCE); + CASE_IDFILTER(SCR); CASE_IDFILTER(SIM); - CASE_IDFILTER(SPK); CASE_IDFILTER(SO); + CASE_IDFILTER(SPK); CASE_IDFILTER(TE); CASE_IDFILTER(TXT); CASE_IDFILTER(VF); CASE_IDFILTER(VO); + CASE_IDFILTER(WM); CASE_IDFILTER(WO); - default: - return 0; + CASE_IDFILTER(WS); } + BLI_assert_unreachable(); + return 0; + #undef CASE_IDFILTER +#undef CASE_IDFILTER_NONE } int BKE_idtype_idcode_to_index(const short idcode) diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 92e98935e83..f8b2d841028 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -2475,7 +2475,10 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, const ImageFormatData *imf) return ok; } -int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf, const bool save_copy) +int BKE_imbuf_write_as(ImBuf *ibuf, + const char *name, + const ImageFormatData *imf, + const bool save_copy) { ImBuf ibuf_back = *ibuf; int ok; @@ -5057,13 +5060,7 @@ void BKE_image_get_size(Image *image, ImageUser *iuser, int *r_width, int *r_hei } else if (image != nullptr && image->type == IMA_TYPE_R_RESULT && iuser != nullptr && iuser->scene != nullptr) { - Scene *scene = iuser->scene; - *r_width = (scene->r.xsch * scene->r.size) / 100; - *r_height = (scene->r.ysch * scene->r.size) / 100; - if ((scene->r.mode & R_BORDER) && (scene->r.mode & R_CROP)) { - *r_width *= BLI_rctf_size_x(&scene->r.border); - *r_height *= BLI_rctf_size_y(&scene->r.border); - } + BKE_render_resolution(&iuser->scene->r, true, r_width, r_height); } else { *r_width = IMG_SIZE_FALLBACK; diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc index 6edb9e1b24c..6506b40b603 100644 --- a/source/blender/blenkernel/intern/image_gpu.cc +++ b/source/blender/blenkernel/intern/image_gpu.cc @@ -737,11 +737,11 @@ static void gpu_texture_update_from_ibuf( } else { /* Byte image is in original colorspace from the file, and may need conversion. */ - if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) || - IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) { + if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) { /* Non-color data, just store buffer as is. */ } - else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) { + else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) || + IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) { /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */ rect = (uchar *)MEM_mallocN(sizeof(uchar[4]) * w * h, __func__); if (rect == nullptr) { diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index 3f6f81845e2..cd86d3f7087 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -204,7 +204,7 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts, return (ibuf != nullptr); } -void BKE_image_save_options_update(ImageSaveOptions *opts, Image *image) +void BKE_image_save_options_update(ImageSaveOptions *opts, const Image *image) { /* Auto update color space when changing save as render and file type. */ if (opts->save_as_render) { @@ -272,7 +272,7 @@ static void image_save_post(ReportList *reports, Image *ima, ImBuf *ibuf, int ok, - ImageSaveOptions *opts, + const ImageSaveOptions *opts, int save_copy, const char *filepath, bool *r_colorspace_changed) @@ -359,7 +359,7 @@ static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf) static bool image_save_single(ReportList *reports, Image *ima, ImageUser *iuser, - ImageSaveOptions *opts, + const ImageSaveOptions *opts, bool *r_colorspace_changed) { void *lock; @@ -375,7 +375,7 @@ static bool image_save_single(ReportList *reports, ImBuf *colormanaged_ibuf = nullptr; const bool save_copy = opts->save_copy; const bool save_as_render = opts->save_as_render; - ImageFormatData *imf = &opts->im_format; + const ImageFormatData *imf = &opts->im_format; if (ima->type == IMA_TYPE_R_RESULT) { /* enforce user setting for RGB or RGBA, but skip BW */ @@ -620,7 +620,7 @@ static bool image_save_single(ReportList *reports, } bool BKE_image_save( - ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts) + ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts) { /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */ ImageUser save_iuser; diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 594cffe6406..97eac0b9f91 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -191,7 +191,7 @@ static void shapekey_blend_read_expand(BlendExpander *expander, ID *id) IDTypeInfo IDType_ID_KE = { .id_code = ID_KE, - .id_filter = 0, + .id_filter = FILTER_ID_KE, .main_listbase_index = INDEX_ID_KE, .struct_size = sizeof(Key), .name = "Key", diff --git a/source/blender/blenkernel/intern/lib_id_remapper.cc b/source/blender/blenkernel/intern/lib_id_remapper.cc index 7e75e0f5d93..98ac9110a48 100644 --- a/source/blender/blenkernel/intern/lib_id_remapper.cc +++ b/source/blender/blenkernel/intern/lib_id_remapper.cc @@ -36,6 +36,7 @@ struct IDRemapper { BLI_assert(old_id != nullptr); BLI_assert(new_id == nullptr || (GS(old_id->name) == GS(new_id->name))); mappings.add(old_id, new_id); + BLI_assert(BKE_idtype_idcode_to_idfilter(GS(old_id->name)) != 0); source_types |= BKE_idtype_idcode_to_idfilter(GS(old_id->name)); } diff --git a/source/blender/blenkernel/intern/lib_id_test.cc b/source/blender/blenkernel/intern/lib_id_test.cc index d6101d71be5..1aba78eed8f 100644 --- a/source/blender/blenkernel/intern/lib_id_test.cc +++ b/source/blender/blenkernel/intern/lib_id_test.cc @@ -18,19 +18,18 @@ namespace blender::bke::tests { struct LibIDMainSortTestContext { - Main *bmain; -}; + Main *bmain = nullptr; -static void test_lib_id_main_sort_init(LibIDMainSortTestContext *ctx) -{ - BKE_idtype_init(); - ctx->bmain = BKE_main_new(); -} - -static void test_lib_id_main_sort_free(LibIDMainSortTestContext *ctx) -{ - BKE_main_free(ctx->bmain); -} + LibIDMainSortTestContext() + { + BKE_idtype_init(); + bmain = BKE_main_new(); + } + ~LibIDMainSortTestContext() + { + BKE_main_free(bmain); + } +}; static void test_lib_id_main_sort_check_order(std::initializer_list<ID *> list) { @@ -47,8 +46,7 @@ static void test_lib_id_main_sort_check_order(std::initializer_list<ID *> list) TEST(lib_id_main_sort, local_ids_1) { - LibIDMainSortTestContext ctx = {nullptr}; - test_lib_id_main_sort_init(&ctx); + LibIDMainSortTestContext ctx; EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries)); ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C")); @@ -57,14 +55,22 @@ TEST(lib_id_main_sort, local_ids_1) EXPECT_TRUE(ctx.bmain->objects.first == id_a); EXPECT_TRUE(ctx.bmain->objects.last == id_c); test_lib_id_main_sort_check_order({id_a, id_b, id_c}); +} - test_lib_id_main_sort_free(&ctx); +static void change_lib(Main * /*bmain*/, ID *id, Library *lib) +{ + id->lib = lib; +} + +static void change_name(Main *bmain, ID *id, const char *name) +{ + BLI_strncpy(id->name + 2, name, MAX_NAME); + BKE_id_new_name_validate(&bmain->objects, id, nullptr, true); } TEST(lib_id_main_sort, linked_ids_1) { - LibIDMainSortTestContext ctx = {nullptr}; - test_lib_id_main_sort_init(&ctx); + LibIDMainSortTestContext ctx; EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries)); Library *lib_a = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_A")); @@ -92,14 +98,11 @@ TEST(lib_id_main_sort, linked_ids_1) EXPECT_TRUE(ctx.bmain->objects.first == id_c); EXPECT_TRUE(ctx.bmain->objects.last == id_b); test_lib_id_main_sort_check_order({id_c, id_a, id_b}); - - test_lib_id_main_sort_free(&ctx); } TEST(lib_id_main_unique_name, local_ids_1) { - LibIDMainSortTestContext ctx = {nullptr}; - test_lib_id_main_sort_init(&ctx); + LibIDMainSortTestContext ctx; EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries)); ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C")); @@ -107,21 +110,18 @@ TEST(lib_id_main_unique_name, local_ids_1) ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B")); test_lib_id_main_sort_check_order({id_a, id_b, id_c}); - BLI_strncpy(id_c->name, id_a->name, sizeof(id_c->name)); - BKE_id_new_name_validate(&ctx.bmain->objects, id_c, nullptr, false); - EXPECT_TRUE(strcmp(id_c->name + 2, "OB_A.001") == 0); - EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0); + change_name(ctx.bmain, id_c, "OB_A"); + + EXPECT_STREQ(id_c->name + 2, "OB_A.001"); + EXPECT_STREQ(id_a->name + 2, "OB_A"); EXPECT_TRUE(ctx.bmain->objects.first == id_a); EXPECT_TRUE(ctx.bmain->objects.last == id_b); test_lib_id_main_sort_check_order({id_a, id_c, id_b}); - - test_lib_id_main_sort_free(&ctx); } TEST(lib_id_main_unique_name, linked_ids_1) { - LibIDMainSortTestContext ctx = {nullptr}; - test_lib_id_main_sort_init(&ctx); + LibIDMainSortTestContext ctx; EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries)); Library *lib_a = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_A")); @@ -130,29 +130,263 @@ TEST(lib_id_main_unique_name, linked_ids_1) ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A")); ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B")); - id_a->lib = lib_a; + change_lib(ctx.bmain, id_a, lib_a); id_sort_by_name(&ctx.bmain->objects, id_a, nullptr); - id_b->lib = lib_a; + change_lib(ctx.bmain, id_b, lib_a); id_sort_by_name(&ctx.bmain->objects, id_b, nullptr); - BLI_strncpy(id_b->name, id_a->name, sizeof(id_b->name)); - BKE_id_new_name_validate(&ctx.bmain->objects, id_b, nullptr, true); - EXPECT_TRUE(strcmp(id_b->name + 2, "OB_A.001") == 0); - EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0); + + change_name(ctx.bmain, id_b, "OB_A"); + EXPECT_STREQ(id_b->name + 2, "OB_A.001"); + EXPECT_STREQ(id_a->name + 2, "OB_A"); EXPECT_TRUE(ctx.bmain->objects.first == id_c); EXPECT_TRUE(ctx.bmain->objects.last == id_b); test_lib_id_main_sort_check_order({id_c, id_a, id_b}); - id_b->lib = lib_b; + change_lib(ctx.bmain, id_b, lib_b); id_sort_by_name(&ctx.bmain->objects, id_b, nullptr); - BLI_strncpy(id_b->name, id_a->name, sizeof(id_b->name)); - BKE_id_new_name_validate(&ctx.bmain->objects, id_b, nullptr, true); - EXPECT_TRUE(strcmp(id_b->name + 2, "OB_A") == 0); - EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0); + change_name(ctx.bmain, id_b, "OB_A"); + EXPECT_STREQ(id_b->name + 2, "OB_A"); + EXPECT_STREQ(id_a->name + 2, "OB_A"); EXPECT_TRUE(ctx.bmain->objects.first == id_c); EXPECT_TRUE(ctx.bmain->objects.last == id_b); test_lib_id_main_sort_check_order({id_c, id_a, id_b}); +} + +TEST(lib_id_main_unique_name, ids_sorted_by_default) +{ + LibIDMainSortTestContext ctx; + + ID *id_foo = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + ID *id_bar = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Bar")); + ID *id_baz = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Baz")); + ID *id_yes = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Yes")); + test_lib_id_main_sort_check_order({id_bar, id_baz, id_foo, id_yes}); +} + +static ID *add_id_in_library(Main *bmain, const char *name, Library *lib) +{ + ID *id = static_cast<ID *>(BKE_id_new(bmain, ID_OB, name)); + id->lib = lib; + id_sort_by_name(&bmain->objects, id, nullptr); + return id; +} + +TEST(lib_id_main_unique_name, ids_sorted_by_default_with_libraries) +{ + LibIDMainSortTestContext ctx; + + Library *lib_one = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LibOne")); + Library *lib_two = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LibTwo")); + + ID *id_foo = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + ID *id_bar = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Bar")); + + ID *id_l1c = add_id_in_library(ctx.bmain, "C", lib_one); + ID *id_l2b = add_id_in_library(ctx.bmain, "B", lib_two); + ID *id_l1a = add_id_in_library(ctx.bmain, "A", lib_one); + + ID *id_baz = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Baz")); + ID *id_yes = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Yes")); + + test_lib_id_main_sort_check_order({id_bar, id_baz, id_foo, id_yes, id_l1a, id_l1c, id_l2b}); +} + +TEST(lib_id_main_unique_name, name_too_long_handling) +{ + LibIDMainSortTestContext ctx; + const char *name_a = "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated"; + const char *name_b = "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix.123456"; + const char *name_c = "Name_That_Has_Too_Long_Number_Suffix.1234567890"; + + ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, name_a)); + ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, name_b)); + ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, name_c)); + + EXPECT_STREQ(id_a->name + 2, "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_"); + EXPECT_STREQ(id_b->name + 2, "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix.123"); + EXPECT_STREQ(id_c->name + 2, "Name_That_Has_Too_Long_Number_Suffix.1234567890"); /* Unchanged */ +} + +TEST(lib_id_main_unique_name, create_equivalent_numeric_suffixes) +{ + LibIDMainSortTestContext ctx; + + /* Create names where many of their numeric suffixes are + * the same number, yet the names are different and thus + * should be allowed as-is. */ + ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123")); + ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.000")); + ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.003")); + ID *id_d = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.3")); + ID *id_e = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0")); + ID *id_f = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.")); + ID *id_g = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0123")); + ID *id_h = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + ID *id_i = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..")); + ID *id_j = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..001")); + ID *id_k = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..000")); + + EXPECT_STREQ(id_a->name + 2, "Foo.123"); + EXPECT_STREQ(id_b->name + 2, "Foo.000"); + EXPECT_STREQ(id_c->name + 2, "Foo.003"); + EXPECT_STREQ(id_d->name + 2, "Foo.3"); + EXPECT_STREQ(id_e->name + 2, "Foo.0"); + EXPECT_STREQ(id_f->name + 2, "Foo."); + EXPECT_STREQ(id_g->name + 2, "Foo.0123"); + EXPECT_STREQ(id_h->name + 2, "Foo"); + EXPECT_STREQ(id_i->name + 2, "Foo.."); + EXPECT_STREQ(id_j->name + 2, "Foo..001"); + EXPECT_STREQ(id_k->name + 2, "Foo..000"); + + /* Now create their exact duplicates again, and check what happens. */ + id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123")); + id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.000")); + id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.003")); + id_d = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.3")); + id_e = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0")); + id_f = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.")); + id_g = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0123")); + id_h = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + id_i = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..")); + id_j = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..001")); + id_k = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..000")); + + EXPECT_STREQ(id_a->name + 2, "Foo.001"); + EXPECT_STREQ(id_b->name + 2, "Foo.002"); + EXPECT_STREQ(id_c->name + 2, "Foo.004"); + EXPECT_STREQ(id_d->name + 2, "Foo.005"); + EXPECT_STREQ(id_e->name + 2, "Foo.006"); + EXPECT_STREQ(id_f->name + 2, "Foo..002"); + EXPECT_STREQ(id_g->name + 2, "Foo.007"); + EXPECT_STREQ(id_h->name + 2, "Foo.008"); + EXPECT_STREQ(id_i->name + 2, "Foo...001"); + EXPECT_STREQ(id_j->name + 2, "Foo..003"); + EXPECT_STREQ(id_k->name + 2, "Foo..004"); +} + +TEST(lib_id_main_unique_name, zero_suffix_is_never_assigned) +{ + LibIDMainSortTestContext ctx; + + /* Creating these should assign 002 to the first one, but the next + * ones should start numbers starting from 1: 001 and 003. */ + ID *id_002 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.002")); + ID *id_001 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.002")); + ID *id_003 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.002")); + + EXPECT_STREQ(id_002->name + 2, "Foo.002"); + EXPECT_STREQ(id_001->name + 2, "Foo.001"); + EXPECT_STREQ(id_003->name + 2, "Foo.003"); +} + +TEST(lib_id_main_unique_name, remove_after_dup_get_original_name) +{ + LibIDMainSortTestContext ctx; + + ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + + EXPECT_STREQ(id_a->name + 2, "Foo"); + EXPECT_STREQ(id_b->name + 2, "Foo.001"); + BKE_id_free(ctx.bmain, id_a); + + id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + EXPECT_STREQ(id_a->name + 2, "Foo"); +} + +TEST(lib_id_main_unique_name, name_number_suffix_assignment) +{ + LibIDMainSortTestContext ctx; + + /* Create <1k objects first. */ + const int total_object_count = 1200; + ID *ids[total_object_count] = {}; + for (int i = 0; i < total_object_count / 2; ++i) { + ids[i] = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + } + + /* They should get assigned sequential numeric suffixes. */ + EXPECT_STREQ(ids[0]->name + 2, "Foo"); + EXPECT_STREQ(ids[1]->name + 2, "Foo.001"); + EXPECT_STREQ(ids[total_object_count / 2 - 1]->name + 2, "Foo.599"); + + /* Free some of the objects. */ + BKE_id_free(ctx.bmain, ids[10]); + BKE_id_free(ctx.bmain, ids[20]); + BKE_id_free(ctx.bmain, ids[30]); + + /* Create objects again; they should get suffixes that were just free'd up. */ + ID *id_010 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + EXPECT_STREQ(id_010->name + 2, "Foo.010"); + ID *id_020 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123")); + EXPECT_STREQ(id_020->name + 2, "Foo.020"); + /* Suffixes >1k do not get the "use the most proper free one" treatment. */ + ID *id_2000 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.2000")); + EXPECT_STREQ(id_2000->name + 2, "Foo.2000"); + /* But smaller than 1k suffixes do get proper empty spots. */ + ID *id_030 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + EXPECT_STREQ(id_030->name + 2, "Foo.030"); + ID *id_600 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + EXPECT_STREQ(id_600->name + 2, "Foo.600"); + + /* Max possible numeric suffix. */ + ID *id_max = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.999999999")); + EXPECT_STREQ(id_max->name + 2, "Foo.999999999"); + /* Try with max. possible suffix again: will assign free suffix under 1k. */ + ID *id_max1 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.999999999")); + EXPECT_STREQ(id_max1->name + 2, "Foo.601"); + + /* Now create the rest of objects, to use all the suffixes up to 1k. + * Once all the ones up to 1k are used, the logic will fall back to + * "use largest number seen + 1", but the largest one is already the max + * possible. So it will shorten the name part and restart the counter, + * i.e. "Fo.001". */ + for (int i = total_object_count / 2; i < total_object_count; ++i) { + ids[i] = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + } + /* At this point creating "Foo" based objects will fall always + * result in shortened name to "Fo". */ + ID *id_fo178 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + EXPECT_STREQ(id_fo178->name + 2, "Fo.178"); + ID *id_fo179 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.2000")); + EXPECT_STREQ(id_fo179->name + 2, "Fo.179"); + ID *id_fo180 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.999999999")); + EXPECT_STREQ(id_fo180->name + 2, "Fo.180"); +} + +TEST(lib_id_main_unique_name, renames_with_duplicates) +{ + LibIDMainSortTestContext ctx; + + ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Bar")); + + EXPECT_STREQ(id_a->name + 2, "Foo"); + EXPECT_STREQ(id_b->name + 2, "Foo.001"); + EXPECT_STREQ(id_c->name + 2, "Bar"); + + BKE_libblock_rename(ctx.bmain, id_a, "Foo.002"); + EXPECT_STREQ(id_a->name + 2, "Foo.002"); + BKE_libblock_rename(ctx.bmain, id_b, "Bar"); + EXPECT_STREQ(id_b->name + 2, "Bar.001"); + BKE_libblock_rename(ctx.bmain, id_c, "Foo"); + EXPECT_STREQ(id_c->name + 2, "Foo"); + BKE_libblock_rename(ctx.bmain, id_b, "Bar"); + EXPECT_STREQ(id_b->name + 2, "Bar"); +} + +TEST(lib_id_main_unique_name, names_are_unique_per_id_type) +{ + LibIDMainSortTestContext ctx; + + ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); + ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_CA, "Foo")); + ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); - test_lib_id_main_sort_free(&ctx); + EXPECT_STREQ(id_a->name + 2, "Foo"); + EXPECT_STREQ(id_b->name + 2, "Foo"); /* Different types (OB & CA) can have the same name. */ + EXPECT_STREQ(id_c->name + 2, "Foo.001"); } } // namespace blender::bke::tests diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc index d816b5ede5f..0c5f59be768 100644 --- a/source/blender/blenkernel/intern/lib_override.cc +++ b/source/blender/blenkernel/intern/lib_override.cc @@ -428,14 +428,42 @@ static void lib_override_prefill_newid_from_existing_overrides(Main *bmain, ID * { ID *id_iter; FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { - if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter) && - id_iter->override_library->hierarchy_root == id_hierarchy_root) { - id_iter->override_library->reference->newid = id_iter; + ID *id = id_iter; + if (GS(id_iter->name) == ID_KE) { + id = reinterpret_cast<Key *>(id_iter)->from; + BLI_assert(id != nullptr); + } + if (ID_IS_OVERRIDE_LIBRARY_REAL(id) && + id->override_library->hierarchy_root == id_hierarchy_root) { + id->override_library->reference->newid = id; + if (GS(id_iter->name) == ID_KE) { + Key *reference_key = BKE_key_from_id(id->override_library->reference); + if (reference_key != nullptr) { + reference_key->id.newid = id_iter; + } + } } } FOREACH_MAIN_ID_END; } +static void lib_override_remapper_overrides_add(IDRemapper *id_remapper, + ID *reference_id, + ID *local_id) +{ + BKE_id_remapper_add(id_remapper, reference_id, local_id); + + Key *reference_key, *local_key = nullptr; + if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) { + if (reference_id->newid != nullptr) { + local_key = BKE_key_from_id(reference_id->newid); + BLI_assert(local_key != nullptr); + } + + BKE_id_remapper_add(id_remapper, &reference_key->id, &local_key->id); + } +} + /* TODO: Make this static local function instead? API is becoming complex, and it's not used * outside of this file anyway. */ bool BKE_lib_override_library_create_from_tag(Main *bmain, @@ -544,6 +572,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, BLI_assert(id_hierarchy_root != nullptr); LinkNode *relinked_ids = nullptr; + IDRemapper *id_remapper = BKE_id_remapper_create(); /* Still checking the whole Main, that way we can tag other local IDs as needing to be * remapped to use newly created overriding IDs, if needed. */ ID *id; @@ -568,6 +597,14 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, * consider we should also relink it, as part of recursive resync. */ if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib != id_root_reference->lib) { BLI_linklist_prepend(&relinked_ids, other_id); + if (ID_IS_OVERRIDE_LIBRARY_REAL(other_id) && + other_id->override_library->hierarchy_root == id_hierarchy_root) { + reference_id = other_id->override_library->reference; + ID *local_id = reference_id->newid; + if (other_id == local_id) { + lib_override_remapper_overrides_add(id_remapper, reference_id, local_id); + } + } } if (other_id != id) { other_id->lib = id_root_reference->lib; @@ -575,7 +612,6 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, } FOREACH_MAIN_ID_END; - IDRemapper *id_remapper = BKE_id_remapper_create(); for (todo_id_iter = static_cast<LinkData *>(todo_ids.first); todo_id_iter != nullptr; todo_id_iter = todo_id_iter->next) { reference_id = static_cast<ID *>(todo_id_iter->data); @@ -587,15 +623,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, local_id->override_library->hierarchy_root = id_hierarchy_root; - BKE_id_remapper_add(id_remapper, reference_id, local_id); - - Key *reference_key, *local_key = nullptr; - if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) { - local_key = BKE_key_from_id(reference_id->newid); - BLI_assert(local_key != nullptr); - - BKE_id_remapper_add(id_remapper, &reference_key->id, &local_key->id); - } + lib_override_remapper_overrides_add(id_remapper, reference_id, local_id); } BKE_libblock_relink_multiple(bmain, @@ -1121,14 +1149,26 @@ static bool lib_override_library_create_do(Main *bmain, BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); lib_override_hierarchy_dependencies_recursive_tag(&data); + /* In case the operation is on an already partially overridden hierarchy, all existing overrides + * in that hierarchy need to be tagged for remapping from linked reference ID usages to newly + * created overrides ones. */ + if (id_hierarchy_root_reference->lib != id_root_reference->lib) { + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference)); + BLI_assert(id_hierarchy_root_reference->override_library->reference->lib == + id_root_reference->lib); + + BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); + data.hierarchy_root_id = id_hierarchy_root_reference; + data.id_root = id_hierarchy_root_reference; + data.is_override = true; + lib_override_overrides_group_tag(&data); + } + BKE_main_relations_free(bmain); lib_override_group_tag_data_clear(&data); bool success = false; if (id_hierarchy_root_reference->lib != id_root_reference->lib) { - BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference)); - BLI_assert(id_hierarchy_root_reference->override_library->reference->lib == - id_root_reference->lib); success = BKE_lib_override_library_create_from_tag(bmain, owner_library, id_root_reference, @@ -1771,6 +1811,11 @@ static bool lib_override_library_resync(Main *bmain, break; } } + if (reference_id == nullptr) { + /* Can happen e.g. when there is a local override of a shapekey, but the matching linked + * obdata (mesh etc.) does not have any shapekey anymore. */ + continue; + } BLI_assert(GS(reference_id->name) == GS(id->name)); if (!BLI_ghash_haskey(linkedref_to_old_override, reference_id)) { diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 38252a46b93..a869bf4c4b0 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -391,8 +391,7 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner) switch ((ID_Type)id_type_owner) { case ID_LI: - /* ID_LI doesn't exist as filter_id. */ - return 0; + return FILTER_ID_LI; case ID_SCE: return FILTER_ID_OB | FILTER_ID_WO | FILTER_ID_SCE | FILTER_ID_MC | FILTER_ID_MA | FILTER_ID_GR | FILTER_ID_TXT | FILTER_ID_LS | FILTER_ID_MSK | FILTER_ID_SO | @@ -472,6 +471,8 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner) /* Deprecated... */ return 0; } + + BLI_assert_unreachable(); return 0; } diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 246999a1179..28b0337d9a2 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -428,10 +428,13 @@ static void libblock_remap_data_update_tags(ID *old_id, ID *new_id, void *user_d } static void libblock_remap_reset_remapping_status_callback(ID *old_id, - ID *UNUSED(new_id), + ID *new_id, void *UNUSED(user_data)) { BKE_libblock_runtime_reset_remapping_status(old_id); + if (new_id != NULL) { + BKE_libblock_runtime_reset_remapping_status(new_id); + } } /** diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 03a17b2ecc5..4962b1c448e 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -63,7 +63,7 @@ static void library_foreach_path(ID *id, BPathForeachPathData *bpath_data) IDTypeInfo IDType_ID_LI = { .id_code = ID_LI, - .id_filter = 0, + .id_filter = FILTER_ID_LI, .main_listbase_index = INDEX_ID_LI, .struct_size = sizeof(Library), .name = "Library", diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 2a14370bf93..cf05dc0404e 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1190,6 +1190,11 @@ static void ensure_orig_index_layer(CustomData &data, const int size) void BKE_mesh_ensure_default_orig_index_customdata(Mesh *mesh) { BLI_assert(mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA); + BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh); +} + +void BKE_mesh_ensure_default_orig_index_customdata_no_check(Mesh *mesh) +{ ensure_orig_index_layer(mesh->vdata, mesh->totvert); ensure_orig_index_layer(mesh->edata, mesh->totedge); ensure_orig_index_layer(mesh->pdata, mesh->totpoly); diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 7ebb3e25fd4..923d2703960 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -751,6 +751,8 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene), void BKE_pointcloud_from_mesh(Mesh *me, PointCloud *pointcloud) { + using namespace blender; + BLI_assert(me != nullptr); pointcloud->totpoint = me->totvert; @@ -758,14 +760,17 @@ void BKE_pointcloud_from_mesh(Mesh *me, PointCloud *pointcloud) /* Copy over all attributes. */ CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, CD_DUPLICATE, me->totvert); - BKE_pointcloud_update_customdata_pointers(pointcloud); - CustomData_update_typemap(&pointcloud->pdata); - MVert *mvert; - mvert = me->mvert; - for (int i = 0; i < me->totvert; i++, mvert++) { - copy_v3_v3(pointcloud->co[i], mvert->co); - } + bke::AttributeAccessor mesh_attributes = bke::mesh_attributes(*me); + bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write( + *pointcloud); + + const VArray<float3> mesh_positions = mesh_attributes.lookup_or_default<float3>( + "position", ATTR_DOMAIN_POINT, float3(0)); + bke::SpanAttributeWriter<float3> point_positions = + point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT); + mesh_positions.materialize(point_positions.span); + point_positions.finish(); } void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob) diff --git a/source/blender/blenkernel/intern/mesh_merge_customdata.cc b/source/blender/blenkernel/intern/mesh_merge_customdata.cc index adaf378ed27..7bc429954b0 100644 --- a/source/blender/blenkernel/intern/mesh_merge_customdata.cc +++ b/source/blender/blenkernel/intern/mesh_merge_customdata.cc @@ -33,11 +33,11 @@ static int compare_v2_classify(const float uv_a[2], const float uv_b[2]) if (uv_a[0] == uv_b[0] && uv_a[1] == uv_b[1]) { return CMP_EQUAL; } - /* Note that the ULP value is the primary value used to compare relative values - * as the absolute value doesn't account for float precision at difference scales. + /* NOTE(@campbellbarton): that the ULP value is the primary value used to compare relative + * values as the absolute value doesn't account for float precision at difference scales. * - For subdivision-surface ULP of 3 is sufficient, * although this value is extremely small. - * - For bevel the URL of 12 is sufficient to merge UV's that appear to be connected + * - For bevel the ULP of 12 is sufficient to merge UV's that appear to be connected * with bevel on Suzanne beveled 15% with 6 segments. * * These values could be tweaked but should be kept on the small side to prevent diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc index 0362e4866e3..0b61b876abe 100644 --- a/source/blender/blenkernel/intern/mesh_wrapper.cc +++ b/source/blender/blenkernel/intern/mesh_wrapper.cc @@ -103,11 +103,7 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me) /* Must isolate multithreaded tasks while holding a mutex lock. */ blender::threading::isolate_task([&]() { - const eMeshWrapperType geom_type_orig = static_cast<eMeshWrapperType>( - me->runtime.wrapper_type); - me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA; - - switch (geom_type_orig) { + switch (static_cast<eMeshWrapperType>(me->runtime.wrapper_type)) { case ME_WRAPPER_TYPE_MDATA: case ME_WRAPPER_TYPE_SUBD: { break; /* Quiet warning. */ @@ -132,7 +128,7 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me) * There is also a performance aspect, where this also assumes that original indices are * always needed when converting an edit mesh to a mesh. That might be wrong, but it's not * harmful. */ - BKE_mesh_ensure_default_orig_index_customdata(me); + BKE_mesh_ensure_default_orig_index_customdata_no_check(me); EditMeshData *edit_data = me->runtime.edit_data; if (edit_data->vertexCos) { @@ -144,8 +140,12 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me) } if (me->runtime.wrapper_type_finalize) { - BKE_mesh_wrapper_deferred_finalize(me, &me->runtime.cd_mask_extra); + BKE_mesh_wrapper_deferred_finalize_mdata(me, &me->runtime.cd_mask_extra); } + + /* Keep type assignment last, so that read-only access only uses the mdata code paths after all + * the underlying data has been initialized. */ + me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA; }); BLI_mutex_unlock(mesh_eval_mutex); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 6348d83362e..831ea084961 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -456,6 +456,40 @@ void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *_for CLOG_ERROR(&LOG, "Object: \"%s\", Modifier: \"%s\", %s", ob->id.name + 2, md->name, md->error); } +void BKE_modifier_set_warning(const struct Object *ob, + struct ModifierData *md, + const char *_format, + ...) +{ + char buffer[512]; + va_list ap; + const char *format = TIP_(_format); + + va_start(ap, _format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + buffer[sizeof(buffer) - 1] = '\0'; + + /* Store the warning in the same field as the error. + * It is not expected to have both error and warning and having a single place to store the + * message simplifies interface code. */ + + if (md->error) { + MEM_freeN(md->error); + } + + md->error = BLI_strdup(buffer); + +#ifndef NDEBUG + if ((md->mode & eModifierMode_Virtual) == 0) { + /* Ensure correct object is passed in. */ + BLI_assert(BKE_modifier_get_original(ob, md) != NULL); + } +#endif + + UNUSED_VARS_NDEBUG(ob); +} + int BKE_modifiers_get_cage_index(const Scene *scene, Object *ob, int *r_lastPossibleCageIndex, diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index f7436b6112c..62ebb45b0ed 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -1402,6 +1402,7 @@ bool BKE_object_supports_modifiers(const Object *ob) { return (ELEM(ob->type, OB_MESH, + OB_CURVES, OB_CURVES_LEGACY, OB_SURF, OB_FONT, diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 89cc25b31e6..9b0d15ac702 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -996,6 +996,12 @@ bool BKE_paint_select_elem_test(Object *ob) return (BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob)); } +bool BKE_paint_always_hide_test(Object *ob) +{ + return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) && + (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT)); +} + void BKE_paint_cavity_curve_preset(Paint *p, int preset) { CurveMapping *cumap = NULL; @@ -2255,12 +2261,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) return NULL; } - bool respect_hide = true; - if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { - if (!(BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob))) { - respect_hide = false; - } - } + const bool respect_hide = true; PBVH *pbvh = ob->sculpt->pbvh; if (pbvh != NULL) { diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index e38c20d8eb7..261b053e4f9 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -68,7 +68,6 @@ static void pointcloud_init_data(ID *id) nullptr, pointcloud->totpoint, POINTCLOUD_ATTR_POSITION); - BKE_pointcloud_update_customdata_pointers(pointcloud); } static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) @@ -83,7 +82,6 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s CD_MASK_ALL, alloc_type, pointcloud_dst->totpoint); - BKE_pointcloud_update_customdata_pointers(pointcloud_dst); pointcloud_dst->batch_cache = nullptr; } @@ -138,7 +136,6 @@ static void pointcloud_blend_read_data(BlendDataReader *reader, ID *id) /* Geometry */ CustomData_blend_read(reader, &pointcloud->pdata, pointcloud->totpoint); - BKE_pointcloud_update_customdata_pointers(pointcloud); /* Materials */ BLO_read_pointer_array(reader, (void **)&pointcloud->mat); @@ -194,17 +191,28 @@ static void pointcloud_random(PointCloud *pointcloud) { pointcloud->totpoint = 400; CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint); - BKE_pointcloud_update_customdata_pointers(pointcloud); RNG *rng = BLI_rng_new(0); - for (int i = 0; i < pointcloud->totpoint; i++) { - pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f; - pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f; - pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f; - pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng); + blender::bke::MutableAttributeAccessor attributes = + blender::bke::pointcloud_attributes_for_write(*pointcloud); + blender::bke::SpanAttributeWriter positions = + attributes.lookup_or_add_for_write_only_span<float3>(POINTCLOUD_ATTR_POSITION, + ATTR_DOMAIN_POINT); + blender::bke::SpanAttributeWriter<float> radii = + attributes.lookup_or_add_for_write_only_span<float>(POINTCLOUD_ATTR_RADIUS, + ATTR_DOMAIN_POINT); + + for (const int i : positions.span.index_range()) { + positions.span[i] = + float3(BLI_rng_get_float(rng), BLI_rng_get_float(rng), BLI_rng_get_float(rng)) * 2.0f - + 1.0f; + radii.span[i] = 0.05f * BLI_rng_get_float(rng); } + positions.finish(); + radii.finish(); + BLI_rng_free(rng); } @@ -250,7 +258,6 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) pointcloud->totpoint = totpoint; CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint); - BKE_pointcloud_update_customdata_pointers(pointcloud); return pointcloud; } @@ -258,10 +265,14 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) static std::optional<blender::bounds::MinMaxResult<float3>> point_cloud_bounds( const PointCloud &pointcloud) { - Span<float3> positions{reinterpret_cast<float3 *>(pointcloud.co), pointcloud.totpoint}; - if (pointcloud.radius) { - Span<float> radii{pointcloud.radius, pointcloud.totpoint}; - return blender::bounds::min_max_with_radii(positions, radii); + blender::bke::AttributeAccessor attributes = blender::bke::pointcloud_attributes(pointcloud); + blender::VArraySpan<float3> positions = attributes.lookup_or_default<float3>( + POINTCLOUD_ATTR_POSITION, ATTR_DOMAIN_POINT, float3(0)); + blender::VArray<float> radii = attributes.lookup_or_default<float>( + POINTCLOUD_ATTR_RADIUS, ATTR_DOMAIN_POINT, 0.0f); + + if (!(radii.is_single() && radii.get_internal_single() == 0.0f)) { + return blender::bounds::min_max_with_radii(positions, radii.get_internal_span()); } return blender::bounds::min_max(positions); } @@ -307,14 +318,6 @@ BoundBox *BKE_pointcloud_boundbox_get(Object *ob) return ob->runtime.bb; } -void BKE_pointcloud_update_customdata_pointers(PointCloud *pointcloud) -{ - pointcloud->co = static_cast<float(*)[3]>( - CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT3, POINTCLOUD_ATTR_POSITION)); - pointcloud->radius = static_cast<float *>( - CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, POINTCLOUD_ATTR_RADIUS)); -} - bool BKE_pointcloud_customdata_required(const PointCloud *UNUSED(pointcloud), const char *name) { return STREQ(name, POINTCLOUD_ATTR_POSITION); @@ -334,7 +337,6 @@ PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int to pointcloud_dst->totpoint = totpoint; CustomData_copy( &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, CD_CALLOC, totpoint); - BKE_pointcloud_update_customdata_pointers(pointcloud_dst); return pointcloud_dst; } diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index 39157bc9890..e2da27fc840 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -2952,6 +2952,20 @@ int BKE_scene_num_threads(const Scene *scene) return BKE_render_num_threads(&scene->r); } +void BKE_render_resolution(const struct RenderData *r, + const bool use_crop, + int *r_width, + int *r_height) +{ + *r_width = (r->xsch * r->size) / 100; + *r_height = (r->ysch * r->size) / 100; + + if (use_crop && (r->mode & R_BORDER) && (r->mode & R_CROP)) { + *r_width *= BLI_rctf_size_x(&r->border); + *r_height *= BLI_rctf_size_y(&r->border); + } +} + int BKE_render_preview_pixel_size(const RenderData *r) { if (r->preview_pixel_size == 0) { diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 12dc1b6d1fa..c16e5ce5655 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -277,7 +277,7 @@ static void screen_blend_read_lib(BlendLibReader *reader, ID *id) IDTypeInfo IDType_ID_SCR = { .id_code = ID_SCR, - .id_filter = 0, + .id_filter = FILTER_ID_SCR, .main_listbase_index = INDEX_ID_SCR, .struct_size = sizeof(bScreen), .name = "Screen", diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c index fda833ffd27..841b47818f1 100644 --- a/source/blender/blenkernel/intern/subdiv_eval.c +++ b/source/blender/blenkernel/intern/subdiv_eval.c @@ -34,8 +34,8 @@ static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type( case SUBDIV_EVALUATOR_TYPE_CPU: { return OPENSUBDIV_EVALUATOR_CPU; } - case SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE: { - return OPENSUBDIV_EVALUATOR_GLSL_COMPUTE; + case SUBDIV_EVALUATOR_TYPE_GPU: { + return OPENSUBDIV_EVALUATOR_GPU; } } BLI_assert_msg(0, "Unknown evaluator type"); diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c index 57af0192d59..2271fd90bda 100644 --- a/source/blender/blenkernel/intern/subdiv_modifier.c +++ b/source/blender/blenkernel/intern/subdiv_modifier.c @@ -98,11 +98,6 @@ static bool is_subdivision_evaluation_possible_on_gpu(void) return false; } - const int available_evaluators = openSubdiv_getAvailableEvaluators(); - if ((available_evaluators & OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) == 0) { - return false; - } - return true; } diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 5e11cd0703a..883591e3e87 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -1485,7 +1485,7 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset) } } -void BKE_ffmpeg_image_type_verify(RenderData *rd, ImageFormatData *imf) +void BKE_ffmpeg_image_type_verify(RenderData *rd, const ImageFormatData *imf) { int audio = 0; |