diff options
author | Joseph Eagar <joeedh@gmail.com> | 2022-03-29 08:54:24 +0300 |
---|---|---|
committer | Joseph Eagar <joeedh@gmail.com> | 2022-03-29 08:54:24 +0300 |
commit | 176b331c43c5378b0a346b7c96b0934c9c5bf19f (patch) | |
tree | 546efd965d57bfa16945c2ef1ab664b2a3667471 /source/blender/blenkernel | |
parent | 2f3ace40240797100161a659a12d995e1480b91b (diff) | |
parent | 540bfbbb27966b4b8affeaa273a70beac9373b23 (diff) |
Merge branch 'master' into temp-sculpt-colors
Diffstat (limited to 'source/blender/blenkernel')
49 files changed, 1635 insertions, 987 deletions
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh index 3075c0689e9..9efa64d1474 100644 --- a/source/blender/blenkernel/BKE_attribute_math.hh +++ b/source/blender/blenkernel/BKE_attribute_math.hh @@ -22,7 +22,7 @@ inline void convert_to_static_type(const CPPType &cpp_type, const Func &func) [&](auto type_tag) { using T = typename decltype(type_tag)::type; if constexpr (std::is_same_v<T, void>) { - /* It's expected that the given cpp type is one of the supported once. */ + /* It's expected that the given cpp type is one of the supported ones. */ BLI_assert_unreachable(); } else { diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index eb4f8f5d5c8..82f77d83bec 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -122,14 +122,14 @@ class CurvesGeometry : public ::CurvesGeometry { * Accessors. */ - int points_size() const; - int curves_size() const; + int points_num() const; + int curves_num() const; IndexRange points_range() const; IndexRange curves_range() const; /** * The index of the first point in every curve. The size of this span is one larger than the - * number of curves. Consider using #range_for_curve rather than using the offsets directly. + * number of curves. Consider using #points_for_curve rather than using the offsets directly. */ Span<int> offsets() const; MutableSpan<int> offsets(); @@ -137,8 +137,8 @@ class CurvesGeometry : public ::CurvesGeometry { /** * Access a range of indices of point data for a specific curve. */ - IndexRange range_for_curve(int index) const; - IndexRange range_for_curves(IndexRange curves) const; + IndexRange points_for_curve(int index) const; + IndexRange points_for_curves(IndexRange curves) const; /** The type (#CurveType) of each curve, or potentially a single if all are the same type. */ VArray<int8_t> curve_types() const; @@ -146,6 +146,8 @@ class CurvesGeometry : public ::CurvesGeometry { MutableSpan<int8_t> curve_types(); bool has_curve_with_type(const CurveType type) const; + /** Return the number of curves with each type. */ + std::array<int, CURVE_TYPES_NUM> count_curve_types() const; MutableSpan<float3> positions(); Span<float3> positions() const; @@ -243,23 +245,36 @@ class CurvesGeometry : public ::CurvesGeometry { * The total number of points in the evaluated poly curve. * This can depend on the resolution attribute if it exists. */ - int evaluated_points_size() const; + int evaluated_points_num() const; /** * Access a range of indices of point data for a specific curve. * Call #evaluated_offsets() first to ensure that the evaluated offsets cache is current. */ - IndexRange evaluated_range_for_curve(int index) const; + IndexRange evaluated_points_for_curve(int index) const; + IndexRange evaluated_points_for_curves(IndexRange curves) const; /** * The index of the first evaluated point for every curve. The size of this span is one larger - * than the number of curves. Consider using #evaluated_range_for_curve rather than using the + * than the number of curves. Consider using #evaluated_points_for_curve rather than using the * offsets directly. */ Span<int> evaluated_offsets() const; + /** Makes sure the data described by #evaluated_offsets if necessary. */ + void ensure_evaluated_offsets() const; + Span<float3> evaluated_positions() const; + /** + * Evaluate a generic data to the standard evaluated points of a specific curve, + * defined by the resolution attribute or other factors, depending on the curve type. + * + * \warning This function expects offsets to the evaluated points for each curve to be + * calculated. That can be ensured with #ensure_evaluated_offsets. + */ + void interpolate_to_evaluated(int curve_index, GSpan src, GMutableSpan dst) const; + private: /** * Make sure the basis weights for NURBS curve's evaluated points are calculated. @@ -275,7 +290,7 @@ class CurvesGeometry : public ::CurvesGeometry { * Change the number of elements. New values for existing attributes should be properly * initialized afterwards. */ - void resize(int point_size, int curve_size); + void resize(int points_num, int curves_num); /** Call after deforming the position attribute. */ void tag_positions_changed(); @@ -314,9 +329,9 @@ namespace curves { * and the fact that curves with two points cannot be cyclic. The logic is simple, but this * function should be used to make intentions clearer. */ -inline int curve_segment_size(const int size, const bool cyclic) +inline int curve_segment_size(const int points_num, const bool cyclic) { - return (cyclic && size > 2) ? size : size - 1; + return (cyclic && points_num > 2) ? points_num : points_num - 1; } namespace bezier { @@ -375,16 +390,23 @@ void calculate_evaluated_positions(Span<float3> positions, Span<int> evaluated_offsets, MutableSpan<float3> evaluated_positions); +/** + * Evaluate generic data to the evaluated points, with counts for each segment described by + * #evaluated_offsets. Unlike other curve types, for Bezier curves generic data and positions + * are treated separately, since attribute values aren't stored for the handle control points. + */ +void interpolate_to_evaluated(GSpan src, Span<int> evaluated_offsets, GMutableSpan dst); + } // namespace bezier namespace catmull_rom { /** * Calculate the number of evaluated points that #interpolate_to_evaluated is expected to produce. - * \param size: The number of points in the curve. + * \param points_num: The number of points in the curve. * \param resolution: The resolution for each segment. */ -int calculate_evaluated_size(int size, bool cyclic, int resolution); +int calculate_evaluated_size(int points_num, bool cyclic, int resolution); /** * Evaluate the Catmull Rom curve. The length of the #dst span should be calculated with @@ -399,7 +421,7 @@ namespace nurbs { /** * Checks the conditions that a NURBS curve needs to evaluate. */ -bool check_valid_size_and_order(int size, int8_t order, bool cyclic, KnotsMode knots_mode); +bool check_valid_size_and_order(int points_num, int8_t order, bool cyclic, KnotsMode knots_mode); /** * Calculate the standard evaluated size for a NURBS curve, using the standard that @@ -410,14 +432,14 @@ bool check_valid_size_and_order(int size, int8_t order, bool cyclic, KnotsMode k * shared. */ int calculate_evaluated_size( - int size, int8_t order, bool cyclic, int resolution, KnotsMode knots_mode); + int points_num, int8_t order, bool cyclic, int resolution, KnotsMode knots_mode); /** * Calculate the length of the knot vector for a NURBS curve with the given properties. * The knots must be longer for a cyclic curve, for example, in order to provide weights for the * last evaluated points that are also influenced by the first control points. */ -int knots_size(int size, int8_t order, bool cyclic); +int knots_size(int points_num, int8_t order, bool cyclic); /** * Calculate the knots for a spline given its properties, based on built-in standards defined by @@ -428,7 +450,7 @@ int knots_size(int size, int8_t order, bool cyclic); * changes, and is generally more intuitive than defining the knot vector manually. */ void calculate_knots( - int size, KnotsMode mode, int8_t order, bool cyclic, MutableSpan<float> knots); + int points_num, KnotsMode mode, int8_t order, bool cyclic, MutableSpan<float> knots); /** * Based on the knots, the order, and other properties of a NURBS curve, calculate a cache that can @@ -436,7 +458,7 @@ void calculate_knots( * two pieces of information for every evaluated point: the first control point that influences it, * and a weight for each control point. */ -void calculate_basis_cache(int size, +void calculate_basis_cache(int points_num, int evaluated_size, int8_t order, bool cyclic, @@ -461,11 +483,11 @@ void interpolate_to_evaluated(const BasisCache &basis_cache, } // namespace curves -Curves *curves_new_nomain(int point_size, int curves_size); +Curves *curves_new_nomain(int points_num, int curves_num); /** * Create a new curves data-block containing a single curve with the given length and type. */ -Curves *curves_new_nomain_single(int point_size, CurveType type); +Curves *curves_new_nomain_single(int points_num, CurveType type); } // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 911f4aab394..6b805a4c29d 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -589,7 +589,7 @@ void CustomData_layers__print(struct CustomData *data); /* External file storage */ void CustomData_external_add( - struct CustomData *data, struct ID *id, int type, int totelem, const char *filename); + struct CustomData *data, struct ID *id, int type, int totelem, const char *filepath); void CustomData_external_remove(struct CustomData *data, struct ID *id, int type, int totelem); bool CustomData_external_test(struct CustomData *data, int type); diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h index 5a1c99774fd..109d3e6d977 100644 --- a/source/blender/blenkernel/BKE_dynamicpaint.h +++ b/source/blender/blenkernel/BKE_dynamicpaint.h @@ -129,7 +129,7 @@ int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface, struct Object *cObject, int frame); void dynamicPaint_outputSurfaceImage(struct DynamicPaintSurface *surface, - char *filename, + const char *filepath, short output_layer); /* PaintPoint state */ diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index 4127030e96f..ad3b1971ca9 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -220,30 +220,78 @@ bool BKE_gpencil_stroke_sample(struct bGPdata *gpd, * \param gps: Stroke to smooth * \param i: Point index * \param inf: Amount of smoothing to apply + * \param iterations: Radius of points to consider, equivalent to iterations * \param smooth_caps: Apply smooth to stroke extremes + * \param keep_shape: Smooth out fine details first + * \param r_gps: Stroke to put the result into */ -bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps, int i, float inf, bool smooth_caps); +bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps, + int point_index, + float influence, + int iterations, + bool smooth_caps, + bool keep_shape, + struct bGPDstroke *r_gps); /** * Apply smooth strength to stroke point. * \param gps: Stroke to smooth * \param point_index: Point index * \param influence: Amount of smoothing to apply + * \param iterations: Radius of points to consider, equivalent to iterations + * \param r_gps: Stroke to put the result into */ -bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps, + int point_index, + float influence, + int iterations, + struct bGPDstroke *r_gps); /** * Apply smooth for thickness to stroke point (use pressure). * \param gps: Stroke to smooth * \param point_index: Point index * \param influence: Amount of smoothing to apply + * \param iterations: Radius of points to consider, equivalent to iterations + * \param r_gps: Stroke to put the result into */ -bool BKE_gpencil_stroke_smooth_thickness(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_stroke_smooth_thickness(struct bGPDstroke *gps, + int point_index, + float influence, + int iterations, + struct bGPDstroke *r_gps); /** - * Apply smooth for UV rotation to stroke point (use pressure). + * Apply smooth for UV rotation/factor to stroke point. * \param gps: Stroke to smooth * \param point_index: Point index * \param influence: Amount of smoothing to apply + * \param iterations: Radius of points to consider, equivalent to iterations + * \param r_gps: Stroke to put the result into */ -bool BKE_gpencil_stroke_smooth_uv(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_stroke_smooth_uv(struct bGPDstroke *gps, + int point_index, + float influence, + int iterations, + struct bGPDstroke *r_gps); +/** + * Apply smooth operation to the stroke. + * \param gps: Stroke to smooth + * \param influence: The interpolation factor for the smooth and the original stroke + * \param iterations: Radius of points to consider, equivalent to iterations + * \param smooth_position: Smooth point locations + * \param smooth_strength: Smooth point strength + * \param smooth_thickness: Smooth point thickness + * \param smooth_uv: Smooth uv rotation/factor + * \param keep_shape: Use different distribution for smooth locations to keep the shape + * \param weights: per point weights to multiply influence with (optional, can be null) + */ +void BKE_gpencil_stroke_smooth(struct bGPDstroke *gps, + const float influence, + const int iterations, + const bool smooth_position, + const bool smooth_strength, + const bool smooth_thickness, + const bool smooth_uv, + const bool keep_shape, + const float *weights); /** * Close grease pencil stroke. * \param gps: Stroke to close diff --git a/source/blender/blenkernel/BKE_image_partial_update.hh b/source/blender/blenkernel/BKE_image_partial_update.hh index 8cbb8819551..393bf003caa 100644 --- a/source/blender/blenkernel/BKE_image_partial_update.hh +++ b/source/blender/blenkernel/BKE_image_partial_update.hh @@ -165,6 +165,7 @@ class ImageTileData : AbstractTileData { * Can be nullptr when the file doesn't exist or when the tile hasn't been initialized. */ ImBuf *tile_buffer = nullptr; + void *tile_buffer_lock = nullptr; ImageTileData(Image *image, ImageUser *image_user) : image(image) { @@ -177,14 +178,15 @@ class ImageTileData : AbstractTileData { { image_user.tile = new_tile_number; tile = BKE_image_get_tile(image, new_tile_number); - tile_buffer = BKE_image_acquire_ibuf(image, &image_user, NULL); + tile_buffer = BKE_image_acquire_ibuf(image, &image_user, &tile_buffer_lock); } void free_data() override { - BKE_image_release_ibuf(image, tile_buffer, nullptr); + BKE_image_release_ibuf(image, tile_buffer, tile_buffer_lock); tile = nullptr; tile_buffer = nullptr; + tile_buffer_lock = nullptr; } }; diff --git a/source/blender/blenkernel/BKE_image_save.h b/source/blender/blenkernel/BKE_image_save.h index b022e677845..052fc937af9 100644 --- a/source/blender/blenkernel/BKE_image_save.h +++ b/source/blender/blenkernel/BKE_image_save.h @@ -49,21 +49,26 @@ bool BKE_image_save(struct ReportList *reports, /* Render saving. */ -/* Save single or multilayer OpenEXR files from the render result. - * Optionally saves only a specific view or layer. */ +/** + * Save single or multi-layer OpenEXR files from the render result. + * Optionally saves only a specific view or layer. + */ bool BKE_image_render_write_exr(struct ReportList *reports, const struct RenderResult *rr, - const char *filename, + const char *filepath, const struct ImageFormatData *imf, const bool save_as_render, const char *view, int layer); +/** + * \param filepath_basis: May be used as-is, or used as a basis for multi-view images. + */ bool BKE_image_render_write(struct ReportList *reports, struct RenderResult *rr, const struct Scene *scene, const bool stamp, - const char *name); + const char *filepath_basis); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 7f099125706..77a3223c064 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -301,10 +301,9 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); #define FOREACH_SELECTED_OBJECT_BEGIN(_view_layer, _v3d, _instance) \ { \ - struct ObjectsVisibleIteratorData data_ = { \ - .view_layer = _view_layer, \ - .v3d = _v3d, \ - }; \ + struct ObjectsVisibleIteratorData data_ = {NULL}; \ + data_.view_layer = _view_layer; \ + data_.v3d = _v3d; \ ITER_BEGIN (BKE_view_layer_selected_objects_iterator_begin, \ BKE_view_layer_selected_objects_iterator_next, \ BKE_view_layer_selected_objects_iterator_end, \ @@ -319,7 +318,9 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); #define FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(_view_layer, _v3d, _instance) \ { \ - struct ObjectsVisibleIteratorData data_ = {_view_layer, _v3d}; \ + struct ObjectsVisibleIteratorData data_ = {NULL}; \ + data_.view_layer = _view_layer; \ + data_.v3d = _v3d; \ ITER_BEGIN (BKE_view_layer_selected_editable_objects_iterator_begin, \ BKE_view_layer_selected_editable_objects_iterator_next, \ BKE_view_layer_selected_editable_objects_iterator_end, \ @@ -334,10 +335,9 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); #define FOREACH_VISIBLE_OBJECT_BEGIN(_view_layer, _v3d, _instance) \ { \ - struct ObjectsVisibleIteratorData data_ = { \ - .view_layer = _view_layer, \ - .v3d = _v3d, \ - }; \ + struct ObjectsVisibleIteratorData data_ = {NULL}; \ + data_.view_layer = _view_layer; \ + data_.v3d = _v3d; \ ITER_BEGIN (BKE_view_layer_visible_objects_iterator_begin, \ BKE_view_layer_visible_objects_iterator_next, \ BKE_view_layer_visible_objects_iterator_end, \ @@ -404,10 +404,9 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); #define FOREACH_VISIBLE_BASE_BEGIN(_view_layer, _v3d, _instance) \ { \ - struct ObjectsVisibleIteratorData data_ = { \ - .view_layer = _view_layer, \ - .v3d = _v3d, \ - }; \ + struct ObjectsVisibleIteratorData data_ = {NULL}; \ + data_.view_layer = _view_layer; \ + data_.v3d = _v3d; \ ITER_BEGIN (BKE_view_layer_visible_bases_iterator_begin, \ BKE_view_layer_visible_bases_iterator_next, \ BKE_view_layer_visible_bases_iterator_end, \ @@ -437,10 +436,9 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); IteratorBeginCb func_begin; \ IteratorCb func_next, func_end; \ void *data_in; \ - struct ObjectsVisibleIteratorData data_ = { \ - .view_layer = _view_layer, \ - .v3d = _v3d, \ - }; \ + struct ObjectsVisibleIteratorData data_ = {NULL}; \ + data_.view_layer = _view_layer; \ + data_.v3d = _v3d; \ \ if (flag == SELECT) { \ func_begin = &BKE_view_layer_selected_objects_iterator_begin; \ diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 040be8d1280..c3122758a72 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -515,7 +515,7 @@ void BKE_main_id_flag_listbase(struct ListBase *lb, int flag, bool value); void BKE_main_id_flag_all(struct Main *bmain, int flag, bool value); /** - * Next to indirect usage in `readfile.c/writefile.c` also in `editobject.c`, `scene.c`. + * Next to indirect usage in `readfile.c/writefile.c` also in `editobject.c`, `scene.cc`. */ void BKE_main_id_newptr_and_tag_clear(struct Main *bmain); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 0ba9713b96d..1ad20c52a4b 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -571,7 +571,7 @@ typedef struct MLoopNorSpaceArray { struct LinkNode *loops_pool; /* Allocated once, avoids to call BLI_linklist_prepend_arena() for each loop! */ char data_type; /* Whether we store loop indices, or pointers to BMLoop. */ - int num_spaces; /* Number of clnors spaces defined in this array. */ + int spaces_num; /* Number of clnors spaces defined in this array. */ struct MemArena *mem; } MLoopNorSpaceArray; /** diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h index 8433894b8c5..893aa2a5b1c 100644 --- a/source/blender/blenkernel/BKE_packedFile.h +++ b/source/blender/blenkernel/BKE_packedFile.h @@ -45,7 +45,7 @@ enum ePF_FileStatus { struct PackedFile *BKE_packedfile_duplicate(const struct PackedFile *pf_src); struct PackedFile *BKE_packedfile_new(struct ReportList *reports, - const char *filename, + const char *filepath, const char *basepath); struct PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen); @@ -102,7 +102,7 @@ int BKE_packedfile_unpack_all_libraries(struct Main *bmain, struct ReportList *r int BKE_packedfile_write_to_file(struct ReportList *reports, const char *ref_file_name, - const char *filename, + const char *filepath, struct PackedFile *pf, bool guimode); @@ -122,7 +122,7 @@ int BKE_packedfile_count_all(struct Main *bmain); * - #PF_NOFILE: the original file doesn't exist. */ enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name, - const char *filename, + const char *filepath_rel, struct PackedFile *pf); /* Read. */ diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 8c50a89ec90..a6402a1e8a1 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -225,7 +225,7 @@ bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *s /* Render profile. */ int get_render_subsurf_level(const struct RenderData *r, int lvl, bool for_render); -int get_render_child_particle_number(const struct RenderData *r, int num, bool for_render); +int get_render_child_particle_number(const struct RenderData *r, int child_num, bool for_render); bool BKE_scene_use_shading_nodes_custom(struct Scene *scene); bool BKE_scene_use_spherical_stereo(struct Scene *scene); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index e4edd01481b..a39d981d74f 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -104,8 +104,6 @@ set(SRC intern/crazyspace.c intern/cryptomatte.cc intern/curve.cc - intern/curves.cc - intern/curves_geometry.cc intern/curve_bevel.c intern/curve_bezier.cc intern/curve_catmull_rom.cc @@ -116,6 +114,8 @@ set(SRC intern/curve_nurbs.cc intern/curve_to_mesh_convert.cc intern/curveprofile.cc + intern/curves.cc + intern/curves_geometry.cc intern/customdata.cc intern/customdata_file.c intern/data_transfer.c @@ -157,9 +157,9 @@ set(SRC intern/idtype.c intern/image.cc intern/image_format.cc - intern/image_partial_update.cc intern/image_gen.c intern/image_gpu.cc + intern/image_partial_update.cc intern/image_save.cc intern/ipo.c intern/kelvinlet.c @@ -248,7 +248,7 @@ set(SRC intern/preferences.c intern/report.c intern/rigidbody.c - intern/scene.c + intern/scene.cc intern/screen.c intern/shader_fx.c intern/shrinkwrap.c @@ -349,10 +349,10 @@ set(SRC BKE_cryptomatte.h BKE_cryptomatte.hh BKE_curve.h - BKE_curves.h - BKE_curves.hh BKE_curve_to_mesh.hh BKE_curveprofile.h + BKE_curves.h + BKE_curves.hh BKE_customdata.h BKE_customdata_file.h BKE_data_transfer.h @@ -600,14 +600,14 @@ if(WITH_IMAGE_CINEON) add_definitions(-DWITH_CINEON) endif() -if(WITH_IMAGE_FRAMESERVER) - add_definitions(-DWITH_FRAMESERVER) -endif() - if(WITH_IMAGE_HDR) add_definitions(-DWITH_HDR) endif() +if(WITH_IMAGE_WEBP) + add_definitions(-DWITH_WEBP) +endif() + if(WITH_CODEC_AVI) list(APPEND INC ../io/avi @@ -821,6 +821,7 @@ if(WITH_GTESTS) intern/fcurve_test.cc intern/idprop_serialize_test.cc intern/image_partial_update_test.cc + intern/image_test.cc intern/lattice_deform_test.cc intern/layer_test.cc intern/lib_id_remapper_test.cc diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index b0393ed723d..8d3649fef08 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -1022,16 +1022,16 @@ void BKE_appdir_app_templates(ListBase *templates) continue; } - struct direntry *dir; - uint totfile = BLI_filelist_dir_contents(subdir, &dir); - for (int f = 0; f < totfile; f++) { - if (!FILENAME_IS_CURRPAR(dir[f].relname) && S_ISDIR(dir[f].type)) { - char *template = BLI_strdup(dir[f].relname); + struct direntry *dirs; + const uint dir_num = BLI_filelist_dir_contents(subdir, &dirs); + for (int f = 0; f < dir_num; f++) { + if (!FILENAME_IS_CURRPAR(dirs[f].relname) && S_ISDIR(dirs[f].type)) { + char *template = BLI_strdup(dirs[f].relname); BLI_addtail(templates, BLI_genericNodeN(template)); } } - BLI_filelist_free(dir, totfile); + BLI_filelist_free(dirs, dir_num); } } diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c index 294fe57c923..be2abdbfb69 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.c +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -999,7 +999,7 @@ static void blendfile_link_append_proxies_convert(Main *bmain, ReportList *repor RPT_WARNING, "Proxies have been removed from Blender (%d proxies were automatically converted " "to library overrides, %d proxies could not be converted and were cleared). " - "Please consider re-saving any library .blend file with the newest Blender version.", + "Please consider re-saving any library .blend file with the newest Blender version", bf_reports.count.proxies_to_lib_overrides_success, bf_reports.count.proxies_to_lib_overrides_failures); } diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 891145b47c9..bdaea487cfb 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -432,7 +432,8 @@ void BKE_collection_add_from_object(Main *bmain, bool is_instantiated = false; FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { - if (!ID_IS_LINKED(collection) && BKE_collection_has_object(collection, ob_src)) { + if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDABLE_LIBRARY(collection) && + BKE_collection_has_object(collection, ob_src)) { collection_child_add(collection, collection_dst, 0, true); is_instantiated = true; } @@ -454,7 +455,8 @@ void BKE_collection_add_from_collection(Main *bmain, bool is_instantiated = false; FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { - if (!ID_IS_LINKED(collection) && collection_find_child(collection, collection_src)) { + if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDABLE_LIBRARY(collection) && + collection_find_child(collection, collection_src)) { collection_child_add(collection, collection_dst, 0, true); is_instantiated = true; } diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index 9d13bf3ac11..96389c44839 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -236,7 +236,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra ModifierData *md; Mesh *me_input = ob->data; Mesh *me = NULL; - int i, a, numleft = 0, numVerts = 0; + int i, a, modifiers_left_num = 0, verts_num = 0; int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1); float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; VirtualModifierData virtualModifierData; @@ -266,14 +266,14 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra BLI_linklist_free((LinkNode *)datamasks, NULL); me = BKE_mesh_wrapper_from_editmesh_with_coords(em, &cd_mask_extra, NULL, me_input); - deformedVerts = editbmesh_vert_coords_alloc(em, &numVerts); - defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats"); + deformedVerts = editbmesh_vert_coords_alloc(em, &verts_num); + defmats = MEM_mallocN(sizeof(*defmats) * verts_num, "defmats"); - for (a = 0; a < numVerts; a++) { + for (a = 0; a < verts_num; a++) { unit_m3(defmats[a]); } } - mti->deformMatricesEM(md, &mectx, em, me, deformedVerts, defmats, numVerts); + mti->deformMatricesEM(md, &mectx, em, me, deformedVerts, defmats, verts_num); } else { break; @@ -283,7 +283,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra for (; md && i <= cageIndex; md = md->next, i++) { if (editbmesh_modifier_is_enabled(scene, ob, md, me != NULL) && BKE_modifier_is_correctable_deformed(md)) { - numleft++; + modifiers_left_num++; } } @@ -294,7 +294,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra *deformmats = defmats; *deformcos = deformedVerts; - return numleft; + return modifiers_left_num; } /** @@ -319,13 +319,13 @@ static void crazyspace_init_verts_and_matrices(const Mesh *mesh, float (**deformmats)[3][3], float (**deformcos)[3]) { - int num_verts; - *deformcos = BKE_mesh_vert_coords_alloc(mesh, &num_verts); - *deformmats = MEM_callocN(sizeof(**deformmats) * num_verts, "defmats"); - for (int a = 0; a < num_verts; a++) { + int verts_num; + *deformcos = BKE_mesh_vert_coords_alloc(mesh, &verts_num); + *deformmats = MEM_callocN(sizeof(**deformmats) * verts_num, "defmats"); + for (int a = 0; a < verts_num; a++) { unit_m3((*deformmats)[a]); } - BLI_assert(num_verts == mesh->totvert); + BLI_assert(verts_num == mesh->totvert); } static bool crazyspace_modifier_supports_deform_matrices(ModifierData *md) @@ -352,7 +352,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, ModifierData *md; Mesh *me_eval = NULL; float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; - int numleft = 0; + int modifiers_left_num = 0; VirtualModifierData virtualModifierData; Object object_eval; crazyspace_init_object_for_eval(depsgraph, object, &object_eval); @@ -364,7 +364,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, if (is_sculpt_mode && has_multires) { *deformmats = NULL; *deformcos = NULL; - return numleft; + return modifiers_left_num; } md = BKE_modifiers_get_virtual_modifierlist(&object_eval, &virtualModifierData); @@ -401,7 +401,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, } if (crazyspace_modifier_supports_deform(md)) { - numleft++; + modifiers_left_num++; } } @@ -412,7 +412,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, *deformmats = defmats; *deformcos = deformedVerts; - return numleft; + return modifiers_left_num; } void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, @@ -489,13 +489,13 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, } if (*deformmats == NULL) { - int a, numVerts; + int a, verts_num; Mesh *mesh = (Mesh *)object->data; - *deformcos = BKE_mesh_vert_coords_alloc(mesh, &numVerts); - *deformmats = MEM_callocN(sizeof(*(*deformmats)) * numVerts, "defmats"); + *deformcos = BKE_mesh_vert_coords_alloc(mesh, &verts_num); + *deformmats = MEM_callocN(sizeof(*(*deformmats)) * verts_num, "defmats"); - for (a = 0; a < numVerts; a++) { + for (a = 0; a < verts_num; a++) { unit_m3((*deformmats)[a]); } } @@ -523,7 +523,7 @@ void BKE_crazyspace_api_eval(Depsgraph *depsgraph, } const Mesh *mesh = (const Mesh *)object->data; - object->runtime.crazyspace_num_verts = mesh->totvert; + object->runtime.crazyspace_verts_num = mesh->totvert; BKE_crazyspace_build_sculpt(depsgraph, scene, object, @@ -537,12 +537,12 @@ void BKE_crazyspace_api_displacement_to_deformed(struct Object *object, float displacement[3], float r_displacement_deformed[3]) { - if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_num_verts) { + if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_verts_num) { BKE_reportf(reports, RPT_ERROR, "Invalid vertex index %d (expected to be within 0 to %d range)", vertex_index, - object->runtime.crazyspace_num_verts); + object->runtime.crazyspace_verts_num); return; } @@ -557,12 +557,12 @@ void BKE_crazyspace_api_displacement_to_original(struct Object *object, float displacement_deformed[3], float r_displacement[3]) { - if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_num_verts) { + if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_verts_num) { BKE_reportf(reports, RPT_ERROR, "Invalid vertex index %d (expected to be within 0 to %d range))", vertex_index, - object->runtime.crazyspace_num_verts); + object->runtime.crazyspace_verts_num); return; } diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index 354ddd7d167..8b58ad848f2 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -4718,11 +4718,11 @@ static NURBSValidationStatus nurb_check_valid(const int pnts, if (pnts <= 1) { return NURBSValidationStatus::AtLeastTwoPointsRequired; } - else if (type == CU_NURBS) { + if (type == CU_NURBS) { if (pnts < order) { return NURBSValidationStatus::MorePointsThanOrderRequired; } - else if (flag & CU_NURB_BEZIER) { + if (flag & CU_NURB_BEZIER) { int points_needed = 0; if (flag & CU_NURB_CYCLIC) { const int remainder = pnts % (order - 1); @@ -4765,7 +4765,7 @@ bool BKE_nurb_valid_message(const int pnts, message_dst[0] = 0; return false; } - msg_template = TIP_("At least two points required."); + msg_template = TIP_("At least two points required"); break; case NURBSValidationStatus::MorePointsThanOrderRequired: msg_template = TIP_("Must have more control points than Order"); diff --git a/source/blender/blenkernel/intern/curve_bezier.cc b/source/blender/blenkernel/intern/curve_bezier.cc index 52a2674ab3d..b11216983b2 100644 --- a/source/blender/blenkernel/intern/curve_bezier.cc +++ b/source/blender/blenkernel/intern/curve_bezier.cc @@ -121,8 +121,8 @@ void calculate_evaluated_positions(const Span<float3> positions, }); /* Evaluate the final cyclic segment if necessary. */ - const IndexRange evaluated_range = offsets_to_range(evaluated_offsets, positions.size() - 2); - if (evaluated_range.size() == 1) { + const IndexRange last_segment_points = offsets_to_range(evaluated_offsets, positions.size() - 2); + if (last_segment_points.size() == 1) { evaluated_positions.last() = positions.last(); } else { @@ -130,10 +130,54 @@ void calculate_evaluated_positions(const Span<float3> positions, handles_right.last(), handles_left.first(), positions.first(), - evaluated_positions.slice(evaluated_range)); + evaluated_positions.slice(last_segment_points)); } } +template<typename T> +static inline void linear_interpolation(const T &a, const T &b, MutableSpan<T> dst) +{ + dst.first() = a; + const float step = 1.0f / dst.size(); + for (const int i : dst.index_range().drop_front(1)) { + dst[i] = attribute_math::mix2(i * step, a, b); + } +} + +template<typename T> +static void interpolate_to_evaluated(const Span<T> src, + const Span<int> evaluated_offsets, + MutableSpan<T> dst) +{ + BLI_assert(!src.is_empty()); + BLI_assert(dst.size() == src.size()); + BLI_assert(evaluated_offsets.last() == dst.size()); + + linear_interpolation(src.first(), src[1], dst.take_front(evaluated_offsets.first())); + + threading::parallel_for( + src.index_range().drop_back(1).drop_front(1), 512, [&](IndexRange range) { + for (const int i : range) { + const IndexRange segment_points = offsets_to_range(evaluated_offsets, i - 1); + linear_interpolation(src[i], src[i + 1], dst.slice(segment_points)); + } + }); + + const IndexRange last_segment_points(evaluated_offsets.last(1), + evaluated_offsets.last() - evaluated_offsets.last(1)); + linear_interpolation(src.last(), src.first(), dst.slice(last_segment_points)); +} + +void interpolate_to_evaluated(const GSpan src, const Span<int> evaluated_offsets, GMutableSpan dst) +{ + attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { + interpolate_to_evaluated(src.typed<T>(), evaluated_offsets, dst.typed<T>()); + } + }); +} + /** \} */ } // namespace blender::bke::curves::bezier diff --git a/source/blender/blenkernel/intern/curve_catmull_rom.cc b/source/blender/blenkernel/intern/curve_catmull_rom.cc index 27687eb736f..ea3672dd56b 100644 --- a/source/blender/blenkernel/intern/curve_catmull_rom.cc +++ b/source/blender/blenkernel/intern/curve_catmull_rom.cc @@ -9,11 +9,11 @@ namespace blender::bke::curves::catmull_rom { -int calculate_evaluated_size(const int size, const bool cyclic, const int resolution) +int calculate_evaluated_size(const int points_num, const bool cyclic, const int resolution) { - const int eval_size = resolution * curve_segment_size(size, cyclic); + const int eval_size = resolution * curve_segment_size(points_num, cyclic); /* If the curve isn't cyclic, one last point is added to the final point. */ - return (cyclic && size > 2) ? eval_size : eval_size + 1; + return (cyclic && points_num > 2) ? eval_size : eval_size + 1; } /* Adapted from Cycles #catmull_rom_basis_eval function. */ diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index b2399f25638..2cf83b57881 100644 --- a/source/blender/blenkernel/intern/curve_eval.cc +++ b/source/blender/blenkernel/intern/curve_eval.cc @@ -398,7 +398,7 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves) VArray<int8_t> curve_types = geometry.curve_types(); std::unique_ptr<CurveEval> curve_eval = std::make_unique<CurveEval>(); for (const int curve_index : curve_types.index_range()) { - const IndexRange point_range = geometry.range_for_curve(curve_index); + const IndexRange point_range = geometry.points_for_curve(curve_index); std::unique_ptr<Spline> spline; switch (curve_types[curve_index]) { @@ -489,7 +489,7 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval) const Spline &spline = *curve_eval.splines()[curve_index]; curve_types[curve_index] = curve_eval.splines()[curve_index]->type(); - const IndexRange point_range = geometry.range_for_curve(curve_index); + const IndexRange point_range = geometry.points_for_curve(curve_index); switch (spline.type()) { case CURVE_TYPE_POLY: diff --git a/source/blender/blenkernel/intern/curve_nurbs.cc b/source/blender/blenkernel/intern/curve_nurbs.cc index a4cdbbca654..0114c0b45f4 100644 --- a/source/blender/blenkernel/intern/curve_nurbs.cc +++ b/source/blender/blenkernel/intern/curve_nurbs.cc @@ -10,53 +10,53 @@ namespace blender::bke::curves::nurbs { -bool check_valid_size_and_order(const int size, +bool check_valid_size_and_order(const int points_num, const int8_t order, const bool cyclic, const KnotsMode knots_mode) { - if (size < order) { + if (points_num < order) { return false; } if (ELEM(knots_mode, NURBS_KNOT_MODE_BEZIER, NURBS_KNOT_MODE_ENDPOINT_BEZIER)) { - if (knots_mode == NURBS_KNOT_MODE_BEZIER && size <= order) { + if (knots_mode == NURBS_KNOT_MODE_BEZIER && points_num <= order) { return false; } - return (!cyclic || size % (order - 1) == 0); + return (!cyclic || points_num % (order - 1) == 0); } return true; } -int calculate_evaluated_size(const int size, +int calculate_evaluated_size(const int points_num, const int8_t order, const bool cyclic, const int resolution, const KnotsMode knots_mode) { - if (!check_valid_size_and_order(size, order, cyclic, knots_mode)) { + if (!check_valid_size_and_order(points_num, order, cyclic, knots_mode)) { return 0; } - return resolution * curve_segment_size(size, cyclic); + return resolution * curve_segment_size(points_num, cyclic); } -int knots_size(const int size, const int8_t order, const bool cyclic) +int knots_size(const int points_num, const int8_t order, const bool cyclic) { if (cyclic) { - return size + order * 2 - 1; + return points_num + order * 2 - 1; } - return size + order; + return points_num + order; } -void calculate_knots(const int size, +void calculate_knots(const int points_num, const KnotsMode mode, const int8_t order, const bool cyclic, MutableSpan<float> knots) { - BLI_assert(knots.size() == knots_size(size, order, cyclic)); - UNUSED_VARS_NDEBUG(size); + BLI_assert(knots.size() == knots_size(points_num, order, cyclic)); + UNUSED_VARS_NDEBUG(points_num); const bool is_bezier = ELEM(mode, NURBS_KNOT_MODE_BEZIER, NURBS_KNOT_MODE_ENDPOINT_BEZIER); const bool is_end_point = ELEM(mode, NURBS_KNOT_MODE_ENDPOINT, NURBS_KNOT_MODE_ENDPOINT_BEZIER); @@ -94,7 +94,7 @@ void calculate_knots(const int size, } static void calculate_basis_for_point(const float parameter, - const int size, + const int points_num, const int degree, const Span<float> knots, MutableSpan<float> r_weights, @@ -104,7 +104,7 @@ static void calculate_basis_for_point(const float parameter, int start = 0; int end = 0; - for (const int i : IndexRange(size + degree)) { + for (const int i : IndexRange(points_num + degree)) { const bool knots_equal = knots[i] == knots[i + 1]; if (knots_equal || parameter < knots[i] || parameter > knots[i + 1]) { continue; @@ -121,7 +121,7 @@ static void calculate_basis_for_point(const float parameter, for (const int i_order : IndexRange(2, degree)) { if (end + i_order >= knots.size()) { - end = size + degree - i_order; + end = points_num + degree - i_order; } for (const int i : IndexRange(end - start + 1)) { const int knot_index = start + i; @@ -146,15 +146,14 @@ static void calculate_basis_for_point(const float parameter, r_start_index = start; } -void calculate_basis_cache(const int size, +void calculate_basis_cache(const int points_num, const int evaluated_size, const int8_t order, const bool cyclic, const Span<float> knots, BasisCache &basis_cache) { - BLI_assert(size > 0); - BLI_assert(evaluated_size > 0); + BLI_assert(points_num > 0); const int8_t degree = order - 1; @@ -168,7 +167,7 @@ void calculate_basis_cache(const int size, MutableSpan<float> basis_weights(basis_cache.weights); MutableSpan<int> basis_start_indices(basis_cache.start_indices); - const int last_control_point_index = cyclic ? size + degree : size; + const int last_control_point_index = cyclic ? points_num + degree : points_num; const int evaluated_segment_size = curve_segment_size(evaluated_size, cyclic); const float start = knots[degree]; @@ -176,7 +175,7 @@ void calculate_basis_cache(const int size, const float step = (end - start) / evaluated_segment_size; for (const int i : IndexRange(evaluated_size)) { /* Clamp parameter due to floating point inaccuracy. */ - const float parameter = std::clamp(start + step * i, knots[0], knots[size + degree]); + const float parameter = std::clamp(start + step * i, knots[0], knots[points_num + degree]); MutableSpan<float> point_weights = basis_weights.slice(i * order, order); diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 838f7f28e93..82db1176759 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -366,19 +366,19 @@ void BKE_curves_batch_cache_free(Curves *curves) namespace blender::bke { -Curves *curves_new_nomain(const int point_size, const int curves_size) +Curves *curves_new_nomain(const int points_num, const int curves_num) { Curves *curves = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr)); CurvesGeometry &geometry = CurvesGeometry::wrap(curves->geometry); - geometry.resize(point_size, curves_size); + geometry.resize(points_num, curves_num); return curves; } -Curves *curves_new_nomain_single(const int point_size, const CurveType type) +Curves *curves_new_nomain_single(const int points_num, const CurveType type) { - Curves *curves = curves_new_nomain(point_size, 1); + Curves *curves = curves_new_nomain(points_num, 1); CurvesGeometry &geometry = CurvesGeometry::wrap(curves->geometry); - geometry.offsets().last() = point_size; + geometry.offsets().last() = points_num; geometry.curve_types().first() = type; return curves; } diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index db69fbc4063..7ceaa8f0f37 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -149,24 +149,24 @@ CurvesGeometry::~CurvesGeometry() /** \name Accessors * \{ */ -int CurvesGeometry::points_size() const +int CurvesGeometry::points_num() const { return this->point_size; } -int CurvesGeometry::curves_size() const +int CurvesGeometry::curves_num() const { return this->curve_size; } IndexRange CurvesGeometry::points_range() const { - return IndexRange(this->points_size()); + return IndexRange(this->points_num()); } IndexRange CurvesGeometry::curves_range() const { - return IndexRange(this->curves_size()); + return IndexRange(this->curves_num()); } -IndexRange CurvesGeometry::range_for_curve(const int index) const +IndexRange CurvesGeometry::points_for_curve(const int index) const { BLI_assert(this->curve_size > 0); BLI_assert(this->curve_offsets != nullptr); @@ -175,7 +175,7 @@ IndexRange CurvesGeometry::range_for_curve(const int index) const return {offset, offset_next - offset}; } -IndexRange CurvesGeometry::range_for_curves(const IndexRange curves) const +IndexRange CurvesGeometry::points_for_curves(const IndexRange curves) const { BLI_assert(this->curve_size > 0); BLI_assert(this->curve_offsets != nullptr); @@ -186,7 +186,7 @@ IndexRange CurvesGeometry::range_for_curves(const IndexRange curves) const static int domain_size(const CurvesGeometry &curves, const AttributeDomain domain) { - return domain == ATTR_DOMAIN_POINT ? curves.points_size() : curves.curves_size(); + return domain == ATTR_DOMAIN_POINT ? curves.points_num() : curves.curves_num(); } static CustomData &domain_custom_data(CurvesGeometry &curves, const AttributeDomain domain) @@ -277,6 +277,40 @@ bool CurvesGeometry::has_curve_with_type(const CurveType type) const return false; } +std::array<int, CURVE_TYPES_NUM> CurvesGeometry::count_curve_types() const +{ + using CountsType = std::array<int, CURVE_TYPES_NUM>; + + CountsType identity; + identity.fill(0); + + const VArray<int8_t> types = this->curve_types(); + if (types.is_single()) { + identity[types.get_internal_single()] = this->curves_num(); + return identity; + } + + Span<int8_t> types_span = types.get_internal_span(); + return threading::parallel_reduce( + this->curves_range(), + 2048, + identity, + [&](const IndexRange curves_range, const CountsType &init) { + CountsType result = init; + for (const int curve_index : curves_range) { + result[types_span[curve_index]]++; + } + return result; + }, + [](const CountsType &a, const CountsType &b) { + CountsType result = a; + for (const int i : IndexRange(CURVE_TYPES_NUM)) { + result[i] += b[i]; + } + return result; + }); +} + MutableSpan<float3> CurvesGeometry::positions() { this->position = (float(*)[3])CustomData_duplicate_referenced_layer_named( @@ -431,7 +465,7 @@ static void calculate_evaluated_offsets(const CurvesGeometry &curves, VArray<int8_t> nurbs_knots_modes = curves.nurbs_knots_modes(); build_offsets(offsets, [&](const int curve_index) -> int { - const IndexRange points = curves.range_for_curve(curve_index); + const IndexRange points = curves.points_for_curve(curve_index); switch (types[curve_index]) { case CURVE_TYPE_CATMULL_ROM: return curves::catmull_rom::calculate_evaluated_size( @@ -457,35 +491,44 @@ static void calculate_evaluated_offsets(const CurvesGeometry &curves, }); } -int CurvesGeometry::evaluated_points_size() const +int CurvesGeometry::evaluated_points_num() const { /* This could avoid calculating offsets in the future in simple circumstances. */ return this->evaluated_offsets().last(); } -IndexRange CurvesGeometry::evaluated_range_for_curve(int index) const +IndexRange CurvesGeometry::evaluated_points_for_curve(int index) const { BLI_assert(!this->runtime->offsets_cache_dirty); return offsets_to_range(this->runtime->evaluated_offsets_cache.as_span(), index); } -Span<int> CurvesGeometry::evaluated_offsets() const +IndexRange CurvesGeometry::evaluated_points_for_curves(const IndexRange curves) const +{ + BLI_assert(!this->runtime->offsets_cache_dirty); + BLI_assert(this->curve_size > 0); + const int offset = this->runtime->evaluated_offsets_cache[curves.start()]; + const int offset_next = this->runtime->evaluated_offsets_cache[curves.one_after_last()]; + return {offset, offset_next - offset}; +} + +void CurvesGeometry::ensure_evaluated_offsets() const { if (!this->runtime->offsets_cache_dirty) { - return this->runtime->evaluated_offsets_cache; + return; } /* A double checked lock. */ std::scoped_lock lock{this->runtime->offsets_cache_mutex}; if (!this->runtime->offsets_cache_dirty) { - return this->runtime->evaluated_offsets_cache; + return; } threading::isolate_task([&]() { - this->runtime->evaluated_offsets_cache.resize(this->curves_size() + 1); + this->runtime->evaluated_offsets_cache.resize(this->curves_num() + 1); if (this->has_curve_with_type(CURVE_TYPE_BEZIER)) { - this->runtime->bezier_evaluated_offsets.resize(this->points_size()); + this->runtime->bezier_evaluated_offsets.resize(this->points_num()); } else { this->runtime->bezier_evaluated_offsets.clear_and_make_inline(); @@ -496,6 +539,11 @@ Span<int> CurvesGeometry::evaluated_offsets() const }); this->runtime->offsets_cache_dirty = false; +} + +Span<int> CurvesGeometry::evaluated_offsets() const +{ + this->ensure_evaluated_offsets(); return this->runtime->evaluated_offsets_cache; } @@ -536,7 +584,7 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const return; } - this->runtime->nurbs_basis_cache.resize(this->curves_size()); + this->runtime->nurbs_basis_cache.resize(this->curves_num()); MutableSpan<curves::nurbs::BasisCache> basis_caches(this->runtime->nurbs_basis_cache); VArray<bool> cyclic = this->cyclic(); @@ -545,8 +593,8 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const threading::parallel_for(nurbs_mask.index_range(), 64, [&](const IndexRange range) { for (const int curve_index : nurbs_mask.slice(range)) { - const IndexRange points = this->range_for_curve(curve_index); - const IndexRange evaluated_points = this->evaluated_range_for_curve(curve_index); + const IndexRange points = this->points_for_curve(curve_index); + const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index); const int8_t order = orders[curve_index]; const bool is_cyclic = cyclic[curve_index]; @@ -564,6 +612,8 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const } }); }); + + this->runtime->nurbs_basis_cache_dirty = false; } Span<float3> CurvesGeometry::evaluated_positions() const @@ -579,7 +629,7 @@ Span<float3> CurvesGeometry::evaluated_positions() const } threading::isolate_task([&]() { - this->runtime->evaluated_position_cache.resize(this->evaluated_points_size()); + this->runtime->evaluated_position_cache.resize(this->evaluated_points_num()); MutableSpan<float3> evaluated_positions = this->runtime->evaluated_position_cache; VArray<int8_t> types = this->curve_types(); @@ -598,8 +648,8 @@ Span<float3> CurvesGeometry::evaluated_positions() const threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) { for (const int curve_index : curves_range) { - const IndexRange points = this->range_for_curve(curve_index); - const IndexRange evaluated_points = this->evaluated_range_for_curve(curve_index); + const IndexRange points = this->points_for_curve(curve_index); + const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index); switch (types[curve_index]) { case CURVE_TYPE_CATMULL_ROM: @@ -639,22 +689,54 @@ Span<float3> CurvesGeometry::evaluated_positions() const return this->runtime->evaluated_position_cache; } +void CurvesGeometry::interpolate_to_evaluated(const int curve_index, + const GSpan src, + GMutableSpan dst) const +{ + BLI_assert(!this->runtime->offsets_cache_dirty); + BLI_assert(!this->runtime->nurbs_basis_cache_dirty); + const IndexRange points = this->points_for_curve(curve_index); + BLI_assert(src.size() == points.size()); + BLI_assert(dst.size() == this->evaluated_points_for_curve(curve_index).size()); + switch (this->curve_types()[curve_index]) { + case CURVE_TYPE_CATMULL_ROM: + curves::catmull_rom::interpolate_to_evaluated( + src, this->cyclic()[curve_index], this->resolution()[curve_index], dst); + return; + case CURVE_TYPE_POLY: + dst.type().copy_assign_n(src.data(), dst.data(), src.size()); + return; + case CURVE_TYPE_BEZIER: + curves::bezier::interpolate_to_evaluated( + src, this->runtime->bezier_evaluated_offsets.as_span().slice(points), dst); + return; + case CURVE_TYPE_NURBS: + curves::nurbs::interpolate_to_evaluated(this->runtime->nurbs_basis_cache[curve_index], + this->nurbs_orders()[curve_index], + this->nurbs_weights().slice(points), + src, + dst); + return; + } + BLI_assert_unreachable(); +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name Operations * \{ */ -void CurvesGeometry::resize(const int point_size, const int curve_size) +void CurvesGeometry::resize(const int points_num, const int curves_num) { - if (point_size != this->point_size) { - CustomData_realloc(&this->point_data, point_size); - this->point_size = point_size; + if (points_num != this->point_size) { + CustomData_realloc(&this->point_data, points_num); + this->point_size = points_num; } - if (curve_size != this->curve_size) { - CustomData_realloc(&this->curve_data, curve_size); - this->curve_size = curve_size; - this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curve_size + 1)); + if (curves_num != this->curve_size) { + CustomData_realloc(&this->curve_data, curves_num); + this->curve_size = curves_num; + this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1)); } this->tag_topology_changed(); this->update_customdata_pointers(); @@ -727,7 +809,7 @@ static std::optional<bounds::MinMaxResult<float3>> curves_bounds(const CurvesGeo { Span<float3> positions = curves.positions(); if (curves.radius) { - Span<float> radii{curves.radius, curves.points_size()}; + Span<float> radii{curves.radius, curves.points_num()}; return bounds::min_max_with_radii(positions, radii); } return bounds::min_max(positions); @@ -784,7 +866,7 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, new_curve_ranges.append(IndexRange(new_tot_curves, curve_range.size())); new_tot_curves += curve_range.size(); - const IndexRange old_point_range = curves.range_for_curves(curve_range); + const IndexRange old_point_range = curves.points_for_curves(curve_range); old_point_ranges.append(old_point_range); new_point_ranges.append(IndexRange(new_tot_points, old_point_range.size())); new_tot_points += old_point_range.size(); @@ -889,7 +971,7 @@ static void reverse_curve_point_data(const CurvesGeometry &curves, { threading::parallel_for(curve_selection.index_range(), 256, [&](IndexRange range) { for (const int curve_i : curve_selection.slice(range)) { - data.slice(curves.range_for_curve(curve_i)).reverse(); + data.slice(curves.points_for_curve(curve_i)).reverse(); } }); } @@ -902,7 +984,7 @@ static void reverse_swap_curve_point_data(const CurvesGeometry &curves, { threading::parallel_for(curve_selection.index_range(), 256, [&](IndexRange range) { for (const int curve_i : curve_selection.slice(range)) { - const IndexRange points = curves.range_for_curve(curve_i); + const IndexRange points = curves.points_for_curve(curve_i); MutableSpan<T> a = data_a.slice(points); MutableSpan<T> b = data_b.slice(points); for (const int i : IndexRange(points.size() / 2)) { @@ -926,7 +1008,7 @@ static bool layer_matches_name_and_type(const CustomDataLayer &layer, void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse) { - CustomData_duplicate_referenced_layers(&this->point_data, this->points_size()); + CustomData_duplicate_referenced_layers(&this->point_data, this->points_num()); /* Collect the Bezier handle attributes while iterating through the point custom data layers; * they need special treatment later. */ @@ -940,22 +1022,22 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse) if (positions_left.is_empty() && layer_matches_name_and_type(layer, ATTR_HANDLE_POSITION_LEFT, CD_PROP_FLOAT3)) { - positions_left = {static_cast<float3 *>(layer.data), this->points_size()}; + positions_left = {static_cast<float3 *>(layer.data), this->points_num()}; continue; } if (positions_right.is_empty() && layer_matches_name_and_type(layer, ATTR_HANDLE_POSITION_RIGHT, CD_PROP_FLOAT3)) { - positions_right = {static_cast<float3 *>(layer.data), this->points_size()}; + positions_right = {static_cast<float3 *>(layer.data), this->points_num()}; continue; } if (types_left.is_empty() && layer_matches_name_and_type(layer, ATTR_HANDLE_TYPE_LEFT, CD_PROP_INT8)) { - types_left = {static_cast<int8_t *>(layer.data), this->points_size()}; + types_left = {static_cast<int8_t *>(layer.data), this->points_num()}; continue; } if (types_right.is_empty() && layer_matches_name_and_type(layer, ATTR_HANDLE_TYPE_RIGHT, CD_PROP_INT8)) { - types_right = {static_cast<int8_t *>(layer.data), this->points_size()}; + types_right = {static_cast<int8_t *>(layer.data), this->points_num()}; continue; } @@ -963,7 +1045,7 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse) attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); reverse_curve_point_data<T>( - *this, curves_to_reverse, {static_cast<T *>(layer.data), this->points_size()}); + *this, curves_to_reverse, {static_cast<T *>(layer.data), this->points_num()}); }); } @@ -1001,8 +1083,8 @@ static void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves, MutableSpan<T> r_values) { attribute_math::DefaultMixer<T> mixer(r_values); - for (const int i_curve : IndexRange(curves.curves_size())) { - for (const int i_point : curves.range_for_curve(i_curve)) { + for (const int i_curve : IndexRange(curves.curves_num())) { + for (const int i_point : curves.points_for_curve(i_curve)) { mixer.mix_in(i_curve, old_values[i_point]); } } @@ -1022,8 +1104,8 @@ void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves, MutableSpan<bool> r_values) { r_values.fill(true); - for (const int i_curve : IndexRange(curves.curves_size())) { - for (const int i_point : curves.range_for_curve(i_curve)) { + for (const int i_curve : IndexRange(curves.curves_num())) { + for (const int i_point : curves.points_for_curve(i_curve)) { if (!old_values[i_point]) { r_values[i_curve] = false; break; @@ -1039,7 +1121,7 @@ static GVArray adapt_curve_domain_point_to_curve(const CurvesGeometry &curves, attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { - Array<T> values(curves.curves_size()); + Array<T> values(curves.curves_num()); adapt_curve_domain_point_to_curve_impl<T>(curves, varray.typed<T>(), values); new_varray = VArray<T>::ForContainer(std::move(values)); } @@ -1059,8 +1141,8 @@ static void adapt_curve_domain_curve_to_point_impl(const CurvesGeometry &curves, const VArray<T> &old_values, MutableSpan<T> r_values) { - for (const int i_curve : IndexRange(curves.curves_size())) { - r_values.slice(curves.range_for_curve(i_curve)).fill(old_values[i_curve]); + for (const int i_curve : IndexRange(curves.curves_num())) { + r_values.slice(curves.points_for_curve(i_curve)).fill(old_values[i_curve]); } } @@ -1070,7 +1152,7 @@ static GVArray adapt_curve_domain_curve_to_point(const CurvesGeometry &curves, GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); - Array<T> values(curves.points_size()); + Array<T> values(curves.points_num()); adapt_curve_domain_curve_to_point_impl<T>(curves, varray.typed<T>(), values); new_varray = VArray<T>::ForContainer(std::move(values)); }); diff --git a/source/blender/blenkernel/intern/curves_geometry_test.cc b/source/blender/blenkernel/intern/curves_geometry_test.cc index 1b3b3f54451..e4dc9eead60 100644 --- a/source/blender/blenkernel/intern/curves_geometry_test.cc +++ b/source/blender/blenkernel/intern/curves_geometry_test.cc @@ -46,7 +46,7 @@ TEST(curves_geometry, Move) CurvesGeometry other = std::move(curves); /* The old curves should be empty, and the offsets are expected to be null. */ - EXPECT_EQ(curves.points_size(), 0); /* NOLINT: bugprone-use-after-move */ + EXPECT_EQ(curves.points_num(), 0); /* NOLINT: bugprone-use-after-move */ EXPECT_EQ(curves.curve_offsets, nullptr); /* NOLINT: bugprone-use-after-move */ /* Just a basic check that the new curves work okay. */ @@ -63,6 +63,28 @@ TEST(curves_geometry, Move) EXPECT_EQ(second_other.offsets().data(), offsets_data); } +TEST(curves_geometry, TypeCount) +{ + CurvesGeometry curves = create_basic_curves(100, 10); + curves.curve_types().copy_from({ + CURVE_TYPE_BEZIER, + CURVE_TYPE_NURBS, + CURVE_TYPE_NURBS, + CURVE_TYPE_NURBS, + CURVE_TYPE_CATMULL_ROM, + CURVE_TYPE_CATMULL_ROM, + CURVE_TYPE_CATMULL_ROM, + CURVE_TYPE_POLY, + CURVE_TYPE_POLY, + CURVE_TYPE_POLY, + }); + std::array<int, CURVE_TYPES_NUM> counts = curves.count_curve_types(); + EXPECT_EQ(counts[CURVE_TYPE_CATMULL_ROM], 3); + EXPECT_EQ(counts[CURVE_TYPE_POLY], 3); + EXPECT_EQ(counts[CURVE_TYPE_BEZIER], 1); + EXPECT_EQ(counts[CURVE_TYPE_NURBS], 3); +} + TEST(curves_geometry, CatmullRomEvaluation) { CurvesGeometry curves(4, 1); @@ -206,7 +228,7 @@ TEST(curves_geometry, CatmullRomTwoPointCyclic) /* The cyclic value should be ignored when there are only two control points. There should * be 12 evaluated points for the single segment and an extra for the last point. */ - EXPECT_EQ(curves.evaluated_points_size(), 13); + EXPECT_EQ(curves.evaluated_points_num(), 13); } TEST(curves_geometry, BezierPositionEvaluation) @@ -383,4 +405,77 @@ TEST(curves_geometry, NURBSEvaluation) } } +TEST(curves_geometry, BezierGenericEvaluation) +{ + CurvesGeometry curves(3, 1); + curves.curve_types().fill(CURVE_TYPE_BEZIER); + curves.resolution().fill(8); + curves.offsets().last() = 3; + + MutableSpan<float3> handles_left = curves.handle_positions_left(); + MutableSpan<float3> handles_right = curves.handle_positions_right(); + MutableSpan<float3> positions = curves.positions(); + positions.first() = {-1, 0, 0}; + handles_right.first() = {-1, 1, 0}; + handles_left[1] = {0, 0, 0}; + positions[1] = {1, 0, 0}; + handles_right[1] = {2, 0, 0}; + handles_left.last() = {1, 1, 0}; + positions.last() = {2, 1, 0}; + + /* Dangling handles shouldn't be used in a non-cyclic curve. */ + handles_left.first() = {100, 100, 100}; + handles_right.last() = {100, 100, 100}; + + Span<float3> evaluated_positions = curves.evaluated_positions(); + static const Array<float3> result_1{{ + {-1.0f, 0.0f, 0.0f}, + {-0.955078f, 0.287109f, 0.0f}, + {-0.828125f, 0.421875f, 0.0f}, + {-0.630859f, 0.439453f, 0.0f}, + {-0.375f, 0.375f, 0.0f}, + {-0.0722656f, 0.263672f, 0.0f}, + {0.265625f, 0.140625f, 0.0f}, + {0.626953f, 0.0410156f, 0.0f}, + {1.0f, 0.0f, 0.0f}, + {1.28906f, 0.0429688f, 0.0f}, + {1.4375f, 0.15625f, 0.0f}, + {1.49219f, 0.316406f, 0.0f}, + {1.5f, 0.5f, 0.0f}, + {1.50781f, 0.683594f, 0.0f}, + {1.5625f, 0.84375f, 0.0f}, + {1.71094f, 0.957031f, 0.0f}, + {2.0f, 1.0f, 0.0f}, + }}; + for (const int i : evaluated_positions.index_range()) { + EXPECT_V3_NEAR(evaluated_positions[i], result_1[i], 1e-5f); + } + + Array<float> radii{{0.0f, 1.0f, 2.0f}}; + Array<float> evaluated_radii(17); + curves.interpolate_to_evaluated(0, radii.as_span(), evaluated_radii.as_mutable_span()); + static const Array<float> result_2{{ + 0.0f, + 0.125f, + 0.25f, + 0.375f, + 0.5f, + 0.625f, + 0.75f, + 0.875f, + 1.0f, + 1.125f, + 1.25f, + 1.375f, + 1.5f, + 1.625f, + 1.75f, + 1.875f, + 2.0f, + }}; + for (const int i : evaluated_radii.index_range()) { + EXPECT_NEAR(evaluated_radii[i], result_2[i], 1e-6f); + } +} + } // namespace blender::bke::tests diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index e5424b39091..702488fb93b 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -62,6 +62,10 @@ BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)nullptr)->typemap) == CD_NUMTYPES, " static CLG_LogRef LOG = {"bke.customdata"}; +/* -------------------------------------------------------------------- */ +/** \name Mesh Mask Utilities + * \{ */ + void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, const CustomData_MeshMasks *mask_src) { @@ -82,7 +86,12 @@ bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref, ((mask_required->lmask & mask_ref->lmask) == mask_required->lmask)); } -/********************* Layer type information **********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Layer Type Information + * \{ */ + struct LayerTypeInfo { int size; /* the memory size of one element of this layer's data */ @@ -164,6 +173,12 @@ struct LayerTypeInfo { int (*layers_max)(); }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#MDeformVert, #CD_MDEFORMVERT) + * \{ */ + static void layerCopy_mdeformvert(const void *source, void *dest, int count) { int i, size = sizeof(MDeformVert); @@ -315,6 +330,12 @@ static void layerInterp_mdeformvert(const void **sources, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#vec3f, #CD_NORMAL) + * \{ */ + static void layerInterp_normal(const void **sources, const float *weights, const float *UNUSED(sub_weights), @@ -371,6 +392,12 @@ static void layerCopyValue_normal(const void *source, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#MTFace, #CD_MTFACE) + * \{ */ + static void layerCopy_tface(const void *source, void *dest, int count) { const MTFace *source_tf = (const MTFace *)source; @@ -436,6 +463,12 @@ static int layerMaxNum_tface() return MAX_MTFACE; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#MFloatProperty, #CD_PROP_FLOAT) + * \{ */ + static void layerCopy_propFloat(const void *source, void *dest, int count) { memcpy(dest, source, sizeof(MFloatProperty) * count); @@ -473,16 +506,34 @@ static bool layerValidate_propFloat(void *data, const uint totitems, const bool return has_errors; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#MIntProperty, #CD_PROP_INT32) + * \{ */ + static void layerCopy_propInt(const void *source, void *dest, int count) { memcpy(dest, source, sizeof(MIntProperty) * count); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#MStringProperty, #CD_PROP_STRING) + * \{ */ + static void layerCopy_propString(const void *source, void *dest, int count) { memcpy(dest, source, sizeof(MStringProperty) * count); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#OrigSpaceFace, #CD_ORIGSPACE) + * \{ */ + static void layerCopy_origspace_face(const void *source, void *dest, int count) { const OrigSpaceFace *source_tf = (const OrigSpaceFace *)source; @@ -541,6 +592,12 @@ static void layerDefault_origspace_face(void *data, int count) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#MDisps, #CD_MDISPS) + * \{ */ + static void layerSwap_mdisps(void *data, const int *ci) { MDisps *s = static_cast<MDisps *>(data); @@ -653,6 +710,13 @@ static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int return size; } + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (`float`, #CD_PAINT_MASK) + * \{ */ + static void layerInterp_paint_mask(const void **sources, const float *weights, const float *UNUSED(sub_weights), @@ -668,6 +732,12 @@ static void layerInterp_paint_mask(const void **sources, *(float *)dest = mask; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#GridPaintMask, #CD_GRID_PAINT_MASK) + * \{ */ + static void layerCopy_grid_paint_mask(const void *source, void *dest, int count) { const GridPaintMask *s = static_cast<const GridPaintMask *>(source); @@ -1179,6 +1249,12 @@ static void layerInterp_shapekey(const void **sources, copy_v3_v3((float *)dest, co); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#MVertSkin, #CD_MVERT_SKIN) + * \{ */ + static void layerDefault_mvert_skin(void *data, int count) { MVertSkin *vs = static_cast<MVertSkin *>(data); @@ -1216,6 +1292,12 @@ static void layerInterp_mvert_skin(const void **sources, vs_dst->flag &= ~MVERT_SKIN_ROOT; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (`short[4][3]`, #CD_TESSLOOPNORMAL) + * \{ */ + static void layerSwap_flnor(void *data, const int *corner_indices) { short(*flnors)[4][3] = static_cast<short(*)[4][3]>(data); @@ -1229,6 +1311,12 @@ static void layerSwap_flnor(void *data, const int *corner_indices) memcpy(flnors, nors, sizeof(nors)); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (`int`, #CD_FACEMAP) + * \{ */ + static void layerDefault_fmap(void *data, int count) { int *fmap_num = (int *)data; @@ -1237,6 +1325,12 @@ static void layerDefault_fmap(void *data, int count) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#MPropCol, #CD_PROP_COLOR) + * \{ */ + static void layerCopyValue_propcol(const void *source, void *dest, const int mixmode, @@ -1360,6 +1454,12 @@ static int layerMaxNum_propcol() return MAX_MCOL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#vec3f, #CD_PROP_FLOAT3) + * \{ */ + static void layerInterp_propfloat3(const void **sources, const float *weights, const float *UNUSED(sub_weights), @@ -1407,6 +1507,12 @@ static bool layerValidate_propfloat3(void *data, const uint totitems, const bool return has_errors; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (#vec2f, #CD_PROP_FLOAT2) + * \{ */ + static void layerInterp_propfloat2(const void **sources, const float *weights, const float *UNUSED(sub_weights), @@ -1452,6 +1558,12 @@ static bool layerValidate_propfloat2(void *data, const uint totitems, const bool return has_errors; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks for (`bool`, #CD_PROP_BOOL) + * \{ */ + static void layerInterp_propbool(const void **sources, const float *weights, const float *UNUSED(sub_weights), @@ -2053,7 +2165,12 @@ void customData_mask_layers__print(const CustomData_MeshMasks *mask) } } -/********************* CustomData functions *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name CustomData Functions + * \{ */ + static void customData_update_offsets(CustomData *data); static CustomDataLayer *customData_add_layer__internal(CustomData *data, @@ -4471,14 +4588,18 @@ void CustomData_layers__print(CustomData *data) printf("}\n"); } -/****************************** External Files *******************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name External Files + * \{ */ -static void customdata_external_filename(char filename[FILE_MAX], +static void customdata_external_filename(char filepath[FILE_MAX], ID *id, CustomDataExternal *external) { - BLI_strncpy(filename, external->filename, FILE_MAX); - BLI_path_abs(filename, ID_BLEND_PATH_FROM_GLOBAL(id)); + BLI_strncpy(filepath, external->filepath, FILE_MAX); + BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(id)); } void CustomData_external_reload(CustomData *data, ID *UNUSED(id), CustomDataMask mask, int totelem) @@ -4503,7 +4624,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int { CustomDataExternal *external = data->external; CustomDataLayer *layer; - char filename[FILE_MAX]; + char filepath[FILE_MAX]; int update = 0; if (!external) { @@ -4529,12 +4650,12 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int return; } - customdata_external_filename(filename, id, external); + customdata_external_filename(filepath, id, external); CDataFile *cdf = cdf_create(CDF_TYPE_MESH); - if (!cdf_read_open(cdf, filename)) { + if (!cdf_read_open(cdf, filepath)) { cdf_free(cdf); - CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filename); + CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filepath); return; } @@ -4577,7 +4698,7 @@ void CustomData_external_write( { CustomDataExternal *external = data->external; int update = 0; - char filename[FILE_MAX]; + char filepath[FILE_MAX]; if (!external) { return; @@ -4602,7 +4723,7 @@ void CustomData_external_write( /* make sure data is read before we try to write */ CustomData_external_read(data, id, mask, totelem); - customdata_external_filename(filename, id, external); + customdata_external_filename(filepath, id, external); CDataFile *cdf = cdf_create(CDF_TYPE_MESH); @@ -4622,8 +4743,8 @@ void CustomData_external_write( } } - if (!cdf_write_open(cdf, filename)) { - CLOG_ERROR(&LOG, "Failed to open %s for writing.", filename); + if (!cdf_write_open(cdf, filepath)) { + CLOG_ERROR(&LOG, "Failed to open %s for writing.", filepath); cdf_free(cdf); return; } @@ -4651,7 +4772,7 @@ void CustomData_external_write( } if (i != data->totlayer) { - CLOG_ERROR(&LOG, "Failed to write data to %s.", filename); + CLOG_ERROR(&LOG, "Failed to write data to %s.", filepath); cdf_write_close(cdf); cdf_free(cdf); return; @@ -4676,7 +4797,7 @@ void CustomData_external_write( } void CustomData_external_add( - CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filename) + CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filepath) { CustomDataExternal *external = data->external; @@ -4695,7 +4816,7 @@ void CustomData_external_add( external = MEM_cnew<CustomDataExternal>(__func__); data->external = external; } - BLI_strncpy(external->filename, filename, sizeof(external->filename)); + BLI_strncpy(external->filepath, filepath, sizeof(external->filepath)); layer->flag |= CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY; } @@ -4735,7 +4856,12 @@ bool CustomData_external_test(CustomData *data, int type) return (layer->flag & CD_FLAG_EXTERNAL) != 0; } -/* ********** Mesh-to-mesh data transfer ********** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh-to-Mesh Data Transfer + * \{ */ + static void copy_bit_flag(void *dst, const void *src, const size_t data_size, const uint64_t flag) { #define COPY_BIT_FLAG(_type, _dst, _src, _f) \ @@ -5014,6 +5140,12 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, MEM_SAFE_FREE(tmp_data_src); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Custom Data IO + * \{ */ + static void write_mdisps(BlendWriter *writer, int count, MDisps *mdlist, int external) { if (mdlist) { @@ -5208,6 +5340,12 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count) CustomData_update_typemap(data); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Custom Data Debugging + * \{ */ + #ifndef NDEBUG void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr) @@ -5238,8 +5376,16 @@ void CustomData_debug_info_from_layers(const CustomData *data, const char *inden #endif /* NDEBUG */ +/** \} */ + namespace blender::bke { +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Custom Data C++ API + * \{ */ + const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type) { switch (type) { @@ -5289,4 +5435,6 @@ CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type) return static_cast<CustomDataType>(-1); } +/** \} */ + } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 8ec7bbea0e5..0f5814c0a23 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -3266,7 +3266,7 @@ static void dynamic_paint_output_surface_image_wetmap_cb( } void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, - char *filename, + const char *filepath, short output_layer) { ImBuf *ibuf = NULL; @@ -3286,7 +3286,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, format = R_IMF_IMTYPE_PNG; } #endif - BLI_strncpy(output_file, filename, sizeof(output_file)); + BLI_strncpy(output_file, filepath, sizeof(output_file)); BKE_image_path_ensure_ext_from_imtype(output_file, format); /* Validate output file path */ diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index 7cf6fc5a03e..27689d70c77 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -236,10 +236,10 @@ int CurveComponent::attribute_domain_size(const AttributeDomain domain) const const blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap( curves_->geometry); if (domain == ATTR_DOMAIN_POINT) { - return geometry.points_size(); + return geometry.points_num(); } if (domain == ATTR_DOMAIN_CURVE) { - return geometry.curves_size(); + return geometry.curves_num(); } return 0; } diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 76c8a0054b3..2bfe984462c 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -944,20 +944,71 @@ class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> { if (dverts_ == nullptr) { return 0.0f; } - const MDeformVert &dvert = dverts_[index]; - for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) { - if (weight.def_nr == dvert_index_) { - return weight.weight; - } + if (const MDeformWeight *weight = this->find_weight_at_index(index)) { + return weight->weight; } return 0.0f; - ; } void set(const int64_t index, const float value) override { - MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_); - weight->weight = value; + MDeformVert &dvert = dverts_[index]; + if (value == 0.0f) { + if (MDeformWeight *weight = this->find_weight_at_index(index)) { + weight->weight = 0.0f; + } + } + else { + MDeformWeight *weight = BKE_defvert_ensure_index(&dvert, dvert_index_); + weight->weight = value; + } + } + + void set_all(Span<float> src) override + { + for (const int64_t index : src.index_range()) { + this->set(index, src[index]); + } + } + + void materialize(IndexMask mask, MutableSpan<float> r_span) const override + { + if (dverts_ == nullptr) { + return r_span.fill_indices(mask, 0.0f); + } + for (const int64_t index : mask) { + if (const MDeformWeight *weight = this->find_weight_at_index(index)) { + r_span[index] = weight->weight; + } + else { + r_span[index] = 0.0f; + } + } + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<float> r_span) const override + { + this->materialize(mask, r_span); + } + + private: + MDeformWeight *find_weight_at_index(const int64_t index) + { + for (MDeformWeight &weight : MutableSpan(dverts_[index].dw, dverts_[index].totweight)) { + if (weight.def_nr == dvert_index_) { + return &weight; + } + } + return nullptr; + } + const MDeformWeight *find_weight_at_index(const int64_t index) const + { + for (const MDeformWeight &weight : Span(dverts_[index].dw, dverts_[index].totweight)) { + if (weight.def_nr == dvert_index_) { + return &weight; + } + } + return nullptr; } }; diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index a5eff1f9d5a..a0b6ab2d654 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -980,74 +980,116 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo /** \name Stroke Smooth Positions * \{ */ -bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf, const bool smooth_caps) +bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, + int i, + float influence, + int iterations, + const bool smooth_caps, + const bool keep_shape, + bGPDstroke *r_gps) { - bGPDspoint *pt = &gps->points[i]; - float sco[3] = {0.0f}; - const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0; - - /* Do nothing if not enough points to smooth out */ - if (gps->totpoints <= 2) { + /* If nothing to do, return early */ + if (gps->totpoints <= 2 || iterations <= 0) { return false; } - /* Only affect endpoints by a fraction of the normal strength, - * to prevent the stroke from shrinking too much + /* Overview of the algorithm here and in the following smooth functions: + * The smooth functions return the new attribute in question for a single point. + * The result is stored in r_gps->points[i], while the data is read from gps. + * To get a correct result, duplicate the stroke point data and read from the copy, + * while writing to the real stroke. Not doing that will result in acceptable, but + * asymmetric results. + * This algorithm works as long as all points are being smoothed. If there is + * points that should not get smoothed, use the old repeat smooth pattern with + * the parameter "iterations" set to 1 or 2. (2 matches the old algorithm). */ - if ((!smooth_caps) && (!is_cyclic && ELEM(i, 0, gps->totpoints - 1))) { - inf *= 0.1f; - } - - /* Compute smoothed coordinate by taking the ones nearby */ - /* XXX: This is potentially slow, - * and suffers from accumulation error as earlier points are handled before later ones. */ - { - /* XXX: this is hardcoded to look at 2 points on either side of the current one - * (i.e. 5 items total). */ - const int steps = 2; - const float average_fac = 1.0f / (float)(steps * 2 + 1); - int step; - - /* add the point itself */ - madd_v3_v3fl(sco, &pt->x, average_fac); - - /* n-steps before/after current point */ - /* XXX: review how the endpoints are treated by this algorithm. */ - /* XXX: falloff measures should also introduce some weighting variations, - * so that further-out points get less weight. */ - for (step = 1; step <= steps; step++) { - bGPDspoint *pt1, *pt2; - int before = i - step; - int after = i + step; - - if (is_cyclic) { - if (before < 0) { - /* Sub to end point (before is already negative). */ - before = gps->totpoints + before; - CLAMP(before, 0, gps->totpoints - 1); - } - if (after > gps->totpoints - 1) { - /* Add to start point. */ - after = after - gps->totpoints; - CLAMP(after, 0, gps->totpoints - 1); + + const bGPDspoint *pt = &gps->points[i]; + const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0; + /* If smooth_caps is false, the caps will not be translated by smoothing. */ + if (!smooth_caps && !is_cyclic && ELEM(i, 0, gps->totpoints - 1)) { + copy_v3_v3(&r_gps->points[i].x, &pt->x); + return true; + } + + /* This function uses a binomial kernel, which is the discrete version of gaussian blur. + * The weight for a vertex at the relative index i is + * w = nCr(n, j + n/2) / 2^n = (n/1 * (n-1)/2 * ... * (n-j-n/2)/(j+n/2)) / 2^n + * All weights together sum up to 1 + * This is equivalent to doing multiple iterations of averaging neighbors, + * where n = iterations * 2 and -n/2 <= j <= n/2 + * + * Now the problem is that nCr(n, j + n/2) is very hard to compute for n > 500, since even + * double precision isn't sufficient. A very good robust approximation for n > 20 is + * nCr(n, j + n/2) / 2^n = sqrt(2/(pi*n)) * exp(-2*j*j/n) + * + * There is one more problem left: The old smooth algorithm was doing a more aggressive + * smooth. To solve that problem, choose a different n/2, which does not match the range and + * normalize the weights on finish. This may cause some artifacts at low values. + * + * keep_shape is a new option to stop the stroke from severly deforming. + * It uses different partially negative weights. + * w = 2 * (nCr(n, j + n/2) / 2^n) - (nCr(3*n, j + n) / 2^(3*n)) + * ~ 2 * sqrt(2/(pi*n)) * exp(-2*j*j/n) - sqrt(2/(pi*3*n)) * exp(-2*j*j/(3*n)) + * All weigths still sum up to 1. + * Note these weights only work because the averaging is done in relative coordinates. + */ + float sco[3] = {0.0f, 0.0f, 0.0f}; + float tmp[3]; + const int n_half = keep_shape ? (iterations * iterations) / 8 + iterations : + (iterations * iterations) / 4 + 2 * iterations + 12; + double w = keep_shape ? 2.0 : 1.0; + double w2 = keep_shape ? + (1.0 / M_SQRT3) * exp((2 * iterations * iterations) / (double)(n_half * 3)) : + 0.0; + double total_w = 0.0; + for (int step = iterations; step > 0; step--) { + int before = i - step; + int after = i + step; + float w_before = (float)(w - w2); + float w_after = (float)(w - w2); + + if (is_cyclic) { + before = (before % gps->totpoints + gps->totpoints) % gps->totpoints; + after = after % gps->totpoints; + } + else { + if (before < 0) { + if (!smooth_caps) { + w_before *= -before / (float)i; } + before = 0; } - else { - CLAMP_MIN(before, 0); - CLAMP_MAX(after, gps->totpoints - 1); + if (after > gps->totpoints - 1) { + if (!smooth_caps) { + w_after *= (after - (gps->totpoints - 1)) / (float)(gps->totpoints - 1 - i); + } + after = gps->totpoints - 1; } + } - pt1 = &gps->points[before]; - pt2 = &gps->points[after]; + /* Add both these points in relative coordinates to the weighted average sum. */ + sub_v3_v3v3(tmp, &gps->points[before].x, &pt->x); + madd_v3_v3fl(sco, tmp, w_before); + sub_v3_v3v3(tmp, &gps->points[after].x, &pt->x); + madd_v3_v3fl(sco, tmp, w_after); - /* add both these points to the average-sum (s += p[i]/n) */ - madd_v3_v3fl(sco, &pt1->x, average_fac); - madd_v3_v3fl(sco, &pt2->x, average_fac); - } + total_w += w_before; + total_w += w_after; + + w *= (n_half + step) / (double)(n_half + 1 - step); + w2 *= (n_half * 3 + step) / (double)(n_half * 3 + 1 - step); } + total_w += w - w2; + /* The accumulated weight total_w should be + * ~sqrt(M_PI * n_half) * exp((iterations * iterations) / n_half) < 100 + * here, but sometimes not quite. */ + mul_v3_fl(sco, (float)(1.0 / total_w)); + /* Shift back to global coordinates. */ + add_v3_v3(sco, &pt->x); - /* Based on influence factor, blend between original and optimal smoothed coordinate */ - interp_v3_v3v3(&pt->x, &pt->x, sco, inf); + /* Based on influence factor, blend between original and optimal smoothed coordinate. */ + interp_v3_v3v3(&r_gps->points[i].x, &pt->x, sco, influence); return true; } @@ -1058,74 +1100,54 @@ bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf, const bo /** \name Stroke Smooth Strength * \{ */ -bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float influence) +bool BKE_gpencil_stroke_smooth_strength( + bGPDstroke *gps, int i, float influence, int iterations, bGPDstroke *r_gps) { - bGPDspoint *ptb = &gps->points[point_index]; - const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0; - - /* Do nothing if not enough points */ - if ((gps->totpoints <= 2) || (point_index < 1)) { + /* If nothing to do, return early */ + if (gps->totpoints <= 2 || iterations <= 0) { return false; } - /* Only affect endpoints by a fraction of the normal influence */ - float inf = influence; - if (!is_cyclic && ELEM(point_index, 0, gps->totpoints - 1)) { - inf *= 0.01f; - } - /* Limit max influence to reduce pop effect. */ - CLAMP_MAX(inf, 0.98f); - - float total = 0.0f; - float max_strength = 0.0f; - const int steps = 4; - const float average_fac = 1.0f / (float)(steps * 2 + 1); - int step; - /* add the point itself */ - total += ptb->strength * average_fac; - max_strength = ptb->strength; + /* See BKE_gpencil_stroke_smooth_point for details on the algorithm. */ - /* n-steps before/after current point */ - for (step = 1; step <= steps; step++) { - bGPDspoint *pt1, *pt2; - int before = point_index - step; - int after = point_index + step; + const bGPDspoint *pt = &gps->points[i]; + const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0; + float strength = 0.0f; + const int n_half = (iterations * iterations) / 4 + iterations; + double w = 1.0; + double total_w = 0.0; + for (int step = iterations; step > 0; step--) { + int before = i - step; + int after = i + step; + float w_before = (float)w; + float w_after = (float)w; if (is_cyclic) { - if (before < 0) { - /* Sub to end point (before is already negative). */ - before = gps->totpoints + before; - CLAMP(before, 0, gps->totpoints - 1); - } - if (after > gps->totpoints - 1) { - /* Add to start point. */ - after = after - gps->totpoints; - CLAMP(after, 0, gps->totpoints - 1); - } + before = (before % gps->totpoints + gps->totpoints) % gps->totpoints; + after = after % gps->totpoints; } else { CLAMP_MIN(before, 0); CLAMP_MAX(after, gps->totpoints - 1); } - pt1 = &gps->points[before]; - pt2 = &gps->points[after]; - /* add both these points to the average-sum (s += p[i]/n) */ - total += pt1->strength * average_fac; - total += pt2->strength * average_fac; - /* Save max value. */ - if (max_strength < pt1->strength) { - max_strength = pt1->strength; - } - if (max_strength < pt2->strength) { - max_strength = pt2->strength; - } + /* Add both these points in relative coordinates to the weighted average sum. */ + strength += w_before * (gps->points[before].strength - pt->strength); + strength += w_after * (gps->points[after].strength - pt->strength); + + total_w += w_before; + total_w += w_after; + + w *= (n_half + step) / (double)(n_half + 1 - step); } + total_w += w; + /* The accumulated weight total_w should be + * ~sqrt(M_PI * n_half) * exp((iterations * iterations) / n_half) < 100 + * here, but sometimes not quite. */ + strength /= total_w; /* Based on influence factor, blend between original and optimal smoothed value. */ - ptb->strength = interpf(ptb->strength, total, inf); - /* Clamp to maximum stroke strength to avoid weird results. */ - CLAMP_MAX(ptb->strength, max_strength); + r_gps->points[i].strength = pt->strength + strength * influence; return true; } @@ -1136,74 +1158,55 @@ bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float /** \name Stroke Smooth Thickness * \{ */ -bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float influence) +bool BKE_gpencil_stroke_smooth_thickness( + bGPDstroke *gps, int i, float influence, int iterations, bGPDstroke *r_gps) { - bGPDspoint *ptb = &gps->points[point_index]; - const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0; - - /* Do nothing if not enough points */ - if ((gps->totpoints <= 2) || (point_index < 1)) { + /* If nothing to do, return early */ + if (gps->totpoints <= 2 || iterations <= 0) { return false; } - /* Only affect endpoints by a fraction of the normal influence */ - float inf = influence; - if (!is_cyclic && ELEM(point_index, 0, gps->totpoints - 1)) { - inf *= 0.01f; - } - /* Limit max influence to reduce pop effect. */ - CLAMP_MAX(inf, 0.98f); - - float total = 0.0f; - float max_pressure = 0.0f; - const int steps = 4; - const float average_fac = 1.0f / (float)(steps * 2 + 1); - int step; - /* add the point itself */ - total += ptb->pressure * average_fac; - max_pressure = ptb->pressure; + /* See BKE_gpencil_stroke_smooth_point for details on the algorithm. */ - /* n-steps before/after current point */ - for (step = 1; step <= steps; step++) { - bGPDspoint *pt1, *pt2; - int before = point_index - step; - int after = point_index + step; + const bGPDspoint *pt = &gps->points[i]; + const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0; + float pressure = 0.0f; + const int n_half = (iterations * iterations) / 4 + iterations; + double w = 1.0; + double total_w = 0.0; + for (int step = iterations; step > 0; step--) { + int before = i - step; + int after = i + step; + float w_before = (float)w; + float w_after = (float)w; if (is_cyclic) { - if (before < 0) { - /* Sub to end point (before is already negative). */ - before = gps->totpoints + before; - CLAMP(before, 0, gps->totpoints - 1); - } - if (after > gps->totpoints - 1) { - /* Add to start point. */ - after = after - gps->totpoints; - CLAMP(after, 0, gps->totpoints - 1); - } + before = (before % gps->totpoints + gps->totpoints) % gps->totpoints; + after = after % gps->totpoints; } else { CLAMP_MIN(before, 0); CLAMP_MAX(after, gps->totpoints - 1); } - pt1 = &gps->points[before]; - pt2 = &gps->points[after]; - /* add both these points to the average-sum (s += p[i]/n) */ - total += pt1->pressure * average_fac; - total += pt2->pressure * average_fac; - /* Save max value. */ - if (max_pressure < pt1->pressure) { - max_pressure = pt1->pressure; - } - if (max_pressure < pt2->pressure) { - max_pressure = pt2->pressure; - } + /* Add both these points in relative coordinates to the weighted average sum. */ + pressure += w_before * (gps->points[before].pressure - pt->pressure); + pressure += w_after * (gps->points[after].pressure - pt->pressure); + + total_w += w_before; + total_w += w_after; + + w *= (n_half + step) / (double)(n_half + 1 - step); } + total_w += w; + /* The accumulated weight total_w should be + * ~sqrt(M_PI * n_half) * exp((iterations * iterations) / n_half) < 100 + * here, but sometimes not quite. */ + pressure /= total_w; /* Based on influence factor, blend between original and optimal smoothed value. */ - ptb->pressure = interpf(ptb->pressure, total, inf); - /* Clamp to maximum stroke thickness to avoid weird results. */ - CLAMP_MAX(ptb->pressure, max_pressure); + r_gps->points[i].pressure = pt->pressure + pressure * influence; + return true; } @@ -1213,57 +1216,127 @@ bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float /** \name Stroke Smooth UV * \{ */ -bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influence) +bool BKE_gpencil_stroke_smooth_uv( + struct bGPDstroke *gps, int i, float influence, int iterations, struct bGPDstroke *r_gps) { - bGPDspoint *ptb = &gps->points[point_index]; + /* If nothing to do, return early */ + if (gps->totpoints <= 2 || iterations <= 0) { + return false; + } + + /* See BKE_gpencil_stroke_smooth_point for details on the algorithm. */ + + const bGPDspoint *pt = &gps->points[i]; const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0; - /* Do nothing if not enough points */ - if (gps->totpoints <= 2) { - return false; + /* If don't change the caps. */ + if (!is_cyclic && ELEM(i, 0, gps->totpoints - 1)) { + r_gps->points[i].uv_rot = pt->uv_rot; + r_gps->points[i].uv_fac = pt->uv_fac; + return true; } - /* Compute theoretical optimal value */ - bGPDspoint *pta, *ptc; - int before = point_index - 1; - int after = point_index + 1; + float uv_rot = 0.0f; + float uv_fac = 0.0f; + const int n_half = iterations * iterations + iterations; + double w = 1.0; + double total_w = 0.0; + for (int step = iterations; step > 0; step--) { + int before = i - step; + int after = i + step; + float w_before = (float)w; + float w_after = (float)w; - if (is_cyclic) { - if (before < 0) { - /* Sub to end point (before is already negative). */ - before = gps->totpoints + before; - CLAMP(before, 0, gps->totpoints - 1); + if (is_cyclic) { + before = (before % gps->totpoints + gps->totpoints) % gps->totpoints; + after = after % gps->totpoints; } - if (after > gps->totpoints - 1) { - /* Add to start point. */ - after = after - gps->totpoints; - CLAMP(after, 0, gps->totpoints - 1); + else { + if (before < 0) { + w_before *= -before / (float)i; + before = 0; + } + if (after > gps->totpoints - 1) { + w_after *= (after - (gps->totpoints - 1)) / (float)(gps->totpoints - 1 - i); + after = gps->totpoints - 1; + } } - } - else { - CLAMP_MIN(before, 0); - CLAMP_MAX(after, gps->totpoints - 1); - } - pta = &gps->points[before]; - ptc = &gps->points[after]; - /* the optimal value is the corresponding to the interpolation of the pressure - * at the distance of point b - */ - float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); - /* sometimes the factor can be wrong due stroke geometry, so use middle point */ - if ((fac < 0.0f) || (fac > 1.0f)) { - fac = 0.5f; + /* Add both these points in relative coordinates to the weighted average sum. */ + uv_rot += w_before * (gps->points[before].uv_rot - pt->uv_rot); + uv_rot += w_after * (gps->points[after].uv_rot - pt->uv_rot); + uv_fac += w_before * (gps->points[before].uv_fac - pt->uv_fac); + uv_fac += w_after * (gps->points[after].uv_fac - pt->uv_fac); + + total_w += w_before; + total_w += w_after; + + w *= (n_half + step) / (double)(n_half + 1 - step); } - float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac); + total_w += w; + /* The accumulated weight total_w should be + * ~sqrt(M_PI * n_half) * exp((iterations * iterations) / n_half) < 100 + * here, but sometimes not quite. */ + uv_rot /= total_w; + uv_fac /= total_w; - /* Based on influence factor, blend between original and optimal */ - ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence); - CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2); + /* Based on influence factor, blend between original and optimal smoothed value. */ + r_gps->points[i].uv_rot = pt->uv_rot + uv_rot * influence; + r_gps->points[i].uv_fac = pt->uv_fac + uv_fac * influence; return true; } +void BKE_gpencil_stroke_smooth(bGPDstroke *gps, + const float influence, + const int iterations, + const bool smooth_position, + const bool smooth_strength, + const bool smooth_thickness, + const bool smooth_uv, + const bool keep_shape, + const float *weights) +{ + if (influence <= 0 || iterations <= 0) { + return; + } + + /* Make a copy of the point data to avoid directionality of the smooth operation. */ + bGPDstroke gps_old = *gps; + gps_old.points = (bGPDspoint *)MEM_dupallocN(gps->points); + + /* Smooth stroke. */ + for (int i = 0; i < gps->totpoints; i++) { + float val = influence; + if (weights != NULL) { + val *= weights[i]; + if (val <= 0.0f) { + continue; + } + } + + /* TODO: Currently the weights only control the influence, but is would be much better if they + * would control the distribution used in smooth, similar to how the ends are handled. */ + + /* Perform smoothing. */ + if (smooth_position) { + BKE_gpencil_stroke_smooth_point(&gps_old, i, val, iterations, false, keep_shape, gps); + } + if (smooth_strength) { + BKE_gpencil_stroke_smooth_strength(&gps_old, i, val, iterations, gps); + } + if (smooth_thickness) { + BKE_gpencil_stroke_smooth_thickness(&gps_old, i, val, iterations, gps); + } + if (smooth_uv) { + BKE_gpencil_stroke_smooth_uv(&gps_old, i, val, iterations, gps); + } + } + + /* Free the copied points array. */ + MEM_freeN(gps_old.points); +} + void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, float (*points2d)[2], @@ -3443,7 +3516,7 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a, for (i = start; i < end; i++) { pt = &gps_a->points[i]; pt->pressure += (avg_pressure - pt->pressure) * ratio; - BKE_gpencil_stroke_smooth_point(gps_a, i, ratio * 0.6f, false); + BKE_gpencil_stroke_smooth_point(gps_a, i, ratio * 0.6f, 2, false, true, gps_a); ratio += step; /* In the center, reverse the ratio. */ diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index cfdd048495d..3eade265bf2 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -9,6 +9,7 @@ #include <cmath> #include <cstdio> #include <cstring> +#include <ctime> #include <fcntl.h> #ifndef WIN32 # include <unistd.h> @@ -16,7 +17,8 @@ # include <io.h> #endif -#include <ctime> +#include <regex> +#include <string> #include "BLI_array.hh" @@ -237,7 +239,7 @@ static void image_foreach_cache(ID *id, auto gputexture_offset = [image](int target, int eye, int resolution) { constexpr size_t base_offset = offsetof(Image, gputexture); - const auto first = &image->gputexture[0][0][0]; + struct GPUTexture **first = &image->gputexture[0][0][0]; const size_t array_offset = sizeof(*first) * (&image->gputexture[target][eye][resolution] - first); return base_offset + array_offset; @@ -466,7 +468,9 @@ constexpr IDTypeInfo get_type_info() IDTypeInfo IDType_ID_IM = get_type_info(); /* prototypes */ -static int image_num_files(struct Image *ima); +static int image_num_viewfiles(Image *ima); +static ImBuf *image_load_image_file( + Image *ima, ImageUser *iuser, int entry, int cfra, bool is_sequence); static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock); static void image_update_views_format(Image *ima, ImageUser *iuser); static void image_add_view(Image *ima, const char *viewname, const char *filepath); @@ -487,9 +491,9 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat /** \name Image Cache * \{ */ -typedef struct ImageCacheKey { +struct ImageCacheKey { int index; -} ImageCacheKey; +}; static unsigned int imagecache_hashhash(const void *key_v) { @@ -1275,9 +1279,9 @@ bool BKE_image_memorypack(Image *ima) void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) { - const int totfiles = image_num_files(ima); + const int tot_viewfiles = image_num_viewfiles(ima); - if (totfiles == 1) { + if (tot_viewfiles == 1) { ImagePackedFile *imapf = static_cast<ImagePackedFile *>( MEM_mallocN(sizeof(ImagePackedFile), "Image packed file")); BLI_addtail(&ima->packedfiles, imapf); @@ -1311,9 +1315,9 @@ void BKE_image_packfiles_from_mem(ReportList *reports, char *data, const size_t data_len) { - const int totfiles = image_num_files(ima); + const int tot_viewfiles = image_num_viewfiles(ima); - if (totfiles != 1) { + if (tot_viewfiles != 1) { BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently..."); } else { @@ -2942,9 +2946,9 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) case IMA_SIGNAL_RELOAD: /* try to repack file */ if (BKE_image_has_packedfile(ima)) { - const int totfiles = image_num_files(ima); + const int tot_viewfiles = image_num_viewfiles(ima); - if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) { + if (tot_viewfiles != BLI_listbase_count_at_most(&ima->packedfiles, tot_viewfiles + 1)) { /* in case there are new available files to be loaded */ image_free_packedfiles(ima); BKE_image_packfiles(nullptr, ima, ID_BLEND_PATH(bmain, &ima->id)); @@ -3111,14 +3115,15 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *tile_start, i int max_udim = 0; int id; - struct direntry *dir; - uint totfile = BLI_filelist_dir_contents(dirname, &dir); - for (int i = 0; i < totfile; i++) { - if (!(dir[i].type & S_IFREG)) { + struct direntry *dirs; + const uint dirs_num = BLI_filelist_dir_contents(dirname, &dirs); + for (int i = 0; i < dirs_num; i++) { + if (!(dirs[i].type & S_IFREG)) { continue; } - if (!BKE_image_get_tile_number_from_filepath(dir[i].relname, udim_pattern, tile_format, &id)) { + if (!BKE_image_get_tile_number_from_filepath( + dirs[i].relname, udim_pattern, tile_format, &id)) { continue; } @@ -3131,7 +3136,7 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *tile_start, i min_udim = min_ii(min_udim, id); max_udim = max_ii(max_udim, id); } - BLI_filelist_free(dir, totfile); + BLI_filelist_free(dirs, dirs_num); MEM_SAFE_FREE(udim_pattern); if (is_udim && min_udim <= IMA_UDIM_MAX) { @@ -3316,69 +3321,24 @@ void BKE_image_ensure_tile_token(char *filename) return; } - /* Is there a sequence of digits in the filename? */ - ushort digits; - char head[FILE_MAX], tail[FILE_MAX]; - BLI_path_sequence_decode(filename, head, tail, &digits); - if (digits == 4) { - sprintf(filename, "%s<UDIM>%s", head, tail); - return; - } - - /* Is there a sequence like u##_v#### in the filename? */ - uint cur = 0; - uint name_end = strlen(filename); - uint u_digits = 0; - uint v_digits = 0; - uint u_start = (uint)-1; - bool u_found = false; - bool v_found = false; - bool sep_found = false; - while (cur < name_end) { - if (filename[cur] == 'u') { - u_found = true; - u_digits = 0; - u_start = cur; - } - else if (filename[cur] == 'v') { - v_found = true; - v_digits = 0; - } - else if (u_found && !v_found) { - if (isdigit(filename[cur]) && u_digits < 2) { - u_digits++; - } - else if (filename[cur] == '_') { - sep_found = true; - } - else { - u_found = false; - } - } - else if (u_found && u_digits > 0 && v_found) { - if (isdigit(filename[cur])) { - if (v_digits < 4) { - v_digits++; - } - else { - u_found = false; - v_found = false; - } - } - else if (v_digits > 0) { - break; - } - } + std::string path(filename); + std::smatch match; - cur++; + /* General 4-digit "udim" pattern. As this format is susceptible to ambiguity + * with other digit sequences, we can leverage the supported range of roughly + * 1000 through 2000 to provide better detection. + */ + std::regex pattern(R"((^|.*?\D)([12]\d{3})(\D.*))"); + if (std::regex_search(path, match, pattern)) { + BLI_strncpy(filename, match.format("$1<UDIM>$3").c_str(), FILE_MAX); + return; } - if (u_found && sep_found && v_found && (u_digits + v_digits > 1)) { - const char *token = "<UVTILE>"; - const size_t token_length = strlen(token); - memmove(filename + u_start + token_length, filename + cur, name_end - cur); - memcpy(filename + u_start, token, token_length); - filename[u_start + token_length + (name_end - cur)] = '\0'; + /* General `u##_v###` `uvtile` pattern. */ + pattern = std::regex(R"((.*)(u\d{1,2}_v\d{1,3})(\D.*))"); + if (std::regex_search(path, match, pattern)) { + BLI_strncpy(filename, match.format("$1<UVTILE>$3").c_str(), FILE_MAX); + return; } } @@ -3393,15 +3353,15 @@ bool BKE_image_tile_filepath_exists(const char *filepath) char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format); bool found = false; - struct direntry *dir; - uint totfile = BLI_filelist_dir_contents(dirname, &dir); - for (int i = 0; i < totfile; i++) { - if (!(dir[i].type & S_IFREG)) { + struct direntry *dirs; + const uint dirs_num = BLI_filelist_dir_contents(dirname, &dirs); + for (int i = 0; i < dirs_num; i++) { + if (!(dirs[i].type & S_IFREG)) { continue; } int id; - if (!BKE_image_get_tile_number_from_filepath(dir[i].path, udim_pattern, tile_format, &id)) { + if (!BKE_image_get_tile_number_from_filepath(dirs[i].path, udim_pattern, tile_format, &id)) { continue; } @@ -3412,7 +3372,7 @@ bool BKE_image_tile_filepath_exists(const char *filepath) found = true; break; } - BLI_filelist_free(dir, totfile); + BLI_filelist_free(dirs, dirs_num); MEM_SAFE_FREE(udim_pattern); return found; @@ -3781,7 +3741,7 @@ static int imbuf_alpha_flags_for_image(Image *ima) /** * \return the number of files will vary according to the stereo format. */ -static int image_num_files(Image *ima) +static int image_num_viewfiles(Image *ima) { const bool is_multiview = BKE_image_is_multiview(ima); @@ -3796,117 +3756,6 @@ static int image_num_files(Image *ima) return BLI_listbase_count(&ima->views); } -static ImBuf *load_sequence_single( - Image *ima, ImageUser *iuser, int frame, const int view_id, bool *r_cache_ibuf) -{ - struct ImBuf *ibuf; - char name[FILE_MAX]; - int flag; - ImageUser iuser_t{}; - - *r_cache_ibuf = true; - - ima->lastframe = frame; - - if (iuser) { - iuser_t = *iuser; - } - else { - /* BKE_image_user_file_path() uses this value for file name for sequences. */ - iuser_t.framenr = frame; - /* TODO(sergey): Do we need to initialize something else here? */ - } - - iuser_t.view = view_id; - BKE_image_user_file_path(&iuser_t, ima, name); - - flag = IB_rect | IB_multilayer | IB_metadata; - flag |= imbuf_alpha_flags_for_image(ima); - - /* read ibuf */ - ibuf = IMB_loadiffname(name, flag, ima->colorspace_settings.name); - -#if 0 - if (ibuf) { - printf(AT " loaded %s\n", name); - } - else { - printf(AT " missed %s\n", name); - } -#endif - - if (ibuf) { -#ifdef WITH_OPENEXR - if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) { - /* Handle multilayer and multiview cases, don't assign ibuf here. - * will be set layer in BKE_image_acquire_ibuf from ima->rr. */ - if (IMB_exr_has_multilayer(ibuf->userdata)) { - image_create_multilayer(ima, ibuf, frame); - ima->type = IMA_TYPE_MULTILAYER; - IMB_freeImBuf(ibuf); - ibuf = nullptr; - /* Null ibuf in the cache means the image failed to load. However for multilayer we load - * pixels into RenderResult instead and intentionally leave ibuf null. */ - *r_cache_ibuf = false; - } - } - else { - image_init_after_load(ima, iuser, ibuf); - } -#else - image_init_after_load(ima, iuser, ibuf); -#endif - } - - return ibuf; -} - -static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry, int frame) -{ - struct ImBuf *ibuf = nullptr; - const bool is_multiview = BKE_image_is_multiview(ima); - const int totfiles = image_num_files(ima); - - if (!is_multiview) { - bool put_in_cache; - ibuf = load_sequence_single(ima, iuser, frame, 0, &put_in_cache); - if (put_in_cache) { - image_assign_ibuf(ima, ibuf, 0, entry); - } - } - else { - const int totviews = BLI_listbase_count(&ima->views); - Array<ImBuf *> ibuf_arr(totviews); - Array<bool> cache_ibuf_arr(totviews); - - for (int i = 0; i < totfiles; i++) { - ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &cache_ibuf_arr[i]); - } - - if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) { - IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); - } - - /* return the original requested ImBuf */ - ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)]; - - for (int i = 0; i < totviews; i++) { - if (cache_ibuf_arr[i]) { - image_assign_ibuf(ima, ibuf_arr[i], i, entry); - } - } - - /* "remove" the others (decrease their refcount) */ - for (int i = 0; i < totviews; i++) { - if (ibuf_arr[i] != ibuf) { - IMB_freeImBuf(ibuf_arr[i]); - } - } - } - - return ibuf; -} - static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int entry, int frame) { struct ImBuf *ibuf = nullptr; @@ -3925,7 +3774,7 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int e ima->rr = nullptr; } - ibuf = image_load_sequence_file(ima, iuser, entry, frame); + ibuf = image_load_image_file(ima, iuser, entry, frame, true); if (ibuf) { /* actually an error */ ima->type = IMA_TYPE_IMAGE; @@ -4012,12 +3861,12 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) { struct ImBuf *ibuf = nullptr; const bool is_multiview = BKE_image_is_multiview(ima); - const int totfiles = image_num_files(ima); + const int tot_viewfiles = image_num_viewfiles(ima); - if (totfiles != BLI_listbase_count_at_most(&ima->anims, totfiles + 1)) { + if (tot_viewfiles != BLI_listbase_count_at_most(&ima->anims, tot_viewfiles + 1)) { image_free_anims(ima); - for (int i = 0; i < totfiles; i++) { + for (int i = 0; i < tot_viewfiles; i++) { /* allocate the ImageAnim */ ImageAnim *ia = MEM_cnew<ImageAnim>("Image Anim"); BLI_addtail(&ima->anims, ia); @@ -4032,7 +3881,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) const int totviews = BLI_listbase_count(&ima->views); Array<ImBuf *> ibuf_arr(totviews); - for (int i = 0; i < totfiles; i++) { + for (int i = 0; i < tot_viewfiles; i++) { ibuf_arr[i] = load_movie_single(ima, iuser, frame, i); } @@ -4063,23 +3912,21 @@ static ImBuf *load_image_single(Image *ima, int cfra, const int view_id, const bool has_packed, + const bool is_sequence, bool *r_cache_ibuf) { char filepath[FILE_MAX]; struct ImBuf *ibuf = nullptr; - int flag; + int flag = IB_rect | IB_multilayer; *r_cache_ibuf = true; /* is there a PackedFile with this image ? */ - if (has_packed) { - ImagePackedFile *imapf; - - flag = IB_rect | IB_multilayer; - flag |= imbuf_alpha_flags_for_image(ima); - - imapf = static_cast<ImagePackedFile *>(BLI_findlink(&ima->packedfiles, view_id)); + if (has_packed && !is_sequence) { + ImagePackedFile *imapf = static_cast<ImagePackedFile *>( + BLI_findlink(&ima->packedfiles, view_id)); if (imapf->packedfile) { + flag |= imbuf_alpha_flags_for_image(ima); ibuf = IMB_ibImageFromMemory((unsigned char *)imapf->packedfile->data, imapf->packedfile->size, flag, @@ -4088,14 +3935,17 @@ static ImBuf *load_image_single(Image *ima, } } else { - ImageUser iuser_t{}; - - flag = IB_rect | IB_multilayer | IB_metadata; - flag |= imbuf_alpha_flags_for_image(ima); + if (is_sequence) { + ima->lastframe = cfra; + } /* get the correct filepath */ - BKE_image_user_frame_calc(ima, iuser, cfra); + const bool is_tiled = (ima->source == IMA_SRC_TILED); + if (!(is_sequence || is_tiled)) { + BKE_image_user_frame_calc(ima, iuser, cfra); + } + ImageUser iuser_t{}; if (iuser) { iuser_t = *iuser; } @@ -4108,6 +3958,8 @@ static ImBuf *load_image_single(Image *ima, BKE_image_user_file_path(&iuser_t, ima, filepath); /* read ibuf */ + flag |= IB_metadata; + flag |= imbuf_alpha_flags_for_image(ima); ibuf = IMB_loadiffname(filepath, flag, ima->colorspace_settings.name); } @@ -4132,7 +3984,7 @@ static ImBuf *load_image_single(Image *ima, image_init_after_load(ima, iuser, ibuf); /* Make packed file for auto-pack. */ - if ((has_packed == false) && (G.fileflags & G_FILE_AUTOPACK)) { + if (!is_sequence && (has_packed == false) && (G.fileflags & G_FILE_AUTOPACK)) { ImagePackedFile *imapf = static_cast<ImagePackedFile *>( MEM_mallocN(sizeof(ImagePackedFile), "Image Pack-file")); BLI_addtail(&ima->packedfiles, imapf); @@ -4150,18 +4002,23 @@ static ImBuf *load_image_single(Image *ima, /* warning, 'iuser' can be null * NOTE: Image->views was already populated (in image_update_views_format) */ -static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) +static ImBuf *image_load_image_file( + Image *ima, ImageUser *iuser, int entry, int cfra, bool is_sequence) { struct ImBuf *ibuf = nullptr; const bool is_multiview = BKE_image_is_multiview(ima); - const int totfiles = image_num_files(ima); + const bool is_tiled = (ima->source == IMA_SRC_TILED); + const int tot_viewfiles = image_num_viewfiles(ima); bool has_packed = BKE_image_has_packedfile(ima); - /* always ensure clean ima */ - BKE_image_free_buffers(ima); + if (!(is_sequence || is_tiled)) { + /* ensure clean ima */ + BKE_image_free_buffers(ima); + } /* this should never happen, but just playing safe */ - if (has_packed) { + if (!is_sequence && has_packed) { + const int totfiles = tot_viewfiles * BLI_listbase_count(&ima->tiles); if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) { image_free_packedfiles(ima); has_packed = false; @@ -4170,9 +4027,10 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) if (!is_multiview) { bool put_in_cache; - ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &put_in_cache); + ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, is_sequence, &put_in_cache); if (put_in_cache) { - image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + const int index = (is_sequence || is_tiled) ? 0 : IMA_NO_INDEX; + image_assign_ibuf(ima, ibuf, index, entry); } } else { @@ -4182,28 +4040,29 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) Array<ImBuf *> ibuf_arr(totviews); Array<bool> cache_ibuf_arr(totviews); - for (int i = 0; i < totfiles; i++) { - ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &cache_ibuf_arr[i]); + for (int i = 0; i < tot_viewfiles; i++) { + ibuf_arr[i] = load_image_single( + ima, iuser, cfra, i, has_packed, is_sequence, &cache_ibuf_arr[i]); } /* multi-views/multi-layers OpenEXR files directly populate ima, and return null ibuf... */ if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D && ibuf_arr[0] && - totfiles == 1 && totviews >= 2) { + tot_viewfiles == 1 && totviews >= 2) { IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); } /* return the original requested ImBuf */ - int i = (iuser && iuser->multi_index < totviews) ? iuser->multi_index : 0; - ibuf = ibuf_arr[i]; + const int ibuf_index = (iuser && iuser->multi_index < totviews) ? iuser->multi_index : 0; + ibuf = ibuf_arr[ibuf_index]; - for (i = 0; i < totviews; i++) { + for (int i = 0; i < totviews; i++) { if (cache_ibuf_arr[i]) { - image_assign_ibuf(ima, ibuf_arr[i], i, 0); + image_assign_ibuf(ima, ibuf_arr[i], i, entry); } } /* "remove" the others (decrease their refcount) */ - for (i = 0; i < totviews; i++) { + for (int i = 0; i < totviews; i++) { if (ibuf_arr[i] != ibuf) { IMB_freeImBuf(ibuf_arr[i]); } @@ -4218,7 +4077,7 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser) ImBuf *ibuf = nullptr; if (ima->rr == nullptr) { - ibuf = image_load_image_file(ima, iuser, 0); + ibuf = image_load_image_file(ima, iuser, 0, 0, false); if (ibuf) { /* actually an error */ ima->type = IMA_TYPE_IMAGE; return ibuf; @@ -4595,7 +4454,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) else if (ima->source == IMA_SRC_SEQUENCE) { if (ima->type == IMA_TYPE_IMAGE) { /* Regular files, ibufs in flip-book, allows saving. */ - ibuf = image_load_sequence_file(ima, iuser, entry, entry); + ibuf = image_load_image_file(ima, iuser, entry, entry, true); } /* no else; on load the ima type can change */ if (ima->type == IMA_TYPE_MULTILAYER) { @@ -4606,7 +4465,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) else if (ima->source == IMA_SRC_TILED) { if (ima->type == IMA_TYPE_IMAGE) { /* Regular files, ibufs in flip-book, allows saving */ - ibuf = image_load_sequence_file(ima, iuser, entry, 0); + ibuf = image_load_image_file(ima, iuser, entry, 0, false); } /* no else; on load the ima type can change */ if (ima->type == IMA_TYPE_MULTILAYER) { @@ -4617,7 +4476,8 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) else if (ima->source == IMA_SRC_FILE) { if (ima->type == IMA_TYPE_IMAGE) { - ibuf = image_load_image_file(ima, iuser, entry); /* cfra only for '#', this global is OK */ + ibuf = image_load_image_file( + ima, iuser, 0, entry, false); /* cfra only for '#', this global is OK */ } /* no else; on load the ima type can change */ if (ima->type == IMA_TYPE_MULTILAYER) { @@ -5096,7 +4956,7 @@ void BKE_image_user_file_path_ex(ImageUser *iuser, Image *ima, char *filepath, b bool BKE_image_has_alpha(Image *image) { void *lock; - ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(image, nullptr, &lock); const int planes = (ibuf ? ibuf->planes : 0); BKE_image_release_ibuf(image, ibuf, lock); diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc index 44aa9e21195..3ff0b3da963 100644 --- a/source/blender/blenkernel/intern/image_format.cc +++ b/source/blender/blenkernel/intern/image_format.cc @@ -5,7 +5,7 @@ * \ingroup bke */ -#include <string.h> +#include <cstring> #include "DNA_defaults.h" #include "DNA_scene_types.h" @@ -120,6 +120,12 @@ int BKE_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options) return IMB_FTYPE_JP2; } #endif +#ifdef WITH_WEBP + if (imtype == R_IMF_IMTYPE_WEBP) { + r_options->quality = 90; + return IMB_FTYPE_WEBP; + } +#endif r_options->quality = 90; return IMB_FTYPE_JPG; @@ -177,6 +183,11 @@ char BKE_ftype_to_imtype(const int ftype, const ImbFormatOptions *options) return R_IMF_IMTYPE_JP2; } #endif +#ifdef WITH_WEBP + if (ftype == IMB_FTYPE_WEBP) { + return R_IMF_IMTYPE_WEBP; + } +#endif return R_IMF_IMTYPE_JPEG90; } @@ -220,6 +231,7 @@ bool BKE_imtype_supports_quality(const char imtype) case R_IMF_IMTYPE_JPEG90: case R_IMF_IMTYPE_JP2: case R_IMF_IMTYPE_AVIJPEG: + case R_IMF_IMTYPE_WEBP: return true; } return false; @@ -259,6 +271,7 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file) case R_IMF_IMTYPE_DDS: case R_IMF_IMTYPE_JP2: case R_IMF_IMTYPE_DPX: + case R_IMF_IMTYPE_WEBP: chan_flag |= IMA_CHAN_FLAG_ALPHA; break; } @@ -379,6 +392,11 @@ char BKE_imtype_from_arg(const char *imtype_arg) return R_IMF_IMTYPE_JP2; } #endif +#ifdef WITH_WEBP + if (STREQ(imtype_arg, "WEBP")) { + return R_IMF_IMTYPE_WEBP; + } +#endif return R_IMF_IMTYPE_INVALID; } @@ -494,6 +512,12 @@ static bool do_add_image_extension(char *string, } } #endif +#ifdef WITH_WEBP + else if (imtype == R_IMF_IMTYPE_WEBP) { + if (!BLI_path_extension_check(string, extension_test = ".webp")) + extension = extension_test; + } +#endif else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90 etc if (!(BLI_path_extension_check_n(string, extension_test = ".jpg", ".jpeg", nullptr))) { extension = extension_test; @@ -732,6 +756,12 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf) } } #endif +#ifdef WITH_WEBP + else if (imtype == R_IMF_IMTYPE_WEBP) { + ibuf->ftype = IMB_FTYPE_WEBP; + ibuf->foptions.quality = quality; + } +#endif else { /* #R_IMF_IMTYPE_JPEG90, etc. default to JPEG. */ if (quality < 10) { @@ -864,6 +894,12 @@ void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf) } } #endif +#ifdef WITH_WEBP + else if (ftype == IMB_FTYPE_WEBP) { + im_format->imtype = R_IMF_IMTYPE_WEBP; + im_format->quality = quality; + } +#endif else { im_format->imtype = R_IMF_IMTYPE_JPEG90; diff --git a/source/blender/blenkernel/intern/image_partial_update.cc b/source/blender/blenkernel/intern/image_partial_update.cc index 4606a14ab69..c77ee77a5f2 100644 --- a/source/blender/blenkernel/intern/image_partial_update.cc +++ b/source/blender/blenkernel/intern/image_partial_update.cc @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2021 Blender Foundation. */ /** - * \file image_gpu_partial_update.cc + * \file * \ingroup bke * * To reduce the overhead of image processing this file contains a mechanism to detect areas of the diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index f530183f967..0d7d238f3b2 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -391,6 +391,10 @@ static bool image_save_single(ReportList *reports, } } + if (rr) { + BKE_image_release_renderresult(opts->scene, ima); + } + return ok; } @@ -693,7 +697,7 @@ bool BKE_image_render_write(ReportList *reports, RenderResult *rr, const Scene *scene, const bool stamp, - const char *filename) + const char *filepath_basis) { bool ok = true; @@ -711,8 +715,8 @@ bool BKE_image_render_write(ReportList *reports, const float dither = scene->r.dither_intensity; if (image_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { - ok = BKE_image_render_write_exr(reports, rr, filename, &image_format, true, nullptr, -1); - image_render_print_save_message(reports, filename, ok, errno); + ok = BKE_image_render_write_exr(reports, rr, filepath_basis, &image_format, true, nullptr, -1); + image_render_print_save_message(reports, filepath_basis, ok, errno); } /* mono, legacy code */ @@ -722,10 +726,10 @@ bool BKE_image_render_write(ReportList *reports, rv = rv->next, view_id++) { char filepath[FILE_MAX]; if (is_mono) { - STRNCPY(filepath, filename); + STRNCPY(filepath, filepath_basis); } else { - BKE_scene_multiview_view_filepath_get(&scene->r, filename, rv->name, filepath); + BKE_scene_multiview_view_filepath_get(&scene->r, filepath_basis, rv->name, filepath); } if (is_exr_rr) { @@ -768,7 +772,7 @@ bool BKE_image_render_write(ReportList *reports, BLI_assert(image_format.views_format == R_IMF_VIEWS_STEREO_3D); char filepath[FILE_MAX]; - STRNCPY(filepath, filename); + STRNCPY(filepath, filepath_basis); if (image_format.imtype == R_IMF_IMTYPE_MULTILAYER) { printf("Stereo 3D not supported for MultiLayer image: %s\n", filepath); diff --git a/source/blender/blenkernel/intern/image_test.cc b/source/blender/blenkernel/intern/image_test.cc new file mode 100644 index 00000000000..9c15fc62d21 --- /dev/null +++ b/source/blender/blenkernel/intern/image_test.cc @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. */ + +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "BKE_image.h" + +#include "MEM_guardedalloc.h" + +#include "testing/testing.h" + +namespace blender::bke::tests { + +TEST(udim, image_ensure_tile_token) +{ + auto verify = [](const char *original, const char *expected) { + char result[FILE_MAX]; + + BLI_strncpy(result, original, sizeof(result)); + BKE_image_ensure_tile_token(result); + EXPECT_STREQ(result, expected); + }; + + /* Already present tokens. */ + verify("test.<UDIM>.png", "test.<UDIM>.png"); + verify("test.<UVTILE>.png", "test.<UVTILE>.png"); + + /* UDIM pattern detection. */ + verify("test.1002.png", "test.<UDIM>.png"); + verify("test-1002-ao.png", "test-<UDIM>-ao.png"); + verify("test_1002_ao.png", "test_<UDIM>_ao.png"); + verify("test.1002.ver0023.png", "test.<UDIM>.ver0023.png"); + verify("test.ver0023.1002.png", "test.ver0023.<UDIM>.png"); + verify("1002test.png", "<UDIM>test.png"); + verify("test1002.png", "test<UDIM>.png"); + + /* UVTILE pattern detection. */ + verify("uv-test.u2_v10.png", "uv-test.<UVTILE>.png"); + verify("uv-test-u2_v10-ao.png", "uv-test-<UVTILE>-ao.png"); + verify("uv-test_u2_v10_ao.png", "uv-test_<UVTILE>_ao.png"); + verify("uv-test.u10_v100.png", "uv-test.<UVTILE>.png"); + verify("u_v-test.u2_v10.png", "u_v-test.<UVTILE>.png"); + verify("u2_v10uv-test.png", "<UVTILE>uv-test.png"); + verify("u2_v10u_v-test.png", "<UVTILE>u_v-test.png"); + + /* Incorrect patterns. */ + for (const char *incorrect : {"test.123.png", + "test.12345.png", + "test.uv.png", + "test.u1v.png", + "test.uv1.png", + "test.u_v.png", + "test.u1_v.png", + "test.u_v2.png", + "test.u2v3.png", + "test.u123_v1.png", + "test.u1_v12345.png"}) { + /* These should not result in modifications happening. */ + verify(incorrect, incorrect); + } +} + +TEST(udim, image_get_tile_strformat) +{ + eUDIM_TILE_FORMAT tile_format; + char *udim_pattern; + + /* Parameter validation. */ + udim_pattern = BKE_image_get_tile_strformat(nullptr, &tile_format); + EXPECT_EQ(udim_pattern, nullptr); + + udim_pattern = BKE_image_get_tile_strformat("", nullptr); + EXPECT_EQ(udim_pattern, nullptr); + + /* Typical usage. */ + udim_pattern = BKE_image_get_tile_strformat("", &tile_format); + EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_NONE); + EXPECT_EQ(udim_pattern, nullptr); + + udim_pattern = BKE_image_get_tile_strformat("test.<UNKNOWN>.png", &tile_format); + EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_NONE); + EXPECT_EQ(udim_pattern, nullptr); + + udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format); + EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM); + EXPECT_STREQ(udim_pattern, "test.%d.png"); + MEM_freeN(udim_pattern); + + udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format); + EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UVTILE); + EXPECT_STREQ(udim_pattern, "test.u%d_v%d.png"); + MEM_freeN(udim_pattern); +} + +TEST(udim, image_get_tile_number_from_filepath) +{ + eUDIM_TILE_FORMAT tile_format; + char *udim_pattern; + int tile_number; + + udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format); + EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM); + EXPECT_NE(udim_pattern, nullptr); + + /* Parameter validation. */ + EXPECT_FALSE( + BKE_image_get_tile_number_from_filepath(nullptr, udim_pattern, tile_format, &tile_number)); + EXPECT_FALSE(BKE_image_get_tile_number_from_filepath( + "test.1004.png", nullptr, tile_format, &tile_number)); + EXPECT_FALSE(BKE_image_get_tile_number_from_filepath( + "test.1004.png", udim_pattern, UDIM_TILE_FORMAT_NONE, &tile_number)); + EXPECT_FALSE(BKE_image_get_tile_number_from_filepath( + "test.1004.png", udim_pattern, tile_format, nullptr)); + + /* UDIM tile format tests. */ + EXPECT_TRUE(BKE_image_get_tile_number_from_filepath( + "test.1004.png", udim_pattern, tile_format, &tile_number)); + EXPECT_EQ(tile_number, 1004); + + EXPECT_FALSE(BKE_image_get_tile_number_from_filepath( + "has_no_number.png", udim_pattern, tile_format, &tile_number)); + EXPECT_FALSE(BKE_image_get_tile_number_from_filepath( + "test.X.png", udim_pattern, tile_format, &tile_number)); + EXPECT_FALSE(BKE_image_get_tile_number_from_filepath( + "wrong.1004.png", udim_pattern, tile_format, &tile_number)); + + MEM_freeN(udim_pattern); + + /* UVTILE tile format tests. */ + udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format); + EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UVTILE); + EXPECT_NE(udim_pattern, nullptr); + + EXPECT_TRUE(BKE_image_get_tile_number_from_filepath( + "test.u2_v2.png", udim_pattern, tile_format, &tile_number)); + EXPECT_EQ(tile_number, 1012); + + EXPECT_FALSE(BKE_image_get_tile_number_from_filepath( + "has_no_number.png", udim_pattern, tile_format, &tile_number)); + EXPECT_FALSE(BKE_image_get_tile_number_from_filepath( + "test.u1_vX.png", udim_pattern, tile_format, &tile_number)); + EXPECT_FALSE(BKE_image_get_tile_number_from_filepath( + "test.uX_v1.png", udim_pattern, tile_format, &tile_number)); + EXPECT_FALSE(BKE_image_get_tile_number_from_filepath( + "wrong.u2_v2.png", udim_pattern, tile_format, &tile_number)); + + MEM_freeN(udim_pattern); +} + +TEST(udim, image_set_filepath_from_tile_number) +{ + eUDIM_TILE_FORMAT tile_format; + char *udim_pattern; + + udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format); + EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM); + EXPECT_NE(udim_pattern, nullptr); + + char filepath[FILE_MAX]; + + /* Parameter validation. */ + BLI_strncpy(filepath, "xxxx", FILE_MAX); + + BKE_image_set_filepath_from_tile_number(nullptr, udim_pattern, tile_format, 1028); + BKE_image_set_filepath_from_tile_number(filepath, nullptr, tile_format, 1028); + EXPECT_STREQ(filepath, "xxxx"); + BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, UDIM_TILE_FORMAT_NONE, 1028); + EXPECT_STREQ(filepath, "xxxx"); + + /* UDIM tile format tests. */ + BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, 1028); + EXPECT_STREQ(filepath, "test.1028.png"); + MEM_freeN(udim_pattern); + + /* UVTILE tile format tests. */ + udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format); + EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UVTILE); + EXPECT_NE(udim_pattern, nullptr); + + BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, 1028); + EXPECT_STREQ(filepath, "test.u8_v3.png"); + MEM_freeN(udim_pattern); +} + +} // namespace blender::bke::tests diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 782d5442c99..5afc3c0be3b 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -199,7 +199,7 @@ static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data) { Mesh *me = (Mesh *)id; if (me->ldata.external) { - BKE_bpath_foreach_path_fixed_process(bpath_data, me->ldata.external->filename); + BKE_bpath_foreach_path_fixed_process(bpath_data, me->ldata.external->filepath); } } diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 40c6fbcf67e..dc9ec002d1a 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -910,18 +910,20 @@ static void curve_to_mesh_eval_ensure(Object &object) * * So we create temporary copy of the object which will use same data as the original bevel, but * will have no modifiers. */ - Object bevel_object = {{nullptr}}; + Object bevel_object; + blender::dna::zero_memory(bevel_object); if (curve.bevobj != nullptr) { - memcpy(&bevel_object, curve.bevobj, sizeof(bevel_object)); + blender::dna::copy_memory(bevel_object, *curve.bevobj); BLI_listbase_clear(&bevel_object.modifiers); BKE_object_runtime_reset(&bevel_object); curve.bevobj = &bevel_object; } /* Same thing for taper. */ - Object taper_object = {{nullptr}}; + Object taper_object; + blender::dna::zero_memory(taper_object); if (curve.taperobj != nullptr) { - memcpy(&taper_object, curve.taperobj, sizeof(taper_object)); + blender::dna::copy_memory(taper_object, *curve.taperobj); BLI_listbase_clear(&taper_object.modifiers); BKE_object_runtime_reset(&taper_object); curve.taperobj = &taper_object; @@ -1066,7 +1068,7 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph, } Object object_for_eval; - memcpy(&object_for_eval, object, sizeof(object_for_eval)); + blender::dna::copy_memory(object_for_eval, *object); if (object_for_eval.runtime.data_orig != nullptr) { object_for_eval.data = object_for_eval.runtime.data_orig; } diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc index da0bd1f021d..6c5a5de31fc 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.cc +++ b/source/blender/blenkernel/intern/mesh_evaluate.cc @@ -695,7 +695,7 @@ static void bm_corners_to_loops_ex(ID *id, if (CustomData_external_test(fdata, CD_MDISPS)) { if (id && fdata->external) { - CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filename); + CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filepath); } } diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index e9c26c80141..9c4098e2db6 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -561,7 +561,7 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map, typedef bool (*MeshRemap_CheckIslandBoundary)(const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge, - const int nbr_edge_users, + const int edge_user_count, const struct MPoly *mpoly_array, const struct MeshElemMap *edge_poly_map, void *user_data); @@ -764,14 +764,14 @@ static void poly_edge_loop_islands_calc(const MEdge *medge, static bool poly_is_island_boundary_smooth_cb(const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, - const int nbr_edge_users, + const int edge_user_count, const MPoly *mpoly_array, const MeshElemMap *edge_poly_map, void *UNUSED(user_data)) { /* Edge is sharp if one of its polys is flat, or edge itself is sharp, * or edge is not used by exactly two polygons. */ - if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (nbr_edge_users == 2)) { + if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (edge_user_count == 2)) { /* In that case, edge appears to be smooth, but we need to check its other poly too. */ const MPoly *mp_other = (mp == &mpoly_array[edge_poly_map->indices[0]]) ? &mpoly_array[edge_poly_map->indices[1]] : @@ -935,7 +935,7 @@ typedef struct MeshCheckIslandBoundaryUv { static bool mesh_check_island_boundary_uv(const MPoly *UNUSED(mp), const MLoop *ml, const MEdge *me, - const int UNUSED(nbr_edge_users), + const int UNUSED(edge_user_count), const MPoly *UNUSED(mpoly_array), const MeshElemMap *UNUSED(edge_poly_map), void *user_data) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 7633a3155ba..ba1004e8371 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -532,7 +532,7 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, lnors_spacearr->loops_pool = (LinkNode *)BLI_memarena_alloc( mem, sizeof(LinkNode) * (size_t)numLoops); - lnors_spacearr->num_spaces = 0; + lnors_spacearr->spaces_num = 0; } BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX)); lnors_spacearr->data_type = data_type; @@ -550,7 +550,7 @@ void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr, { BLI_assert(lnors_spacearr->data_type == lnors_spacearr_tls->data_type); BLI_assert(lnors_spacearr->mem != lnors_spacearr_tls->mem); - lnors_spacearr->num_spaces += lnors_spacearr_tls->num_spaces; + lnors_spacearr->spaces_num += lnors_spacearr_tls->spaces_num; BLI_memarena_merge(lnors_spacearr->mem, lnors_spacearr_tls->mem); BLI_memarena_free(lnors_spacearr_tls->mem); lnors_spacearr_tls->mem = nullptr; @@ -559,7 +559,7 @@ void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr, void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr) { - lnors_spacearr->num_spaces = 0; + lnors_spacearr->spaces_num = 0; lnors_spacearr->lspacearr = nullptr; lnors_spacearr->loops_pool = nullptr; if (lnors_spacearr->mem != nullptr) { @@ -569,7 +569,7 @@ void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr) void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr) { - lnors_spacearr->num_spaces = 0; + lnors_spacearr->spaces_num = 0; lnors_spacearr->lspacearr = nullptr; lnors_spacearr->loops_pool = nullptr; BLI_memarena_free(lnors_spacearr->mem); @@ -578,7 +578,7 @@ void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr) MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr) { - lnors_spacearr->num_spaces++; + lnors_spacearr->spaces_num++; return (MLoopNorSpace *)BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace)); } @@ -613,19 +613,19 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, /* Compute ref alpha, average angle of all available edge vectors to lnor. */ if (edge_vectors) { float alpha = 0.0f; - int nbr = 0; + int count = 0; while (!BLI_stack_is_empty(edge_vectors)) { const float *vec = (const float *)BLI_stack_peek(edge_vectors); alpha += saacosf(dot_v3v3(vec, lnor)); BLI_stack_discard(edge_vectors); - nbr++; + count++; } - /* NOTE: In theory, this could be `nbr > 2`, + /* NOTE: In theory, this could be `count > 2`, * but there is one case where we only have two edges for two loops: * a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). */ - BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop. */ - lnor_space->ref_alpha = alpha / (float)nbr; + BLI_assert(count >= 2); /* This piece of code shall only be called for more than one loop. */ + lnor_space->ref_alpha = alpha / (float)count; } else { lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) + @@ -1134,7 +1134,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli /* We validate clnors data on the fly - cheapest way to do! */ int clnors_avg[2] = {0, 0}; short(*clnor_ref)[2] = nullptr; - int clnors_nbr = 0; + int clnors_count = 0; bool clnors_invalid = false; /* Temp loop normal stack. */ @@ -1194,7 +1194,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli if (clnors_data) { /* Accumulate all clnors, if they are not all equal we have to fix that! */ short(*clnor)[2] = &clnors_data[mlfan_vert_index]; - if (clnors_nbr) { + if (clnors_count) { clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]); } else { @@ -1202,7 +1202,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli } clnors_avg[0] += (*clnor)[0]; clnors_avg[1] += (*clnor)[1]; - clnors_nbr++; + clnors_count++; /* We store here a pointer to all custom lnors processed. */ BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor); } @@ -1262,8 +1262,8 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli if (clnors_invalid) { short *clnor; - clnors_avg[0] /= clnors_nbr; - clnors_avg[1] /= clnors_nbr; + clnors_avg[0] /= clnors_count; + clnors_avg[1] /= clnors_count; /* Fix/update all clnors of this fan with computed average value. */ if (G.debug & G_DEBUG) { printf("Invalid clnors in this fan!\n"); @@ -1952,7 +1952,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, BLI_BITMAP_DISABLE(done_loops, i); } else { - int nbr_nors = 0; + int avg_nor_count = 0; float avg_nor[3]; short clnor_data_tmp[2], *clnor_data; @@ -1962,7 +1962,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, const int nidx = use_vertices ? (int)mloops[lidx].v : lidx; float *nor = r_custom_loopnors[nidx]; - nbr_nors++; + avg_nor_count++; add_v3_v3(avg_nor, nor); BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]); @@ -1970,7 +1970,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, BLI_BITMAP_DISABLE(done_loops, lidx); } - mul_v3_fl(avg_nor, 1.0f / (float)nbr_nors); + mul_v3_fl(avg_nor, 1.0f / (float)avg_nor_count); BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp); while ((clnor_data = (short *)BLI_SMALLSTACK_POP(clnors_data))) { @@ -2088,8 +2088,8 @@ void BKE_mesh_normals_loop_to_vertex(const int numVerts, const float (*clnors)[3], float (*r_vert_clnors)[3]) { - int *vert_loops_nbr = (int *)MEM_calloc_arrayN( - (size_t)numVerts, sizeof(*vert_loops_nbr), __func__); + int *vert_loops_count = (int *)MEM_calloc_arrayN( + (size_t)numVerts, sizeof(*vert_loops_count), __func__); copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f); @@ -2099,14 +2099,14 @@ void BKE_mesh_normals_loop_to_vertex(const int numVerts, const uint v = ml->v; add_v3_v3(r_vert_clnors[v], clnors[i]); - vert_loops_nbr[v]++; + vert_loops_count[v]++; } for (i = 0; i < numVerts; i++) { - mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_nbr[i]); + mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_count[i]); } - MEM_freeN(vert_loops_nbr); + MEM_freeN(vert_loops_count); } #undef LNOR_SPACE_TRIGO_THRESHOLD diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc index 4374659bff8..6af765d7de5 100644 --- a/source/blender/blenkernel/intern/mesh_validate.cc +++ b/source/blender/blenkernel/intern/mesh_validate.cc @@ -577,7 +577,8 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, else if (mp->loopstart + mp->totloop > totloop) { /* Invalid loop data. */ PRINT_ERR( - "\tPoly %u uses loops out of range (loopstart: %d, loopend: %d, max nbr of loops: %u)", + "\tPoly %u uses loops out of range " + "(loopstart: %d, loopend: %d, max number of loops: %u)", sp->index, mp->loopstart, mp->loopstart + mp->totloop - 1, diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 1e3b5d77fa7..4714a79de58 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -766,7 +766,7 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id) hmd->indexar = hook->indexar; hmd->object = hook->parent; memcpy(hmd->parentinv, hook->parentinv, sizeof(hmd->parentinv)); - hmd->totindex = hook->totindex; + hmd->indexar_num = hook->totindex; BLI_addhead(&ob->modifiers, hmd); BLI_remlink(&ob->hooks, hook); @@ -1236,7 +1236,7 @@ IDTypeInfo IDType_ID_OB = { void BKE_object_workob_clear(Object *workob) { - memset(workob, 0, sizeof(Object)); + blender::dna::zero_memory(*workob); workob->scale[0] = workob->scale[1] = workob->scale[2] = 1.0f; workob->dscale[0] = workob->dscale[1] = workob->dscale[2] = 1.0f; @@ -3946,7 +3946,7 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph, /* pass */ } else { - Object temp_ob = *dob->ob; + Object temp_ob = blender::dna::shallow_copy(*dob->ob); /* Do not modify the original boundbox. */ temp_ob.runtime.bb = nullptr; BKE_object_replace_data_on_shallow_copy(&temp_ob, dob->ob_data); diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 4c5fefefd8e..e7ed100ed03 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -174,16 +174,16 @@ PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen) return pf; } -PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const char *basepath) +PackedFile *BKE_packedfile_new(ReportList *reports, const char *filepath, const char *basepath) { PackedFile *pf = NULL; int file, filelen; char name[FILE_MAX]; void *data; - /* render result has no filename and can be ignored + /* render result has no filepath and can be ignored * any other files with no name can be ignored too */ - if (filename[0] == '\0') { + if (filepath[0] == '\0') { return pf; } @@ -191,7 +191,7 @@ PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const /* convert relative filenames to absolute filenames */ - BLI_strncpy(name, filename, sizeof(name)); + BLI_strncpy(name, filepath, sizeof(name)); BLI_path_abs(name, basepath); /* open the file @@ -285,7 +285,7 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose) int BKE_packedfile_write_to_file(ReportList *reports, const char *ref_file_name, - const char *filename, + const char *filepath, PackedFile *pf, const bool guimode) { @@ -299,7 +299,7 @@ int BKE_packedfile_write_to_file(ReportList *reports, if (guimode) { } // XXX waitcursor(1); - BLI_strncpy(name, filename, sizeof(name)); + BLI_strncpy(name, filepath, sizeof(name)); BLI_path_abs(name, ref_file_name); if (BLI_exists(name)) { @@ -358,7 +358,7 @@ int BKE_packedfile_write_to_file(ReportList *reports, } enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name, - const char *filename, + const char *filepath, PackedFile *pf) { BLI_stat_t st; @@ -366,7 +366,7 @@ enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name, char buf[4096]; char name[FILE_MAX]; - BLI_strncpy(name, filename, sizeof(name)); + BLI_strncpy(name, filepath, sizeof(name)); BLI_path_abs(name, ref_file_name); if (BLI_stat(name, &st) == -1) { diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index c47b22dcd34..9ea1336a95a 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -2661,8 +2661,8 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params int from = PART_FROM_FACE; totparent = (int)(totchild * part->parents * 0.3f); - if (use_render_params && part->child_nbr && part->ren_child_nbr) { - totparent *= (float)part->child_nbr / (float)part->ren_child_nbr; + if (use_render_params && part->child_percent && part->child_render_percent) { + totparent *= (float)part->child_percent / (float)part->child_render_percent; } /* hard limit, workaround for it being ignored above */ @@ -2736,8 +2736,8 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, if (totchild && part->childtype == PART_CHILD_FACES) { totparent = (int)(totchild * part->parents * 0.3f); - if (use_render_params && part->child_nbr && part->ren_child_nbr) { - totparent *= (float)part->child_nbr / (float)part->ren_child_nbr; + if (use_render_params && part->child_percent && part->child_render_percent) { + totparent *= (float)part->child_percent / (float)part->child_render_percent; } /* part->parents could still be 0 so we can't test with totparent */ diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 83fb52ce1ef..d2c3776d4ea 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -64,14 +64,14 @@ static void distribute_simple_children(Scene *scene, { ChildParticle *cpa = NULL; int i, p; - int child_nbr = psys_get_child_number(scene, psys, use_render_params); - int totpart = psys_get_tot_child(scene, psys, use_render_params); + const int child_num = psys_get_child_number(scene, psys, use_render_params); + const int totpart = psys_get_tot_child(scene, psys, use_render_params); RNG *rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed); alloc_child_particles(psys, totpart); cpa = psys->child; - for (i = 0; i < child_nbr; i++) { + for (i = 0; i < child_num; i++) { for (p = 0; p < psys->totpart; p++, cpa++) { float length = 2.0; cpa->parent = p; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 3a1aefec2d3..7fdc60a265b 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -98,9 +98,9 @@ float psys_get_current_display_percentage(ParticleSystem *psys, const bool use_r ParticleSettings *part = psys->part; if ((use_render_params && - !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */ - (part->child_nbr && part->childtype) || /* display percentage applies to children */ - (psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */ + !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */ + (part->child_percent && part->childtype) || /* display percentage applies to children */ + (psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */ { return 1.0f; } @@ -280,20 +280,20 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart) int psys_get_child_number(Scene *scene, ParticleSystem *psys, const bool use_render_params) { - int nbr; + int child_num; if (!psys->part->childtype) { return 0; } if (use_render_params) { - nbr = psys->part->ren_child_nbr; + child_num = psys->part->child_render_percent; } else { - nbr = psys->part->child_nbr; + child_num = psys->part->child_percent; } - return get_render_child_particle_number(&scene->r, nbr, use_render_params); + return get_render_child_particle_number(&scene->r, child_num, use_render_params); } int psys_get_tot_child(Scene *scene, ParticleSystem *psys, const bool use_render_params) diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.cc index 6797538d190..cebe4482eb7 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.cc @@ -8,9 +8,9 @@ /* Allow using deprecated functionality for .blend file I/O. */ #define DNA_DEPRECATED_ALLOW -#include <stddef.h> -#include <stdio.h> -#include <string.h> +#include <cstddef> +#include <cstdio> +#include <cstring> #include "MEM_guardedalloc.h" @@ -183,11 +183,11 @@ static void scene_init_data(ID *id) /* multiview - stereo */ BKE_scene_add_render_view(scene, STEREO_LEFT_NAME); - srv = scene->r.views.first; + srv = static_cast<SceneRenderView *>(scene->r.views.first); BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix)); BKE_scene_add_render_view(scene, STEREO_RIGHT_NAME); - srv = scene->r.views.last; + srv = static_cast<SceneRenderView *>(scene->r.views.last); BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix)); BKE_sound_reset_scene_runtime(scene); @@ -218,14 +218,14 @@ static void scene_init_data(ID *id) /* Master Collection */ scene->master_collection = BKE_collection_master_add(); - BKE_view_layer_add(scene, "ViewLayer", NULL, VIEWLAYER_ADD_NEW); + BKE_view_layer_add(scene, "ViewLayer", nullptr, VIEWLAYER_ADD_NEW); } static void scene_copy_markers(Scene *scene_dst, const Scene *scene_src, const int flag) { BLI_duplicatelist(&scene_dst->markers, &scene_src->markers); LISTBASE_FOREACH (TimeMarker *, marker, &scene_dst->markers) { - if (marker->prop != NULL) { + if (marker->prop != nullptr) { marker->prop = IDP_CopyProperty_ex(marker->prop, flag); } } @@ -240,9 +240,9 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int /* We always need allocation of our private ID data. */ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE; - scene_dst->ed = NULL; - scene_dst->depsgraph_hash = NULL; - scene_dst->fps_info = NULL; + scene_dst->ed = nullptr; + scene_dst->depsgraph_hash = nullptr; + scene_dst->fps_info = nullptr; /* Master Collection */ if (scene_src->master_collection) { @@ -254,8 +254,8 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int /* View Layers */ BLI_duplicatelist(&scene_dst->view_layers, &scene_src->view_layers); - for (ViewLayer *view_layer_src = scene_src->view_layers.first, - *view_layer_dst = scene_dst->view_layers.first; + for (ViewLayer *view_layer_src = static_cast<ViewLayer *>(scene_src->view_layers.first), + *view_layer_dst = static_cast<ViewLayer *>(scene_dst->view_layers.first); view_layer_src; view_layer_src = view_layer_src->next, view_layer_dst = view_layer_dst->next) { BKE_view_layer_copy_data(scene_dst, scene_src, view_layer_dst, view_layer_src, flag_subdata); @@ -299,7 +299,8 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int /* make a private copy of the avicodecdata */ if (scene_src->r.avicodecdata) { - scene_dst->r.avicodecdata = MEM_dupallocN(scene_src->r.avicodecdata); + scene_dst->r.avicodecdata = static_cast<AviCodecData *>( + MEM_dupallocN(scene_src->r.avicodecdata)); scene_dst->r.avicodecdata->lpFormat = MEM_dupallocN(scene_dst->r.avicodecdata->lpFormat); scene_dst->r.avicodecdata->lpParms = MEM_dupallocN(scene_dst->r.avicodecdata->lpParms); } @@ -312,7 +313,7 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int /* Copy sequencer, this is local data! */ if (scene_src->ed) { - scene_dst->ed = MEM_callocN(sizeof(*scene_dst->ed), __func__); + scene_dst->ed = MEM_cnew<Editing>(__func__); scene_dst->ed->seqbasep = &scene_dst->ed->seqbase; SEQ_sequence_base_dupli_recursive(scene_src, scene_dst, @@ -326,7 +327,7 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int BKE_previewimg_id_copy(&scene_dst->id, &scene_src->id); } else { - scene_dst->preview = NULL; + scene_dst->preview = nullptr; } BKE_scene_copy_data_eevee(scene_dst, scene_src); @@ -335,7 +336,7 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int static void scene_free_markers(Scene *scene, bool do_id_user) { LISTBASE_FOREACH_MUTABLE (TimeMarker *, marker, &scene->markers) { - if (marker->prop != NULL) { + if (marker->prop != nullptr) { IDP_FreePropertyContent_ex(marker->prop, do_id_user); MEM_freeN(marker->prop); } @@ -357,22 +358,22 @@ static void scene_free_data(ID *id) if (scene->nodetree) { ntreeFreeEmbeddedTree(scene->nodetree); MEM_freeN(scene->nodetree); - scene->nodetree = NULL; + scene->nodetree = nullptr; } if (scene->rigidbody_world) { /* Prevent rigidbody freeing code to follow other IDs pointers, this should never be allowed * nor necessary from here, and with new undo code, those pointers may be fully invalid or * worse, pointing to data actually belonging to new BMain! */ - scene->rigidbody_world->constraints = NULL; - scene->rigidbody_world->group = NULL; + scene->rigidbody_world->constraints = nullptr; + scene->rigidbody_world->group = nullptr; BKE_rigidbody_free_world(scene); } if (scene->r.avicodecdata) { free_avicodecdata(scene->r.avicodecdata); MEM_freeN(scene->r.avicodecdata); - scene->r.avicodecdata = NULL; + scene->r.avicodecdata = nullptr; } scene_free_markers(scene, do_id_user); @@ -380,7 +381,7 @@ static void scene_free_data(ID *id) BLI_freelistN(&scene->r.views); BKE_toolsettings_free(scene->toolsettings); - scene->toolsettings = NULL; + scene->toolsettings = nullptr; BKE_scene_free_depsgraph_hash(scene); @@ -395,10 +396,7 @@ static void scene_free_data(ID *id) BKE_previewimg_free(&scene->preview); BKE_curvemapping_free_data(&scene->r.mblur_shutter_curve); - for (ViewLayer *view_layer = scene->view_layers.first, *view_layer_next; view_layer; - view_layer = view_layer_next) { - view_layer_next = view_layer->next; - + LISTBASE_FOREACH_MUTABLE (ViewLayer *, view_layer, &scene->view_layers) { BLI_remlink(&scene->view_layers, view_layer); BKE_view_layer_free_ex(view_layer, do_id_user); } @@ -412,21 +410,21 @@ static void scene_free_data(ID *id) BKE_collection_free_data(scene->master_collection); BKE_libblock_free_data_py(&scene->master_collection->id); MEM_freeN(scene->master_collection); - scene->master_collection = NULL; + scene->master_collection = nullptr; } if (scene->eevee.light_cache_data) { EEVEE_lightcache_free(scene->eevee.light_cache_data); - scene->eevee.light_cache_data = NULL; + scene->eevee.light_cache_data = nullptr; } if (scene->display.shading.prop) { IDP_FreeProperty(scene->display.shading.prop); - scene->display.shading.prop = NULL; + scene->display.shading.prop = nullptr; } /* These are freed on doversion. */ - BLI_assert(scene->layer_properties == NULL); + BLI_assert(scene->layer_properties == nullptr); } static void scene_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw), @@ -443,14 +441,14 @@ static void scene_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSE * This code is shared by both the regular `foreach_id` looper, and the code trying to restore or * preserve ID pointers like brushes across undo-steps. */ -typedef enum eSceneForeachUndoPreserveProcess { +enum eSceneForeachUndoPreserveProcess { /* Undo when preserving tool-settings from old scene, we also want to try to preserve that ID * pointer from its old scene's value. */ SCENE_FOREACH_UNDO_RESTORE, /* Undo when preserving tool-settings from old scene, we want to keep the new value of that ID * pointer. */ SCENE_FOREACH_UNDO_NO_RESTORE, -} eSceneForeachUndoPreserveProcess; +}; static void scene_foreach_toolsettings_id_pointer_process( ID **id_p, @@ -464,9 +462,10 @@ static void scene_foreach_toolsettings_id_pointer_process( ID *id_old = *id_old_p; /* Old data has not been remapped to new values of the pointers, if we want to keep the old * pointer here we need its new address. */ - ID *id_old_new = id_old != NULL ? BLO_read_get_new_id_address(reader, id_old->lib, id_old) : - NULL; - if (id_old_new != NULL) { + ID *id_old_new = id_old != nullptr ? + BLO_read_get_new_id_address(reader, id_old->lib, id_old) : + nullptr; + if (id_old_new != nullptr) { BLI_assert(ELEM(id_old, id_old_new, id_old_new->orig_id)); *id_old_p = id_old_new; if (cb_flag & IDWALK_CB_USER) { @@ -489,7 +488,7 @@ static void scene_foreach_toolsettings_id_pointer_process( /* Special handling is needed here, as `scene_foreach_toolsettings` (and its dependency * `scene_foreach_paint`) are also used by `scene_undo_preserve`, where `LibraryForeachIDData - * *data` is NULL. */ + * *data` is nullptr. */ #define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER( \ __data, __id, __do_undo_restore, __action, __reader, __id_old, __cb_flag) \ { \ @@ -498,7 +497,7 @@ static void scene_foreach_toolsettings_id_pointer_process( (ID **)&(__id), __action, __reader, (ID **)&(__id_old), __cb_flag); \ } \ else { \ - BLI_assert((__data) != NULL); \ + BLI_assert((__data) != nullptr); \ BKE_LIB_FOREACHID_PROCESS_IDSUPER(__data, __id, __cb_flag); \ } \ } \ @@ -511,7 +510,7 @@ static void scene_foreach_toolsettings_id_pointer_process( __func_call; \ } \ else { \ - BLI_assert((__data) != NULL); \ + BLI_assert((__data) != nullptr); \ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(__data, __func_call); \ } \ } \ @@ -536,10 +535,10 @@ static void scene_foreach_paint(LibraryForeachIDData *data, * this is equivalent to simply looping over slots from `paint`. * - In case we do `undo_restore`, we only want to consider the slots from the old one, since * those are the one we keep in the end. - * + In case the new data has less valid slots, we feed in a dummy NULL pointer. + * + In case the new data has less valid slots, we feed in a dummy null pointer. * + In case the new data has more valid slots, the extra ones are ignored. */ - Brush *brush_tmp = NULL; + Brush *brush_tmp = nullptr; Brush **brush_p = i < paint->tool_slots_len ? &paint->tool_slots[i].brush : &brush_tmp; BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, *brush_p, @@ -725,7 +724,7 @@ static void scene_foreach_layer_collection(LibraryForeachIDData *data, ListBase LISTBASE_FOREACH (LayerCollection *, lc, lb) { /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad * anyway... */ - const int cb_flag = (lc->collection != NULL && + const int cb_flag = (lc->collection != nullptr && (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? IDWALK_CB_EMBEDDED : IDWALK_CB_NOP; @@ -760,7 +759,7 @@ static bool seq_foreach_member_id_cb(Sequence *seq, void *user_data) } if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) { - TextVars *text_data = seq->effectdata; + TextVars *text_data = static_cast<TextVars *>(seq->effectdata); FOREACHID_PROCESS_IDSUPER(data, text_data->text_font, IDWALK_CB_USER); } @@ -792,8 +791,8 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_keyingsets_foreach_id(data, &scene->keyingsets)); - /* This pointer can be NULL during old files reading, better be safe than sorry. */ - if (scene->master_collection != NULL) { + /* This pointer can be nullptr during old files reading, better be safe than sorry. */ + if (scene->master_collection != nullptr) { BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection)); } @@ -839,7 +838,7 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) ToolSettings *toolsett = scene->toolsettings; if (toolsett) { BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( - data, scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett)); + data, scene_foreach_toolsettings(data, toolsett, false, nullptr, toolsett)); } if (scene->rigidbody_world) { @@ -855,11 +854,10 @@ static void scene_foreach_cache(ID *id, void *user_data) { Scene *scene = (Scene *)id; - IDCacheKey key = { - .id_session_uuid = id->session_uuid, - .offset_in_ID = offsetof(Scene, eevee.light_cache_data), - .cache_v = scene->eevee.light_cache_data, - }; + IDCacheKey key{}; + key.id_session_uuid = id->session_uuid; + key.offset_in_ID = offsetof(Scene, eevee.light_cache_data); + key.cache_v = scene->eevee.light_cache_data; function_callback(id, &key, @@ -902,7 +900,7 @@ static bool seq_foreach_path_callback(Sequence *seq, void *user_data) static void scene_foreach_path(ID *id, BPathForeachPathData *bpath_data) { Scene *scene = (Scene *)id; - if (scene->ed != NULL) { + if (scene->ed != nullptr) { SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_path_callback, bpath_data); } } @@ -1012,7 +1010,7 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres LISTBASE_FOREACH (TimeMarker *, marker, &sce->markers) { BLO_write_struct(writer, TimeMarker, marker); - if (marker->prop != NULL) { + if (marker->prop != nullptr) { IDP_BlendWrite(writer, marker->prop); } } @@ -1069,7 +1067,7 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres BKE_screen_view3d_shading_blend_write(writer, &sce->display.shading); /* Freed on doversion. */ - BLI_assert(sce->layer_properties == NULL); + BLI_assert(sce->layer_properties == nullptr); } static void direct_link_paint_helper(BlendDataReader *reader, const Scene *scene, Paint **paint) @@ -1102,8 +1100,8 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) { Scene *sce = (Scene *)id; - sce->depsgraph_hash = NULL; - sce->fps_info = NULL; + sce->depsgraph_hash = nullptr; + sce->fps_info = nullptr; memset(&sce->customdata_mask, 0, sizeof(sce->customdata_mask)); memset(&sce->customdata_mask_modal, 0, sizeof(sce->customdata_mask_modal)); @@ -1144,10 +1142,10 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) BKE_paint_blend_read_data(reader, sce, &sce->toolsettings->imapaint.paint); - sce->toolsettings->particle.paintcursor = NULL; - sce->toolsettings->particle.scene = NULL; - sce->toolsettings->particle.object = NULL; - sce->toolsettings->gp_sculpt.paintcursor = NULL; + sce->toolsettings->particle.paintcursor = nullptr; + sce->toolsettings->particle.scene = nullptr; + sce->toolsettings->particle.object = nullptr; + sce->toolsettings->gp_sculpt.paintcursor = nullptr; /* relink grease pencil interpolation curves */ BLO_read_data_address(reader, &sce->toolsettings->gp_interpolate.custom_ipo); @@ -1181,9 +1179,9 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) Editing *ed = sce->ed; BLO_read_data_address(reader, &ed->act_seq); - ed->cache = NULL; - ed->prefetch_job = NULL; - ed->runtime.sequence_lookup = NULL; + ed->cache = nullptr; + ed->prefetch_job = nullptr; + ed->runtime.sequence_lookup = nullptr; /* recursive link sequences, lb will be correctly initialized */ link_recurs_seq(reader, &ed->seqbase); @@ -1275,9 +1273,9 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) if (rbw) { BLO_read_data_address(reader, &rbw->shared); - if (rbw->shared == NULL) { + if (rbw->shared == nullptr) { /* Link deprecated caches if they exist, so we can use them for versioning. - * We should only do this when rbw->shared == NULL, because those pointers + * We should only do this when rbw->shared == nullptr, because those pointers * are always set (for compatibility with older Blenders). We mustn't link * the same pointcache twice. */ BKE_ptcache_blend_read_data(reader, &rbw->ptcaches, &rbw->pointcache, false); @@ -1291,7 +1289,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) /* must nullify the reference to physics sim object, since it no-longer exist * (and will need to be recalculated) */ - rbw->shared->physics_world = NULL; + rbw->shared->physics_world = nullptr; /* link caches */ BKE_ptcache_blend_read_data(reader, &rbw->shared->ptcaches, &rbw->shared->pointcache, false); @@ -1301,13 +1299,13 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) rbw->ltime = (float)rbw->shared->pointcache->startframe; } } - rbw->objects = NULL; + rbw->objects = nullptr; rbw->numbodies = 0; /* set effector weights */ BLO_read_data_address(reader, &rbw->effector_weights); if (!rbw->effector_weights) { - rbw->effector_weights = BKE_effector_add_weights(NULL); + rbw->effector_weights = BKE_effector_add_weights(nullptr); } } @@ -1352,7 +1350,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) static void composite_patch(bNodeTree *ntree, Scene *scene) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->id == NULL && + if (node->id == nullptr && ((node->type == CMP_NODE_R_LAYERS) || (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER))) { node->id = &scene->id; @@ -1423,14 +1421,14 @@ static void scene_blend_read_lib(BlendLibReader *reader, ID *id) LISTBASE_FOREACH_MUTABLE (Base *, base_legacy, &sce->base) { BLO_read_id_address(reader, sce->id.lib, &base_legacy->object); - if (base_legacy->object == NULL) { + if (base_legacy->object == nullptr) { BLO_reportf_wrap(BLO_read_lib_reports(reader), RPT_WARNING, TIP_("LIB: object lost from scene: '%s'"), sce->id.name + 2); BLI_remlink(&sce->base, base_legacy); if (base_legacy == sce->basact) { - sce->basact = NULL; + sce->basact = nullptr; } MEM_freeN(base_legacy); } @@ -1494,7 +1492,7 @@ static void scene_blend_read_lib(BlendLibReader *reader, ID *id) } #ifdef USE_SETSCENE_CHECK - if (sce->set != NULL) { + if (sce->set != nullptr) { sce->flag |= SCE_READFILE_LIBLINK_NEED_SETSCENE_CHECK; } #endif @@ -1588,12 +1586,12 @@ static void scene_undo_preserve(BlendLibReader *reader, ID *id_new, ID *id_old) Scene *scene_old = (Scene *)id_old; SWAP(View3DCursor, scene_old->cursor, scene_new->cursor); - if (scene_new->toolsettings != NULL && scene_old->toolsettings != NULL) { + if (scene_new->toolsettings != nullptr && scene_old->toolsettings != nullptr) { /* First try to restore ID pointers that can be and should be preserved (like brushes or * palettes), and counteract the swap of the whole ToolSettings structs below for the others * (like object ones). */ scene_foreach_toolsettings( - NULL, scene_new->toolsettings, true, reader, scene_old->toolsettings); + nullptr, scene_new->toolsettings, true, reader, scene_old->toolsettings); SWAP(ToolSettings, *scene_old->toolsettings, *scene_new->toolsettings); } } @@ -1602,46 +1600,50 @@ static void scene_lib_override_apply_post(ID *id_dst, ID *UNUSED(id_src)) { Scene *scene = (Scene *)id_dst; - if (scene->rigidbody_world != NULL) { + if (scene->rigidbody_world != nullptr) { PTCacheID pid; - BKE_ptcache_id_from_rigidbody(&pid, NULL, scene->rigidbody_world); + BKE_ptcache_id_from_rigidbody(&pid, nullptr, scene->rigidbody_world); LISTBASE_FOREACH (PointCache *, point_cache, pid.ptcaches) { point_cache->flag |= PTCACHE_FLAG_INFO_DIRTY; } } } -IDTypeInfo IDType_ID_SCE = { - .id_code = ID_SCE, - .id_filter = FILTER_ID_SCE, - .main_listbase_index = INDEX_ID_SCE, - .struct_size = sizeof(Scene), - .name = "Scene", - .name_plural = "scenes", - .translation_context = BLT_I18NCONTEXT_ID_SCENE, - .flags = 0, - .asset_type_info = NULL, +constexpr IDTypeInfo get_type_info() +{ + IDTypeInfo info{}; + info.id_code = ID_SCE; + info.id_filter = FILTER_ID_SCE; + info.main_listbase_index = INDEX_ID_SCE; + info.struct_size = sizeof(Scene); + info.name = "Scene"; + info.name_plural = "scenes"; + info.translation_context = BLT_I18NCONTEXT_ID_SCENE; + info.flags = 0; + info.asset_type_info = nullptr; - .init_data = scene_init_data, - .copy_data = scene_copy_data, - .free_data = scene_free_data, - /* For now default `BKE_lib_id_make_local_generic()` should work, may need more work though to - * support all possible corner cases. */ - .make_local = NULL, - .foreach_id = scene_foreach_id, - .foreach_cache = scene_foreach_cache, - .foreach_path = scene_foreach_path, - .owner_get = NULL, + info.init_data = scene_init_data; + info.copy_data = scene_copy_data; + info.free_data = scene_free_data; + /* For now default `BKE_lib_id_make_local_generic()` should work, may need more work though to + * support all possible corner cases. */ + info.make_local = nullptr; + info.foreach_id = scene_foreach_id; + info.foreach_cache = scene_foreach_cache; + info.foreach_path = scene_foreach_path; + info.owner_get = nullptr; - .blend_write = scene_blend_write, - .blend_read_data = scene_blend_read_data, - .blend_read_lib = scene_blend_read_lib, - .blend_read_expand = scene_blend_read_expand, + info.blend_write = scene_blend_write; + info.blend_read_data = scene_blend_read_data; + info.blend_read_lib = scene_blend_read_lib; + info.blend_read_expand = scene_blend_read_expand; - .blend_read_undo_preserve = scene_undo_preserve, + info.blend_read_undo_preserve = scene_undo_preserve; - .lib_override_apply_post = scene_lib_override_apply_post, -}; + info.lib_override_apply_post = scene_lib_override_apply_post; + return info; +} +IDTypeInfo IDType_ID_SCE = get_type_info(); const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE"; const char *RE_engine_id_BLENDER_WORKBENCH = "BLENDER_WORKBENCH"; @@ -1652,12 +1654,12 @@ void free_avicodecdata(AviCodecData *acd) if (acd) { if (acd->lpFormat) { MEM_freeN(acd->lpFormat); - acd->lpFormat = NULL; + acd->lpFormat = nullptr; acd->cbFormat = 0; } if (acd->lpParms) { MEM_freeN(acd->lpParms); - acd->lpParms = NULL; + acd->lpParms = nullptr; acd->cbParms = 0; } } @@ -1668,11 +1670,7 @@ static void remove_sequencer_fcurves(Scene *sce) AnimData *adt = BKE_animdata_from_id(&sce->id); if (adt && adt->action) { - FCurve *fcu, *nextfcu; - - for (fcu = adt->action->curves.first; fcu; fcu = nextfcu) { - nextfcu = fcu->next; - + LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &adt->action->curves) { if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) { action_groups_remove_channel(adt->action, fcu); BKE_fcurve_free(fcu); @@ -1683,51 +1681,51 @@ static void remove_sequencer_fcurves(Scene *sce) ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) { - if (toolsettings == NULL) { - return NULL; + if (toolsettings == nullptr) { + return nullptr; } - ToolSettings *ts = MEM_dupallocN(toolsettings); + ToolSettings *ts = static_cast<ToolSettings *>(MEM_dupallocN(toolsettings)); if (ts->vpaint) { - ts->vpaint = MEM_dupallocN(ts->vpaint); + ts->vpaint = static_cast<VPaint *>(MEM_dupallocN(ts->vpaint)); BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag); } if (ts->wpaint) { - ts->wpaint = MEM_dupallocN(ts->wpaint); + ts->wpaint = static_cast<VPaint *>(MEM_dupallocN(ts->wpaint)); BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag); } if (ts->sculpt) { - ts->sculpt = MEM_dupallocN(ts->sculpt); + ts->sculpt = static_cast<Sculpt *>(MEM_dupallocN(ts->sculpt)); BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag); } if (ts->uvsculpt) { - ts->uvsculpt = MEM_dupallocN(ts->uvsculpt); + ts->uvsculpt = static_cast<UvSculpt *>(MEM_dupallocN(ts->uvsculpt)); BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag); } if (ts->gp_paint) { - ts->gp_paint = MEM_dupallocN(ts->gp_paint); + ts->gp_paint = static_cast<GpPaint *>(MEM_dupallocN(ts->gp_paint)); BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag); } if (ts->gp_vertexpaint) { - ts->gp_vertexpaint = MEM_dupallocN(ts->gp_vertexpaint); + ts->gp_vertexpaint = static_cast<GpVertexPaint *>(MEM_dupallocN(ts->gp_vertexpaint)); BKE_paint_copy(&ts->gp_vertexpaint->paint, &ts->gp_vertexpaint->paint, flag); } if (ts->gp_sculptpaint) { - ts->gp_sculptpaint = MEM_dupallocN(ts->gp_sculptpaint); + ts->gp_sculptpaint = static_cast<GpSculptPaint *>(MEM_dupallocN(ts->gp_sculptpaint)); BKE_paint_copy(&ts->gp_sculptpaint->paint, &ts->gp_sculptpaint->paint, flag); } if (ts->gp_weightpaint) { - ts->gp_weightpaint = MEM_dupallocN(ts->gp_weightpaint); + ts->gp_weightpaint = static_cast<GpWeightPaint *>(MEM_dupallocN(ts->gp_weightpaint)); BKE_paint_copy(&ts->gp_weightpaint->paint, &ts->gp_weightpaint->paint, flag); } if (ts->curves_sculpt) { - ts->curves_sculpt = MEM_dupallocN(ts->curves_sculpt); + ts->curves_sculpt = static_cast<CurvesSculpt *>(MEM_dupallocN(ts->curves_sculpt)); BKE_paint_copy(&ts->curves_sculpt->paint, &ts->curves_sculpt->paint, flag); } BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag); - ts->particle.paintcursor = NULL; - ts->particle.scene = NULL; - ts->particle.object = NULL; + ts->particle.paintcursor = nullptr; + ts->particle.scene = nullptr; + ts->particle.object = nullptr; /* duplicate Grease Pencil interpolation curve */ ts->gp_interpolate.custom_ipo = BKE_curvemapping_copy(ts->gp_interpolate.custom_ipo); @@ -1743,7 +1741,7 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) void BKE_toolsettings_free(ToolSettings *toolsettings) { - if (toolsettings == NULL) { + if (toolsettings == nullptr) { return; } if (toolsettings->vpaint) { @@ -1811,7 +1809,7 @@ void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src) { /* Copy eevee data between scenes. */ sce_dst->eevee = sce_src->eevee; - sce_dst->eevee.light_cache_data = NULL; + sce_dst->eevee.light_cache_data = nullptr; sce_dst->eevee.light_cache_info[0] = '\0'; /* TODO: Copy the cache. */ } @@ -1862,7 +1860,7 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) /* make a private copy of the avicodecdata */ if (sce->r.avicodecdata) { - sce_copy->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata); + sce_copy->r.avicodecdata = static_cast<AviCodecData *>(MEM_dupallocN(sce->r.avicodecdata)); sce_copy->r.avicodecdata->lpFormat = MEM_dupallocN(sce_copy->r.avicodecdata->lpFormat); sce_copy->r.avicodecdata->lpParms = MEM_dupallocN(sce_copy->r.avicodecdata->lpParms); } @@ -1870,14 +1868,14 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) BKE_sound_reset_scene_runtime(sce_copy); /* grease pencil */ - sce_copy->gpd = NULL; + sce_copy->gpd = nullptr; - sce_copy->preview = NULL; + sce_copy->preview = nullptr; return sce_copy; } - eDupli_ID_Flags duplicate_flags = U.dupflag | USER_DUP_OBJECT; + eDupli_ID_Flags duplicate_flags = (eDupli_ID_Flags)(U.dupflag | USER_DUP_OBJECT); sce_copy = (Scene *)BKE_id_copy(bmain, (ID *)sce); id_us_min(&sce_copy->id); @@ -1900,7 +1898,7 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) /* In case root duplicated ID is linked, assume we want to get a local copy of it and * duplicate all expected linked data. */ if (ID_IS_LINKED(sce)) { - duplicate_flags |= USER_DUP_LINKED_ID; + duplicate_flags = (eDupli_ID_Flags)(duplicate_flags | USER_DUP_LINKED_ID); } } @@ -1919,22 +1917,25 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) /* Deep-duplicate collections and objects (using preferences' settings for which sub-data to * duplicate along the object itself). */ - BKE_collection_duplicate( - bmain, NULL, sce_copy->master_collection, duplicate_flags, LIB_ID_DUPLICATE_IS_SUBPROCESS); + BKE_collection_duplicate(bmain, + nullptr, + sce_copy->master_collection, + duplicate_flags, + LIB_ID_DUPLICATE_IS_SUBPROCESS); /* Rigid body world collections may not be instantiated as scene's collections, ensure they * also get properly duplicated. */ - if (sce_copy->rigidbody_world != NULL) { - if (sce_copy->rigidbody_world->group != NULL) { + if (sce_copy->rigidbody_world != nullptr) { + if (sce_copy->rigidbody_world->group != nullptr) { BKE_collection_duplicate(bmain, - NULL, + nullptr, sce_copy->rigidbody_world->group, duplicate_flags, LIB_ID_DUPLICATE_IS_SUBPROCESS); } - if (sce_copy->rigidbody_world->constraints != NULL) { + if (sce_copy->rigidbody_world->constraints != nullptr) { BKE_collection_duplicate(bmain, - NULL, + nullptr, sce_copy->rigidbody_world->constraints, duplicate_flags, LIB_ID_DUPLICATE_IS_SUBPROCESS); @@ -1995,9 +1996,7 @@ bool BKE_scene_can_be_removed(const Main *bmain, const Scene *scene) Scene *BKE_scene_add(Main *bmain, const char *name) { - Scene *sce; - - sce = BKE_id_new(bmain, ID_SCE, name); + Scene *sce = static_cast<Scene *>(BKE_id_new(bmain, ID_SCE, name)); id_us_min(&sce->id); id_us_ensure_real(&sce->id); @@ -2023,25 +2022,22 @@ Object *BKE_scene_object_find_by_name(const Scene *scene, const char *name) } } } - return NULL; + return nullptr; } void BKE_scene_set_background(Main *bmain, Scene *scene) { - Object *ob; - /* check for cyclic sets, for reading old files but also for definite security (py?) */ BKE_scene_validate_setscene(bmain, scene); /* deselect objects (for dataselect) */ - for (ob = bmain->objects.first; ob; ob = ob->id.next) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { ob->flag &= ~SELECT; } /* copy layers and flags from bases to objects */ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { - ob = base->object; /* collection patch... */ BKE_scene_object_base_flag_sync_from_base(base); } @@ -2060,7 +2056,7 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) } printf("Can't find scene: '%s' in file: '%s'\n", name, BKE_main_blendfile_path(bmain)); - return NULL; + return nullptr; } int BKE_scene_base_iter_next( @@ -2071,9 +2067,9 @@ int BKE_scene_base_iter_next( /* init */ if (val == 0) { iter->phase = F_START; - iter->dupob = NULL; - iter->duplilist = NULL; - iter->dupli_refob = NULL; + iter->dupob = nullptr; + iter->duplilist = nullptr; + iter->dupli_refob = nullptr; } else { /* run_again is set when a duplilist has been ended */ @@ -2084,7 +2080,7 @@ int BKE_scene_base_iter_next( if (iter->phase == F_START) { ViewLayer *view_layer = (depsgraph) ? DEG_get_evaluated_view_layer(depsgraph) : BKE_view_layer_context_active_PLACEHOLDER(*scene); - *base = view_layer->object_bases.first; + *base = static_cast<Base *>(view_layer->object_bases.first); if (*base) { *ob = (*base)->object; iter->phase = F_SCENE; @@ -2095,7 +2091,7 @@ int BKE_scene_base_iter_next( (*scene) = (*scene)->set; ViewLayer *view_layer_set = BKE_view_layer_default_render(*scene); if (view_layer_set->object_bases.first) { - *base = view_layer_set->object_bases.first; + *base = static_cast<Base *>(view_layer_set->object_bases.first); *ob = (*base)->object; iter->phase = F_SCENE; break; @@ -2116,7 +2112,7 @@ int BKE_scene_base_iter_next( (*scene) = (*scene)->set; ViewLayer *view_layer_set = BKE_view_layer_default_render(*scene); if (view_layer_set->object_bases.first) { - *base = view_layer_set->object_bases.first; + *base = static_cast<Base *>(view_layer_set->object_bases.first); *ob = (*base)->object; break; } @@ -2126,7 +2122,7 @@ int BKE_scene_base_iter_next( } } - if (*base == NULL) { + if (*base == nullptr) { iter->phase = F_START; } else { @@ -2135,16 +2131,16 @@ int BKE_scene_base_iter_next( /* Collections cannot be duplicated for meta-balls yet, * this enters eternal loop because of * makeDispListMBall getting called inside of collection_duplilist */ - if ((*base)->object->instance_collection == NULL) { + if ((*base)->object->instance_collection == nullptr) { iter->duplilist = object_duplilist(depsgraph, (*scene), (*base)->object); - iter->dupob = iter->duplilist->first; + iter->dupob = static_cast<DupliObject *>(iter->duplilist->first); if (!iter->dupob) { free_object_duplilist(iter->duplilist); - iter->duplilist = NULL; + iter->duplilist = nullptr; } - iter->dupli_refob = NULL; + iter->dupli_refob = nullptr; } } } @@ -2174,11 +2170,11 @@ int BKE_scene_base_iter_next( if (iter->dupli_refob) { /* Restore last object's real matrix. */ copy_m4_m4(iter->dupli_refob->obmat, iter->omat); - iter->dupli_refob = NULL; + iter->dupli_refob = nullptr; } free_object_duplilist(iter->duplilist); - iter->duplilist = NULL; + iter->duplilist = nullptr; run_again = true; } } @@ -2195,7 +2191,7 @@ bool BKE_scene_has_view_layer(const Scene *scene, const ViewLayer *layer) Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *collection) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { LISTBASE_FOREACH (ViewLayer *, layer, &scene->view_layers) { if (BKE_view_layer_has_collection(layer, collection)) { return scene; @@ -2203,21 +2199,21 @@ Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *colle } } - return NULL; + return nullptr; } #ifdef DURIAN_CAMERA_SWITCH Object *BKE_scene_camera_switch_find(Scene *scene) { if (scene->r.mode & R_NO_CAMERA_SWITCH) { - return NULL; + return nullptr; } const int ctime = (int)BKE_scene_ctime_get(scene); int frame = -(MAXFRAME + 1); int min_frame = MAXFRAME + 1; - Object *camera = NULL; - Object *first_camera = NULL; + Object *camera = nullptr; + Object *first_camera = nullptr; LISTBASE_FOREACH (TimeMarker *, m, &scene->markers) { if (m->camera && (m->camera->visibility_flag & OB_HIDE_RENDER) == 0) { @@ -2237,7 +2233,7 @@ Object *BKE_scene_camera_switch_find(Scene *scene) } } - if (camera == NULL) { + if (camera == nullptr) { /* If there's no marker to the left of current frame, * use camera from left-most marker to solve all sort * of Schrodinger uncertainties. @@ -2270,7 +2266,10 @@ const char *BKE_scene_find_marker_name(const Scene *scene, int frame) const TimeMarker *m1, *m2; /* search through markers for match */ - for (m1 = markers->first, m2 = markers->last; m1 && m2; m1 = m1->next, m2 = m2->prev) { + for (m1 = static_cast<const TimeMarker *>(markers->first), + m2 = static_cast<const TimeMarker *>(markers->last); + m1 && m2; + m1 = m1->next, m2 = m2->prev) { if (m1->frame == frame) { return m1->name; } @@ -2284,14 +2283,14 @@ const char *BKE_scene_find_marker_name(const Scene *scene, int frame) } } - return NULL; + return nullptr; } const char *BKE_scene_find_last_marker_name(const Scene *scene, int frame) { - const TimeMarker *marker, *best_marker = NULL; + const TimeMarker *best_marker = nullptr; int best_frame = -MAXFRAME * 2; - for (marker = scene->markers.first; marker; marker = marker->next) { + LISTBASE_FOREACH (const TimeMarker *, marker, &scene->markers) { if (marker->frame == frame) { return marker->name; } @@ -2302,7 +2301,7 @@ const char *BKE_scene_find_last_marker_name(const Scene *scene, int frame) } } - return best_marker ? best_marker->name : NULL; + return best_marker ? best_marker->name : nullptr; } int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, int frame) @@ -2335,7 +2334,7 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce) Scene *sce_iter; int a, totscene; - if (sce->set == NULL) { + if (sce->set == nullptr) { return true; } totscene = BLI_listbase_count(&bmain->scenes); @@ -2344,7 +2343,7 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce) /* more iterations than scenes means we have a cycle */ if (a > totscene) { /* the tested scene gets zero'ed, that's typically current scene */ - sce->set = NULL; + sce->set = nullptr; return false; } } @@ -2437,9 +2436,8 @@ int BKE_scene_orientation_get_index_from_flag(Scene *scene, int flag) static bool check_rendered_viewport_visible(Main *bmain) { - wmWindowManager *wm = bmain->wm.first; - wmWindow *window; - for (window = wm->windows.first; window != NULL; window = window->next) { + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); + LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) { const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); Scene *scene = window->scene; RenderEngineType *type = RE_engines_find(scene->r.engine); @@ -2448,8 +2446,8 @@ static bool check_rendered_viewport_visible(Main *bmain) continue; } - for (ScrArea *area = screen->areabase.first; area != NULL; area = area->next) { - View3D *v3d = area->spacedata.first; + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + View3D *v3d = static_cast<View3D *>(area->spacedata.first); if (area->spacetype != SPACE_VIEW3D) { continue; } @@ -2462,7 +2460,7 @@ static bool check_rendered_viewport_visible(Main *bmain) } /* TODO(campbell): shouldn't we be able to use 'DEG_get_view_layer' here? - * Currently this is NULL on load, so don't. */ + * Currently this is nullptr on load, so don't. */ static void prepare_mesh_for_viewport_render(Main *bmain, const ViewLayer *view_layer) { /* This is needed to prepare mesh to be used by the render @@ -2476,18 +2474,15 @@ static void prepare_mesh_for_viewport_render(Main *bmain, const ViewLayer *view_ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); if (obedit) { - Mesh *mesh = obedit->data; + Mesh *mesh = static_cast<Mesh *>(obedit->data); if ((obedit->type == OB_MESH) && ((obedit->id.recalc & ID_RECALC_ALL) || (mesh->id.recalc & ID_RECALC_ALL))) { if (check_rendered_viewport_visible(bmain)) { BMesh *bm = mesh->edit_mesh->bm; - BM_mesh_bm_to_me(bmain, - bm, - mesh, - (&(struct BMeshToMeshParams){ - .calc_object_remap = true, - .update_shapekey_indices = true, - })); + BMeshToMeshParams params{}; + params.calc_object_remap = true; + params.update_shapekey_indices = true; + BM_mesh_bm_to_me(bmain, bm, mesh, ¶ms); DEG_id_tag_update(&mesh->id, 0); } } @@ -2697,13 +2692,11 @@ void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, View SceneRenderView *BKE_scene_add_render_view(Scene *sce, const char *name) { - SceneRenderView *srv; - if (!name) { name = DATA_("RenderView"); } - srv = MEM_callocN(sizeof(SceneRenderView), "new render view"); + SceneRenderView *srv = MEM_cnew<SceneRenderView>(__func__); BLI_strncpy(srv->name, name, sizeof(srv->name)); BLI_uniquename(&sce->r.views, srv, @@ -2751,17 +2744,17 @@ int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render) return lvl; } -int get_render_child_particle_number(const RenderData *r, int num, bool for_render) +int get_render_child_particle_number(const RenderData *r, int child_num, bool for_render) { if (r->mode & R_SIMPLIFY) { if (for_render) { - return (int)(r->simplify_particles_render * num); + return (int)(r->simplify_particles_render * child_num); } - return (int)(r->simplify_particles * num); + return (int)(r->simplify_particles * child_num); } - return num; + return child_num; } Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base) @@ -2770,7 +2763,7 @@ Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base) /* Common case, step to the next. */ return base->next; } - if ((base == NULL) && (view_layer != NULL)) { + if ((base == nullptr) && (view_layer != nullptr)) { /* First time looping, return the scenes first base. */ /* For the first loop we should get the layer from workspace when available. */ if (view_layer->object_bases.first) { @@ -2792,7 +2785,7 @@ Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base) } } - return NULL; + return nullptr; } bool BKE_scene_use_shading_nodes_custom(Scene *scene) @@ -2823,10 +2816,10 @@ bool BKE_scene_uses_cycles(const Scene *scene) } /* This enumeration has to match the one defined in the Cycles addon. */ -typedef enum eCyclesFeatureSet { +enum eCyclesFeatureSet { CYCLES_FEATURES_SUPPORTED = 0, CYCLES_FEATURES_EXPERIMENTAL = 1, -} eCyclesFeatureSet; +}; bool BKE_scene_uses_cycles_experimental_features(Scene *scene) { @@ -2845,7 +2838,7 @@ bool BKE_scene_uses_cycles_experimental_features(Scene *scene) void BKE_scene_base_flag_to_objects(ViewLayer *view_layer) { - Base *base = view_layer->object_bases.first; + Base *base = static_cast<Base *>(view_layer->object_bases.first); while (base) { BKE_scene_object_base_flag_sync_from_base(base); @@ -2954,7 +2947,6 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl int BKE_scene_multiview_num_views_get(const RenderData *rd) { - SceneRenderView *srv; int totviews = 0; if ((rd->scemode & R_MULTIVIEW) == 0) { @@ -2962,18 +2954,20 @@ int BKE_scene_multiview_num_views_get(const RenderData *rd) } if (rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) { - srv = BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name)); + SceneRenderView *srv = static_cast<SceneRenderView *>( + BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name))); if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) { totviews++; } - srv = BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name)); + srv = static_cast<SceneRenderView *>( + BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name))); if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) { totviews++; } } else { - for (srv = rd->views.first; srv; srv = srv->next) { + LISTBASE_FOREACH (SceneRenderView *, srv, &rd->views) { if ((srv->viewflag & SCE_VIEW_DISABLE) == 0) { totviews++; } @@ -3001,7 +2995,7 @@ bool BKE_scene_multiview_is_stereo3d(const RenderData *rd) bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv) { - if (srv == NULL) { + if (srv == nullptr) { return false; } @@ -3027,8 +3021,6 @@ bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const Scene bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname) { - SceneRenderView *srv; - if ((rd->scemode & R_MULTIVIEW) == 0) { return true; } @@ -3037,7 +3029,7 @@ bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char * return true; } - for (srv = rd->views.first; srv; srv = srv->next) { + LISTBASE_FOREACH (const SceneRenderView *, srv, &rd->views) { if (BKE_scene_multiview_is_render_view_active(rd, srv)) { return STREQ(viewname, srv->name); } @@ -3048,8 +3040,6 @@ bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char * bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *viewname) { - SceneRenderView *srv; - if ((rd->scemode & R_MULTIVIEW) == 0) { return true; } @@ -3058,7 +3048,7 @@ bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *v return true; } - for (srv = rd->views.last; srv; srv = srv->prev) { + LISTBASE_FOREACH_BACKWARD (const SceneRenderView *, srv, &rd->views) { if (BKE_scene_multiview_is_render_view_active(rd, srv)) { return STREQ(viewname, srv->name); } @@ -3073,10 +3063,10 @@ SceneRenderView *BKE_scene_multiview_render_view_findindex(const RenderData *rd, size_t nr; if ((rd->scemode & R_MULTIVIEW) == 0) { - return NULL; + return nullptr; } - for (srv = rd->views.first, nr = 0; srv; srv = srv->next) { + for (srv = static_cast<SceneRenderView *>(rd->views.first), nr = 0; srv; srv = srv->next) { if (BKE_scene_multiview_is_render_view_active(rd, srv)) { if (nr++ == view_id) { return srv; @@ -3110,7 +3100,7 @@ int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname) return 0; } - for (srv = rd->views.first, nr = 0; srv; srv = srv->next) { + for (srv = static_cast<SceneRenderView *>(rd->views.first), nr = 0; srv; srv = srv->next) { if (BKE_scene_multiview_is_render_view_active(rd, srv)) { if (STREQ(viewname, srv->name)) { return nr; @@ -3139,7 +3129,8 @@ void BKE_scene_multiview_view_filepath_get(const RenderData *rd, SceneRenderView *srv; char suffix[FILE_MAX]; - srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name)); + srv = static_cast<SceneRenderView *>( + BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name))); if (srv) { BLI_strncpy(suffix, srv->suffix, sizeof(suffix)); } @@ -3155,11 +3146,12 @@ const char *BKE_scene_multiview_view_suffix_get(const RenderData *rd, const char { SceneRenderView *srv; - if ((viewname == NULL) || (viewname[0] == '\0')) { + if ((viewname == nullptr) || (viewname[0] == '\0')) { return viewname; } - srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name)); + srv = static_cast<SceneRenderView *>( + BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name))); if (srv) { return srv->suffix; } @@ -3182,7 +3174,6 @@ void BKE_scene_multiview_view_prefix_get(Scene *scene, char *r_prefix, const char **r_ext) { - SceneRenderView *srv; size_t index_act; const char *suf_act; const char delims[] = {'.', '\0'}; @@ -3191,13 +3182,13 @@ void BKE_scene_multiview_view_prefix_get(Scene *scene, /* begin of extension */ index_act = BLI_str_rpartition(name, delims, r_ext, &suf_act); - if (*r_ext == NULL) { + if (*r_ext == nullptr) { return; } BLI_assert(index_act > 0); UNUSED_VARS_NDEBUG(index_act); - for (srv = scene->r.views.first; srv; srv = srv->next) { + LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) { if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) { const size_t len = strlen(srv->suffix); const size_t ext_len = strlen(*r_ext); @@ -3250,16 +3241,16 @@ int BKE_scene_multiview_num_videos_get(const RenderData *rd) /* Manipulation of depsgraph storage. */ /* This is a key which identifies depsgraph. */ -typedef struct DepsgraphKey { +struct DepsgraphKey { const ViewLayer *view_layer; /* TODO(sergey): Need to include window somehow (same layer might be in a * different states in different windows). */ -} DepsgraphKey; +}; static unsigned int depsgraph_key_hash(const void *key_v) { - const DepsgraphKey *key = key_v; + const DepsgraphKey *key = static_cast<const DepsgraphKey *>(key_v); unsigned int hash = BLI_ghashutil_ptrhash(key->view_layer); /* TODO(sergey): Include hash from other fields in the key. */ return hash; @@ -3267,21 +3258,21 @@ static unsigned int depsgraph_key_hash(const void *key_v) static bool depsgraph_key_compare(const void *key_a_v, const void *key_b_v) { - const DepsgraphKey *key_a = key_a_v; - const DepsgraphKey *key_b = key_b_v; + const DepsgraphKey *key_a = static_cast<const DepsgraphKey *>(key_a_v); + const DepsgraphKey *key_b = static_cast<const DepsgraphKey *>(key_b_v); /* TODO(sergey): Compare rest of. */ return !(key_a->view_layer == key_b->view_layer); } static void depsgraph_key_free(void *key_v) { - DepsgraphKey *key = key_v; + DepsgraphKey *key = static_cast<DepsgraphKey *>(key_v); MEM_freeN(key); } static void depsgraph_key_value_free(void *value) { - Depsgraph *depsgraph = value; + Depsgraph *depsgraph = static_cast<Depsgraph *>(value); DEG_graph_free(depsgraph); } @@ -3293,23 +3284,23 @@ void BKE_scene_allocate_depsgraph_hash(Scene *scene) void BKE_scene_ensure_depsgraph_hash(Scene *scene) { - if (scene->depsgraph_hash == NULL) { + if (scene->depsgraph_hash == nullptr) { BKE_scene_allocate_depsgraph_hash(scene); } } void BKE_scene_free_depsgraph_hash(Scene *scene) { - if (scene->depsgraph_hash == NULL) { + if (scene->depsgraph_hash == nullptr) { return; } BLI_ghash_free(scene->depsgraph_hash, depsgraph_key_free, depsgraph_key_value_free); - scene->depsgraph_hash = NULL; + scene->depsgraph_hash = nullptr; } void BKE_scene_free_view_layer_depsgraph(Scene *scene, ViewLayer *view_layer) { - if (scene->depsgraph_hash != NULL) { + if (scene->depsgraph_hash != nullptr) { DepsgraphKey key = {view_layer}; BLI_ghash_remove(scene->depsgraph_hash, &key, depsgraph_key_free, depsgraph_key_value_free); } @@ -3321,17 +3312,17 @@ static Depsgraph **scene_get_depsgraph_p(Scene *scene, ViewLayer *view_layer, const bool allocate_ghash_entry) { - /* bmain may be NULL here! */ - BLI_assert(scene != NULL); - BLI_assert(view_layer != NULL); + /* bmain may be nullptr here! */ + BLI_assert(scene != nullptr); + BLI_assert(view_layer != nullptr); BLI_assert(BKE_scene_has_view_layer(scene, view_layer)); /* Make sure hash itself exists. */ if (allocate_ghash_entry) { BKE_scene_ensure_depsgraph_hash(scene); } - if (scene->depsgraph_hash == NULL) { - return NULL; + if (scene->depsgraph_hash == nullptr) { + return nullptr; } DepsgraphKey key; @@ -3350,23 +3341,23 @@ static Depsgraph **scene_get_depsgraph_p(Scene *scene, } /* Depsgraph was not found in the ghash, but the key still needs allocating. */ - *key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__); + *key_ptr = MEM_new<DepsgraphKey>(__func__); **key_ptr = key; - *depsgraph_ptr = NULL; + *depsgraph_ptr = nullptr; return depsgraph_ptr; } static Depsgraph **scene_ensure_depsgraph_p(Main *bmain, Scene *scene, ViewLayer *view_layer) { - BLI_assert(bmain != NULL); + BLI_assert(bmain != nullptr); Depsgraph **depsgraph_ptr = scene_get_depsgraph_p(scene, view_layer, true); - if (depsgraph_ptr == NULL) { + if (depsgraph_ptr == nullptr) { /* The scene has no depsgraph hash. */ - return NULL; + return nullptr; } - if (*depsgraph_ptr != NULL) { + if (*depsgraph_ptr != nullptr) { /* The depsgraph was found, no need to allocate. */ return depsgraph_ptr; } @@ -3393,25 +3384,25 @@ Depsgraph *BKE_scene_get_depsgraph(const Scene *scene, const ViewLayer *view_lay { BLI_assert(BKE_scene_has_view_layer(scene, view_layer)); - if (scene->depsgraph_hash == NULL) { - return NULL; + if (scene->depsgraph_hash == nullptr) { + return nullptr; } DepsgraphKey key; key.view_layer = view_layer; - return BLI_ghash_lookup(scene->depsgraph_hash, &key); + return static_cast<Depsgraph *>(BLI_ghash_lookup(scene->depsgraph_hash, &key)); } Depsgraph *BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer) { Depsgraph **depsgraph_ptr = scene_ensure_depsgraph_p(bmain, scene, view_layer); - return (depsgraph_ptr != NULL) ? *depsgraph_ptr : NULL; + return (depsgraph_ptr != nullptr) ? *depsgraph_ptr : nullptr; } static char *scene_undo_depsgraph_gen_key(Scene *scene, ViewLayer *view_layer, char *key_full) { - if (key_full == NULL) { - key_full = MEM_callocN(MAX_ID_NAME + FILE_MAX + MAX_NAME, __func__); + if (key_full == nullptr) { + key_full = static_cast<char *>(MEM_callocN(MAX_ID_NAME + FILE_MAX + MAX_NAME, __func__)); } size_t key_full_offset = BLI_strncpy_rlen(key_full, scene->id.name, MAX_ID_NAME); @@ -3430,24 +3421,23 @@ GHash *BKE_scene_undo_depsgraphs_extract(Main *bmain) GHash *depsgraph_extract = BLI_ghash_new( BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); - for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { - if (scene->depsgraph_hash == NULL) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->depsgraph_hash == nullptr) { /* In some cases, e.g. when undo has to perform multiple steps at once, no depsgraph will - * be built so this pointer may be NULL. */ + * be built so this pointer may be nullptr. */ continue; } - for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL; - view_layer = view_layer->next) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { DepsgraphKey key; key.view_layer = view_layer; Depsgraph **depsgraph = (Depsgraph **)BLI_ghash_lookup_p(scene->depsgraph_hash, &key); - if (depsgraph != NULL && *depsgraph != NULL) { - char *key_full = scene_undo_depsgraph_gen_key(scene, view_layer, NULL); + if (depsgraph != nullptr && *depsgraph != nullptr) { + char *key_full = scene_undo_depsgraph_gen_key(scene, view_layer, nullptr); /* We steal the depsgraph from the scene. */ BLI_ghash_insert(depsgraph_extract, key_full, *depsgraph); - *depsgraph = NULL; + *depsgraph = nullptr; } } } @@ -3457,22 +3447,21 @@ GHash *BKE_scene_undo_depsgraphs_extract(Main *bmain) void BKE_scene_undo_depsgraphs_restore(Main *bmain, GHash *depsgraph_extract) { - for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { - for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL; - view_layer = view_layer->next) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { char key_full[MAX_ID_NAME + FILE_MAX + MAX_NAME] = {0}; scene_undo_depsgraph_gen_key(scene, view_layer, key_full); Depsgraph **depsgraph_extract_ptr = (Depsgraph **)BLI_ghash_lookup_p(depsgraph_extract, key_full); - if (depsgraph_extract_ptr == NULL) { + if (depsgraph_extract_ptr == nullptr) { continue; } - BLI_assert(*depsgraph_extract_ptr != NULL); + BLI_assert(*depsgraph_extract_ptr != nullptr); Depsgraph **depsgraph_scene_ptr = scene_get_depsgraph_p(scene, view_layer, true); - BLI_assert(depsgraph_scene_ptr != NULL); - BLI_assert(*depsgraph_scene_ptr == NULL); + BLI_assert(depsgraph_scene_ptr != nullptr); + BLI_assert(*depsgraph_scene_ptr == nullptr); /* We steal the depsgraph back from our 'extract' storage to the scene. */ Depsgraph *depsgraph = *depsgraph_extract_ptr; @@ -3482,7 +3471,7 @@ void BKE_scene_undo_depsgraphs_restore(Main *bmain, GHash *depsgraph_extract) DEG_graph_tag_relations_update(depsgraph); *depsgraph_scene_ptr = depsgraph; - *depsgraph_extract_ptr = NULL; + *depsgraph_extract_ptr = nullptr; } } @@ -3515,7 +3504,7 @@ void BKE_scene_transform_orientation_remove(Scene *scene, TransformOrientation * TransformOrientation *BKE_scene_transform_orientation_find(const Scene *scene, const int index) { - return BLI_findlink(&scene->transform_spaces, index); + return static_cast<TransformOrientation *>(BLI_findlink(&scene->transform_spaces, index)); } int BKE_scene_transform_orientation_get_index(const Scene *scene, diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index 7d0c6598440..f17450ac3f4 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -1166,18 +1166,18 @@ static void studiolight_add_files_from_datafolder(const int folder_id, const char *subfolder, int flag) { - struct direntry *dir; + struct direntry *dirs; const char *folder = BKE_appdir_folder_id(folder_id, subfolder); if (folder) { - uint totfile = BLI_filelist_dir_contents(folder, &dir); + const uint dirs_num = BLI_filelist_dir_contents(folder, &dirs); int i; - for (i = 0; i < totfile; i++) { - if (dir[i].type & S_IFREG) { - studiolight_add_file(dir[i].path, flag); + for (i = 0; i < dirs_num; i++) { + if (dirs[i].type & S_IFREG) { + studiolight_add_file(dirs[i].path, flag); } } - BLI_filelist_free(dir, totfile); - dir = NULL; + BLI_filelist_free(dirs, dirs_num); + dirs = NULL; } } diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c index 7b1ebd5df1f..ee1976d5946 100644 --- a/source/blender/blenkernel/intern/subdiv.c +++ b/source/blender/blenkernel/intern/subdiv.c @@ -106,7 +106,7 @@ Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings, * The thing here is: OpenSubdiv can only deal with faces, but our * side of subdiv also deals with loose vertices and edges. */ } - Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converetr"); + Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converter"); subdiv->settings = *settings; subdiv->topology_refiner = osd_topology_refiner; subdiv->evaluator = NULL; |