102
103
static void foreachObjectLink(
103
ModifierData *md, Object *ob,
104
void (*walk)(void *userData, Object *ob, Object **obpoin),
104
ModifierData *md, Object *ob,
105
void (*walk)(void *userData, Object *ob, Object **obpoin),
107
ArrayModifierData *amd = (ArrayModifierData*) md;
108
ArrayModifierData *amd = (ArrayModifierData *) md;
109
110
walk(userData, ob, &amd->start_cap);
110
111
walk(userData, ob, &amd->end_cap);
115
116
static void updateDepgraph(ModifierData *md, DagForest *forest,
116
struct Scene *UNUSED(scene), Object *UNUSED(ob), DagNode *obNode)
117
struct Scene *UNUSED(scene), Object *UNUSED(ob), DagNode *obNode)
118
ArrayModifierData *amd = (ArrayModifierData*) md;
119
ArrayModifierData *amd = (ArrayModifierData *) md;
120
121
if (amd->start_cap) {
121
122
DagNode *curNode = dag_get_node(forest, amd->start_cap);
173
174
int *index_map, i;
175
BMO_op_initf(bm, &find_op,
176
"finddoubles verts=%av dist=%f keepverts=%s",
177
amd->merge_dist, dupe_op, "geom");
176
BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
177
"find_doubles verts=%av dist=%f keep_verts=%s",
178
amd->merge_dist, dupe_op, "geom");
179
180
BMO_op_exec(bm, &find_op);
182
BMO_ITER (ele, &oiter, bm, dupe_op, "geom", BM_ALL) {
183
BMO_ITER (ele, &oiter, dupe_op->slots_in, "geom", BM_ALL) {
183
184
BM_elem_index_set(ele, i); /* set_dirty */
187
BMO_ITER (ele, &oiter, bm, dupe_op, "newout", BM_ALL) {
188
BMO_ITER (ele, &oiter, dupe_op->slots_out, "geom.out", BM_ALL) {
188
189
BM_elem_index_set(ele, i); /* set_dirty */
191
192
/* above loops over all, so set all to dirty, if this is somehow
192
* setting valid values, this line can be remvoed - campbell */
193
* setting valid values, this line can be removed - campbell */
193
194
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
195
196
(*index_map_length) = i;
196
197
index_map = MEM_callocN(sizeof(int) * (*index_map_length), "index_map");
198
199
/*element type argument doesn't do anything here*/
199
BMO_ITER (v, &oiter, bm, &find_op, "targetmapout", 0) {
200
BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) {
200
201
v2 = BMO_iter_map_value_p(&oiter);
202
203
index_map[BM_elem_index_get(v)] = BM_elem_index_get(v2) + 1;
215
216
* All verts will be tagged on exit.
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,
218
static void bm_merge_dm_transform(BMesh *bm, DerivedMesh *dm, float mat[4][4],
219
const ArrayModifierData *amd,
221
BMOpSlot dupe_op_slot_args[BMO_OP_MAX_SLOTS], const char *dupe_slot_name,
224
const int is_input = (dupe_op->slots_in == dupe_op_slot_args);
228
/* Add the DerivedMesh's elements to the BMesh. The pre-existing
229
* elements were already tagged, so the new elements can be
230
* identified by not having the BM_ELEM_TAG flag set. */
226
231
DM_to_bmesh_ex(dm, bm);
228
233
if (amd->flags & MOD_ARR_MERGE) {
232
237
BMOperator find_op;
238
BMOpSlot *slot_targetmap;
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);
240
BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
242
"find_doubles verts=%Hv dist=%f keep_verts=%s" :
243
"find_doubles verts=%Hv dist=%f keep_verts=%S",
244
BM_ELEM_TAG, amd->merge_dist,
245
dupe_op, dupe_slot_name);
239
247
/* append the dupe's geom to the findop input verts */
240
BMO_slot_buffer_append(&find_op, "verts", dupe_op, dupe_slot_name);
249
BMO_slot_buffer_append(&find_op, slots_in, "verts",
250
dupe_op, slots_in, dupe_slot_name);
252
else if (dupe_op->slots_out == dupe_op_slot_args) {
253
BMO_slot_buffer_append(&find_op, slots_in, "verts",
254
dupe_op, slots_out, dupe_slot_name);
242
260
/* transform and tag verts */
243
261
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
250
268
BMO_op_exec(bm, &find_op);
270
slot_targetmap = BMO_slot_get(weld_op->slots_in, "targetmap");
252
272
/* add new merge targets to weld operator */
253
BMO_ITER (v, &oiter, bm, &find_op, "targetmapout", 0) {
273
BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) {
254
274
v2 = BMO_iter_map_value_p(&oiter);
255
BMO_slot_map_ptr_insert(bm, weld_op, "targetmap", v, v2);
275
/* check in case the target vertex (v2) is already marked
277
while ((v3 = BMO_slot_map_elem_get(slot_targetmap, v2))) {
280
BMO_slot_map_elem_insert(weld_op, slot_targetmap, v, v2);
258
283
BMO_op_finish(bm, &find_op);
271
static void merge_first_last(BMesh* bm,
272
const ArrayModifierData *amd,
273
BMOperator *dupe_first,
274
BMOperator *dupe_last,
296
static void merge_first_last(BMesh *bm,
297
const ArrayModifierData *amd,
298
BMOperator *dupe_first,
299
BMOperator *dupe_last,
277
302
BMOperator find_op;
305
BMOpSlot *slot_targetmap;
281
BMO_op_initf(bm, &find_op,
282
"finddoubles verts=%s dist=%f keepverts=%s",
283
dupe_first, "geom", amd->merge_dist,
307
BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
308
"find_doubles verts=%s dist=%f keep_verts=%s",
309
dupe_first, "geom", amd->merge_dist,
286
312
/* append the last dupe's geom to the findop input verts */
287
BMO_slot_buffer_append(&find_op, "verts", dupe_last, "newout");
313
BMO_slot_buffer_append(&find_op, slots_in, "verts",
314
dupe_last, slots_out, "geom.out");
289
316
BMO_op_exec(bm, &find_op);
291
318
/* add new merge targets to weld operator */
292
BMO_ITER (v, &oiter, bm, &find_op, "targetmapout", 0) {
319
slot_targetmap = BMO_slot_get(weld_op->slots_in, "targetmap");
320
BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) {
293
321
v2 = BMO_iter_map_value_p(&oiter);
294
BMO_slot_map_ptr_insert(bm, weld_op, "targetmap", v, v2);
322
BMO_slot_map_elem_insert(weld_op, slot_targetmap, v, v2);
297
325
BMO_op_finish(bm, &find_op);
302
330
int UNUSED(initFlags))
304
332
DerivedMesh *result;
305
BMEditMesh *em = DM_to_editbmesh(dm, NULL, FALSE);
333
BMesh *bm = DM_to_bmesh(dm);
306
334
BMOperator first_dupe_op, dupe_op, old_dupe_op, weld_op;
307
335
BMVert **first_geom = NULL;
337
int index_len = -1; /* initialize to an invalid value */
309
338
/* offset matrix */
310
339
float offset[4][4];
311
340
float final_offset[4][4];
356
385
float tmp_mat[3][3];
359
object_to_mat3(amd->curve_ob, tmp_mat);
388
BKE_object_to_mat3(amd->curve_ob, tmp_mat);
360
389
scale = mat3_to_scale(tmp_mat);
363
392
cu->flag |= CU_PATH; // needed for path & bevlist
364
makeDispListCurveTypes(scene, amd->curve_ob, 0);
393
BKE_displist_make_curveTypes(scene, amd->curve_ob, 0);
367
length = scale*cu->path->totdist;
396
length = scale * cu->path->totdist;
399
428
* cleaner way to do this. One possibility: a "mirror" BMOp would
400
429
* certainly help by compressing it all into one top-level BMOp that
401
430
* 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");
431
BM_mesh_elem_toolflags_ensure(bm);
433
bmesh_edit_begin(bm, 0);
435
if (amd->flags & MOD_ARR_MERGE) {
436
BMO_op_init(bm, &weld_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
439
slot_targetmap = BMO_slot_get(weld_op.slots_in, "targetmap");
442
BMO_op_initf(bm, &dupe_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
443
"duplicate geom=%avef");
409
444
first_dupe_op = dupe_op;
411
for (j=0; j < count - 1; j++) {
446
for (j = 0; j < count - 1; j++) {
412
447
BMVert *v, *v2, *v3;
413
448
BMOpSlot *geom_slot;
414
BMOpSlot *newout_slot;
449
BMOpSlot *geom_out_slot;
418
BMO_op_initf(em->bm, &dupe_op, "dupe geom=%s", &old_dupe_op, "newout");
419
BMO_op_exec(em->bm, &dupe_op);
453
BMO_op_initf(bm, &dupe_op,
454
(BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
455
"duplicate geom=%S", &old_dupe_op, "geom.out");
457
BMO_op_exec(bm, &dupe_op);
421
geom_slot = BMO_slot_get(&dupe_op, "geom");
422
newout_slot = BMO_slot_get(&dupe_op, "newout");
459
geom_slot = BMO_slot_get(dupe_op.slots_in, "geom");
460
geom_out_slot = BMO_slot_get(dupe_op.slots_out, "geom.out");
424
462
if ((amd->flags & MOD_ARR_MERGEFINAL) && j == 0) {
425
int first_geom_bytes = sizeof(BMVert*) * geom_slot->len;
463
int first_geom_bytes = sizeof(BMVert *) * geom_slot->len;
427
465
/* make a copy of the initial geometry ordering so the
428
466
* last duplicate can be merged into it */
433
471
/* apply transformation matrix */
434
BMO_ITER (v, &oiter, em->bm, &dupe_op, "newout", BM_VERT) {
472
BMO_ITER (v, &oiter, dupe_op.slots_out, "geom.out", BM_VERT) {
435
473
mul_m4_v3(offset, v->co);
438
476
if (amd->flags & MOD_ARR_MERGE) {
439
477
/*calculate merge mapping*/
441
indexMap = find_doubles_index_map(em->bm, &dupe_op,
479
indexMap = find_doubles_index_map(bm, &dupe_op,
445
483
#define _E(s, i) ((BMVert **)(s)->data.buf)[i]
447
for (i=0; i<indexLen; i++) {
485
/* ensure this is set */
486
BLI_assert(index_len != -1);
488
for (i = 0; i < index_len; i++) {
448
489
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);
491
/* merge v (from 'geom.out') into v2 (from old 'geom') */
492
v = _E(geom_out_slot, i - geom_slot->len);
493
v2 = _E(geom_slot, indexMap[i] - 1);
454
495
/* check in case the target vertex (v2) is already marked
456
while ((v3 = BMO_slot_map_ptr_get(em->bm, &weld_op, "targetmap", v2))) {
497
while ((v3 = BMO_slot_map_elem_get(slot_targetmap, v2))) {
460
BMO_slot_map_ptr_insert(em->bm, &weld_op, "targetmap", v, v2);
501
BMO_slot_map_elem_insert(&weld_op, slot_targetmap, v, v2);
482
523
* loop) the offset between first and last is different from
483
524
* dupe X to dupe X+1. */
485
merge_first_last(em->bm, amd, &first_dupe_op, &dupe_op, &weld_op);
526
merge_first_last(bm, amd, &first_dupe_op, &dupe_op, &weld_op);
488
529
/* start capping */
489
530
if (start_cap || end_cap) {
490
BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT, BM_ELEM_TAG, FALSE);
531
BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, FALSE);
493
534
float startoffset[4][4];
494
535
invert_m4_m4(startoffset, offset);
495
bm_merge_dm_transform(em->bm, start_cap, startoffset, amd,
496
&first_dupe_op, "geom", &weld_op);
536
bm_merge_dm_transform(bm, start_cap, startoffset, amd,
537
&first_dupe_op, first_dupe_op.slots_in, "geom", &weld_op);
500
541
float endoffset[4][4];
501
542
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);
543
bm_merge_dm_transform(bm, end_cap, endoffset, amd,
544
&dupe_op, (count == 1) ? dupe_op.slots_in : dupe_op.slots_out,
545
(count == 1) ? "geom" : "geom.out", &weld_op);
506
548
/* done capping */
508
550
/* free remaining dupe operators */
509
BMO_op_finish(em->bm, &first_dupe_op);
551
BMO_op_finish(bm, &first_dupe_op);
511
BMO_op_finish(em->bm, &dupe_op);
553
BMO_op_finish(bm, &dupe_op);
513
555
/* run merge operator */
514
556
if (amd->flags & MOD_ARR_MERGE) {
515
BMO_op_exec(em->bm, &weld_op);
516
BMO_op_finish(em->bm, &weld_op);
557
BMO_op_exec(bm, &weld_op);
558
BMO_op_finish(bm, &weld_op);
519
561
/* 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);
564
result = CDDM_from_bmesh(bm, FALSE);
525
566
if ((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
526
567
/* Update normals in case offset object has rotation. */
544
585
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
546
int UNUSED(useRenderParams),
547
int UNUSED(isFinalCalc))
587
ModifierApplyFlag UNUSED(flag))
549
589
DerivedMesh *result;
550
ArrayModifierData *amd = (ArrayModifierData*) md;
590
ArrayModifierData *amd = (ArrayModifierData *) md;
552
592
result = arrayModifier_doArray(amd, md->scene, ob, dm, 0);
560
600
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
561
struct BMEditMesh *UNUSED(editData),
601
struct BMEditMesh *UNUSED(editData),
564
return applyModifier(md, ob, dm, 0, 1);
604
return applyModifier(md, ob, dm, MOD_APPLY_USECACHE);
570
610
/* structName */ "ArrayModifierData",
571
611
/* structSize */ sizeof(ArrayModifierData),
572
612
/* type */ eModifierTypeType_Constructive,
573
/* flags */ eModifierTypeFlag_AcceptsMesh
574
| eModifierTypeFlag_SupportsMapping
575
| eModifierTypeFlag_SupportsEditmode
576
| eModifierTypeFlag_EnableInEditmode
577
| eModifierTypeFlag_AcceptsCVs,
613
/* flags */ eModifierTypeFlag_AcceptsMesh |
614
eModifierTypeFlag_SupportsMapping |
615
eModifierTypeFlag_SupportsEditmode |
616
eModifierTypeFlag_EnableInEditmode |
617
eModifierTypeFlag_AcceptsCVs,
579
619
/* copyData */ copyData,
580
620
/* deformVerts */ NULL,