135
149
float min_co, max_co;
137
151
/* if there are no vertices, width is 0 */
138
if(numVerts == 0) return 0;
152
if (numVerts == 0) return 0;
140
154
/* find the minimum and maximum coordinates on the desired axis */
141
155
min_co = max_co = mvert->co[axis];
143
for(i = 1; i < numVerts; ++i, ++mvert) {
144
if(mvert->co[axis] < min_co) min_co = mvert->co[axis];
145
if(mvert->co[axis] > max_co) max_co = mvert->co[axis];
157
for (i = 1; i < numVerts; ++i, ++mvert) {
158
if (mvert->co[axis] < min_co) min_co = mvert->co[axis];
159
if (mvert->co[axis] > max_co) max_co = mvert->co[axis];
148
162
return max_co - min_co;
151
typedef struct IndexMapEntry {
152
/* the new vert index that this old vert index maps to */
154
/* -1 if this vert isn't merged, otherwise the old vert index it
155
* should be replaced with
158
/* 1 if this vert's first copy is merged with the last copy of its
159
* merge target, otherwise 0
164
/* indexMap - an array of IndexMap entries
165
* oldIndex - the old index to map
166
* copyNum - the copy number to map to (original = 0, first copy = 1, etc.)
165
static int *find_doubles_index_map(BMesh *bm, BMOperator *dupe_op,
166
const ArrayModifierData *amd,
167
int *index_map_length)
175
BMO_op_initf(bm, &find_op,
176
"finddoubles verts=%av dist=%f keepverts=%s",
177
amd->merge_dist, dupe_op, "geom");
179
BMO_op_exec(bm, &find_op);
182
BMO_ITER (ele, &oiter, bm, dupe_op, "geom", BM_ALL) {
183
BM_elem_index_set(ele, i); /* set_dirty */
187
BMO_ITER (ele, &oiter, bm, dupe_op, "newout", BM_ALL) {
188
BM_elem_index_set(ele, i); /* set_dirty */
191
/* above loops over all, so set all to dirty, if this is somehow
192
* setting valid values, this line can be remvoed - campbell */
193
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
195
(*index_map_length) = i;
196
index_map = MEM_callocN(sizeof(int) * (*index_map_length), "index_map");
198
/*element type argument doesn't do anything here*/
199
BMO_ITER (v, &oiter, bm, &find_op, "targetmapout", 0) {
200
v2 = BMO_iter_map_value_p(&oiter);
202
index_map[BM_elem_index_get(v)] = BM_elem_index_get(v2) + 1;
205
BMO_op_finish(bm, &find_op);
210
/* Used for start/end cap.
212
* this function expects all existing vertices to be tagged,
213
* so we can know new verts are not tagged.
215
* All verts will be tagged on exit.
168
static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum)
170
if(indexMap[oldIndex].merge < 0) {
171
/* vert wasn't merged, so use copy of this vert */
172
return indexMap[oldIndex].new + copyNum;
173
} else if(indexMap[oldIndex].merge == oldIndex) {
174
/* vert was merged with itself */
175
return indexMap[oldIndex].new;
177
/* vert was merged with another vert */
178
/* follow the chain of merges to the end, or until we've passed
179
* a number of vertices equal to the copy number
182
return indexMap[oldIndex].new;
184
return calc_mapping(indexMap, indexMap[oldIndex].merge,
217
static void bm_merge_dm_transform(BMesh* bm, DerivedMesh *dm, float mat[4][4],
218
const ArrayModifierData *amd,
220
const char *dupe_slot_name,
226
DM_to_bmesh_ex(dm, bm);
228
if (amd->flags & MOD_ARR_MERGE) {
229
/* if merging is enabled, find doubles */
234
BMO_op_initf(bm, &find_op,
235
"finddoubles verts=%Hv dist=%f keepverts=%s",
236
BM_ELEM_TAG, amd->merge_dist,
237
dupe_op, dupe_slot_name);
239
/* append the dupe's geom to the findop input verts */
240
BMO_slot_buffer_append(&find_op, "verts", dupe_op, dupe_slot_name);
242
/* transform and tag verts */
243
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
244
if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
245
mul_m4_v3(mat, v->co);
246
BM_elem_flag_enable(v, BM_ELEM_TAG);
250
BMO_op_exec(bm, &find_op);
252
/* add new merge targets to weld operator */
253
BMO_ITER (v, &oiter, bm, &find_op, "targetmapout", 0) {
254
v2 = BMO_iter_map_value_p(&oiter);
255
BMO_slot_map_ptr_insert(bm, weld_op, "targetmap", v, v2);
258
BMO_op_finish(bm, &find_op);
261
/* transform and tag verts */
262
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
263
if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
264
mul_m4_v3(mat, v->co);
265
BM_elem_flag_enable(v, BM_ELEM_TAG);
271
static void merge_first_last(BMesh* bm,
272
const ArrayModifierData *amd,
273
BMOperator *dupe_first,
274
BMOperator *dupe_last,
281
BMO_op_initf(bm, &find_op,
282
"finddoubles verts=%s dist=%f keepverts=%s",
283
dupe_first, "geom", amd->merge_dist,
286
/* append the last dupe's geom to the findop input verts */
287
BMO_slot_buffer_append(&find_op, "verts", dupe_last, "newout");
289
BMO_op_exec(bm, &find_op);
291
/* add new merge targets to weld operator */
292
BMO_ITER (v, &oiter, bm, &find_op, "targetmapout", 0) {
293
v2 = BMO_iter_map_value_p(&oiter);
294
BMO_slot_map_ptr_insert(bm, weld_op, "targetmap", v, v2);
297
BMO_op_finish(bm, &find_op);
189
300
static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
190
struct Scene *scene, Object *ob, DerivedMesh *dm,
301
Scene *scene, Object *ob, DerivedMesh *dm,
302
int UNUSED(initFlags))
305
BMEditMesh *em = DM_to_editbmesh(dm, NULL, FALSE);
306
BMOperator first_dupe_op, dupe_op, old_dupe_op, weld_op;
307
BMVert **first_geom = NULL;
194
309
/* offset matrix */
195
310
float offset[4][4];
196
311
float final_offset[4][4];
197
312
float tmp_mat[4][4];
198
313
float length = amd->length;
199
int count = amd->count;
200
int numVerts, numEdges, numFaces;
201
int maxVerts, maxEdges, maxFaces;
202
int finalVerts, finalEdges, finalFaces;
203
DerivedMesh *result, *start_cap = NULL, *end_cap = NULL;
204
MVert *mvert, *src_mvert;
208
IndexMapEntry *indexMap;
314
int count = amd->count, maxVerts;
315
int *indexMap = NULL;
316
DerivedMesh *start_cap = NULL, *end_cap = NULL;
212
319
/* need to avoid infinite recursion here */
213
if(amd->start_cap && amd->start_cap != ob)
214
start_cap = amd->start_cap->derivedFinal;
215
if(amd->end_cap && amd->end_cap != ob)
216
end_cap = amd->end_cap->derivedFinal;
320
if (amd->start_cap && amd->start_cap != ob)
321
start_cap = mesh_get_derived_final(scene, amd->start_cap, CD_MASK_MESH);
322
if (amd->end_cap && amd->end_cap != ob)
323
end_cap = mesh_get_derived_final(scene, amd->end_cap, CD_MASK_MESH);
220
indexMap = MEM_callocN(sizeof(*indexMap) * dm->getNumVerts(dm),
223
327
src_mvert = dm->getVertArray(dm);
225
328
maxVerts = dm->getNumVerts(dm);
227
if(amd->offset_type & MOD_ARR_OFF_CONST)
228
add_v3_v3(offset[3], amd->offset);
229
if(amd->offset_type & MOD_ARR_OFF_RELATIVE) {
230
for(j = 0; j < 3; j++)
330
if (amd->offset_type & MOD_ARR_OFF_CONST)
331
add_v3_v3v3(offset[3], offset[3], amd->offset);
332
if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
333
for (j = 0; j < 3; j++)
231
334
offset[3][j] += amd->scale[j] * vertarray_size(src_mvert,
235
if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
338
if ((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
236
339
float obinv[4][4];
237
340
float result_mat[4][4];
240
343
invert_m4_m4(obinv, ob->obmat);
244
347
mul_serie_m4(result_mat, offset,
245
obinv, amd->offset_ob->obmat,
246
NULL, NULL, NULL, NULL, NULL);
348
obinv, amd->offset_ob->obmat,
349
NULL, NULL, NULL, NULL, NULL);
247
350
copy_m4_m4(offset, result_mat);
250
if(amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
353
if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
251
354
Curve *cu = amd->curve_ob->data;
253
356
float tmp_mat[3][3];
256
359
object_to_mat3(amd->curve_ob, tmp_mat);
257
360
scale = mat3_to_scale(tmp_mat);
260
363
cu->flag |= CU_PATH; // needed for path & bevlist
261
364
makeDispListCurveTypes(scene, amd->curve_ob, 0);
264
367
length = scale*cu->path->totdist;
268
371
/* calculate the maximum number of copies which will fit within the
270
if(amd->fit_type == MOD_ARR_FITLENGTH
271
|| amd->fit_type == MOD_ARR_FITCURVE) {
372
* prescribed length */
373
if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) {
272
374
float dist = sqrt(dot_v3v3(offset[3], offset[3]));
275
377
/* this gives length = first copy start to last copy end
276
add a tiny offset for floating point rounding errors */
378
* add a tiny offset for floating point rounding errors */
277
379
count = (length + 1e-6f) / dist;
279
381
/* if the offset has no translation, just make one copy */
286
/* allocate memory for count duplicates (including original) plus
289
finalVerts = dm->getNumVerts(dm) * count;
290
finalEdges = dm->getNumEdges(dm) * count;
291
finalFaces = dm->getNumFaces(dm) * count;
293
finalVerts += start_cap->getNumVerts(start_cap);
294
finalEdges += start_cap->getNumEdges(start_cap);
295
finalFaces += start_cap->getNumFaces(start_cap);
298
finalVerts += end_cap->getNumVerts(end_cap);
299
finalEdges += end_cap->getNumEdges(end_cap);
300
finalFaces += end_cap->getNumFaces(end_cap);
302
result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces);
304
/* calculate the offset matrix of the final copy (for merging) */
305
unit_m4(final_offset);
307
for(j=0; j < count - 1; j++) {
308
mul_m4_m4m4(tmp_mat, final_offset, offset);
309
copy_m4_m4(final_offset, tmp_mat);
312
numVerts = numEdges = numFaces = 0;
313
mvert = CDDM_get_verts(result);
315
for (i = 0; i < maxVerts; i++) {
316
indexMap[i].merge = -1; /* default to no merge */
317
indexMap[i].merge_final = 0; /* default to no merge */
320
for (i = 0; i < maxVerts; i++) {
322
MVert *mv = &mvert[numVerts];
326
inMV = &src_mvert[i];
328
DM_copy_vert_data(dm, result, i, numVerts, 1);
332
indexMap[i].new = numVerts - 1;
334
copy_v3_v3(co, mv->co);
336
/* Attempts to merge verts from one duplicate with verts from the
337
* next duplicate which are closer than amd->merge_dist.
338
* Only the first such vert pair is merged.
339
* If verts are merged in the first duplicate pair, they are merged
342
if((count > 1) && (amd->flags & MOD_ARR_MERGE)) {
344
mul_v3_m4v3(tmp_co, offset, mv->co);
346
for(j = 0; j < maxVerts; j++) {
347
/* if vertex already merged, don't use it */
348
if( indexMap[j].merge != -1 ) continue;
350
inMV = &src_mvert[j];
351
/* if this vert is within merge limit, merge */
352
if(compare_len_v3v3(tmp_co, inMV->co, amd->merge_dist)) {
353
indexMap[i].merge = j;
355
/* test for merging with final copy of merge target */
356
if(amd->flags & MOD_ARR_MERGEFINAL) {
357
copy_v3_v3(tmp_co, inMV->co);
358
inMV = &src_mvert[i];
359
mul_m4_v3(final_offset, tmp_co);
360
if(compare_len_v3v3(tmp_co, inMV->co, amd->merge_dist))
361
indexMap[i].merge_final = 1;
368
/* if no merging, generate copies of this vert */
369
if(indexMap[i].merge < 0) {
370
for(j=0; j < count - 1; j++) {
371
mv2 = &mvert[numVerts];
373
DM_copy_vert_data(result, result, numVerts - 1, numVerts, 1);
377
mul_m4_v3(offset, co);
378
copy_v3_v3(mv2->co, co);
380
} else if(indexMap[i].merge != i && indexMap[i].merge_final) {
381
/* if this vert is not merging with itself, and it is merging
382
* with the final copy of its merge target, remove the first copy
385
DM_free_vert_data(result, numVerts, 1);
389
/* make a hashtable so we can avoid duplicate edges from merging */
390
edges = BLI_edgehash_new();
392
maxEdges = dm->getNumEdges(dm);
393
medge = CDDM_get_edges(result);
394
for(i = 0; i < maxEdges; i++) {
400
dm->getEdge(dm, i, &inMED);
403
med.v1 = indexMap[inMED.v1].new;
404
med.v2 = indexMap[inMED.v2].new;
406
/* if vertices are to be merged with the final copies of their
407
* merge targets, calculate that final copy
409
if(indexMap[inMED.v1].merge_final) {
410
med.v1 = calc_mapping(indexMap, indexMap[inMED.v1].merge,
413
if(indexMap[inMED.v2].merge_final) {
414
med.v2 = calc_mapping(indexMap, indexMap[inMED.v2].merge,
418
if(med.v1 == med.v2) continue;
421
med.flag |= ME_EDGEDRAW | ME_EDGERENDER;
424
if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) {
425
DM_copy_edge_data(dm, result, i, numEdges, 1);
426
medge[numEdges] = med;
429
BLI_edgehash_insert(edges, med.v1, med.v2, NULL);
432
for(j = 1; j < count; j++)
434
vert1 = calc_mapping(indexMap, inMED.v1, j);
435
vert2 = calc_mapping(indexMap, inMED.v2, j);
436
/* avoid duplicate edges */
437
if(!BLI_edgehash_haskey(edges, vert1, vert2)) {
438
med2 = &medge[numEdges];
440
DM_copy_edge_data(dm, result, i, numEdges, 1);
447
BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL);
452
maxFaces = dm->getNumFaces(dm);
453
mface = CDDM_get_faces(result);
454
for (i=0; i < maxFaces; i++) {
456
MFace *mf = &mface[numFaces];
458
dm->getFace(dm, i, &inMF);
460
DM_copy_face_data(dm, result, i, numFaces, 1);
463
mf->v1 = indexMap[inMF.v1].new;
464
mf->v2 = indexMap[inMF.v2].new;
465
mf->v3 = indexMap[inMF.v3].new;
467
mf->v4 = indexMap[inMF.v4].new;
469
/* if vertices are to be merged with the final copies of their
470
* merge targets, calculate that final copy
472
if(indexMap[inMF.v1].merge_final)
473
mf->v1 = calc_mapping(indexMap, indexMap[inMF.v1].merge, count-1);
474
if(indexMap[inMF.v2].merge_final)
475
mf->v2 = calc_mapping(indexMap, indexMap[inMF.v2].merge, count-1);
476
if(indexMap[inMF.v3].merge_final)
477
mf->v3 = calc_mapping(indexMap, indexMap[inMF.v3].merge, count-1);
478
if(inMF.v4 && indexMap[inMF.v4].merge_final)
479
mf->v4 = calc_mapping(indexMap, indexMap[inMF.v4].merge, count-1);
481
if(test_index_face(mf, &result->faceData, numFaces, inMF.v4?4:3) < 3)
486
/* if the face has fewer than 3 vertices, don't create it */
487
if(mf->v3 == 0 || (mf->v1 && (mf->v1 == mf->v3 || mf->v1 == mf->v4))) {
489
DM_free_face_data(result, numFaces, 1);
492
for(j = 1; j < count; j++)
494
MFace *mf2 = &mface[numFaces];
496
DM_copy_face_data(dm, result, i, numFaces, 1);
499
mf2->v1 = calc_mapping(indexMap, inMF.v1, j);
500
mf2->v2 = calc_mapping(indexMap, inMF.v2, j);
501
mf2->v3 = calc_mapping(indexMap, inMF.v3, j);
503
mf2->v4 = calc_mapping(indexMap, inMF.v4, j);
505
test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3);
508
/* if the face has fewer than 3 vertices, don't create it */
509
if(mf2->v3 == 0 || (mf2->v1 && (mf2->v1 == mf2->v3 || mf2->v1 ==
512
DM_free_face_data(result, numFaces, 1);
517
/* add start and end caps */
519
float startoffset[4][4];
525
int capVerts, capEdges, capFaces;
527
capVerts = start_cap->getNumVerts(start_cap);
528
capEdges = start_cap->getNumEdges(start_cap);
529
capFaces = start_cap->getNumFaces(start_cap);
530
cap_mvert = start_cap->getVertArray(start_cap);
531
cap_medge = start_cap->getEdgeArray(start_cap);
532
cap_mface = start_cap->getFaceArray(start_cap);
534
invert_m4_m4(startoffset, offset);
536
vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
537
"arrayModifier_doArray vert_map");
539
origindex = result->getVertDataArray(result, CD_ORIGINDEX);
540
for(i = 0; i < capVerts; i++) {
541
MVert *mv = &cap_mvert[i];
544
if(amd->flags & MOD_ARR_MERGE) {
549
copy_v3_v3(tmp_co, mv->co);
550
mul_m4_v3(startoffset, tmp_co);
552
for(j = 0; j < maxVerts; j++) {
553
in_mv = &src_mvert[j];
554
/* if this vert is within merge limit, merge */
555
if(compare_len_v3v3(tmp_co, in_mv->co, amd->merge_dist)) {
556
vert_map[i] = calc_mapping(indexMap, j, 0);
564
DM_copy_vert_data(start_cap, result, i, numVerts, 1);
565
mvert[numVerts] = *mv;
566
mul_m4_v3(startoffset, mvert[numVerts].co);
567
origindex[numVerts] = ORIGINDEX_NONE;
569
vert_map[i] = numVerts;
574
origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
575
for(i = 0; i < capEdges; i++) {
578
v1 = vert_map[cap_medge[i].v1];
579
v2 = vert_map[cap_medge[i].v2];
581
if(!BLI_edgehash_haskey(edges, v1, v2)) {
582
DM_copy_edge_data(start_cap, result, i, numEdges, 1);
583
medge[numEdges] = cap_medge[i];
584
medge[numEdges].v1 = v1;
585
medge[numEdges].v2 = v2;
586
origindex[numEdges] = ORIGINDEX_NONE;
591
origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
592
for(i = 0; i < capFaces; i++) {
593
DM_copy_face_data(start_cap, result, i, numFaces, 1);
594
mface[numFaces] = cap_mface[i];
595
mface[numFaces].v1 = vert_map[mface[numFaces].v1];
596
mface[numFaces].v2 = vert_map[mface[numFaces].v2];
597
mface[numFaces].v3 = vert_map[mface[numFaces].v3];
598
if(mface[numFaces].v4) {
599
mface[numFaces].v4 = vert_map[mface[numFaces].v4];
601
test_index_face(&mface[numFaces], &result->faceData,
606
test_index_face(&mface[numFaces], &result->faceData,
610
origindex[numFaces] = ORIGINDEX_NONE;
616
start_cap->release(start_cap);
620
float endoffset[4][4];
626
int capVerts, capEdges, capFaces;
628
capVerts = end_cap->getNumVerts(end_cap);
629
capEdges = end_cap->getNumEdges(end_cap);
630
capFaces = end_cap->getNumFaces(end_cap);
631
cap_mvert = end_cap->getVertArray(end_cap);
632
cap_medge = end_cap->getEdgeArray(end_cap);
633
cap_mface = end_cap->getFaceArray(end_cap);
635
mul_m4_m4m4(endoffset, final_offset, offset);
637
vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
638
"arrayModifier_doArray vert_map");
640
origindex = result->getVertDataArray(result, CD_ORIGINDEX);
641
for(i = 0; i < capVerts; i++) {
642
MVert *mv = &cap_mvert[i];
645
if(amd->flags & MOD_ARR_MERGE) {
650
copy_v3_v3(tmp_co, mv->co);
651
mul_m4_v3(offset, tmp_co);
653
for(j = 0; j < maxVerts; j++) {
654
in_mv = &src_mvert[j];
655
/* if this vert is within merge limit, merge */
656
if(compare_len_v3v3(tmp_co, in_mv->co, amd->merge_dist)) {
657
vert_map[i] = calc_mapping(indexMap, j, count - 1);
665
DM_copy_vert_data(end_cap, result, i, numVerts, 1);
666
mvert[numVerts] = *mv;
667
mul_m4_v3(endoffset, mvert[numVerts].co);
668
origindex[numVerts] = ORIGINDEX_NONE;
670
vert_map[i] = numVerts;
675
origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
676
for(i = 0; i < capEdges; i++) {
679
v1 = vert_map[cap_medge[i].v1];
680
v2 = vert_map[cap_medge[i].v2];
682
if(!BLI_edgehash_haskey(edges, v1, v2)) {
683
DM_copy_edge_data(end_cap, result, i, numEdges, 1);
684
medge[numEdges] = cap_medge[i];
685
medge[numEdges].v1 = v1;
686
medge[numEdges].v2 = v2;
687
origindex[numEdges] = ORIGINDEX_NONE;
692
origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
693
for(i = 0; i < capFaces; i++) {
694
DM_copy_face_data(end_cap, result, i, numFaces, 1);
695
mface[numFaces] = cap_mface[i];
696
mface[numFaces].v1 = vert_map[mface[numFaces].v1];
697
mface[numFaces].v2 = vert_map[mface[numFaces].v2];
698
mface[numFaces].v3 = vert_map[mface[numFaces].v3];
699
if(mface[numFaces].v4) {
700
mface[numFaces].v4 = vert_map[mface[numFaces].v4];
702
test_index_face(&mface[numFaces], &result->faceData,
707
test_index_face(&mface[numFaces], &result->faceData,
710
origindex[numFaces] = ORIGINDEX_NONE;
716
end_cap->release(end_cap);
719
BLI_edgehash_free(edges, NULL);
722
CDDM_lower_num_verts(result, numVerts);
723
CDDM_lower_num_edges(result, numEdges);
724
CDDM_lower_num_faces(result, numFaces);
729
static DerivedMesh *applyModifier(
730
ModifierData *md, Object *ob, DerivedMesh *derivedData,
731
int useRenderParams, int isFinalCalc)
734
ArrayModifierData *amd = (ArrayModifierData*) md;
736
result = arrayModifier_doArray(amd, md->scene, ob, derivedData, 0);
738
if(result != derivedData)
388
/* calculate the offset matrix of the final copy (for merging) */
389
unit_m4(final_offset);
391
for (j=0; j < count - 1; j++) {
392
mult_m4_m4m4(tmp_mat, offset, final_offset);
393
copy_m4_m4(final_offset, tmp_mat);
396
/* BMESH_TODO: bumping up the stack level avoids computing the normals
397
* after every top-level operator execution (and this modifier has the
398
* potential to execute a *lot* of top-level BMOps. There should be a
399
* cleaner way to do this. One possibility: a "mirror" BMOp would
400
* certainly help by compressing it all into one top-level BMOp that
401
* executes a lot of second-level BMOps. */
402
BMO_push(em->bm, NULL);
403
bmesh_edit_begin(em->bm, 0);
405
if (amd->flags & MOD_ARR_MERGE)
406
BMO_op_init(em->bm, &weld_op, "weldverts");
408
BMO_op_initf(em->bm, &dupe_op, "dupe geom=%avef");
409
first_dupe_op = dupe_op;
411
for (j=0; j < count - 1; j++) {
414
BMOpSlot *newout_slot;
418
BMO_op_initf(em->bm, &dupe_op, "dupe geom=%s", &old_dupe_op, "newout");
419
BMO_op_exec(em->bm, &dupe_op);
421
geom_slot = BMO_slot_get(&dupe_op, "geom");
422
newout_slot = BMO_slot_get(&dupe_op, "newout");
424
if ((amd->flags & MOD_ARR_MERGEFINAL) && j == 0) {
425
int first_geom_bytes = sizeof(BMVert*) * geom_slot->len;
427
/* make a copy of the initial geometry ordering so the
428
* last duplicate can be merged into it */
429
first_geom = MEM_mallocN(first_geom_bytes, "first_geom");
430
memcpy(first_geom, geom_slot->data.buf, first_geom_bytes);
433
/* apply transformation matrix */
434
BMO_ITER (v, &oiter, em->bm, &dupe_op, "newout", BM_VERT) {
435
mul_m4_v3(offset, v->co);
438
if (amd->flags & MOD_ARR_MERGE) {
439
/*calculate merge mapping*/
441
indexMap = find_doubles_index_map(em->bm, &dupe_op,
445
#define _E(s, i) ((BMVert **)(s)->data.buf)[i]
447
for (i=0; i<indexLen; i++) {
448
if (!indexMap[i]) continue;
450
/* merge v (from 'newout') into v2 (from old 'geom') */
451
v = _E(newout_slot, i - geom_slot->len);
452
v2 = _E(geom_slot, indexMap[i]-1);
454
/* check in case the target vertex (v2) is already marked
456
while ((v3 = BMO_slot_map_ptr_get(em->bm, &weld_op, "targetmap", v2))) {
460
BMO_slot_map_ptr_insert(em->bm, &weld_op, "targetmap", v, v2);
466
/* already copied earlier, but after executation more slot
467
* memory may be allocated */
469
first_dupe_op = dupe_op;
472
BMO_op_finish(em->bm, &old_dupe_op);
473
old_dupe_op = dupe_op;
476
if ((amd->flags & MOD_ARR_MERGE) &&
477
(amd->flags & MOD_ARR_MERGEFINAL) &&
480
/* Merge first and last copies. Note that we can't use the
481
* indexMap for this because (unless the array is forming a
482
* loop) the offset between first and last is different from
483
* dupe X to dupe X+1. */
485
merge_first_last(em->bm, amd, &first_dupe_op, &dupe_op, &weld_op);
489
if (start_cap || end_cap) {
490
BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT, BM_ELEM_TAG, FALSE);
493
float startoffset[4][4];
494
invert_m4_m4(startoffset, offset);
495
bm_merge_dm_transform(em->bm, start_cap, startoffset, amd,
496
&first_dupe_op, "geom", &weld_op);
500
float endoffset[4][4];
501
mult_m4_m4m4(endoffset, offset, final_offset);
502
bm_merge_dm_transform(em->bm, end_cap, endoffset, amd,
503
&dupe_op, count == 1 ? "geom" : "newout", &weld_op);
508
/* free remaining dupe operators */
509
BMO_op_finish(em->bm, &first_dupe_op);
511
BMO_op_finish(em->bm, &dupe_op);
513
/* run merge operator */
514
if (amd->flags & MOD_ARR_MERGE) {
515
BMO_op_exec(em->bm, &weld_op);
516
BMO_op_finish(em->bm, &weld_op);
519
/* Bump the stack level back down to match the adjustment up above */
522
BLI_assert(em->looptris == NULL);
523
result = CDDM_from_BMEditMesh(em, NULL, FALSE, FALSE);
525
if ((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
526
/* Update normals in case offset object has rotation. */
528
/* BMESH_TODO: check if normal recalc needed under any other
739
531
CDDM_calc_normals(result);
744
static DerivedMesh *applyModifierEM(
745
ModifierData *md, Object *ob, struct EditMesh *editData,
746
DerivedMesh *derivedData)
748
return applyModifier(md, ob, derivedData, 0, 1);
539
MEM_freeN(first_geom);
544
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
546
int UNUSED(useRenderParams),
547
int UNUSED(isFinalCalc))
550
ArrayModifierData *amd = (ArrayModifierData*) md;
552
result = arrayModifier_doArray(amd, md->scene, ob, dm, 0);
555
// CDDM_calc_normals_mapping(result);
560
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
561
struct BMEditMesh *UNUSED(editData),
564
return applyModifier(md, ob, dm, 0, 1);