diff options
Diffstat (limited to 'source/blender/blenkernel')
21 files changed, 363 insertions, 409 deletions
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index 13eefd27bec..3f4981993eb 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -90,7 +90,7 @@ int BKE_id_attributes_length(const struct ID *id, eCustomDataMask mask); struct CustomDataLayer *BKE_id_attributes_active_get(struct ID *id); -void BKE_id_attributes_active_set(struct ID *id, struct CustomDataLayer *layer); +void BKE_id_attributes_active_set(struct ID *id, const char *name); int *BKE_id_attributes_active_index_p(struct ID *id); CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers); diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index cbdf37e14bd..b4de24e3b64 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -167,7 +167,7 @@ void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm); * \param mtype: Type of modifier (if 0, doesn't matter). * \param acttype: Type of action to perform (if -1, doesn't matter). */ -bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype); +bool list_has_suitable_fmodifier(const ListBase *modifiers, int mtype, short acttype); typedef struct FModifiersStackStorage { uint modifier_count; @@ -369,12 +369,12 @@ int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache, * Calculate the extents of F-Curve's keyframes. */ bool BKE_fcurve_calc_range( - struct FCurve *fcu, float *min, float *max, bool do_sel_only, bool do_min_length); + const struct FCurve *fcu, float *min, float *max, bool do_sel_only, bool do_min_length); /** * Calculate the extents of F-Curve's data. */ -bool BKE_fcurve_calc_bounds(struct FCurve *fcu, +bool BKE_fcurve_calc_bounds(const struct FCurve *fcu, float *xmin, float *xmax, float *ymin, @@ -421,14 +421,14 @@ void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, flo * Usability of keyframes refers to whether they should be displayed, * and also whether they will have any influence on the final result. */ -bool BKE_fcurve_are_keyframes_usable(struct FCurve *fcu); +bool BKE_fcurve_are_keyframes_usable(const struct FCurve *fcu); /** * Can keyframes be added to F-Curve? * Keyframes can only be added if they are already visible. */ -bool BKE_fcurve_is_keyframable(struct FCurve *fcu); -bool BKE_fcurve_is_protected(struct FCurve *fcu); +bool BKE_fcurve_is_keyframable(const struct FCurve *fcu); +bool BKE_fcurve_is_protected(const struct FCurve *fcu); /** * Are any of the keyframe control points selected on the F-Curve? @@ -439,7 +439,7 @@ bool BKE_fcurve_has_selected_control_points(const struct FCurve *fcu); * Checks if the F-Curve has a Cycles modifier with simple settings * that warrant transition smoothing. */ -bool BKE_fcurve_is_cyclic(struct FCurve *fcu); +bool BKE_fcurve_is_cyclic(const struct FCurve *fcu); /* Type of infinite cycle for a curve. */ typedef enum eFCU_Cycle_Type { @@ -453,7 +453,7 @@ typedef enum eFCU_Cycle_Type { /** * Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior. */ -eFCU_Cycle_Type BKE_fcurve_get_cycle_type(struct FCurve *fcu); +eFCU_Cycle_Type BKE_fcurve_get_cycle_type(const struct FCurve *fcu); /** * Recompute bezier handles of all three given BezTriples, so that `bezt` can be inserted between @@ -544,7 +544,7 @@ float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, /** * Checks if the curve has valid keys, drivers or modifiers that produce an actual curve. */ -bool BKE_fcurve_is_empty(struct FCurve *fcu); +bool BKE_fcurve_is_empty(const struct FCurve *fcu); /** * Calculate the value of the given F-Curve at the given frame, * and store it's value in #FCurve.curval. diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 8f6786d4113..b1488c93ba6 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -494,15 +494,6 @@ void BKE_mesh_calc_normals_looptri(const struct MVert *mverts, const struct MLoopTri *looptri, int looptri_num, float (*r_tri_nors)[3]); -void BKE_mesh_loop_manifold_fan_around_vert_next(const struct MLoop *mloops, - const struct MPoly *mpolys, - const int *loop_to_poly, - const int *e2lfan_curr, - uint mv_pivot_index, - const struct MLoop **r_mlfan_curr, - int *r_mlfan_curr_index, - int *r_mlfan_vert_index, - int *r_mpfan_curr_index); /** * Define sharp edges as needed to mimic 'autosmooth' from angle threshold. @@ -630,6 +621,8 @@ void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals'). * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry * (splitting edges). + * + * \param loop_to_poly_map: Optional pre-created map from loops to their polygon. */ void BKE_mesh_normals_loop_split(const struct MVert *mverts, const float (*vert_normals)[3], @@ -644,9 +637,9 @@ void BKE_mesh_normals_loop_split(const struct MVert *mverts, int numPolys, bool use_split_normals, float split_angle, + const int *loop_to_poly_map, MLoopNorSpaceArray *r_lnors_spacearr, - short (*clnors_data)[2], - int *r_loop_to_poly); + short (*clnors_data)[2]); void BKE_mesh_normals_loop_custom_set(const struct MVert *mverts, const float (*vert_normals)[3], diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 4d883f9e31e..ae8eea4a6bf 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -746,7 +746,14 @@ struct bNode *nodeFindNodebyName(struct bNodeTree *ntree, const char *name); /** * Finds a node based on given socket and returns true on success. */ -bool nodeFindNode(struct bNodeTree *ntree, +bool nodeFindNodeTry(struct bNodeTree *ntree, + struct bNodeSocket *sock, + struct bNode **r_node, + int *r_sockindex); +/** + * Same as above but expects that the socket definitely is in the node tree. + */ +void nodeFindNode(struct bNodeTree *ntree, struct bNodeSocket *sock, struct bNode **r_node, int *r_sockindex); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 9fc4aa5307d..434255b2d9c 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -119,6 +119,7 @@ typedef enum ePaintSymmetryAreas { PAINT_SYMM_AREA_Y = (1 << 1), PAINT_SYMM_AREA_Z = (1 << 2), } ePaintSymmetryAreas; +ENUM_OPERATORS(ePaintSymmetryAreas, PAINT_SYMM_AREA_Z); #define PAINT_SYMM_AREAS 8 diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index b375d69b61c..4badd1bc269 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -416,6 +416,8 @@ typedef enum { PBVH_Subdivide = 1, PBVH_Collapse = 2, } PBVHTopologyUpdateMode; +ENUM_OPERATORS(PBVHTopologyUpdateMode, PBVH_Collapse); + /** * Collapse short edges, subdivide long edges. */ diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc index 1a54454bf9a..80647362826 100644 --- a/source/blender/blenkernel/intern/attribute.cc +++ b/source/blender/blenkernel/intern/attribute.cc @@ -495,29 +495,14 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id) return nullptr; } -void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer) +void BKE_id_attributes_active_set(ID *id, const char *name) { - DomainInfo info[ATTR_DOMAIN_NUM]; - get_domains(id, info); - - int index = 0; + const CustomDataLayer *layer = BKE_id_attribute_search( + id, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL); + BLI_assert(layer != nullptr); - for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) { - const CustomData *customdata = info[domain].customdata; - if (customdata == nullptr) { - continue; - } - for (int i = 0; i < customdata->totlayer; i++) { - const CustomDataLayer *layer = &customdata->layers[i]; - if (layer == active_layer) { - *BKE_id_attributes_active_index_p(id) = index; - return; - } - if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) { - index++; - } - } - } + const int index = BKE_id_attribute_to_index(id, layer, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL); + *BKE_id_attributes_active_index_p(id) = index; } int *BKE_id_attributes_active_index_p(ID *id) diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 84aa2207400..bccb625feb2 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2799,6 +2799,14 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, const LayerTypeInfo *typeInfo = layerType_getInfo(type); int flag = 0; + /* Some layer types only support a single layer. */ + if (!typeInfo->defaultname && CustomData_has_layer(data, type)) { + /* This function doesn't support dealing with existing layer data for these layer types when + * the layer already exists. */ + BLI_assert(layerdata == nullptr); + return &data->layers[CustomData_get_layer_index(data, type)]; + } + void *newlayerdata = nullptr; switch (alloctype) { case CD_SET_DEFAULT: @@ -2851,21 +2859,6 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, break; } - /* Some layer types only support a single layer. */ - const bool reuse_existing_layer = !typeInfo->defaultname && CustomData_has_layer(data, type); - if (reuse_existing_layer) { - CustomDataLayer &layer = data->layers[CustomData_get_layer_index(data, type)]; - if (layer.data != nullptr) { - if (typeInfo->free) { - typeInfo->free(layer.data, totelem, typeInfo->size); - } - MEM_SAFE_FREE(layer.data); - } - layer.data = newlayerdata; - layer.flag = flag; - return &layer; - } - int index = data->totlayer; if (index >= data->maxlayer) { if (!customData_resize(data, CUSTOMDATA_GROW)) { diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index e6afca11b40..7b81f74206d 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -300,8 +300,8 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src, use_split_nors_dst, split_angle_dst, NULL, - custom_nors_dst, - NULL); + NULL, + custom_nors_dst); } } } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index d248faaab00..3e772e37177 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -85,8 +85,6 @@ void BKE_fcurve_free(FCurve *fcu) void BKE_fcurves_free(ListBase *list) { - FCurve *fcu, *fcn; - /* Sanity check. */ if (list == NULL) { return; @@ -96,7 +94,8 @@ void BKE_fcurves_free(ListBase *list) * as we store reference to next, and freeing only touches the curve * it's given. */ - for (fcu = list->first; fcu; fcu = fcn) { + FCurve *fcn = NULL; + for (FCurve *fcu = list->first; fcu; fcu = fcn) { fcn = fcu->next; BKE_fcurve_free(fcu); } @@ -113,15 +112,13 @@ void BKE_fcurves_free(ListBase *list) FCurve *BKE_fcurve_copy(const FCurve *fcu) { - FCurve *fcu_d; - /* Sanity check. */ if (fcu == NULL) { return NULL; } /* Make a copy. */ - fcu_d = MEM_dupallocN(fcu); + FCurve *fcu_d = MEM_dupallocN(fcu); fcu_d->next = fcu_d->prev = NULL; fcu_d->grp = NULL; @@ -145,8 +142,6 @@ FCurve *BKE_fcurve_copy(const FCurve *fcu) void BKE_fcurves_copy(ListBase *dst, ListBase *src) { - FCurve *dfcu, *sfcu; - /* Sanity checks. */ if (ELEM(NULL, dst, src)) { return; @@ -156,8 +151,8 @@ void BKE_fcurves_copy(ListBase *dst, ListBase *src) BLI_listbase_clear(dst); /* Copy one-by-one. */ - for (sfcu = src->first; sfcu; sfcu = sfcu->next) { - dfcu = BKE_fcurve_copy(sfcu); + LISTBASE_FOREACH (FCurve *, sfcu, src) { + FCurve *dfcu = BKE_fcurve_copy(sfcu); BLI_addtail(dst, dfcu); } } @@ -203,12 +198,10 @@ FCurve *id_data_find_fcurve( { /* Anim vars */ AnimData *adt = BKE_animdata_from_id(id); - FCurve *fcu = NULL; /* Rna vars */ PointerRNA ptr; PropertyRNA *prop; - char *path; if (r_driven) { *r_driven = false; @@ -225,7 +218,7 @@ FCurve *id_data_find_fcurve( return NULL; } - path = RNA_path_from_ID_to_property(&ptr, prop); + char *path = RNA_path_from_ID_to_property(&ptr, prop); if (path == NULL) { return NULL; } @@ -233,7 +226,7 @@ FCurve *id_data_find_fcurve( /* FIXME: The way drivers are handled here (always NULL-ifying `fcu`) is very weird, this needs * to be re-checked I think?. */ bool is_driven = false; - fcu = BKE_animadata_fcurve_find_by_rna_path(adt, path, index, NULL, &is_driven); + FCurve *fcu = BKE_animadata_fcurve_find_by_rna_path(adt, path, index, NULL, &is_driven); if (is_driven) { if (r_driven != NULL) { *r_driven = is_driven; @@ -248,15 +241,13 @@ FCurve *id_data_find_fcurve( FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index) { - FCurve *fcu; - /* Sanity checks. */ - if (ELEM(NULL, list, rna_path) || (array_index < 0)) { + if (ELEM(NULL, list, rna_path) || array_index < 0) { return NULL; } /* Check paths of curves, then array indices... */ - for (fcu = list->first; fcu; fcu = fcu->next) { + LISTBASE_FOREACH (FCurve *, fcu, list) { /* Check indices first, much cheaper than a string comparison. */ /* Simple string-compare (this assumes that they have the same root...) */ if (UNLIKELY(fcu->array_index == array_index && fcu->rna_path && @@ -276,15 +267,13 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[]) { - FCurve *fcu; - /* Sanity checks. */ if (ELEM(NULL, fcu_iter, rna_path)) { return NULL; } /* Check paths of curves, then array indices... */ - for (fcu = fcu_iter; fcu; fcu = fcu->next) { + for (FCurve *fcu = fcu_iter; fcu; fcu = fcu->next) { /* Simple string-compare (this assumes that they have the same root...) */ if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) { return fcu; @@ -296,7 +285,6 @@ FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[]) int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName) { - FCurve *fcu; int matches = 0; /* Sanity checks. */ @@ -311,7 +299,7 @@ int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, con char *quotedName = alloca(quotedName_size); /* Search each F-Curve one by one. */ - for (fcu = src->first; fcu; fcu = fcu->next) { + LISTBASE_FOREACH (FCurve *, fcu, src) { /* Check if quoted string matches the path. */ if (fcu->rna_path == NULL) { continue; @@ -487,16 +475,14 @@ static int BKE_fcurve_bezt_binarysearch_index_ex(const BezTriple array[], * - Keyframe to be added is to be added out of current bounds. * - Keyframe to be added would replace one of the existing ones on bounds. */ - if ((arraylen <= 0) || (array == NULL)) { + if (arraylen <= 0 || array == NULL) { CLOG_WARN(&LOG, "encountered invalid array"); return 0; } /* Check whether to add before/after/on. */ - float framenum; - /* 'First' Keyframe (when only one keyframe, this case is used) */ - framenum = array[0].vec[1][0]; + float framenum = array[0].vec[1][0]; if (IS_EQT(frame, framenum, threshold)) { *r_replace = true; return 0; @@ -522,9 +508,9 @@ static int BKE_fcurve_bezt_binarysearch_index_ex(const BezTriple array[], /* Compute and get midpoint. */ /* We calculate the midpoint this way to avoid int overflows... */ - int mid = start + ((end - start) / 2); + const int mid = start + ((end - start) / 2); - float midfra = array[mid].vec[1][0]; + const float midfra = array[mid].vec[1][0]; /* Check if exactly equal to midpoint. */ if (IS_EQT(frame, midfra, threshold)) { @@ -571,7 +557,7 @@ int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], /* ...................................... */ /* Helper for calc_fcurve_* functions -> find first and last BezTriple to be used. */ -static short get_fcurve_end_keyframes(FCurve *fcu, +static short get_fcurve_end_keyframes(const FCurve *fcu, BezTriple **first, BezTriple **last, const bool do_sel_only) @@ -589,10 +575,8 @@ static short get_fcurve_end_keyframes(FCurve *fcu, /* Only include selected items? */ if (do_sel_only) { - BezTriple *bezt; - /* Find first selected. */ - bezt = fcu->bezt; + BezTriple *bezt = fcu->bezt; for (int i = 0; i < fcu->totvert; bezt++, i++) { if (BEZT_ISSEL_ANY(bezt)) { *first = bezt; @@ -621,7 +605,7 @@ static short get_fcurve_end_keyframes(FCurve *fcu, return found; } -bool BKE_fcurve_calc_bounds(FCurve *fcu, +bool BKE_fcurve_calc_bounds(const FCurve *fcu, float *xmin, float *xmax, float *ymin, @@ -696,10 +680,9 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu, /* Only loop over keyframes to find extents for values if needed. */ if (ymin || ymax) { - FPoint *fpt; - int i; + int i = 0; - for (fpt = fcu->fpt, i = 0; i < fcu->totvert; fpt++, i++) { + for (FPoint *fpt = fcu->fpt; i < fcu->totvert; fpt++, i++) { if (fpt->vec[1] < yminv) { yminv = fpt->vec[1]; } @@ -752,7 +735,7 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu, } bool BKE_fcurve_calc_range( - FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length) + const FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length) { float min = 999999999.0f, max = -999999999.0f; bool foundvert = false; @@ -855,7 +838,7 @@ void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt) /* Gracefully handle out-of-bounds pointers. Ideally this would do a BLI_assert() as well, but * then the unit tests would break in debug mode. */ - ptrdiff_t offset = active_bezt - fcu->bezt; + const ptrdiff_t offset = active_bezt - fcu->bezt; if (offset < 0 || offset >= fcu->totvert) { fcu->active_keyframe_index = FCURVE_ACTIVE_KEYFRAME_NONE; return; @@ -872,8 +855,7 @@ int BKE_fcurve_active_keyframe_index(const FCurve *fcu) const int active_keyframe_index = fcu->active_keyframe_index; /* Array access boundary checks. */ - if ((fcu->bezt == NULL) || (active_keyframe_index >= fcu->totvert) || - (active_keyframe_index < 0)) { + if (fcu->bezt == NULL || active_keyframe_index >= fcu->totvert || active_keyframe_index < 0) { return FCURVE_ACTIVE_KEYFRAME_NONE; } @@ -900,7 +882,7 @@ void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, con /** \name Status Checks * \{ */ -bool BKE_fcurve_are_keyframes_usable(FCurve *fcu) +bool BKE_fcurve_are_keyframes_usable(const FCurve *fcu) { /* F-Curve must exist. */ if (fcu == NULL) { @@ -914,11 +896,9 @@ bool BKE_fcurve_are_keyframes_usable(FCurve *fcu) /* If it has modifiers, none of these should "drastically" alter the curve. */ if (fcu->modifiers.first) { - FModifier *fcm; - /* Check modifiers from last to first, as last will be more influential. */ /* TODO: optionally, only check modifier if it is the active one... (Joshua Leung 2010) */ - for (fcm = fcu->modifiers.last; fcm; fcm = fcm->prev) { + LISTBASE_FOREACH_BACKWARD (FModifier *, fcm, &fcu->modifiers) { /* Ignore if muted/disabled. */ if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) { continue; @@ -960,9 +940,9 @@ bool BKE_fcurve_are_keyframes_usable(FCurve *fcu) return true; } -bool BKE_fcurve_is_protected(FCurve *fcu) +bool BKE_fcurve_is_protected(const FCurve *fcu) { - return ((fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED))); + return ((fcu->flag & FCURVE_PROTECTED) || (fcu->grp && (fcu->grp->flag & AGRP_PROTECTED))); } bool BKE_fcurve_has_selected_control_points(const FCurve *fcu) @@ -977,7 +957,7 @@ bool BKE_fcurve_has_selected_control_points(const FCurve *fcu) return false; } -bool BKE_fcurve_is_keyframable(FCurve *fcu) +bool BKE_fcurve_is_keyframable(const FCurve *fcu) { /* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */ if (BKE_fcurve_are_keyframes_usable(fcu) == 0) { @@ -1048,9 +1028,6 @@ float fcurve_samplingcb_evalcurve(FCurve *fcu, void *UNUSED(data), float evaltim void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb) { - FPoint *fpt, *new_fpt; - int cfra; - /* Sanity checks. */ /* TODO: make these tests report errors using reports not CLOG's (Joshua Leung 2009) */ if (ELEM(NULL, fcu, sample_cb)) { @@ -1063,10 +1040,11 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample } /* Set up sample data. */ - fpt = new_fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "FPoint Samples"); + FPoint *new_fpt; + FPoint *fpt = new_fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "FPoint Samples"); /* Use the sampling callback at 1-frame intervals from start to end frames. */ - for (cfra = start; cfra <= end; cfra++, fpt++) { + for (int cfra = start; cfra <= end; cfra++, fpt++) { fpt->vec[0] = (float)cfra; fpt->vec[1] = sample_cb(fcu, data, (float)cfra); } @@ -1119,12 +1097,12 @@ void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end) MEM_freeN(fcu->bezt); } - BezTriple *bezt; FPoint *fpt = fcu->fpt; int keyframes_to_insert = end - start; int sample_points = fcu->totvert; - bezt = fcu->bezt = MEM_callocN(sizeof(*fcu->bezt) * (size_t)keyframes_to_insert, __func__); + BezTriple *bezt = fcu->bezt = MEM_callocN(sizeof(*fcu->bezt) * (size_t)keyframes_to_insert, + __func__); fcu->totvert = keyframes_to_insert; /* Get first sample point to 'copy' as keyframe. */ @@ -1168,7 +1146,7 @@ void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end) * that the handles are correct. */ -eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu) +eFCU_Cycle_Type BKE_fcurve_get_cycle_type(const FCurve *fcu) { FModifier *fcm = fcu->modifiers.first; @@ -1201,7 +1179,7 @@ eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu) return FCU_CYCLE_NONE; } -bool BKE_fcurve_is_cyclic(FCurve *fcu) +bool BKE_fcurve_is_cyclic(const FCurve *fcu) { return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE; } @@ -1231,7 +1209,6 @@ static BezTriple *cycle_offset_triple( void BKE_fcurve_handles_recalc_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag) { - BezTriple *bezt, *prev, *next; int a = fcu->totvert; /* Error checking: @@ -1247,12 +1224,12 @@ void BKE_fcurve_handles_recalc_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag) BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1]; BezTriple tmp; - bool cycle = BKE_fcurve_is_cyclic(fcu) && BEZT_IS_AUTOH(first) && BEZT_IS_AUTOH(last); + const bool cycle = BKE_fcurve_is_cyclic(fcu) && BEZT_IS_AUTOH(first) && BEZT_IS_AUTOH(last); /* Get initial pointers. */ - bezt = fcu->bezt; - prev = cycle_offset_triple(cycle, &tmp, &fcu->bezt[fcu->totvert - 2], last, first); - next = (bezt + 1); + BezTriple *bezt = fcu->bezt; + BezTriple *prev = cycle_offset_triple(cycle, &tmp, &fcu->bezt[fcu->totvert - 2], last, first); + BezTriple *next = (bezt + 1); /* Loop over all beztriples, adjusting handles. */ while (a--) { @@ -1319,15 +1296,14 @@ void BKE_fcurve_handles_recalc(FCurve *fcu) void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle) { - BezTriple *bezt; - uint a; - /* Only beztriples have handles (bpoints don't though). */ if (ELEM(NULL, fcu, fcu->bezt)) { return; } /* Loop over beztriples. */ + BezTriple *bezt; + uint a; for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) { BKE_nurb_bezt_handle_test(bezt, sel_flag, use_handle, false); } @@ -1701,12 +1677,12 @@ void BKE_fcurve_delete_key(FCurve *fcu, int index) bool BKE_fcurve_delete_keys_selected(FCurve *fcu) { - bool changed = false; - if (fcu->bezt == NULL) { /* ignore baked curves */ return false; } + bool changed = false; + /* Delete selected BezTriples */ for (int i = 0; i < fcu->totvert; i++) { if (fcu->bezt[i].f2 & SELECT) { @@ -1742,9 +1718,9 @@ void BKE_fcurve_delete_keys_all(FCurve *fcu) static float fcurve_eval_keyframes_extrapolate( FCurve *fcu, BezTriple *bezts, float evaltime, int endpoint_offset, int direction_to_neighbor) { - BezTriple *endpoint_bezt = bezts + endpoint_offset; /* The first/last keyframe. */ - BezTriple *neighbor_bezt = endpoint_bezt + - direction_to_neighbor; /* The second (to last) keyframe. */ + const BezTriple *endpoint_bezt = bezts + endpoint_offset; /* The first/last keyframe. */ + const BezTriple *neighbor_bezt = endpoint_bezt + + direction_to_neighbor; /* The second (to last) keyframe. */ if (endpoint_bezt->ipo == BEZT_IPO_CONST || fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT || (fcu->flag & FCURVE_DISCRETE_VALUES) != 0) { @@ -1759,7 +1735,7 @@ static float fcurve_eval_keyframes_extrapolate( return endpoint_bezt->vec[1][1]; } - float dx = endpoint_bezt->vec[1][0] - evaltime; + const float dx = endpoint_bezt->vec[1][0] - evaltime; float fac = neighbor_bezt->vec[1][0] - endpoint_bezt->vec[1][0]; /* Prevent division by zero. */ @@ -1773,8 +1749,8 @@ static float fcurve_eval_keyframes_extrapolate( /* Use the gradient of the second handle (later) of neighbor to calculate the gradient and thus * the value of the curve at evaluation time. */ - int handle = direction_to_neighbor > 0 ? 0 : 2; - float dx = endpoint_bezt->vec[1][0] - evaltime; + const int handle = direction_to_neighbor > 0 ? 0 : 2; + const float dx = endpoint_bezt->vec[1][0] - evaltime; float fac = endpoint_bezt->vec[1][0] - endpoint_bezt->vec[handle][0]; /* Prevent division by zero. */ @@ -1786,10 +1762,11 @@ static float fcurve_eval_keyframes_extrapolate( return endpoint_bezt->vec[1][1] - (fac * dx); } -static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, float evaltime) +static float fcurve_eval_keyframes_interpolate(const FCurve *fcu, + const BezTriple *bezts, + float evaltime) { const float eps = 1.e-8f; - BezTriple *bezt, *prevbezt; uint a; /* Evaltime occurs somewhere in the middle of the curve. */ @@ -1806,7 +1783,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd. */ a = BKE_fcurve_bezt_binarysearch_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact); - bezt = bezts + a; + const BezTriple *bezt = bezts + a; if (exact) { /* Index returned must be interpreted differently when it sits on top of an existing keyframe @@ -1818,7 +1795,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl /* Index returned refers to the keyframe that the eval-time occurs *before* * - hence, that keyframe marks the start of the segment we're dealing with. */ - prevbezt = (a > 0) ? (bezt - 1) : bezt; + const BezTriple *prevbezt = (a > 0) ? (bezt - 1) : bezt; /* Use if the key is directly on the frame, in rare cases this is needed else we get 0.0 instead. * XXX: consult T39207 for examples of files where failure of these checks can cause issues. */ @@ -2054,7 +2031,7 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1); } - BezTriple *lastbezt = bezts + fcu->totvert - 1; + const BezTriple *lastbezt = bezts + fcu->totvert - 1; if (lastbezt->vec[1][0] <= evaltime) { return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1); } @@ -2063,14 +2040,13 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime } /* Calculate F-Curve value for 'evaltime' using #FPoint samples. */ -static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime) +static float fcurve_eval_samples(const FCurve *fcu, const FPoint *fpts, float evaltime) { - FPoint *prevfpt, *lastfpt, *fpt; float cvalue = 0.0f; /* Get pointers. */ - prevfpt = fpts; - lastfpt = prevfpt + fcu->totvert - 1; + const FPoint *prevfpt = fpts; + const FPoint *lastfpt = prevfpt + fcu->totvert - 1; /* Evaluation time at or past endpoints? */ if (prevfpt->vec[0] >= evaltime) { @@ -2085,10 +2061,10 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime) float t = fabsf(evaltime - floorf(evaltime)); /* Find the one on the right frame (assume that these are spaced on 1-frame intervals). */ - fpt = prevfpt + ((int)evaltime - (int)prevfpt->vec[0]); + const FPoint *fpt = prevfpt + ((int)evaltime - (int)prevfpt->vec[0]); /* If not exactly on the frame, perform linear interpolation with the next one. */ - if ((t != 0.0f) && (t < 1.0f)) { + if (t != 0.0f && t < 1.0f) { cvalue = interpf(fpt->vec[1], (fpt + 1)->vec[1], 1.0f - t); } else { @@ -2110,15 +2086,14 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime) */ static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue) { - float devaltime; - /* Evaluate modifiers which modify time to evaluate the base curve at. */ FModifiersStackStorage storage; storage.modifier_count = BLI_listbase_count(&fcu->modifiers); storage.size_per_modifier = evaluate_fmodifiers_storage_size_per_modifier(&fcu->modifiers); storage.buffer = alloca(storage.modifier_count * storage.size_per_modifier); - devaltime = evaluate_time_fmodifiers(&storage, &fcu->modifiers, fcu, cvalue, evaltime); + const float devaltime = evaluate_time_fmodifiers( + &storage, &fcu->modifiers, fcu, cvalue, evaltime); /* Evaluate curve-data * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying @@ -2177,16 +2152,15 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, /* Only do a default 1-1 mapping if it's unlikely that anything else will set a value... */ if (fcu->totvert == 0) { - FModifier *fcm; bool do_linear = true; /* Out-of-range F-Modifiers will block, as will those which just plain overwrite the values * XXX: additive is a bit more dicey; it really depends then if things are in range or not... */ - for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) { + LISTBASE_FOREACH (FModifier *, fcm, &fcu->modifiers) { /* If there are range-restrictions, we must definitely block T36950. */ if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 || - ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) { + (fcm->sfra <= evaltime && fcm->efra >= evaltime)) { /* Within range: here it probably doesn't matter, * though we'd want to check on additive. */ } @@ -2207,9 +2181,9 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, return evaluate_fcurve_ex(fcu, evaltime, cvalue); } -bool BKE_fcurve_is_empty(FCurve *fcu) +bool BKE_fcurve_is_empty(const FCurve *fcu) { - return (fcu->totvert == 0) && (fcu->driver == NULL) && + return fcu->totvert == 0 && fcu->driver == NULL && !list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE); } diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index 551bab75d4b..46dc01edbff 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -1283,7 +1283,7 @@ void set_active_fmodifier(ListBase *modifiers, FModifier *fcm) } } -bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype) +bool list_has_suitable_fmodifier(const ListBase *modifiers, int mtype, short acttype) { FModifier *fcm; diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 2ba81c54872..53147c94f43 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -2296,8 +2296,8 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb, (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, - clnors, - NULL); + NULL, + clnors); } if (free_vert_normals) { diff --git a/source/blender/blenkernel/intern/lattice_deform_test.cc b/source/blender/blenkernel/intern/lattice_deform_test.cc index 58aadf652b7..c66feedc878 100644 --- a/source/blender/blenkernel/intern/lattice_deform_test.cc +++ b/source/blender/blenkernel/intern/lattice_deform_test.cc @@ -13,6 +13,9 @@ #include "BLI_rand.hh" +#define DO_PERF_TESTS 0 + +#if DO_PERF_TESTS namespace blender::bke::tests { struct LatticeDeformTestContext { @@ -122,3 +125,4 @@ TEST(lattice_deform_performance, performance_no_dvert_10000000) } } // namespace blender::bke::tests +#endif diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 2d613f24a0a..b8658139161 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1829,9 +1829,9 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, polys.size(), use_split_normals, split_angle, + nullptr, r_lnors_spacearr, - clnors, - nullptr); + clnors); BKE_mesh_assert_normals_dirty_or_calculated(mesh); } diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c index ce3fc5d99c8..9f00d8860b8 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.c +++ b/source/blender/blenkernel/intern/mesh_mirror.c @@ -418,9 +418,9 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, totpoly, true, mesh->smoothresh, + NULL, &lnors_spacearr, - clnors, - NULL); + clnors); /* mirroring has to account for loops being reversed in polys in second half */ MPoly *result_polys = BKE_mesh_polys_for_write(result); diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index ebb5a72d137..404357bda8d 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -33,18 +33,20 @@ #include "BKE_editmesh_cache.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" #include "atomic_ops.h" using blender::BitVector; +using blender::float3; using blender::MutableSpan; +using blender::short2; using blender::Span; -// #define DEBUG_TIME +#define DEBUG_TIME #ifdef DEBUG_TIME -# include "PIL_time.h" -# include "PIL_time_utildefines.h" +# include "BLI_timeit.hh" #endif /* -------------------------------------------------------------------- */ @@ -442,7 +444,7 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh) BKE_mesh_poly_normals_ensure(mesh); break; case ME_WRAPPER_TYPE_BMESH: { - struct BMEditMesh *em = mesh->edit_mesh; + BMEditMesh *em = mesh->edit_mesh; EditMeshData *emd = mesh->runtime->edit_data; if (emd->vertexCos) { BKE_editmesh_cache_ensure_vert_normals(em, emd); @@ -456,12 +458,9 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh) void BKE_mesh_calc_normals(Mesh *mesh) { #ifdef DEBUG_TIME - TIMEIT_START_AVERAGED(BKE_mesh_calc_normals); + SCOPED_TIMER_AVERAGED(__func__); #endif BKE_mesh_vertex_normals_ensure(mesh); -#ifdef DEBUG_TIME - TIMEIT_END_AVERAGED(BKE_mesh_calc_normals); -#endif } void BKE_mesh_calc_normals_looptri(const MVert *mverts, @@ -788,7 +787,7 @@ struct LoopSplitTaskData { /** We have to create those outside of tasks, since #MemArena is not thread-safe. */ MLoopNorSpace *lnor_space; - float (*lnor)[3]; + float3 *lnor; const MLoop *ml_curr; const MLoop *ml_prev; int ml_curr_index; @@ -809,22 +808,18 @@ struct LoopSplitTaskDataCommon { * Note we do not need to protect it, though, since two different tasks will *always* affect * different elements in the arrays. */ MLoopNorSpaceArray *lnors_spacearr; - float (*loopnors)[3]; - short (*clnors_data)[2]; + MutableSpan<float3> loopnors; + MutableSpan<short2> clnors_data; /* Read-only. */ - const MVert *mverts; - const MEdge *medges; - const MLoop *mloops; - const MPoly *mpolys; + Span<MVert> verts; + MutableSpan<MEdge> edges; + Span<MLoop> loops; + Span<MPoly> polys; int (*edge_to_loops)[2]; - int *loop_to_poly; - const float (*polynors)[3]; - const float (*vert_normals)[3]; - - int numEdges; - int numLoops; - int numPolys; + Span<int> loop_to_poly; + Span<float3> polynors; + Span<float3> vert_normals; }; #define INDEX_UNSET INT_MIN @@ -837,47 +832,38 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data, const float split_angle, const bool do_sharp_edges_tag) { - const MEdge *medges = data->medges; - const MLoop *mloops = data->mloops; + MutableSpan<MEdge> edges = data->edges; + const Span<MPoly> polys = data->polys; + const Span<MLoop> loops = data->loops; + const Span<int> loop_to_poly = data->loop_to_poly; - const MPoly *mpolys = data->mpolys; - - const int numEdges = data->numEdges; - const int numPolys = data->numPolys; - - float(*loopnors)[3] = data->loopnors; /* NOTE: loopnors may be nullptr here. */ - const float(*polynors)[3] = data->polynors; + MutableSpan<float3> loopnors = data->loopnors; /* NOTE: loopnors may be empty here. */ + const Span<float3> polynors = data->polynors; int(*edge_to_loops)[2] = data->edge_to_loops; - int *loop_to_poly = data->loop_to_poly; BitVector sharp_edges; if (do_sharp_edges_tag) { - sharp_edges.resize(numEdges, false); + sharp_edges.resize(edges.size(), false); } - const MPoly *mp; - int mp_index; - const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; - for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { - const MLoop *ml_curr; + for (const int mp_index : polys.index_range()) { + const MPoly &poly = polys[mp_index]; int *e2l; - int ml_curr_index = mp->loopstart; - const int ml_last_index = (ml_curr_index + mp->totloop) - 1; + int ml_curr_index = poly.loopstart; + const int ml_last_index = (ml_curr_index + poly.totloop) - 1; - ml_curr = &mloops[ml_curr_index]; + const MLoop *ml_curr = &loops[ml_curr_index]; for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) { e2l = edge_to_loops[ml_curr->e]; - loop_to_poly[ml_curr_index] = mp_index; - /* Pre-populate all loop normals as if their verts were all-smooth, * this way we don't have to compute those later! */ - if (loopnors) { + if (!loopnors.is_empty()) { copy_v3_v3(loopnors[ml_curr_index], data->vert_normals[ml_curr->v]); } @@ -886,7 +872,7 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data, /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */ e2l[0] = ml_curr_index; /* We have to check this here too, else we might miss some flat faces!!! */ - e2l[1] = (mp->flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID; + e2l[1] = (poly.flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID; } else if (e2l[1] == INDEX_UNSET) { const bool is_angle_sharp = (check_angle && @@ -898,8 +884,8 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data, * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the * same vertex, or angle between both its polys' normals is above split_angle value. */ - if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) || - ml_curr->v == mloops[e2l[0]].v || is_angle_sharp) { + if (!(poly.flag & ME_SMOOTH) || (edges[ml_curr->e].flag & ME_SHARP) || + ml_curr->v == loops[e2l[0]].v || is_angle_sharp) { /* NOTE: we are sure that loop != 0 here ;). */ e2l[1] = INDEX_INVALID; @@ -929,69 +915,64 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data, /* If requested, do actual tagging of edges as sharp in another loop. */ if (do_sharp_edges_tag) { - MEdge *me; - int me_index; - for (me = (MEdge *)medges, me_index = 0; me_index < numEdges; me++, me_index++) { - if (sharp_edges[me_index]) { - me->flag |= ME_SHARP; + for (const int i : edges.index_range()) { + if (sharp_edges[i]) { + edges[i].flag |= ME_SHARP; } } } } -void BKE_edges_sharp_from_angle_set(const struct MVert *mverts, - const int /*numVerts*/, - struct MEdge *medges, +void BKE_edges_sharp_from_angle_set(const MVert *mverts, + const int numVerts, + MEdge *medges, const int numEdges, - const struct MLoop *mloops, + const MLoop *mloops, const int numLoops, - const struct MPoly *mpolys, + const MPoly *mpolys, const float (*polynors)[3], const int numPolys, const float split_angle) { + using namespace blender; + using namespace blender::bke; if (split_angle >= float(M_PI)) { /* Nothing to do! */ return; } - /* Mapping edge -> loops. See BKE_mesh_normals_loop_split() for details. */ + /* Mapping edge -> loops. See #BKE_mesh_normals_loop_split for details. */ int(*edge_to_loops)[2] = (int(*)[2])MEM_calloc_arrayN( size_t(numEdges), sizeof(*edge_to_loops), __func__); /* Simple mapping from a loop to its polygon index. */ - int *loop_to_poly = (int *)MEM_malloc_arrayN(size_t(numLoops), sizeof(*loop_to_poly), __func__); + const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map({mpolys, numPolys}, + numLoops); LoopSplitTaskDataCommon common_data = {}; - common_data.mverts = mverts; - common_data.medges = medges; - common_data.mloops = mloops; - common_data.mpolys = mpolys; + common_data.verts = {mverts, numVerts}; + common_data.edges = {medges, numEdges}; + common_data.polys = {mpolys, numPolys}; + common_data.loops = {mloops, numLoops}; common_data.edge_to_loops = edge_to_loops; common_data.loop_to_poly = loop_to_poly; - common_data.polynors = polynors; - common_data.numEdges = numEdges; - common_data.numPolys = numPolys; + common_data.polynors = {reinterpret_cast<const float3 *>(polynors), numPolys}; mesh_edges_sharp_tag(&common_data, true, split_angle, true); MEM_freeN(edge_to_loops); - MEM_freeN(loop_to_poly); } -void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops, - const MPoly *mpolys, - const int *loop_to_poly, - const int *e2lfan_curr, - const uint mv_pivot_index, - const MLoop **r_mlfan_curr, - int *r_mlfan_curr_index, - int *r_mlfan_vert_index, - int *r_mpfan_curr_index) +static void loop_manifold_fan_around_vert_next(const Span<MLoop> loops, + const Span<MPoly> polys, + const Span<int> loop_to_poly, + const int *e2lfan_curr, + const uint mv_pivot_index, + const MLoop **r_mlfan_curr, + int *r_mlfan_curr_index, + int *r_mlfan_vert_index, + int *r_mpfan_curr_index) { - const MLoop *mlfan_next; - const MPoly *mpfan_next; - /* WARNING: This is rather complex! * We have to find our next edge around the vertex (fan mode). * First we find the next loop, which is either previous or next to mlfan_curr_index, depending @@ -1005,38 +986,38 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops, BLI_assert(*r_mlfan_curr_index >= 0); BLI_assert(*r_mpfan_curr_index >= 0); - mlfan_next = &mloops[*r_mlfan_curr_index]; - mpfan_next = &mpolys[*r_mpfan_curr_index]; - if (((*r_mlfan_curr)->v == mlfan_next->v && (*r_mlfan_curr)->v == mv_pivot_index) || - ((*r_mlfan_curr)->v != mlfan_next->v && (*r_mlfan_curr)->v != mv_pivot_index)) { + const MLoop &mlfan_next = loops[*r_mlfan_curr_index]; + const MPoly &mpfan_next = polys[*r_mpfan_curr_index]; + if (((*r_mlfan_curr)->v == mlfan_next.v && (*r_mlfan_curr)->v == mv_pivot_index) || + ((*r_mlfan_curr)->v != mlfan_next.v && (*r_mlfan_curr)->v != mv_pivot_index)) { /* We need the previous loop, but current one is our vertex's loop. */ *r_mlfan_vert_index = *r_mlfan_curr_index; - if (--(*r_mlfan_curr_index) < mpfan_next->loopstart) { - *r_mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1; + if (--(*r_mlfan_curr_index) < mpfan_next.loopstart) { + *r_mlfan_curr_index = mpfan_next.loopstart + mpfan_next.totloop - 1; } } else { /* We need the next loop, which is also our vertex's loop. */ - if (++(*r_mlfan_curr_index) >= mpfan_next->loopstart + mpfan_next->totloop) { - *r_mlfan_curr_index = mpfan_next->loopstart; + if (++(*r_mlfan_curr_index) >= mpfan_next.loopstart + mpfan_next.totloop) { + *r_mlfan_curr_index = mpfan_next.loopstart; } *r_mlfan_vert_index = *r_mlfan_curr_index; } - *r_mlfan_curr = &mloops[*r_mlfan_curr_index]; + *r_mlfan_curr = &loops[*r_mlfan_curr_index]; /* And now we are back in sync, mlfan_curr_index is the index of `mlfan_curr`! Pff! */ } static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data) { MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; - const short(*clnors_data)[2] = common_data->clnors_data; + const Span<short2> clnors_data = common_data->clnors_data; - const MVert *mverts = common_data->mverts; - const MEdge *medges = common_data->medges; - const float(*polynors)[3] = common_data->polynors; + const Span<MVert> verts = common_data->verts; + const Span<MEdge> edges = common_data->edges; + const Span<float3> polynors = common_data->polynors; MLoopNorSpace *lnor_space = data->lnor_space; - float(*lnor)[3] = data->lnor; + float3 *lnor = data->lnor; const MLoop *ml_curr = data->ml_curr; const MLoop *ml_prev = data->ml_prev; const int ml_curr_index = data->ml_curr_index; @@ -1064,13 +1045,13 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS float vec_curr[3], vec_prev[3]; const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ - const MVert *mv_pivot = &mverts[mv_pivot_index]; - const MEdge *me_curr = &medges[ml_curr->e]; - const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : - &mverts[me_curr->v1]; - const MEdge *me_prev = &medges[ml_prev->e]; - const MVert *mv_3 = (me_prev->v1 == mv_pivot_index) ? &mverts[me_prev->v2] : - &mverts[me_prev->v1]; + const MVert *mv_pivot = &verts[mv_pivot_index]; + const MEdge *me_curr = &edges[ml_curr->e]; + const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &verts[me_curr->v2] : + &verts[me_curr->v1]; + const MEdge *me_prev = &edges[ml_prev->e]; + const MVert *mv_3 = (me_prev->v1 == mv_pivot_index) ? &verts[me_prev->v2] : + &verts[me_prev->v1]; sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co); normalize_v3(vec_curr); @@ -1081,7 +1062,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS /* We know there is only one loop in this space, no need to create a link-list in this case. */ BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, nullptr, true); - if (clnors_data) { + if (!clnors_data.is_empty()) { BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor); } } @@ -1090,16 +1071,16 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data) { MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; - float(*loopnors)[3] = common_data->loopnors; - short(*clnors_data)[2] = common_data->clnors_data; + MutableSpan<float3> loopnors = common_data->loopnors; + MutableSpan<short2> clnors_data = common_data->clnors_data; - const MVert *mverts = common_data->mverts; - const MEdge *medges = common_data->medges; - const MLoop *mloops = common_data->mloops; - const MPoly *mpolys = common_data->mpolys; + const Span<MVert> verts = common_data->verts; + const Span<MEdge> edges = common_data->edges; + const Span<MPoly> polys = common_data->polys; + const Span<MLoop> loops = common_data->loops; const int(*edge_to_loops)[2] = common_data->edge_to_loops; - const int *loop_to_poly = common_data->loop_to_poly; - const float(*polynors)[3] = common_data->polynors; + const Span<int> loop_to_poly = common_data->loop_to_poly; + const Span<float3> polynors = common_data->polynors; MLoopNorSpace *lnor_space = data->lnor_space; #if 0 /* Not needed for 'fan' loops. */ @@ -1121,22 +1102,17 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli * number of sharp edges per vertex, I doubt the additional memory usage would be worth it, * especially as it should not be a common case in real-life meshes anyway). */ const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ - const MVert *mv_pivot = &mverts[mv_pivot_index]; + const MVert *mv_pivot = &verts[mv_pivot_index]; /* `ml_curr` would be mlfan_prev if we needed that one. */ - const MEdge *me_org = &medges[ml_curr->e]; + const MEdge *me_org = &edges[ml_curr->e]; - const int *e2lfan_curr; float vec_curr[3], vec_prev[3], vec_org[3]; - const MLoop *mlfan_curr; float lnor[3] = {0.0f, 0.0f, 0.0f}; - /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex! - */ - int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index; /* We validate clnors data on the fly - cheapest way to do! */ int clnors_avg[2] = {0, 0}; - short(*clnor_ref)[2] = nullptr; + short2 *clnor_ref = nullptr; int clnors_count = 0; bool clnors_invalid = false; @@ -1145,11 +1121,13 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli /* Temp clnors stack. */ BLI_SMALLSTACK_DECLARE(clnors, short *); - e2lfan_curr = e2l_prev; - mlfan_curr = ml_prev; - mlfan_curr_index = ml_prev_index; - mlfan_vert_index = ml_curr_index; - mpfan_curr_index = mp_index; + const int *e2lfan_curr = e2l_prev; + const MLoop *mlfan_curr = ml_prev; + /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex! + */ + int mlfan_curr_index = ml_prev_index; + int mlfan_vert_index = ml_curr_index; + int mpfan_curr_index = mp_index; BLI_assert(mlfan_curr_index >= 0); BLI_assert(mlfan_vert_index >= 0); @@ -1157,7 +1135,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli /* Only need to compute previous edge's vector once, then we can just reuse old current one! */ { - const MVert *mv_2 = (me_org->v1 == mv_pivot_index) ? &mverts[me_org->v2] : &mverts[me_org->v1]; + const MVert *mv_2 = (me_org->v1 == mv_pivot_index) ? &verts[me_org->v2] : &verts[me_org->v1]; sub_v3_v3v3(vec_org, mv_2->co, mv_pivot->co); normalize_v3(vec_org); @@ -1171,15 +1149,15 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli // printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e); while (true) { - const MEdge *me_curr = &medges[mlfan_curr->e]; + const MEdge *me_curr = &edges[mlfan_curr->e]; /* Compute edge vectors. * NOTE: We could pre-compute those into an array, in the first iteration, instead of computing * them twice (or more) here. However, time gained is not worth memory and time lost, * given the fact that this code should not be called that much in real-life meshes. */ { - const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : - &mverts[me_curr->v1]; + const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &verts[me_curr->v2] : + &verts[me_curr->v1]; sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co); normalize_v3(vec_curr); @@ -1194,9 +1172,9 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli /* Accumulate */ madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac); - if (clnors_data) { + if (!clnors_data.is_empty()) { /* Accumulate all clnors, if they are not all equal we have to fix that! */ - short(*clnor)[2] = &clnors_data[mlfan_vert_index]; + short2 *clnor = &clnors_data[mlfan_vert_index]; if (clnors_count) { clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]); } @@ -1233,15 +1211,15 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli copy_v3_v3(vec_prev, vec_curr); /* Find next loop of the smooth fan. */ - BKE_mesh_loop_manifold_fan_around_vert_next(mloops, - mpolys, - loop_to_poly, - e2lfan_curr, - mv_pivot_index, - &mlfan_curr, - &mlfan_curr_index, - &mlfan_vert_index, - &mpfan_curr_index); + loop_manifold_fan_around_vert_next(loops, + polys, + loop_to_poly, + e2lfan_curr, + mv_pivot_index, + &mlfan_curr, + &mlfan_curr_index, + &mlfan_vert_index, + &mpfan_curr_index); e2lfan_curr = edge_to_loops[mlfan_curr->e]; } @@ -1261,7 +1239,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors); - if (clnors_data) { + if (!clnors_data.is_empty()) { if (clnors_invalid) { short *clnor; @@ -1325,10 +1303,6 @@ static void loop_split_worker(TaskPool *__restrict pool, void *taskdata) BLI_stack_new(sizeof(float[3]), __func__) : nullptr; -#ifdef DEBUG_TIME - TIMEIT_START_AVERAGED(loop_split_worker); -#endif - for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) { /* A nullptr ml_curr is used to tag ended data! */ if (data->ml_curr == nullptr) { @@ -1341,10 +1315,6 @@ static void loop_split_worker(TaskPool *__restrict pool, void *taskdata) if (edge_vectors) { BLI_stack_free(edge_vectors); } - -#ifdef DEBUG_TIME - TIMEIT_END_AVERAGED(loop_split_worker); -#endif } /** @@ -1352,10 +1322,10 @@ static void loop_split_worker(TaskPool *__restrict pool, void *taskdata) * Needed because cyclic smooth fans have no obvious 'entry point', * and yet we need to walk them once, and only once. */ -static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops, - const MPoly *mpolys, +static bool loop_split_generator_check_cyclic_smooth_fan(const Span<MLoop> mloops, + const Span<MPoly> mpolys, const int (*edge_to_loops)[2], - const int *loop_to_poly, + const Span<int> loop_to_poly, const int *e2l_prev, BitVector<> &skip_loops, const MLoop *ml_curr, @@ -1365,22 +1335,19 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops, const int mp_curr_index) { const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ - const int *e2lfan_curr; - const MLoop *mlfan_curr; - /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex! - */ - int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index; - e2lfan_curr = e2l_prev; + const int *e2lfan_curr = e2l_prev; if (IS_EDGE_SHARP(e2lfan_curr)) { /* Sharp loop, so not a cyclic smooth fan. */ return false; } - mlfan_curr = ml_prev; - mlfan_curr_index = ml_prev_index; - mlfan_vert_index = ml_curr_index; - mpfan_curr_index = mp_curr_index; + /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex! + */ + const MLoop *mlfan_curr = ml_prev; + int mlfan_curr_index = ml_prev_index; + int mlfan_vert_index = ml_curr_index; + int mpfan_curr_index = mp_curr_index; BLI_assert(mlfan_curr_index >= 0); BLI_assert(mlfan_vert_index >= 0); @@ -1391,15 +1358,15 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops, while (true) { /* Find next loop of the smooth fan. */ - BKE_mesh_loop_manifold_fan_around_vert_next(mloops, - mpolys, - loop_to_poly, - e2lfan_curr, - mv_pivot_index, - &mlfan_curr, - &mlfan_curr_index, - &mlfan_vert_index, - &mpfan_curr_index); + loop_manifold_fan_around_vert_next(mloops, + mpolys, + loop_to_poly, + e2lfan_curr, + mv_pivot_index, + &mlfan_curr, + &mlfan_curr_index, + &mlfan_vert_index, + &mpfan_curr_index); e2lfan_curr = edge_to_loops[mlfan_curr->e]; @@ -1426,24 +1393,14 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops, static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data) { MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; - float(*loopnors)[3] = common_data->loopnors; + MutableSpan<float3> loopnors = common_data->loopnors; - const MLoop *mloops = common_data->mloops; - const MPoly *mpolys = common_data->mpolys; - const int *loop_to_poly = common_data->loop_to_poly; + const Span<MLoop> loops = common_data->loops; + const Span<MPoly> polys = common_data->polys; + const Span<int> loop_to_poly = common_data->loop_to_poly; const int(*edge_to_loops)[2] = common_data->edge_to_loops; - const int numLoops = common_data->numLoops; - const int numPolys = common_data->numPolys; - const MPoly *mp; - int mp_index; - - const MLoop *ml_curr; - const MLoop *ml_prev; - int ml_curr_index; - int ml_prev_index; - - BitVector<> skip_loops(numLoops, false); + BitVector<> skip_loops(loops.size(), false); LoopSplitTaskData *data_buff = nullptr; int data_idx = 0; @@ -1453,7 +1410,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common BLI_Stack *edge_vectors = nullptr; #ifdef DEBUG_TIME - TIMEIT_START_AVERAGED(loop_split_generator); + SCOPED_TIMER_AVERAGED(__func__); #endif if (!pool) { @@ -1465,15 +1422,15 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common /* We now know edges that can be smoothed (with their vector, and their two loops), * and edges that will be hard! Now, time to generate the normals. */ - for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { - float(*lnors)[3]; - const int ml_last_index = (mp->loopstart + mp->totloop) - 1; - ml_curr_index = mp->loopstart; - ml_prev_index = ml_last_index; + for (const int mp_index : polys.index_range()) { + const MPoly &poly = polys[mp_index]; + const int ml_last_index = (poly.loopstart + poly.totloop) - 1; + int ml_curr_index = poly.loopstart; + int ml_prev_index = ml_last_index; - ml_curr = &mloops[ml_curr_index]; - ml_prev = &mloops[ml_prev_index]; - lnors = &loopnors[ml_curr_index]; + const MLoop *ml_curr = &loops[ml_curr_index]; + const MLoop *ml_prev = &loops[ml_prev_index]; + float3 *lnors = &loopnors[ml_curr_index]; for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++, lnors++) { const int *e2l_curr = edge_to_loops[ml_curr->e]; @@ -1499,8 +1456,8 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common * complexity, #loop_manifold_fan_around_vert_next() is quite cheap in term of CPU cycles, * so really think it's not worth it. */ if (!IS_EDGE_SHARP(e2l_curr) && (skip_loops[ml_curr_index] || - !loop_split_generator_check_cyclic_smooth_fan(mloops, - mpolys, + !loop_split_generator_check_cyclic_smooth_fan(loops, + polys, edge_to_loops, loop_to_poly, e2l_prev, @@ -1593,15 +1550,11 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common if (edge_vectors) { BLI_stack_free(edge_vectors); } - -#ifdef DEBUG_TIME - TIMEIT_END_AVERAGED(loop_split_generator); -#endif } void BKE_mesh_normals_loop_split(const MVert *mverts, const float (*vert_normals)[3], - const int /*numVerts*/, + const int numVerts, const MEdge *medges, const int numEdges, const MLoop *mloops, @@ -1612,10 +1565,12 @@ void BKE_mesh_normals_loop_split(const MVert *mverts, const int numPolys, const bool use_split_normals, const float split_angle, + const int *loop_to_poly_map, MLoopNorSpaceArray *r_lnors_spacearr, - short (*clnors_data)[2], - int *r_loop_to_poly) + short (*clnors_data)[2]) { + using namespace blender; + using namespace blender::bke; /* For now this is not supported. * If we do not use split normals, we do not generate anything fancy! */ BLI_assert(use_split_normals || !(r_lnors_spacearr)); @@ -1636,9 +1591,6 @@ void BKE_mesh_normals_loop_split(const MVert *mverts, const bool is_poly_flat = ((mp->flag & ME_SMOOTH) == 0); for (; ml_index < ml_index_end; ml_index++) { - if (r_loop_to_poly) { - r_loop_to_poly[ml_index] = mp_index; - } if (is_poly_flat) { copy_v3_v3(r_loopnors[ml_index], polynors[mp_index]); } @@ -1668,9 +1620,15 @@ void BKE_mesh_normals_loop_split(const MVert *mverts, size_t(numEdges), sizeof(*edge_to_loops), __func__); /* Simple mapping from a loop to its polygon index. */ - int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : - (int *)MEM_malloc_arrayN( - size_t(numLoops), sizeof(*loop_to_poly), __func__); + Span<int> loop_to_poly; + Array<int> local_loop_to_poly_map; + if (loop_to_poly_map) { + loop_to_poly = {loop_to_poly_map, numLoops}; + } + else { + local_loop_to_poly_map = mesh_topology::build_loop_to_poly_map({mpolys, numPolys}, numLoops); + loop_to_poly = local_loop_to_poly_map; + } /* When using custom loop normals, disable the angle feature! */ const bool check_angle = (split_angle < float(M_PI)) && (clnors_data == nullptr); @@ -1678,7 +1636,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts, MLoopNorSpaceArray _lnors_spacearr = {nullptr}; #ifdef DEBUG_TIME - TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split); + SCOPED_TIMER_AVERAGED(__func__); #endif if (!r_lnors_spacearr && clnors_data) { @@ -1692,19 +1650,16 @@ void BKE_mesh_normals_loop_split(const MVert *mverts, /* Init data common to all tasks. */ LoopSplitTaskDataCommon common_data; common_data.lnors_spacearr = r_lnors_spacearr; - common_data.loopnors = r_loopnors; - common_data.clnors_data = clnors_data; - common_data.mverts = mverts; - common_data.medges = medges; - common_data.mloops = mloops; - common_data.mpolys = mpolys; + common_data.loopnors = {reinterpret_cast<float3 *>(r_loopnors), numLoops}; + common_data.clnors_data = {reinterpret_cast<short2 *>(clnors_data), clnors_data ? numLoops : 0}; + common_data.verts = {mverts, numVerts}; + common_data.edges = {const_cast<MEdge *>(medges), numEdges}; + common_data.polys = {mpolys, numPolys}; + common_data.loops = {mloops, numLoops}; common_data.edge_to_loops = edge_to_loops; common_data.loop_to_poly = loop_to_poly; - common_data.polynors = polynors; - common_data.vert_normals = vert_normals; - common_data.numEdges = numEdges; - common_data.numLoops = numLoops; - common_data.numPolys = numPolys; + common_data.polynors = {reinterpret_cast<const float3 *>(polynors), numPolys}; + common_data.vert_normals = {reinterpret_cast<const float3 *>(vert_normals), numVerts}; /* This first loop check which edges are actually smooth, and compute edge vectors. */ mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false); @@ -1724,19 +1679,12 @@ void BKE_mesh_normals_loop_split(const MVert *mverts, } MEM_freeN(edge_to_loops); - if (!r_loop_to_poly) { - MEM_freeN(loop_to_poly); - } if (r_lnors_spacearr) { if (r_lnors_spacearr == &_lnors_spacearr) { BKE_lnor_spacearr_free(r_lnors_spacearr); } } - -#ifdef DEBUG_TIME - TIMEIT_END_AVERAGED(BKE_mesh_normals_loop_split); -#endif } #undef INDEX_UNSET @@ -1766,6 +1714,8 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, short (*r_clnors_data)[2], const bool use_vertices) { + using namespace blender; + using namespace blender::bke; /* We *may* make that poor #BKE_mesh_normals_loop_split() even more complex by making it handling * that feature too, would probably be more efficient in absolute. * However, this function *is not* performance-critical, since it is mostly expected to be called @@ -1775,7 +1725,8 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, MLoopNorSpaceArray lnors_spacearr = {nullptr}; BitVector<> done_loops(numLoops, false); float(*lnors)[3] = (float(*)[3])MEM_calloc_arrayN(size_t(numLoops), sizeof(*lnors), __func__); - int *loop_to_poly = (int *)MEM_malloc_arrayN(size_t(numLoops), sizeof(int), __func__); + const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map({mpolys, numPolys}, + numLoops); /* In this case we always consider split nors as ON, * and do not want to use angle to define smooth fans! */ const bool use_split_normals = true; @@ -1797,9 +1748,9 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, numPolys, use_split_normals, split_angle, + loop_to_poly.data(), &lnors_spacearr, - nullptr, - loop_to_poly); + nullptr); /* Set all given zero vectors to their default value. */ if (use_vertices) { @@ -1920,9 +1871,9 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, numPolys, use_split_normals, split_angle, + loop_to_poly.data(), &lnors_spacearr, - nullptr, - loop_to_poly); + nullptr); } else { done_loops.fill(true); @@ -1984,7 +1935,6 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, } MEM_freeN(lnors); - MEM_freeN(loop_to_poly); BKE_lnor_spacearr_free(&lnors_spacearr); } diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index 90798ea593d..d96cd54e198 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -1372,8 +1372,8 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, use_split_nors_dst, split_angle_dst, NULL, - custom_nors_dst, - NULL); + NULL, + custom_nors_dst); } } if (need_pnors_src || need_lnors_src) { diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 31fc8afea84..5400fd78ddb 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -2019,7 +2019,7 @@ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) return (bNode *)BLI_findstring(&ntree->nodes, name, offsetof(bNode, name)); } -bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex) +void nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex) { *r_node = nullptr; if (!ntree->runtime->topology_cache_is_dirty) { @@ -2029,9 +2029,15 @@ bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_so ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; *r_sockindex = BLI_findindex(sockets, sock); } - return true; + return; } + const bool success = nodeFindNodeTry(ntree, sock, r_node, r_sockindex); + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} +bool nodeFindNodeTry(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex) +{ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; int i; diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index 5efd44c620b..cca609a2e0d 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -79,6 +79,8 @@ namespace geo_log = blender::nodes::geo_eval_log; /** \name Internal Duplicate Context * \{ */ +static constexpr short GEOMETRY_SET_DUPLI_GENERATOR_TYPE = 1; + struct DupliContext { Depsgraph *depsgraph; /** XXX child objects are selected from this group if set, could be nicer. */ @@ -87,6 +89,9 @@ struct DupliContext { Object *obedit; Scene *scene; + /** Root parent object at the scene level. */ + Object *root_object; + /** Immediate parent object in the context. */ Object *object; float space_mat[4][4]; /** @@ -106,6 +111,14 @@ struct DupliContext { */ Vector<Object *> *instance_stack; + /** + * Older code relies on the "dupli generator type" for various visibility or processing + * decisions. However, new code uses geometry instances in places that weren't using the dupli + * system previously. To fix this, keep track of the last dupli generator type that wasn't a + * geometry set instance. + * */ + Vector<short> *dupli_gen_type_stack; + int persistent_id[MAX_DUPLI_RECUR]; int64_t instance_idx[MAX_DUPLI_RECUR]; const GeometrySet *instance_data[MAX_DUPLI_RECUR]; @@ -132,15 +145,18 @@ static void init_context(DupliContext *r_ctx, Scene *scene, Object *ob, const float space_mat[4][4], - Vector<Object *> &instance_stack) + Vector<Object *> &instance_stack, + Vector<short> &dupli_gen_type_stack) { r_ctx->depsgraph = depsgraph; r_ctx->scene = scene; r_ctx->collection = nullptr; + r_ctx->root_object = ob; r_ctx->object = ob; r_ctx->obedit = OBEDIT_FROM_OBACT(ob); r_ctx->instance_stack = &instance_stack; + r_ctx->dupli_gen_type_stack = &dupli_gen_type_stack; if (space_mat) { copy_m4_m4(r_ctx->space_mat, space_mat); } @@ -150,6 +166,9 @@ static void init_context(DupliContext *r_ctx, r_ctx->level = 0; r_ctx->gen = get_dupli_generator(r_ctx); + if (r_ctx->gen && r_ctx->gen->type != GEOMETRY_SET_DUPLI_GENERATOR_TYPE) { + r_ctx->dupli_gen_type_stack->append(r_ctx->gen->type); + } r_ctx->duplilist = nullptr; r_ctx->preview_instance_index = -1; @@ -191,6 +210,9 @@ static bool copy_dupli_context(DupliContext *r_ctx, } r_ctx->gen = get_dupli_generator(r_ctx); + if (r_ctx->gen && r_ctx->gen->type != GEOMETRY_SET_DUPLI_GENERATOR_TYPE) { + r_ctx->dupli_gen_type_stack->append(r_ctx->gen->type); + } return true; } @@ -223,7 +245,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, dob->ob = ob; dob->ob_data = const_cast<ID *>(object_data); mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat); - dob->type = ctx->gen == nullptr ? 0 : ctx->gen->type; + dob->type = ctx->gen == nullptr ? 0 : ctx->dupli_gen_type_stack->last(); dob->preview_base_geometry = ctx->preview_base_geometry; dob->preview_instance_index = ctx->preview_instance_index; @@ -264,8 +286,9 @@ static DupliObject *make_dupli(const DupliContext *ctx, dob->no_draw = true; } - /* Random number. - * The logic here is designed to match Cycles. */ + /* Random number per instance. + * The root object in the scene, persistent ID up to the instance object, and the instance object + * name together result in a unique random number. */ dob->random_id = BLI_hash_string(dob->ob->id.name + 2); if (dob->persistent_id[0] != INT_MAX) { @@ -277,8 +300,8 @@ static DupliObject *make_dupli(const DupliContext *ctx, dob->random_id = BLI_hash_int_2d(dob->random_id, 0); } - if (ctx->object != ob) { - dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2)); + if (ctx->root_object != ob) { + dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->root_object->id.name + 2)); } return dob; @@ -321,6 +344,9 @@ static void make_recursive_duplis(const DupliContext *ctx, ctx->instance_stack->append(ob); rctx.gen->make_duplis(&rctx); ctx->instance_stack->remove_last(); + if (!ctx->dupli_gen_type_stack->is_empty()) { + ctx->dupli_gen_type_stack->remove_last(); + } } } } @@ -365,6 +391,9 @@ static void make_child_duplis(const DupliContext *ctx, ob->flag |= OB_DONE; /* Doesn't render. */ } make_child_duplis_cb(&pctx, userdata, ob); + if (!ctx->dupli_gen_type_stack->is_empty()) { + ctx->dupli_gen_type_stack->remove_last(); + } } } } @@ -390,6 +419,9 @@ static void make_child_duplis(const DupliContext *ctx, } make_child_duplis_cb(&pctx, userdata, ob); + if (!ctx->dupli_gen_type_stack->is_empty()) { + ctx->dupli_gen_type_stack->remove_last(); + } } } persistent_dupli_id++; @@ -991,7 +1023,7 @@ static void make_duplis_geometry_set(const DupliContext *ctx) } static const DupliGenerator gen_dupli_geometry_set = { - 0, + GEOMETRY_SET_DUPLI_GENERATOR_TYPE, make_duplis_geometry_set, }; @@ -1712,8 +1744,9 @@ ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob) ListBase *duplilist = MEM_cnew<ListBase>("duplilist"); DupliContext ctx; Vector<Object *> instance_stack; + Vector<short> dupli_gen_type_stack({0}); instance_stack.append(ob); - init_context(&ctx, depsgraph, sce, ob, nullptr, instance_stack); + init_context(&ctx, depsgraph, sce, ob, nullptr, instance_stack, dupli_gen_type_stack); if (ctx.gen) { ctx.duplilist = duplilist; ctx.gen->make_duplis(&ctx); @@ -1730,8 +1763,9 @@ ListBase *object_duplilist_preview(Depsgraph *depsgraph, ListBase *duplilist = MEM_cnew<ListBase>("duplilist"); DupliContext ctx; Vector<Object *> instance_stack; + Vector<short> dupli_gen_type_stack({0}); instance_stack.append(ob_eval); - init_context(&ctx, depsgraph, sce, ob_eval, nullptr, instance_stack); + init_context(&ctx, depsgraph, sce, ob_eval, nullptr, instance_stack, dupli_gen_type_stack); ctx.duplilist = duplilist; Object *ob_orig = DEG_get_original_object(ob_eval); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 98e89b09060..24ea2de98f6 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -833,7 +833,12 @@ void BKE_pbvh_build_grids(PBVH *pbvh, pbvh->gridkey = *key; pbvh->grid_hidden = grid_hidden; pbvh->subdiv_ccg = subdiv_ccg; - pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 1); + + /* Ensure leaf limit is at least 4 so there's room + * to split at original face boundaries. + * Fixes T102209. + */ + pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 4); /* We need the base mesh attribute layout for PBVH draw. */ pbvh->vdata = &me->vdata; diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 3b0f35263d3..d03f12b98bd 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -1527,8 +1527,8 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, float location[3] = {0.0f}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); for (int j = 0; j < 3; j++) { - if (len_squared_v3v3(location, cos[j]) < - len_squared_v3v3(location, nearest_vertex_co)) { + if (j == 0 || len_squared_v3v3(location, cos[j]) < + len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, cos[j]); r_active_vertex->i = (intptr_t)node->bm_orvert[node->bm_ortri[i][j]]; } @@ -1559,8 +1559,8 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, float location[3] = {0.0f}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); for (int j = 0; j < 3; j++) { - if (len_squared_v3v3(location, v_tri[j]->co) < - len_squared_v3v3(location, nearest_vertex_co)) { + if (j == 0 || len_squared_v3v3(location, v_tri[j]->co) < + len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, v_tri[j]->co); r_active_vertex->i = (intptr_t)v_tri[j]; } |