Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/modifiers/intern/MOD_array.c')
-rw-r--r--source/blender/modifiers/intern/MOD_array.c1370
1 files changed, 692 insertions, 678 deletions
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 542c7665807..c909f9dc076 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -50,87 +50,96 @@
static void initData(ModifierData *md)
{
- ArrayModifierData *amd = (ArrayModifierData *) md;
-
- /* default to 2 duplicates distributed along the x-axis by an
- * offset of 1 object-width
- */
- amd->start_cap = amd->end_cap = amd->curve_ob = amd->offset_ob = NULL;
- amd->count = 2;
- zero_v3(amd->offset);
- amd->scale[0] = 1;
- amd->scale[1] = amd->scale[2] = 0;
- amd->length = 0;
- amd->merge_dist = 0.01;
- amd->fit_type = MOD_ARR_FIXEDCOUNT;
- amd->offset_type = MOD_ARR_OFF_RELATIVE;
- amd->flags = 0;
+ ArrayModifierData *amd = (ArrayModifierData *)md;
+
+ /* default to 2 duplicates distributed along the x-axis by an
+ * offset of 1 object-width
+ */
+ amd->start_cap = amd->end_cap = amd->curve_ob = amd->offset_ob = NULL;
+ amd->count = 2;
+ zero_v3(amd->offset);
+ amd->scale[0] = 1;
+ amd->scale[1] = amd->scale[2] = 0;
+ amd->length = 0;
+ amd->merge_dist = 0.01;
+ amd->fit_type = MOD_ARR_FIXEDCOUNT;
+ amd->offset_type = MOD_ARR_OFF_RELATIVE;
+ amd->flags = 0;
}
-static void foreachObjectLink(
- ModifierData *md, Object *ob,
- ObjectWalkFunc walk, void *userData)
+static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
- ArrayModifierData *amd = (ArrayModifierData *) md;
+ ArrayModifierData *amd = (ArrayModifierData *)md;
- walk(userData, ob, &amd->start_cap, IDWALK_CB_NOP);
- walk(userData, ob, &amd->end_cap, IDWALK_CB_NOP);
- walk(userData, ob, &amd->curve_ob, IDWALK_CB_NOP);
- walk(userData, ob, &amd->offset_ob, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->start_cap, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->end_cap, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->curve_ob, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->offset_ob, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
- ArrayModifierData *amd = (ArrayModifierData *)md;
- if (amd->start_cap != NULL) {
- DEG_add_object_relation(ctx->node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap");
- DEG_add_object_relation(ctx->node, amd->start_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier Start Cap");
- }
- if (amd->end_cap != NULL) {
- DEG_add_object_relation(ctx->node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap");
- DEG_add_object_relation(ctx->node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier End Cap");
- }
- if (amd->curve_ob) {
- DEG_add_object_relation(ctx->node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve");
- DEG_add_special_eval_flag(ctx->node, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
- }
- if (amd->offset_ob != NULL) {
- DEG_add_object_relation(ctx->node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset");
- }
- DEG_add_modifier_to_transform_relation(ctx->node, "Array Modifier");
+ ArrayModifierData *amd = (ArrayModifierData *)md;
+ if (amd->start_cap != NULL) {
+ DEG_add_object_relation(
+ ctx->node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap");
+ DEG_add_object_relation(
+ ctx->node, amd->start_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier Start Cap");
+ }
+ if (amd->end_cap != NULL) {
+ DEG_add_object_relation(
+ ctx->node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap");
+ DEG_add_object_relation(
+ ctx->node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier End Cap");
+ }
+ if (amd->curve_ob) {
+ DEG_add_object_relation(
+ ctx->node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve");
+ DEG_add_special_eval_flag(ctx->node, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
+ }
+ if (amd->offset_ob != NULL) {
+ DEG_add_object_relation(
+ ctx->node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset");
+ }
+ DEG_add_modifier_to_transform_relation(ctx->node, "Array Modifier");
}
BLI_INLINE float sum_v3(const float v[3])
{
- return v[0] + v[1] + v[2];
+ return v[0] + v[1] + v[2];
}
/* Structure used for sorting vertices, when processing doubles */
typedef struct SortVertsElem {
- int vertex_num; /* The original index of the vertex, prior to sorting */
- float co[3]; /* Its coordinates */
- float sum_co; /* sum_v3(co), just so we don't do the sum many times. */
+ int vertex_num; /* The original index of the vertex, prior to sorting */
+ float co[3]; /* Its coordinates */
+ float sum_co; /* sum_v3(co), just so we don't do the sum many times. */
} SortVertsElem;
-
static int svert_sum_cmp(const void *e1, const void *e2)
{
- const SortVertsElem *sv1 = e1;
- const SortVertsElem *sv2 = e2;
-
- if (sv1->sum_co > sv2->sum_co) return 1;
- else if (sv1->sum_co < sv2->sum_co) return -1;
- else return 0;
+ const SortVertsElem *sv1 = e1;
+ const SortVertsElem *sv2 = e2;
+
+ if (sv1->sum_co > sv2->sum_co)
+ return 1;
+ else if (sv1->sum_co < sv2->sum_co)
+ return -1;
+ else
+ return 0;
}
-static void svert_from_mvert(SortVertsElem *sv, const MVert *mv, const int i_begin, const int i_end)
+static void svert_from_mvert(SortVertsElem *sv,
+ const MVert *mv,
+ const int i_begin,
+ const int i_end)
{
- int i;
- for (i = i_begin; i < i_end; i++, sv++, mv++) {
- sv->vertex_num = i;
- copy_v3_v3(sv->co, mv->co);
- sv->sum_co = sum_v3(mv->co);
- }
+ int i;
+ for (i = i_begin; i < i_end; i++, sv++, mv++) {
+ sv->vertex_num = i;
+ copy_v3_v3(sv->co, mv->co);
+ sv->sum_co = sum_v3(mv->co);
+ }
}
/**
@@ -139,637 +148,642 @@ static void svert_from_mvert(SortVertsElem *sv, const MVert *mv, const int i_beg
* It builds a mapping for all vertices within source, to vertices within target, or -1 if no double found
* The int doubles_map[num_verts_source] array must have been allocated by caller.
*/
-static void dm_mvert_map_doubles(
- int *doubles_map,
- const MVert *mverts,
- const int target_start,
- const int target_num_verts,
- const int source_start,
- const int source_num_verts,
- const float dist)
+static void dm_mvert_map_doubles(int *doubles_map,
+ const MVert *mverts,
+ const int target_start,
+ const int target_num_verts,
+ const int source_start,
+ const int source_num_verts,
+ const float dist)
{
- const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */
- int i_source, i_target, i_target_low_bound, target_end, source_end;
- SortVertsElem *sorted_verts_target, *sorted_verts_source;
- SortVertsElem *sve_source, *sve_target, *sve_target_low_bound;
- bool target_scan_completed;
-
- target_end = target_start + target_num_verts;
- source_end = source_start + source_num_verts;
-
- /* build array of MVerts to be tested for merging */
- sorted_verts_target = MEM_malloc_arrayN(target_num_verts, sizeof(SortVertsElem), __func__);
- sorted_verts_source = MEM_malloc_arrayN(source_num_verts, sizeof(SortVertsElem), __func__);
-
- /* Copy target vertices index and cos into SortVertsElem array */
- svert_from_mvert(sorted_verts_target, mverts + target_start, target_start, target_end);
-
- /* Copy source vertices index and cos into SortVertsElem array */
- svert_from_mvert(sorted_verts_source, mverts + source_start, source_start, source_end);
-
- /* sort arrays according to sum of vertex coordinates (sumco) */
- qsort(sorted_verts_target, target_num_verts, sizeof(SortVertsElem), svert_sum_cmp);
- qsort(sorted_verts_source, source_num_verts, sizeof(SortVertsElem), svert_sum_cmp);
-
- sve_target_low_bound = sorted_verts_target;
- i_target_low_bound = 0;
- target_scan_completed = false;
-
- /* Scan source vertices, in SortVertsElem sorted array, */
- /* all the while maintaining the lower bound of possible doubles in target vertices */
- for (i_source = 0, sve_source = sorted_verts_source;
- i_source < source_num_verts;
- i_source++, sve_source++)
- {
- int best_target_vertex = -1;
- float best_dist_sq = dist * dist;
- float sve_source_sumco;
-
- /* If source has already been assigned to a target (in an earlier call, with other chunks) */
- if (doubles_map[sve_source->vertex_num] != -1) {
- continue;
- }
-
- /* If target fully scanned already, then all remaining source vertices cannot have a double */
- if (target_scan_completed) {
- doubles_map[sve_source->vertex_num] = -1;
- continue;
- }
-
- sve_source_sumco = sum_v3(sve_source->co);
-
- /* Skip all target vertices that are more than dist3 lower in terms of sumco */
- /* and advance the overall lower bound, applicable to all remaining vertices as well. */
- while ((i_target_low_bound < target_num_verts) &&
- (sve_target_low_bound->sum_co < sve_source_sumco - dist3))
- {
- i_target_low_bound++;
- sve_target_low_bound++;
- }
- /* If end of target list reached, then no more possible doubles */
- if (i_target_low_bound >= target_num_verts) {
- doubles_map[sve_source->vertex_num] = -1;
- target_scan_completed = true;
- continue;
- }
- /* Test target candidates starting at the low bound of possible doubles, ordered in terms of sumco */
- i_target = i_target_low_bound;
- sve_target = sve_target_low_bound;
-
- /* i_target will scan vertices in the [v_source_sumco - dist3; v_source_sumco + dist3] range */
-
- while ((i_target < target_num_verts) &&
- (sve_target->sum_co <= sve_source_sumco + dist3))
- {
- /* Testing distance for candidate double in target */
- /* v_target is within dist3 of v_source in terms of sumco; check real distance */
- float dist_sq;
- if ((dist_sq = len_squared_v3v3(sve_source->co, sve_target->co)) <= best_dist_sq) {
- /* Potential double found */
- best_dist_sq = dist_sq;
- best_target_vertex = sve_target->vertex_num;
-
- /* If target is already mapped, we only follow that mapping if final target remains
- * close enough from current vert (otherwise no mapping at all).
- * Note that if we later find another target closer than this one, then we check it. But if other
- * potential targets are farther, then there will be no mapping at all for this source. */
- while (best_target_vertex != -1 && !ELEM(doubles_map[best_target_vertex], -1, best_target_vertex)) {
- if (compare_len_v3v3(mverts[sve_source->vertex_num].co,
- mverts[doubles_map[best_target_vertex]].co,
- dist))
- {
- best_target_vertex = doubles_map[best_target_vertex];
- }
- else {
- best_target_vertex = -1;
- }
- }
- }
- i_target++;
- sve_target++;
- }
- /* End of candidate scan: if none found then no doubles */
- doubles_map[sve_source->vertex_num] = best_target_vertex;
- }
-
- MEM_freeN(sorted_verts_source);
- MEM_freeN(sorted_verts_target);
+ const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */
+ int i_source, i_target, i_target_low_bound, target_end, source_end;
+ SortVertsElem *sorted_verts_target, *sorted_verts_source;
+ SortVertsElem *sve_source, *sve_target, *sve_target_low_bound;
+ bool target_scan_completed;
+
+ target_end = target_start + target_num_verts;
+ source_end = source_start + source_num_verts;
+
+ /* build array of MVerts to be tested for merging */
+ sorted_verts_target = MEM_malloc_arrayN(target_num_verts, sizeof(SortVertsElem), __func__);
+ sorted_verts_source = MEM_malloc_arrayN(source_num_verts, sizeof(SortVertsElem), __func__);
+
+ /* Copy target vertices index and cos into SortVertsElem array */
+ svert_from_mvert(sorted_verts_target, mverts + target_start, target_start, target_end);
+
+ /* Copy source vertices index and cos into SortVertsElem array */
+ svert_from_mvert(sorted_verts_source, mverts + source_start, source_start, source_end);
+
+ /* sort arrays according to sum of vertex coordinates (sumco) */
+ qsort(sorted_verts_target, target_num_verts, sizeof(SortVertsElem), svert_sum_cmp);
+ qsort(sorted_verts_source, source_num_verts, sizeof(SortVertsElem), svert_sum_cmp);
+
+ sve_target_low_bound = sorted_verts_target;
+ i_target_low_bound = 0;
+ target_scan_completed = false;
+
+ /* Scan source vertices, in SortVertsElem sorted array, */
+ /* all the while maintaining the lower bound of possible doubles in target vertices */
+ for (i_source = 0, sve_source = sorted_verts_source; i_source < source_num_verts;
+ i_source++, sve_source++) {
+ int best_target_vertex = -1;
+ float best_dist_sq = dist * dist;
+ float sve_source_sumco;
+
+ /* If source has already been assigned to a target (in an earlier call, with other chunks) */
+ if (doubles_map[sve_source->vertex_num] != -1) {
+ continue;
+ }
+
+ /* If target fully scanned already, then all remaining source vertices cannot have a double */
+ if (target_scan_completed) {
+ doubles_map[sve_source->vertex_num] = -1;
+ continue;
+ }
+
+ sve_source_sumco = sum_v3(sve_source->co);
+
+ /* Skip all target vertices that are more than dist3 lower in terms of sumco */
+ /* and advance the overall lower bound, applicable to all remaining vertices as well. */
+ while ((i_target_low_bound < target_num_verts) &&
+ (sve_target_low_bound->sum_co < sve_source_sumco - dist3)) {
+ i_target_low_bound++;
+ sve_target_low_bound++;
+ }
+ /* If end of target list reached, then no more possible doubles */
+ if (i_target_low_bound >= target_num_verts) {
+ doubles_map[sve_source->vertex_num] = -1;
+ target_scan_completed = true;
+ continue;
+ }
+ /* Test target candidates starting at the low bound of possible doubles, ordered in terms of sumco */
+ i_target = i_target_low_bound;
+ sve_target = sve_target_low_bound;
+
+ /* i_target will scan vertices in the [v_source_sumco - dist3; v_source_sumco + dist3] range */
+
+ while ((i_target < target_num_verts) && (sve_target->sum_co <= sve_source_sumco + dist3)) {
+ /* Testing distance for candidate double in target */
+ /* v_target is within dist3 of v_source in terms of sumco; check real distance */
+ float dist_sq;
+ if ((dist_sq = len_squared_v3v3(sve_source->co, sve_target->co)) <= best_dist_sq) {
+ /* Potential double found */
+ best_dist_sq = dist_sq;
+ best_target_vertex = sve_target->vertex_num;
+
+ /* If target is already mapped, we only follow that mapping if final target remains
+ * close enough from current vert (otherwise no mapping at all).
+ * Note that if we later find another target closer than this one, then we check it. But if other
+ * potential targets are farther, then there will be no mapping at all for this source. */
+ while (best_target_vertex != -1 &&
+ !ELEM(doubles_map[best_target_vertex], -1, best_target_vertex)) {
+ if (compare_len_v3v3(mverts[sve_source->vertex_num].co,
+ mverts[doubles_map[best_target_vertex]].co,
+ dist)) {
+ best_target_vertex = doubles_map[best_target_vertex];
+ }
+ else {
+ best_target_vertex = -1;
+ }
+ }
+ }
+ i_target++;
+ sve_target++;
+ }
+ /* End of candidate scan: if none found then no doubles */
+ doubles_map[sve_source->vertex_num] = best_target_vertex;
+ }
+
+ MEM_freeN(sorted_verts_source);
+ MEM_freeN(sorted_verts_target);
}
-
-static void mesh_merge_transform(
- Mesh *result, Mesh *cap_mesh, float cap_offset[4][4],
- unsigned int cap_verts_index, unsigned int cap_edges_index, int cap_loops_index, int cap_polys_index,
- int cap_nverts, int cap_nedges, int cap_nloops, int cap_npolys, int *remap, int remap_len)
+static void mesh_merge_transform(Mesh *result,
+ Mesh *cap_mesh,
+ float cap_offset[4][4],
+ unsigned int cap_verts_index,
+ unsigned int cap_edges_index,
+ int cap_loops_index,
+ int cap_polys_index,
+ int cap_nverts,
+ int cap_nedges,
+ int cap_nloops,
+ int cap_npolys,
+ int *remap,
+ int remap_len)
{
- int *index_orig;
- int i;
- MVert *mv;
- MEdge *me;
- MLoop *ml;
- MPoly *mp;
-
- CustomData_copy_data(&cap_mesh->vdata, &result->vdata, 0, cap_verts_index, cap_nverts);
- CustomData_copy_data(&cap_mesh->edata, &result->edata, 0, cap_edges_index, cap_nedges);
- CustomData_copy_data(&cap_mesh->ldata, &result->ldata, 0, cap_loops_index, cap_nloops);
- CustomData_copy_data(&cap_mesh->pdata, &result->pdata, 0, cap_polys_index, cap_npolys);
-
- mv = result->mvert + cap_verts_index;
-
- for (i = 0; i < cap_nverts; i++, mv++) {
- mul_m4_v3(cap_offset, mv->co);
- /* Reset MVert flags for caps */
- mv->flag = mv->bweight = 0;
- }
-
- /* remap the vertex groups if necessary */
- if (result->dvert != NULL) {
- BKE_object_defgroup_index_map_apply(&result->dvert[cap_verts_index], cap_nverts, remap, remap_len);
- }
-
- /* adjust cap edge vertex indices */
- me = result->medge + cap_edges_index;
- for (i = 0; i < cap_nedges; i++, me++) {
- me->v1 += cap_verts_index;
- me->v2 += cap_verts_index;
- }
-
- /* adjust cap poly loopstart indices */
- mp = result->mpoly + cap_polys_index;
- for (i = 0; i < cap_npolys; i++, mp++) {
- mp->loopstart += cap_loops_index;
- }
-
- /* adjust cap loop vertex and edge indices */
- ml = result->mloop + cap_loops_index;
- for (i = 0; i < cap_nloops; i++, ml++) {
- ml->v += cap_verts_index;
- ml->e += cap_edges_index;
- }
-
- /* set origindex */
- index_orig = CustomData_get_layer(&result->vdata, CD_ORIGINDEX);
- if (index_orig) {
- copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE);
- }
-
- index_orig = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
- if (index_orig) {
- copy_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE);
- }
-
- index_orig = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
- if (index_orig) {
- copy_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE);
- }
-
- index_orig = CustomData_get_layer(&result->ldata, CD_ORIGINDEX);
- if (index_orig) {
- copy_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE);
- }
+ int *index_orig;
+ int i;
+ MVert *mv;
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+
+ CustomData_copy_data(&cap_mesh->vdata, &result->vdata, 0, cap_verts_index, cap_nverts);
+ CustomData_copy_data(&cap_mesh->edata, &result->edata, 0, cap_edges_index, cap_nedges);
+ CustomData_copy_data(&cap_mesh->ldata, &result->ldata, 0, cap_loops_index, cap_nloops);
+ CustomData_copy_data(&cap_mesh->pdata, &result->pdata, 0, cap_polys_index, cap_npolys);
+
+ mv = result->mvert + cap_verts_index;
+
+ for (i = 0; i < cap_nverts; i++, mv++) {
+ mul_m4_v3(cap_offset, mv->co);
+ /* Reset MVert flags for caps */
+ mv->flag = mv->bweight = 0;
+ }
+
+ /* remap the vertex groups if necessary */
+ if (result->dvert != NULL) {
+ BKE_object_defgroup_index_map_apply(
+ &result->dvert[cap_verts_index], cap_nverts, remap, remap_len);
+ }
+
+ /* adjust cap edge vertex indices */
+ me = result->medge + cap_edges_index;
+ for (i = 0; i < cap_nedges; i++, me++) {
+ me->v1 += cap_verts_index;
+ me->v2 += cap_verts_index;
+ }
+
+ /* adjust cap poly loopstart indices */
+ mp = result->mpoly + cap_polys_index;
+ for (i = 0; i < cap_npolys; i++, mp++) {
+ mp->loopstart += cap_loops_index;
+ }
+
+ /* adjust cap loop vertex and edge indices */
+ ml = result->mloop + cap_loops_index;
+ for (i = 0; i < cap_nloops; i++, ml++) {
+ ml->v += cap_verts_index;
+ ml->e += cap_edges_index;
+ }
+
+ /* set origindex */
+ index_orig = CustomData_get_layer(&result->vdata, CD_ORIGINDEX);
+ if (index_orig) {
+ copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE);
+ }
+
+ index_orig = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
+ if (index_orig) {
+ copy_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE);
+ }
+
+ index_orig = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
+ if (index_orig) {
+ copy_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE);
+ }
+
+ index_orig = CustomData_get_layer(&result->ldata, CD_ORIGINDEX);
+ if (index_orig) {
+ copy_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE);
+ }
}
-static Mesh *arrayModifier_doArray(
- ArrayModifierData *amd, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
- const float eps = 1e-6f;
- const MVert *src_mvert;
- MVert *mv, *mv_prev, *result_dm_verts;
-
- MEdge *me;
- MLoop *ml;
- MPoly *mp;
- int i, j, c, count;
- float length = amd->length;
- /* offset matrix */
- float offset[4][4];
- float scale[3];
- bool offset_has_scale;
- float current_offset[4][4];
- float final_offset[4][4];
- int *full_doubles_map = NULL;
- int tot_doubles;
-
- const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0;
- const bool use_recalc_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || use_merge;
- const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob != NULL);
-
- int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0;
- int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0;
- int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0;
- int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys;
- int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts;
-
- Mesh *result, *start_cap_mesh = NULL, *end_cap_mesh = NULL;
-
- int *vgroup_start_cap_remap = NULL;
- int vgroup_start_cap_remap_len = 0;
- int *vgroup_end_cap_remap = NULL;
- int vgroup_end_cap_remap_len = 0;
-
- chunk_nverts = mesh->totvert;
- chunk_nedges = mesh->totedge;
- chunk_nloops = mesh->totloop;
- chunk_npolys = mesh->totpoly;
-
- count = amd->count;
-
- Object *start_cap_ob = amd->start_cap;
- if (start_cap_ob && start_cap_ob != ctx->object && start_cap_ob->type == OB_MESH) {
- vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(
- start_cap_ob, ctx->object, &vgroup_start_cap_remap_len);
-
- start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob, false);
- if (start_cap_mesh) {
- start_cap_nverts = start_cap_mesh->totvert;
- start_cap_nedges = start_cap_mesh->totedge;
- start_cap_nloops = start_cap_mesh->totloop;
- start_cap_npolys = start_cap_mesh->totpoly;
- }
- }
- Object *end_cap_ob = amd->end_cap;
- if (end_cap_ob && end_cap_ob != ctx->object && end_cap_ob->type == OB_MESH) {
- vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(
- end_cap_ob, ctx->object, &vgroup_end_cap_remap_len);
-
- end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(end_cap_ob, false);
- if (end_cap_mesh) {
- end_cap_nverts = end_cap_mesh->totvert;
- end_cap_nedges = end_cap_mesh->totedge;
- end_cap_nloops = end_cap_mesh->totloop;
- end_cap_npolys = end_cap_mesh->totpoly;
- }
- }
-
- /* Build up offset array, cumulating all settings options */
-
- unit_m4(offset);
- src_mvert = mesh->mvert;
-
- if (amd->offset_type & MOD_ARR_OFF_CONST) {
- add_v3_v3(offset[3], amd->offset);
- }
-
- if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
- float min[3], max[3];
- const MVert *src_mv;
-
- INIT_MINMAX(min, max);
- for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) {
- minmax_v3v3_v3(min, max, src_mv->co);
- }
-
- for (j = 3; j--; ) {
- offset[3][j] += amd->scale[j] * (max[j] - min[j]);
- }
- }
-
- if (use_offset_ob) {
- float obinv[4][4];
- float result_mat[4][4];
-
- if (ctx->object)
- invert_m4_m4(obinv, ctx->object->obmat);
- else
- unit_m4(obinv);
-
- mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat);
- copy_m4_m4(offset, result_mat);
- }
-
- /* Check if there is some scaling. If scaling, then we will not translate mapping */
- mat4_to_size(scale, offset);
- offset_has_scale = !is_one_v3(scale);
-
- if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob != NULL) {
- Object *curve_ob = amd->curve_ob;
- Curve *cu = curve_ob->data;
- if (cu) {
- CurveCache *curve_cache = curve_ob->runtime.curve_cache;
- if (curve_cache != NULL && curve_cache->path != NULL) {
- float scale_fac = mat4_to_scale(curve_ob->obmat);
- length = scale_fac * curve_cache->path->totdist;
- }
- }
- }
-
- /* calculate the maximum number of copies which will fit within the
- * prescribed length */
- if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) {
- float dist = len_v3(offset[3]);
-
- if (dist > eps) {
- /* this gives length = first copy start to last copy end
- * add a tiny offset for floating point rounding errors */
- count = (length + eps) / dist + 1;
- }
- else {
- /* if the offset has no translation, just make one copy */
- count = 1;
- }
- }
-
- if (count < 1)
- count = 1;
-
- /* The number of verts, edges, loops, polys, before eventually merging doubles */
- result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts;
- result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges;
- result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops;
- result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys;
-
- /* Initialize a result dm */
- result = BKE_mesh_new_nomain_from_template(mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
- result_dm_verts = result->mvert;
-
- if (use_merge) {
- /* Will need full_doubles_map for handling merge */
- full_doubles_map = MEM_malloc_arrayN(result_nverts, sizeof(int), "mod array doubles map");
- copy_vn_i(full_doubles_map, result_nverts, -1);
- }
-
- /* copy customdata to original geometry */
- CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, chunk_nverts);
- CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, chunk_nedges);
- CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, chunk_nloops);
- CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, chunk_npolys);
-
- /* Subsurf for eg won't have mesh data in the custom data arrays.
- * now add mvert/medge/mpoly layers. */
- if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
- memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
- }
- if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
- memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
- }
- if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
- memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
- memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
- }
-
- /* Remember first chunk, in case of cap merge */
- first_chunk_start = 0;
- first_chunk_nverts = chunk_nverts;
-
- unit_m4(current_offset);
- for (c = 1; c < count; c++) {
- /* copy customdata to new geometry */
- CustomData_copy_data(&mesh->vdata, &result->vdata, 0, c * chunk_nverts, chunk_nverts);
- CustomData_copy_data(&mesh->edata, &result->edata, 0, c * chunk_nedges, chunk_nedges);
- CustomData_copy_data(&mesh->ldata, &result->ldata, 0, c * chunk_nloops, chunk_nloops);
- CustomData_copy_data(&mesh->pdata, &result->pdata, 0, c * chunk_npolys, chunk_npolys);
-
- mv_prev = result_dm_verts;
- mv = mv_prev + c * chunk_nverts;
-
- /* recalculate cumulative offset here */
- mul_m4_m4m4(current_offset, current_offset, offset);
-
- /* apply offset to all new verts */
- for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) {
- mul_m4_v3(current_offset, mv->co);
-
- /* We have to correct normals too, if we do not tag them as dirty! */
- if (!use_recalc_normals) {
- float no[3];
- normal_short_to_float_v3(no, mv->no);
- mul_mat3_m4_v3(current_offset, no);
- normalize_v3(no);
- normal_float_to_short_v3(mv->no, no);
- }
- }
-
- /* adjust edge vertex indices */
- me = result->medge + c * chunk_nedges;
- for (i = 0; i < chunk_nedges; i++, me++) {
- me->v1 += c * chunk_nverts;
- me->v2 += c * chunk_nverts;
- }
-
- mp = result->mpoly + c * chunk_npolys;
- for (i = 0; i < chunk_npolys; i++, mp++) {
- mp->loopstart += c * chunk_nloops;
- }
-
- /* adjust loop vertex and edge indices */
- ml = result->mloop + c * chunk_nloops;
- for (i = 0; i < chunk_nloops; i++, ml++) {
- ml->v += c * chunk_nverts;
- ml->e += c * chunk_nedges;
- }
-
- /* Handle merge between chunk n and n-1 */
- if (use_merge && (c >= 1)) {
- if (!offset_has_scale && (c >= 2)) {
- /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1
- * ... that is except if scaling makes the distance grow */
- int k;
- int this_chunk_index = c * chunk_nverts;
- int prev_chunk_index = (c - 1) * chunk_nverts;
- for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) {
- int target = full_doubles_map[prev_chunk_index];
- if (target != -1) {
- target += chunk_nverts; /* translate mapping */
- while (target != -1 && !ELEM(full_doubles_map[target], -1, target)) {
- /* If target is already mapped, we only follow that mapping if final target remains
- * close enough from current vert (otherwise no mapping at all). */
- if (compare_len_v3v3(result_dm_verts[this_chunk_index].co,
- result_dm_verts[full_doubles_map[target]].co,
- amd->merge_dist))
- {
- target = full_doubles_map[target];
- }
- else {
- target = -1;
- }
- }
- }
- full_doubles_map[this_chunk_index] = target;
- }
- }
- else {
- dm_mvert_map_doubles(
- full_doubles_map,
- result_dm_verts,
- (c - 1) * chunk_nverts,
- chunk_nverts,
- c * chunk_nverts,
- chunk_nverts,
- amd->merge_dist);
- }
- }
- }
-
- /* handle UVs */
- if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) {
- const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
- for (i = 0; i < totuv; i++) {
- MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, i);
- dmloopuv += chunk_nloops;
- for (c = 1; c < count; c++) {
- const float uv_offset[2] = {
- amd->uv_offset[0] * (float)c,
- amd->uv_offset[1] * (float)c,
- };
- int l_index = chunk_nloops;
- for (; l_index-- != 0; dmloopuv++) {
- dmloopuv->uv[0] += uv_offset[0];
- dmloopuv->uv[1] += uv_offset[1];
- }
- }
- }
- }
-
- last_chunk_start = (count - 1) * chunk_nverts;
- last_chunk_nverts = chunk_nverts;
-
- copy_m4_m4(final_offset, current_offset);
-
- if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) {
- /* Merge first and last copies */
- dm_mvert_map_doubles(
- full_doubles_map,
- result_dm_verts,
- last_chunk_start,
- last_chunk_nverts,
- first_chunk_start,
- first_chunk_nverts,
- amd->merge_dist);
- }
-
- /* start capping */
- if (start_cap_mesh) {
- float start_offset[4][4];
- int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts;
- invert_m4_m4(start_offset, offset);
- mesh_merge_transform(
- result, start_cap_mesh, start_offset,
- result_nverts - start_cap_nverts - end_cap_nverts,
- result_nedges - start_cap_nedges - end_cap_nedges,
- result_nloops - start_cap_nloops - end_cap_nloops,
- result_npolys - start_cap_npolys - end_cap_npolys,
- start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys,
- vgroup_start_cap_remap, vgroup_start_cap_remap_len);
- /* Identify doubles with first chunk */
- if (use_merge) {
- dm_mvert_map_doubles(
- full_doubles_map,
- result_dm_verts,
- first_chunk_start,
- first_chunk_nverts,
- start_cap_start,
- start_cap_nverts,
- amd->merge_dist);
- }
- }
-
- if (end_cap_mesh) {
- float end_offset[4][4];
- int end_cap_start = result_nverts - end_cap_nverts;
- mul_m4_m4m4(end_offset, current_offset, offset);
- mesh_merge_transform(
- result, end_cap_mesh, end_offset,
- result_nverts - end_cap_nverts,
- result_nedges - end_cap_nedges,
- result_nloops - end_cap_nloops,
- result_npolys - end_cap_npolys,
- end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys,
- vgroup_end_cap_remap, vgroup_end_cap_remap_len);
- /* Identify doubles with last chunk */
- if (use_merge) {
- dm_mvert_map_doubles(
- full_doubles_map,
- result_dm_verts,
- last_chunk_start,
- last_chunk_nverts,
- end_cap_start,
- end_cap_nverts,
- amd->merge_dist);
- }
- }
- /* done capping */
-
- /* Handle merging */
- tot_doubles = 0;
- if (use_merge) {
- for (i = 0; i < result_nverts; i++) {
- int new_i = full_doubles_map[i];
- if (new_i != -1) {
- /* We have to follow chains of doubles (merge start/end especially is likely to create some),
- * those are not supported at all by BKE_mesh_merge_verts! */
- while (!ELEM(full_doubles_map[new_i], -1, new_i)) {
- new_i = full_doubles_map[new_i];
- }
- if (i == new_i) {
- full_doubles_map[i] = -1;
- }
- else {
- full_doubles_map[i] = new_i;
- tot_doubles++;
- }
- }
- }
- if (tot_doubles > 0) {
- result = BKE_mesh_merge_verts(result, full_doubles_map, tot_doubles, MESH_MERGE_VERTS_DUMP_IF_EQUAL);
- }
- MEM_freeN(full_doubles_map);
- }
-
- /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new mesh!
- * TODO: we may need to set other dirty flags as well?
- */
- if (use_recalc_normals) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
- }
-
- if (vgroup_start_cap_remap) {
- MEM_freeN(vgroup_start_cap_remap);
- }
- if (vgroup_end_cap_remap) {
- MEM_freeN(vgroup_end_cap_remap);
- }
-
- return result;
+ const float eps = 1e-6f;
+ const MVert *src_mvert;
+ MVert *mv, *mv_prev, *result_dm_verts;
+
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+ int i, j, c, count;
+ float length = amd->length;
+ /* offset matrix */
+ float offset[4][4];
+ float scale[3];
+ bool offset_has_scale;
+ float current_offset[4][4];
+ float final_offset[4][4];
+ int *full_doubles_map = NULL;
+ int tot_doubles;
+
+ const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0;
+ const bool use_recalc_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || use_merge;
+ const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob != NULL);
+
+ int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0;
+ int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0;
+ int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0;
+ int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys;
+ int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts;
+
+ Mesh *result, *start_cap_mesh = NULL, *end_cap_mesh = NULL;
+
+ int *vgroup_start_cap_remap = NULL;
+ int vgroup_start_cap_remap_len = 0;
+ int *vgroup_end_cap_remap = NULL;
+ int vgroup_end_cap_remap_len = 0;
+
+ chunk_nverts = mesh->totvert;
+ chunk_nedges = mesh->totedge;
+ chunk_nloops = mesh->totloop;
+ chunk_npolys = mesh->totpoly;
+
+ count = amd->count;
+
+ Object *start_cap_ob = amd->start_cap;
+ if (start_cap_ob && start_cap_ob != ctx->object && start_cap_ob->type == OB_MESH) {
+ vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(
+ start_cap_ob, ctx->object, &vgroup_start_cap_remap_len);
+
+ start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob, false);
+ if (start_cap_mesh) {
+ start_cap_nverts = start_cap_mesh->totvert;
+ start_cap_nedges = start_cap_mesh->totedge;
+ start_cap_nloops = start_cap_mesh->totloop;
+ start_cap_npolys = start_cap_mesh->totpoly;
+ }
+ }
+ Object *end_cap_ob = amd->end_cap;
+ if (end_cap_ob && end_cap_ob != ctx->object && end_cap_ob->type == OB_MESH) {
+ vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(
+ end_cap_ob, ctx->object, &vgroup_end_cap_remap_len);
+
+ end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(end_cap_ob, false);
+ if (end_cap_mesh) {
+ end_cap_nverts = end_cap_mesh->totvert;
+ end_cap_nedges = end_cap_mesh->totedge;
+ end_cap_nloops = end_cap_mesh->totloop;
+ end_cap_npolys = end_cap_mesh->totpoly;
+ }
+ }
+
+ /* Build up offset array, cumulating all settings options */
+
+ unit_m4(offset);
+ src_mvert = mesh->mvert;
+
+ if (amd->offset_type & MOD_ARR_OFF_CONST) {
+ add_v3_v3(offset[3], amd->offset);
+ }
+
+ if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
+ float min[3], max[3];
+ const MVert *src_mv;
+
+ INIT_MINMAX(min, max);
+ for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) {
+ minmax_v3v3_v3(min, max, src_mv->co);
+ }
+
+ for (j = 3; j--;) {
+ offset[3][j] += amd->scale[j] * (max[j] - min[j]);
+ }
+ }
+
+ if (use_offset_ob) {
+ float obinv[4][4];
+ float result_mat[4][4];
+
+ if (ctx->object)
+ invert_m4_m4(obinv, ctx->object->obmat);
+ else
+ unit_m4(obinv);
+
+ mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat);
+ copy_m4_m4(offset, result_mat);
+ }
+
+ /* Check if there is some scaling. If scaling, then we will not translate mapping */
+ mat4_to_size(scale, offset);
+ offset_has_scale = !is_one_v3(scale);
+
+ if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob != NULL) {
+ Object *curve_ob = amd->curve_ob;
+ Curve *cu = curve_ob->data;
+ if (cu) {
+ CurveCache *curve_cache = curve_ob->runtime.curve_cache;
+ if (curve_cache != NULL && curve_cache->path != NULL) {
+ float scale_fac = mat4_to_scale(curve_ob->obmat);
+ length = scale_fac * curve_cache->path->totdist;
+ }
+ }
+ }
+
+ /* calculate the maximum number of copies which will fit within the
+ * prescribed length */
+ if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) {
+ float dist = len_v3(offset[3]);
+
+ if (dist > eps) {
+ /* this gives length = first copy start to last copy end
+ * add a tiny offset for floating point rounding errors */
+ count = (length + eps) / dist + 1;
+ }
+ else {
+ /* if the offset has no translation, just make one copy */
+ count = 1;
+ }
+ }
+
+ if (count < 1)
+ count = 1;
+
+ /* The number of verts, edges, loops, polys, before eventually merging doubles */
+ result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts;
+ result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges;
+ result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops;
+ result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys;
+
+ /* Initialize a result dm */
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
+ result_dm_verts = result->mvert;
+
+ if (use_merge) {
+ /* Will need full_doubles_map for handling merge */
+ full_doubles_map = MEM_malloc_arrayN(result_nverts, sizeof(int), "mod array doubles map");
+ copy_vn_i(full_doubles_map, result_nverts, -1);
+ }
+
+ /* copy customdata to original geometry */
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, chunk_nverts);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, chunk_nedges);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, chunk_nloops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, chunk_npolys);
+
+ /* Subsurf for eg won't have mesh data in the custom data arrays.
+ * now add mvert/medge/mpoly layers. */
+ if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
+ memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
+ }
+ if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
+ memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
+ }
+ if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
+ memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
+ memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
+ }
+
+ /* Remember first chunk, in case of cap merge */
+ first_chunk_start = 0;
+ first_chunk_nverts = chunk_nverts;
+
+ unit_m4(current_offset);
+ for (c = 1; c < count; c++) {
+ /* copy customdata to new geometry */
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, c * chunk_nverts, chunk_nverts);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, c * chunk_nedges, chunk_nedges);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, c * chunk_nloops, chunk_nloops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, c * chunk_npolys, chunk_npolys);
+
+ mv_prev = result_dm_verts;
+ mv = mv_prev + c * chunk_nverts;
+
+ /* recalculate cumulative offset here */
+ mul_m4_m4m4(current_offset, current_offset, offset);
+
+ /* apply offset to all new verts */
+ for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) {
+ mul_m4_v3(current_offset, mv->co);
+
+ /* We have to correct normals too, if we do not tag them as dirty! */
+ if (!use_recalc_normals) {
+ float no[3];
+ normal_short_to_float_v3(no, mv->no);
+ mul_mat3_m4_v3(current_offset, no);
+ normalize_v3(no);
+ normal_float_to_short_v3(mv->no, no);
+ }
+ }
+
+ /* adjust edge vertex indices */
+ me = result->medge + c * chunk_nedges;
+ for (i = 0; i < chunk_nedges; i++, me++) {
+ me->v1 += c * chunk_nverts;
+ me->v2 += c * chunk_nverts;
+ }
+
+ mp = result->mpoly + c * chunk_npolys;
+ for (i = 0; i < chunk_npolys; i++, mp++) {
+ mp->loopstart += c * chunk_nloops;
+ }
+
+ /* adjust loop vertex and edge indices */
+ ml = result->mloop + c * chunk_nloops;
+ for (i = 0; i < chunk_nloops; i++, ml++) {
+ ml->v += c * chunk_nverts;
+ ml->e += c * chunk_nedges;
+ }
+
+ /* Handle merge between chunk n and n-1 */
+ if (use_merge && (c >= 1)) {
+ if (!offset_has_scale && (c >= 2)) {
+ /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1
+ * ... that is except if scaling makes the distance grow */
+ int k;
+ int this_chunk_index = c * chunk_nverts;
+ int prev_chunk_index = (c - 1) * chunk_nverts;
+ for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) {
+ int target = full_doubles_map[prev_chunk_index];
+ if (target != -1) {
+ target += chunk_nverts; /* translate mapping */
+ while (target != -1 && !ELEM(full_doubles_map[target], -1, target)) {
+ /* If target is already mapped, we only follow that mapping if final target remains
+ * close enough from current vert (otherwise no mapping at all). */
+ if (compare_len_v3v3(result_dm_verts[this_chunk_index].co,
+ result_dm_verts[full_doubles_map[target]].co,
+ amd->merge_dist)) {
+ target = full_doubles_map[target];
+ }
+ else {
+ target = -1;
+ }
+ }
+ }
+ full_doubles_map[this_chunk_index] = target;
+ }
+ }
+ else {
+ dm_mvert_map_doubles(full_doubles_map,
+ result_dm_verts,
+ (c - 1) * chunk_nverts,
+ chunk_nverts,
+ c * chunk_nverts,
+ chunk_nverts,
+ amd->merge_dist);
+ }
+ }
+ }
+
+ /* handle UVs */
+ if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) {
+ const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
+ for (i = 0; i < totuv; i++) {
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, i);
+ dmloopuv += chunk_nloops;
+ for (c = 1; c < count; c++) {
+ const float uv_offset[2] = {
+ amd->uv_offset[0] * (float)c,
+ amd->uv_offset[1] * (float)c,
+ };
+ int l_index = chunk_nloops;
+ for (; l_index-- != 0; dmloopuv++) {
+ dmloopuv->uv[0] += uv_offset[0];
+ dmloopuv->uv[1] += uv_offset[1];
+ }
+ }
+ }
+ }
+
+ last_chunk_start = (count - 1) * chunk_nverts;
+ last_chunk_nverts = chunk_nverts;
+
+ copy_m4_m4(final_offset, current_offset);
+
+ if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) {
+ /* Merge first and last copies */
+ dm_mvert_map_doubles(full_doubles_map,
+ result_dm_verts,
+ last_chunk_start,
+ last_chunk_nverts,
+ first_chunk_start,
+ first_chunk_nverts,
+ amd->merge_dist);
+ }
+
+ /* start capping */
+ if (start_cap_mesh) {
+ float start_offset[4][4];
+ int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts;
+ invert_m4_m4(start_offset, offset);
+ mesh_merge_transform(result,
+ start_cap_mesh,
+ start_offset,
+ result_nverts - start_cap_nverts - end_cap_nverts,
+ result_nedges - start_cap_nedges - end_cap_nedges,
+ result_nloops - start_cap_nloops - end_cap_nloops,
+ result_npolys - start_cap_npolys - end_cap_npolys,
+ start_cap_nverts,
+ start_cap_nedges,
+ start_cap_nloops,
+ start_cap_npolys,
+ vgroup_start_cap_remap,
+ vgroup_start_cap_remap_len);
+ /* Identify doubles with first chunk */
+ if (use_merge) {
+ dm_mvert_map_doubles(full_doubles_map,
+ result_dm_verts,
+ first_chunk_start,
+ first_chunk_nverts,
+ start_cap_start,
+ start_cap_nverts,
+ amd->merge_dist);
+ }
+ }
+
+ if (end_cap_mesh) {
+ float end_offset[4][4];
+ int end_cap_start = result_nverts - end_cap_nverts;
+ mul_m4_m4m4(end_offset, current_offset, offset);
+ mesh_merge_transform(result,
+ end_cap_mesh,
+ end_offset,
+ result_nverts - end_cap_nverts,
+ result_nedges - end_cap_nedges,
+ result_nloops - end_cap_nloops,
+ result_npolys - end_cap_npolys,
+ end_cap_nverts,
+ end_cap_nedges,
+ end_cap_nloops,
+ end_cap_npolys,
+ vgroup_end_cap_remap,
+ vgroup_end_cap_remap_len);
+ /* Identify doubles with last chunk */
+ if (use_merge) {
+ dm_mvert_map_doubles(full_doubles_map,
+ result_dm_verts,
+ last_chunk_start,
+ last_chunk_nverts,
+ end_cap_start,
+ end_cap_nverts,
+ amd->merge_dist);
+ }
+ }
+ /* done capping */
+
+ /* Handle merging */
+ tot_doubles = 0;
+ if (use_merge) {
+ for (i = 0; i < result_nverts; i++) {
+ int new_i = full_doubles_map[i];
+ if (new_i != -1) {
+ /* We have to follow chains of doubles (merge start/end especially is likely to create some),
+ * those are not supported at all by BKE_mesh_merge_verts! */
+ while (!ELEM(full_doubles_map[new_i], -1, new_i)) {
+ new_i = full_doubles_map[new_i];
+ }
+ if (i == new_i) {
+ full_doubles_map[i] = -1;
+ }
+ else {
+ full_doubles_map[i] = new_i;
+ tot_doubles++;
+ }
+ }
+ }
+ if (tot_doubles > 0) {
+ result = BKE_mesh_merge_verts(
+ result, full_doubles_map, tot_doubles, MESH_MERGE_VERTS_DUMP_IF_EQUAL);
+ }
+ MEM_freeN(full_doubles_map);
+ }
+
+ /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new mesh!
+ * TODO: we may need to set other dirty flags as well?
+ */
+ if (use_recalc_normals) {
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+
+ if (vgroup_start_cap_remap) {
+ MEM_freeN(vgroup_start_cap_remap);
+ }
+ if (vgroup_end_cap_remap) {
+ MEM_freeN(vgroup_end_cap_remap);
+ }
+
+ return result;
}
-
-static Mesh *applyModifier(
- ModifierData *md, const ModifierEvalContext *ctx,
- Mesh *mesh)
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
- ArrayModifierData *amd = (ArrayModifierData *) md;
- return arrayModifier_doArray(amd, ctx, mesh);
+ ArrayModifierData *amd = (ArrayModifierData *)md;
+ return arrayModifier_doArray(amd, ctx, mesh);
}
-
ModifierTypeInfo modifierType_Array = {
- /* name */ "Array",
- /* structName */ "ArrayModifierData",
- /* structSize */ sizeof(ArrayModifierData),
- /* type */ eModifierTypeType_Constructive,
- /* flags */ eModifierTypeFlag_AcceptsMesh |
- eModifierTypeFlag_SupportsMapping |
- eModifierTypeFlag_SupportsEditmode |
- eModifierTypeFlag_EnableInEditmode |
- eModifierTypeFlag_AcceptsCVs,
-
- /* copyData */ modifier_copyData_generic,
-
- /* deformVerts */ NULL,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
-
- /* initData */ initData,
- /* requiredDataMask */ NULL,
- /* freeData */ NULL,
- /* isDisabled */ NULL,
- /* updateDepsgraph */ updateDepsgraph,
- /* dependsOnTime */ NULL,
- /* dependsOnNormals */ NULL,
- /* foreachObjectLink */ foreachObjectLink,
- /* foreachIDLink */ NULL,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
+ /* name */ "Array",
+ /* structName */ "ArrayModifierData",
+ /* structSize */ sizeof(ArrayModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
+ eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
+ eModifierTypeFlag_AcceptsCVs,
+
+ /* copyData */ modifier_copyData_generic,
+
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+
+ /* initData */ initData,
+ /* requiredDataMask */ NULL,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* freeRuntimeData */ NULL,
};