2010-04-11 22:12:30 +00:00
|
|
|
/*
|
2011-10-23 17:52:20 +00:00
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s): Daniel Dunbar
|
|
|
|
* Ton Roosendaal,
|
|
|
|
* Ben Batt,
|
|
|
|
* Brecht Van Lommel,
|
|
|
|
* Campbell Barton
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
*/
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2011-12-29 04:04:27 +00:00
|
|
|
/** \file blender/modifiers/intern/MOD_array.c
|
|
|
|
* \ingroup modifiers
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2010-04-12 22:33:43 +00:00
|
|
|
/* Array modifier: duplicates the object multiple times along an axis */
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2010-08-16 05:46:10 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2011-12-29 04:04:27 +00:00
|
|
|
#include "BLI_math.h"
|
2011-05-09 04:06:48 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2011-11-16 19:06:38 +00:00
|
|
|
#include "BLI_string.h"
|
2010-04-12 22:33:43 +00:00
|
|
|
#include "BLI_ghash.h"
|
|
|
|
#include "BLI_edgehash.h"
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2010-08-16 05:46:10 +00:00
|
|
|
#include "DNA_curve_types.h"
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
2012-02-11 10:15:11 +00:00
|
|
|
#include "DNA_scene_types.h"
|
2010-08-16 05:46:10 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
#include "BKE_cdderivedmesh.h"
|
|
|
|
#include "BKE_displist.h"
|
2013-08-19 09:25:24 +00:00
|
|
|
#include "BKE_curve.h"
|
2010-04-11 22:12:30 +00:00
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_modifier.h"
|
|
|
|
#include "BKE_object.h"
|
2012-10-24 07:24:11 +00:00
|
|
|
|
2013-12-26 17:24:42 +06:00
|
|
|
#include "MOD_util.h"
|
|
|
|
|
2012-10-24 07:24:11 +00:00
|
|
|
#include "bmesh.h"
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
#include "depsgraph_private.h"
|
|
|
|
|
2011-02-27 06:19:40 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2011-02-13 14:16:36 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
static void initData(ModifierData *md)
|
|
|
|
{
|
2012-05-06 13:38:33 +00:00
|
|
|
ArrayModifierData *amd = (ArrayModifierData *) md;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
/* default to 2 duplicates distributed along the x-axis by an
|
2012-03-09 18:28:30 +00:00
|
|
|
* offset of 1 object-width
|
|
|
|
*/
|
2010-04-11 22:12:30 +00:00
|
|
|
amd->start_cap = amd->end_cap = amd->curve_ob = amd->offset_ob = NULL;
|
|
|
|
amd->count = 2;
|
2012-03-23 20:18:09 +00:00
|
|
|
zero_v3(amd->offset);
|
2010-04-11 22:12:30 +00:00
|
|
|
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 copyData(ModifierData *md, ModifierData *target)
|
|
|
|
{
|
2013-12-22 04:35:52 +11:00
|
|
|
#if 0
|
2012-05-06 13:38:33 +00:00
|
|
|
ArrayModifierData *amd = (ArrayModifierData *) md;
|
|
|
|
ArrayModifierData *tamd = (ArrayModifierData *) target;
|
2013-12-22 04:35:52 +11:00
|
|
|
#endif
|
|
|
|
modifier_copyData_generic(md, target);
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void foreachObjectLink(
|
2012-05-06 13:38:33 +00:00
|
|
|
ModifierData *md, Object *ob,
|
|
|
|
void (*walk)(void *userData, Object *ob, Object **obpoin),
|
|
|
|
void *userData)
|
2010-04-11 22:12:30 +00:00
|
|
|
{
|
2012-05-06 13:38:33 +00:00
|
|
|
ArrayModifierData *amd = (ArrayModifierData *) md;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
walk(userData, ob, &amd->start_cap);
|
|
|
|
walk(userData, ob, &amd->end_cap);
|
|
|
|
walk(userData, ob, &amd->curve_ob);
|
|
|
|
walk(userData, ob, &amd->offset_ob);
|
|
|
|
}
|
|
|
|
|
2011-12-29 04:04:27 +00:00
|
|
|
static void updateDepgraph(ModifierData *md, DagForest *forest,
|
2012-05-06 13:38:33 +00:00
|
|
|
struct Scene *UNUSED(scene), Object *UNUSED(ob), DagNode *obNode)
|
2010-04-11 22:12:30 +00:00
|
|
|
{
|
2012-05-06 13:38:33 +00:00
|
|
|
ArrayModifierData *amd = (ArrayModifierData *) md;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
if (amd->start_cap) {
|
|
|
|
DagNode *curNode = dag_get_node(forest, amd->start_cap);
|
|
|
|
|
|
|
|
dag_add_relation(forest, curNode, obNode,
|
2011-11-11 13:09:14 +00:00
|
|
|
DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
if (amd->end_cap) {
|
|
|
|
DagNode *curNode = dag_get_node(forest, amd->end_cap);
|
|
|
|
|
|
|
|
dag_add_relation(forest, curNode, obNode,
|
2011-11-11 13:09:14 +00:00
|
|
|
DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
if (amd->curve_ob) {
|
|
|
|
DagNode *curNode = dag_get_node(forest, amd->curve_ob);
|
2014-01-10 02:10:43 +06:00
|
|
|
curNode->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
dag_add_relation(forest, curNode, obNode,
|
2011-11-11 13:09:14 +00:00
|
|
|
DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
if (amd->offset_ob) {
|
|
|
|
DagNode *curNode = dag_get_node(forest, amd->offset_ob);
|
|
|
|
|
|
|
|
dag_add_relation(forest, curNode, obNode,
|
2011-11-11 13:09:14 +00:00
|
|
|
DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static float vertarray_size(MVert *mvert, int numVerts, int axis)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
float min_co, max_co;
|
|
|
|
|
|
|
|
/* if there are no vertices, width is 0 */
|
2012-03-24 06:24:53 +00:00
|
|
|
if (numVerts == 0) return 0;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
/* find the minimum and maximum coordinates on the desired axis */
|
|
|
|
min_co = max_co = mvert->co[axis];
|
2012-05-09 09:24:15 +00:00
|
|
|
mvert++;
|
2012-03-24 06:24:53 +00:00
|
|
|
for (i = 1; i < numVerts; ++i, ++mvert) {
|
|
|
|
if (mvert->co[axis] < min_co) min_co = mvert->co[axis];
|
|
|
|
if (mvert->co[axis] > max_co) max_co = mvert->co[axis];
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return max_co - min_co;
|
|
|
|
}
|
|
|
|
|
2012-03-28 22:03:46 +00:00
|
|
|
static int *find_doubles_index_map(BMesh *bm, BMOperator *dupe_op,
|
2012-05-06 13:38:33 +00:00
|
|
|
const ArrayModifierData *amd,
|
|
|
|
int *index_map_length)
|
2012-03-28 22:03:46 +00:00
|
|
|
{
|
|
|
|
BMOperator find_op;
|
|
|
|
BMOIter oiter;
|
|
|
|
BMVert *v, *v2;
|
|
|
|
BMElem *ele;
|
|
|
|
int *index_map, i;
|
|
|
|
|
2012-07-21 00:58:02 +00:00
|
|
|
BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
|
2012-06-30 15:27:13 +00:00
|
|
|
"find_doubles verts=%av dist=%f keep_verts=%s",
|
2012-05-06 13:38:33 +00:00
|
|
|
amd->merge_dist, dupe_op, "geom");
|
2012-03-28 22:03:46 +00:00
|
|
|
|
|
|
|
BMO_op_exec(bm, &find_op);
|
2012-11-19 14:58:31 +00:00
|
|
|
|
2012-03-28 22:03:46 +00:00
|
|
|
i = 0;
|
2012-11-19 14:58:31 +00:00
|
|
|
BMO_ITER (ele, &oiter, dupe_op->slots_in, "geom", BM_ALL) {
|
2012-03-28 22:03:46 +00:00
|
|
|
BM_elem_index_set(ele, i); /* set_dirty */
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_ITER (ele, &oiter, dupe_op->slots_out, "geom.out", BM_ALL) {
|
2012-03-28 22:03:46 +00:00
|
|
|
BM_elem_index_set(ele, i); /* set_dirty */
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
/* above loops over all, so set all to dirty, if this is somehow
|
2012-07-16 23:23:33 +00:00
|
|
|
* setting valid values, this line can be removed - campbell */
|
2012-03-28 22:03:46 +00:00
|
|
|
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
|
|
|
|
|
|
|
|
(*index_map_length) = i;
|
|
|
|
index_map = MEM_callocN(sizeof(int) * (*index_map_length), "index_map");
|
|
|
|
|
|
|
|
/*element type argument doesn't do anything here*/
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) {
|
2013-09-02 03:13:51 +00:00
|
|
|
v2 = BMO_iter_map_value_ptr(&oiter);
|
2012-03-28 22:03:46 +00:00
|
|
|
|
|
|
|
index_map[BM_elem_index_get(v)] = BM_elem_index_get(v2) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
BMO_op_finish(bm, &find_op);
|
|
|
|
|
|
|
|
return index_map;
|
|
|
|
}
|
|
|
|
|
2012-03-30 17:30:56 +00:00
|
|
|
/* Used for start/end cap.
|
|
|
|
*
|
|
|
|
* this function expects all existing vertices to be tagged,
|
|
|
|
* so we can know new verts are not tagged.
|
|
|
|
*
|
|
|
|
* All verts will be tagged on exit.
|
|
|
|
*/
|
2012-05-06 13:38:33 +00:00
|
|
|
static void bm_merge_dm_transform(BMesh *bm, DerivedMesh *dm, float mat[4][4],
|
|
|
|
const ArrayModifierData *amd,
|
|
|
|
BMOperator *dupe_op,
|
2012-11-19 14:58:31 +00:00
|
|
|
BMOpSlot dupe_op_slot_args[BMO_OP_MAX_SLOTS], const char *dupe_slot_name,
|
2012-05-06 13:38:33 +00:00
|
|
|
BMOperator *weld_op)
|
2012-03-30 17:30:56 +00:00
|
|
|
{
|
2014-01-28 03:52:21 +11:00
|
|
|
const bool is_input = (dupe_op->slots_in == dupe_op_slot_args);
|
2012-06-11 09:41:08 +00:00
|
|
|
BMVert *v, *v2, *v3;
|
2012-03-30 17:30:56 +00:00
|
|
|
BMIter iter;
|
|
|
|
|
2012-06-11 09:41:08 +00:00
|
|
|
/* Add the DerivedMesh's elements to the BMesh. The pre-existing
|
2012-06-30 22:49:33 +00:00
|
|
|
* elements were already tagged, so the new elements can be
|
|
|
|
* identified by not having the BM_ELEM_TAG flag set. */
|
2013-06-02 23:20:49 +00:00
|
|
|
DM_to_bmesh_ex(dm, bm, false);
|
2012-03-30 17:30:56 +00:00
|
|
|
|
|
|
|
if (amd->flags & MOD_ARR_MERGE) {
|
|
|
|
/* if merging is enabled, find doubles */
|
|
|
|
|
|
|
|
BMOIter oiter;
|
|
|
|
BMOperator find_op;
|
2012-11-20 13:29:27 +00:00
|
|
|
BMOpSlot *slot_targetmap;
|
2012-03-30 17:30:56 +00:00
|
|
|
|
2012-07-21 00:58:02 +00:00
|
|
|
BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
|
2012-11-19 14:58:31 +00:00
|
|
|
is_input ? /* ugh */
|
|
|
|
"find_doubles verts=%Hv dist=%f keep_verts=%s" :
|
|
|
|
"find_doubles verts=%Hv dist=%f keep_verts=%S",
|
2012-05-06 13:38:33 +00:00
|
|
|
BM_ELEM_TAG, amd->merge_dist,
|
|
|
|
dupe_op, dupe_slot_name);
|
2012-03-30 17:30:56 +00:00
|
|
|
|
|
|
|
/* append the dupe's geom to the findop input verts */
|
2012-11-19 14:58:31 +00:00
|
|
|
if (is_input) {
|
|
|
|
BMO_slot_buffer_append(&find_op, slots_in, "verts",
|
|
|
|
dupe_op, slots_in, dupe_slot_name);
|
|
|
|
}
|
|
|
|
else if (dupe_op->slots_out == dupe_op_slot_args) {
|
|
|
|
BMO_slot_buffer_append(&find_op, slots_in, "verts",
|
|
|
|
dupe_op, slots_out, dupe_slot_name);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_assert(0);
|
|
|
|
}
|
2012-03-30 17:30:56 +00:00
|
|
|
|
|
|
|
/* transform and tag verts */
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
2012-03-30 17:30:56 +00:00
|
|
|
if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
|
|
|
|
mul_m4_v3(mat, v->co);
|
|
|
|
BM_elem_flag_enable(v, BM_ELEM_TAG);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BMO_op_exec(bm, &find_op);
|
|
|
|
|
2012-11-20 13:29:27 +00:00
|
|
|
slot_targetmap = BMO_slot_get(weld_op->slots_in, "targetmap");
|
|
|
|
|
2012-03-30 17:30:56 +00:00
|
|
|
/* add new merge targets to weld operator */
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) {
|
2013-09-02 03:13:51 +00:00
|
|
|
v2 = BMO_iter_map_value_ptr(&oiter);
|
2012-06-11 09:41:08 +00:00
|
|
|
/* check in case the target vertex (v2) is already marked
|
|
|
|
* for merging */
|
2012-11-26 03:16:29 +00:00
|
|
|
while ((v3 = BMO_slot_map_elem_get(slot_targetmap, v2))) {
|
2012-06-11 09:41:08 +00:00
|
|
|
v2 = v3;
|
|
|
|
}
|
2012-11-26 03:16:29 +00:00
|
|
|
BMO_slot_map_elem_insert(weld_op, slot_targetmap, v, v2);
|
2012-03-30 17:30:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BMO_op_finish(bm, &find_op);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* transform and tag verts */
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
2012-03-30 17:30:56 +00:00
|
|
|
if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
|
|
|
|
mul_m4_v3(mat, v->co);
|
|
|
|
BM_elem_flag_enable(v, BM_ELEM_TAG);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
static void merge_first_last(BMesh *bm,
|
|
|
|
const ArrayModifierData *amd,
|
|
|
|
BMOperator *dupe_first,
|
|
|
|
BMOperator *dupe_last,
|
|
|
|
BMOperator *weld_op)
|
2012-03-30 17:30:56 +00:00
|
|
|
{
|
|
|
|
BMOperator find_op;
|
|
|
|
BMOIter oiter;
|
|
|
|
BMVert *v, *v2;
|
2012-11-20 13:29:27 +00:00
|
|
|
BMOpSlot *slot_targetmap;
|
2012-03-30 17:30:56 +00:00
|
|
|
|
2012-07-21 00:58:02 +00:00
|
|
|
BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
|
2012-06-30 15:27:13 +00:00
|
|
|
"find_doubles verts=%s dist=%f keep_verts=%s",
|
2012-05-06 13:38:33 +00:00
|
|
|
dupe_first, "geom", amd->merge_dist,
|
|
|
|
dupe_first, "geom");
|
2012-03-30 17:30:56 +00:00
|
|
|
|
|
|
|
/* append the last dupe's geom to the findop input verts */
|
2012-11-19 14:58:31 +00:00
|
|
|
BMO_slot_buffer_append(&find_op, slots_in, "verts",
|
2012-11-20 05:50:19 +00:00
|
|
|
dupe_last, slots_out, "geom.out");
|
2012-03-30 17:30:56 +00:00
|
|
|
|
|
|
|
BMO_op_exec(bm, &find_op);
|
|
|
|
|
|
|
|
/* add new merge targets to weld operator */
|
2012-11-22 12:03:15 +00:00
|
|
|
slot_targetmap = BMO_slot_get(weld_op->slots_in, "targetmap");
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) {
|
2013-08-27 23:32:11 +00:00
|
|
|
if (!BMO_slot_map_contains(slot_targetmap, v)) {
|
2013-09-02 03:13:51 +00:00
|
|
|
v2 = BMO_iter_map_value_ptr(&oiter);
|
2013-08-27 23:32:11 +00:00
|
|
|
BMO_slot_map_elem_insert(weld_op, slot_targetmap, v, v2);
|
|
|
|
}
|
2012-03-30 17:30:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BMO_op_finish(bm, &find_op);
|
|
|
|
}
|
2012-03-28 22:03:46 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
|
2014-01-10 02:10:43 +06:00
|
|
|
Object *ob, DerivedMesh *dm,
|
2013-12-26 17:24:42 +06:00
|
|
|
ModifierApplyFlag flag)
|
2010-04-11 22:12:30 +00:00
|
|
|
{
|
2012-02-12 15:02:33 +00:00
|
|
|
DerivedMesh *result;
|
2013-06-02 23:20:49 +00:00
|
|
|
BMesh *bm = DM_to_bmesh(dm, false);
|
2012-03-30 17:30:56 +00:00
|
|
|
BMOperator first_dupe_op, dupe_op, old_dupe_op, weld_op;
|
2012-03-29 20:58:25 +00:00
|
|
|
BMVert **first_geom = NULL;
|
2012-10-29 15:43:54 +00:00
|
|
|
int i, j;
|
|
|
|
int index_len = -1; /* initialize to an invalid value */
|
2010-04-11 22:12:30 +00:00
|
|
|
/* offset matrix */
|
|
|
|
float offset[4][4];
|
2012-02-13 08:06:44 +00:00
|
|
|
float final_offset[4][4];
|
2010-04-11 22:12:30 +00:00
|
|
|
float length = amd->length;
|
2010-07-19 04:44:37 +00:00
|
|
|
int count = amd->count, maxVerts;
|
|
|
|
int *indexMap = NULL;
|
|
|
|
DerivedMesh *start_cap = NULL, *end_cap = NULL;
|
|
|
|
MVert *src_mvert;
|
2013-08-27 23:32:11 +00:00
|
|
|
BMOpSlot *slot_targetmap = NULL; /* for weld_op */
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
/* need to avoid infinite recursion here */
|
2013-05-12 09:14:07 +00:00
|
|
|
if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH)
|
2013-12-26 17:24:42 +06:00
|
|
|
start_cap = get_dm_for_modifier(amd->start_cap, flag);
|
2013-05-12 09:14:07 +00:00
|
|
|
if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH)
|
2013-12-26 17:24:42 +06:00
|
|
|
end_cap = get_dm_for_modifier(amd->end_cap, flag);
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
unit_m4(offset);
|
|
|
|
|
2012-02-12 15:02:33 +00:00
|
|
|
src_mvert = dm->getVertArray(dm);
|
|
|
|
maxVerts = dm->getNumVerts(dm);
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (amd->offset_type & MOD_ARR_OFF_CONST)
|
2010-07-19 04:44:37 +00:00
|
|
|
add_v3_v3v3(offset[3], offset[3], amd->offset);
|
2012-03-24 06:24:53 +00:00
|
|
|
if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
|
|
|
|
for (j = 0; j < 3; j++)
|
2012-05-06 13:38:33 +00:00
|
|
|
offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, maxVerts, j);
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if ((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
|
2010-04-11 22:12:30 +00:00
|
|
|
float obinv[4][4];
|
|
|
|
float result_mat[4][4];
|
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (ob)
|
2010-04-11 22:12:30 +00:00
|
|
|
invert_m4_m4(obinv, ob->obmat);
|
|
|
|
else
|
|
|
|
unit_m4(obinv);
|
|
|
|
|
|
|
|
mul_serie_m4(result_mat, offset,
|
2011-11-11 13:09:14 +00:00
|
|
|
obinv, amd->offset_ob->obmat,
|
|
|
|
NULL, NULL, NULL, NULL, NULL);
|
2010-04-11 22:12:30 +00:00
|
|
|
copy_m4_m4(offset, result_mat);
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
|
2010-04-11 22:12:30 +00:00
|
|
|
Curve *cu = amd->curve_ob->data;
|
2012-03-24 06:24:53 +00:00
|
|
|
if (cu) {
|
2013-11-18 14:02:49 +13:00
|
|
|
if (amd->curve_ob->curve_cache->path) {
|
|
|
|
float scale = mat4_to_scale(amd->curve_ob->obmat);
|
2013-08-19 09:25:24 +00:00
|
|
|
length = scale * amd->curve_ob->curve_cache->path->totdist;
|
2013-11-18 14:02:49 +13:00
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate the maximum number of copies which will fit within the
|
2012-03-09 18:28:30 +00:00
|
|
|
* prescribed length */
|
2012-04-21 15:11:03 +00:00
|
|
|
if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) {
|
2013-09-03 22:32:03 +00:00
|
|
|
float dist = len_v3(offset[3]);
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (dist > 1e-6f)
|
2010-04-11 22:12:30 +00:00
|
|
|
/* this gives length = first copy start to last copy end
|
2012-03-09 18:28:30 +00:00
|
|
|
* add a tiny offset for floating point rounding errors */
|
2010-04-11 22:12:30 +00:00
|
|
|
count = (length + 1e-6f) / dist;
|
|
|
|
else
|
|
|
|
/* if the offset has no translation, just make one copy */
|
|
|
|
count = 1;
|
2010-07-19 04:44:37 +00:00
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (count < 1)
|
2010-07-19 04:44:37 +00:00
|
|
|
count = 1;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2012-03-26 19:50:45 +00:00
|
|
|
/* calculate the offset matrix of the final copy (for merging) */
|
|
|
|
unit_m4(final_offset);
|
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
for (j = 0; j < count - 1; j++) {
|
2013-03-17 10:26:23 +00:00
|
|
|
float tmp_mat[4][4];
|
2013-05-26 18:36:25 +00:00
|
|
|
mul_m4_m4m4(tmp_mat, offset, final_offset);
|
2012-03-26 19:50:45 +00:00
|
|
|
copy_m4_m4(final_offset, tmp_mat);
|
|
|
|
}
|
|
|
|
|
2011-10-27 17:39:15 +00:00
|
|
|
/* BMESH_TODO: bumping up the stack level avoids computing the normals
|
2012-03-09 18:28:30 +00:00
|
|
|
* after every top-level operator execution (and this modifier has the
|
|
|
|
* potential to execute a *lot* of top-level BMOps. There should be a
|
|
|
|
* cleaner way to do this. One possibility: a "mirror" BMOp would
|
|
|
|
* certainly help by compressing it all into one top-level BMOp that
|
|
|
|
* executes a lot of second-level BMOps. */
|
2012-11-18 12:14:22 +00:00
|
|
|
BM_mesh_elem_toolflags_ensure(bm);
|
2012-10-24 07:24:11 +00:00
|
|
|
BMO_push(bm, NULL);
|
|
|
|
bmesh_edit_begin(bm, 0);
|
2011-10-27 17:39:15 +00:00
|
|
|
|
2012-11-20 13:29:27 +00:00
|
|
|
if (amd->flags & MOD_ARR_MERGE) {
|
2012-10-24 07:24:11 +00:00
|
|
|
BMO_op_init(bm, &weld_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
|
2012-07-21 00:58:02 +00:00
|
|
|
"weld_verts");
|
2012-03-30 17:30:56 +00:00
|
|
|
|
2012-11-20 13:29:27 +00:00
|
|
|
slot_targetmap = BMO_slot_get(weld_op.slots_in, "targetmap");
|
|
|
|
}
|
|
|
|
|
2012-10-24 07:24:11 +00:00
|
|
|
BMO_op_initf(bm, &dupe_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
|
2012-07-21 00:58:02 +00:00
|
|
|
"duplicate geom=%avef");
|
2012-03-30 17:30:56 +00:00
|
|
|
first_dupe_op = dupe_op;
|
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
for (j = 0; j < count - 1; j++) {
|
2012-03-28 22:03:46 +00:00
|
|
|
BMVert *v, *v2, *v3;
|
2012-03-29 20:58:25 +00:00
|
|
|
BMOpSlot *geom_slot;
|
2012-11-20 05:50:19 +00:00
|
|
|
BMOpSlot *geom_out_slot;
|
2012-03-31 12:29:41 +00:00
|
|
|
BMOIter oiter;
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2012-07-21 00:58:02 +00:00
|
|
|
if (j != 0) {
|
2012-10-24 07:24:11 +00:00
|
|
|
BMO_op_initf(bm, &dupe_op,
|
2012-07-21 00:58:02 +00:00
|
|
|
(BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
|
2012-11-20 05:50:19 +00:00
|
|
|
"duplicate geom=%S", &old_dupe_op, "geom.out");
|
2012-07-21 00:58:02 +00:00
|
|
|
}
|
2012-10-24 07:24:11 +00:00
|
|
|
BMO_op_exec(bm, &dupe_op);
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2012-11-19 14:58:31 +00:00
|
|
|
geom_slot = BMO_slot_get(dupe_op.slots_in, "geom");
|
2012-11-20 05:50:19 +00:00
|
|
|
geom_out_slot = BMO_slot_get(dupe_op.slots_out, "geom.out");
|
2012-03-29 20:58:25 +00:00
|
|
|
|
|
|
|
if ((amd->flags & MOD_ARR_MERGEFINAL) && j == 0) {
|
2012-05-06 13:38:33 +00:00
|
|
|
int first_geom_bytes = sizeof(BMVert *) * geom_slot->len;
|
2012-03-29 20:58:25 +00:00
|
|
|
|
|
|
|
/* make a copy of the initial geometry ordering so the
|
2012-04-22 11:54:53 +00:00
|
|
|
* last duplicate can be merged into it */
|
2012-03-29 20:58:25 +00:00
|
|
|
first_geom = MEM_mallocN(first_geom_bytes, "first_geom");
|
|
|
|
memcpy(first_geom, geom_slot->data.buf, first_geom_bytes);
|
|
|
|
}
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2012-03-31 12:29:41 +00:00
|
|
|
/* apply transformation matrix */
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_ITER (v, &oiter, dupe_op.slots_out, "geom.out", BM_VERT) {
|
2012-03-31 12:29:41 +00:00
|
|
|
mul_m4_v3(offset, v->co);
|
|
|
|
}
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2012-03-29 11:31:44 +00:00
|
|
|
if (amd->flags & MOD_ARR_MERGE) {
|
|
|
|
/*calculate merge mapping*/
|
|
|
|
if (j == 0) {
|
2012-10-24 07:24:11 +00:00
|
|
|
indexMap = find_doubles_index_map(bm, &dupe_op,
|
2012-10-29 15:43:54 +00:00
|
|
|
amd, &index_len);
|
2012-03-29 11:31:44 +00:00
|
|
|
}
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#define _E(s, i) ((BMVert **)(s)->data.buf)[i]
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2012-10-29 15:43:54 +00:00
|
|
|
/* ensure this is set */
|
|
|
|
BLI_assert(index_len != -1);
|
|
|
|
|
|
|
|
for (i = 0; i < index_len; i++) {
|
2012-03-29 11:31:44 +00:00
|
|
|
if (!indexMap[i]) continue;
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2012-11-20 05:50:19 +00:00
|
|
|
/* merge v (from 'geom.out') into v2 (from old 'geom') */
|
|
|
|
v = _E(geom_out_slot, i - geom_slot->len);
|
2012-05-06 13:38:33 +00:00
|
|
|
v2 = _E(geom_slot, indexMap[i] - 1);
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2012-03-29 11:31:44 +00:00
|
|
|
/* check in case the target vertex (v2) is already marked
|
2012-04-21 12:51:47 +00:00
|
|
|
* for merging */
|
2012-11-26 03:16:29 +00:00
|
|
|
while ((v3 = BMO_slot_map_elem_get(slot_targetmap, v2))) {
|
2012-03-29 11:31:44 +00:00
|
|
|
v2 = v3;
|
2012-04-21 12:51:47 +00:00
|
|
|
}
|
2012-03-28 22:03:46 +00:00
|
|
|
|
2012-11-26 03:16:29 +00:00
|
|
|
BMO_slot_map_elem_insert(&weld_op, slot_targetmap, v, v2);
|
2012-03-29 11:31:44 +00:00
|
|
|
}
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#undef _E
|
2012-03-29 11:31:44 +00:00
|
|
|
}
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2012-03-30 17:30:56 +00:00
|
|
|
/* already copied earlier, but after executation more slot
|
2012-04-22 11:54:53 +00:00
|
|
|
* memory may be allocated */
|
2012-03-30 17:30:56 +00:00
|
|
|
if (j == 0)
|
|
|
|
first_dupe_op = dupe_op;
|
|
|
|
|
|
|
|
if (j >= 2)
|
2012-10-24 07:24:11 +00:00
|
|
|
BMO_op_finish(bm, &old_dupe_op);
|
2012-03-28 22:03:46 +00:00
|
|
|
old_dupe_op = dupe_op;
|
2010-07-19 04:44:37 +00:00
|
|
|
}
|
|
|
|
|
2012-03-30 17:30:56 +00:00
|
|
|
if ((amd->flags & MOD_ARR_MERGE) &&
|
2012-04-02 04:45:44 +00:00
|
|
|
(amd->flags & MOD_ARR_MERGEFINAL) &&
|
|
|
|
(count > 1))
|
|
|
|
{
|
2012-03-30 17:30:56 +00:00
|
|
|
/* Merge first and last copies. Note that we can't use the
|
2012-04-02 04:45:44 +00:00
|
|
|
* indexMap for this because (unless the array is forming a
|
|
|
|
* loop) the offset between first and last is different from
|
|
|
|
* dupe X to dupe X+1. */
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2012-10-24 07:24:11 +00:00
|
|
|
merge_first_last(bm, amd, &first_dupe_op, &dupe_op, &weld_op);
|
2012-03-30 17:30:56 +00:00
|
|
|
}
|
2012-02-13 08:06:44 +00:00
|
|
|
|
|
|
|
/* start capping */
|
2012-04-02 04:45:44 +00:00
|
|
|
if (start_cap || end_cap) {
|
2012-10-24 07:24:11 +00:00
|
|
|
BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, FALSE);
|
2012-02-13 08:06:44 +00:00
|
|
|
|
|
|
|
if (start_cap) {
|
|
|
|
float startoffset[4][4];
|
|
|
|
invert_m4_m4(startoffset, offset);
|
2012-10-24 07:24:11 +00:00
|
|
|
bm_merge_dm_transform(bm, start_cap, startoffset, amd,
|
2012-11-19 14:58:31 +00:00
|
|
|
&first_dupe_op, first_dupe_op.slots_in, "geom", &weld_op);
|
2012-02-13 08:06:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (end_cap) {
|
|
|
|
float endoffset[4][4];
|
2013-05-26 18:36:25 +00:00
|
|
|
mul_m4_m4m4(endoffset, offset, final_offset);
|
2012-10-24 07:24:11 +00:00
|
|
|
bm_merge_dm_transform(bm, end_cap, endoffset, amd,
|
2012-11-19 14:58:31 +00:00
|
|
|
&dupe_op, (count == 1) ? dupe_op.slots_in : dupe_op.slots_out,
|
2012-11-20 05:50:19 +00:00
|
|
|
(count == 1) ? "geom" : "geom.out", &weld_op);
|
2012-02-13 08:06:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* done capping */
|
|
|
|
|
2012-03-30 17:30:56 +00:00
|
|
|
/* free remaining dupe operators */
|
2012-10-24 07:24:11 +00:00
|
|
|
BMO_op_finish(bm, &first_dupe_op);
|
2012-03-30 17:30:56 +00:00
|
|
|
if (count > 2)
|
2012-10-24 07:24:11 +00:00
|
|
|
BMO_op_finish(bm, &dupe_op);
|
2012-03-30 17:30:56 +00:00
|
|
|
|
|
|
|
/* run merge operator */
|
2012-03-29 11:31:44 +00:00
|
|
|
if (amd->flags & MOD_ARR_MERGE) {
|
2012-10-24 07:24:11 +00:00
|
|
|
BMO_op_exec(bm, &weld_op);
|
|
|
|
BMO_op_finish(bm, &weld_op);
|
2012-03-29 11:31:44 +00:00
|
|
|
}
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2011-10-27 17:39:15 +00:00
|
|
|
/* Bump the stack level back down to match the adjustment up above */
|
2012-10-24 07:24:11 +00:00
|
|
|
BMO_pop(bm);
|
2011-10-27 17:39:15 +00:00
|
|
|
|
2014-01-23 14:50:50 +01:00
|
|
|
result = CDDM_from_bmesh(bm, false);
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2013-06-02 00:20:26 +00:00
|
|
|
if ((dm->dirty & DM_DIRTY_NORMALS) ||
|
|
|
|
((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)))
|
|
|
|
{
|
2012-03-27 13:08:40 +00:00
|
|
|
/* Update normals in case offset object has rotation. */
|
2013-05-30 17:36:43 +00:00
|
|
|
result->dirty |= DM_DIRTY_NORMALS;
|
2012-03-27 13:08:40 +00:00
|
|
|
}
|
|
|
|
|
2012-10-24 07:24:11 +00:00
|
|
|
BM_mesh_free(bm);
|
|
|
|
|
2012-03-26 19:44:25 +00:00
|
|
|
if (indexMap)
|
|
|
|
MEM_freeN(indexMap);
|
2012-03-29 20:58:25 +00:00
|
|
|
if (first_geom)
|
|
|
|
MEM_freeN(first_geom);
|
2010-07-19 04:44:37 +00:00
|
|
|
|
2012-02-12 15:02:33 +00:00
|
|
|
return result;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2011-12-29 04:04:27 +00:00
|
|
|
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
|
2012-05-06 13:38:33 +00:00
|
|
|
DerivedMesh *dm,
|
2013-12-26 17:24:42 +06:00
|
|
|
ModifierApplyFlag flag)
|
2010-04-11 22:12:30 +00:00
|
|
|
{
|
|
|
|
DerivedMesh *result;
|
2012-05-06 13:38:33 +00:00
|
|
|
ArrayModifierData *amd = (ArrayModifierData *) md;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2014-01-10 02:10:43 +06:00
|
|
|
result = arrayModifier_doArray(amd, ob, dm, flag);
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ModifierTypeInfo modifierType_Array = {
|
|
|
|
/* name */ "Array",
|
|
|
|
/* structName */ "ArrayModifierData",
|
|
|
|
/* structSize */ sizeof(ArrayModifierData),
|
|
|
|
/* type */ eModifierTypeType_Constructive,
|
2012-05-06 13:38:33 +00:00
|
|
|
/* flags */ eModifierTypeFlag_AcceptsMesh |
|
|
|
|
eModifierTypeFlag_SupportsMapping |
|
|
|
|
eModifierTypeFlag_SupportsEditmode |
|
|
|
|
eModifierTypeFlag_EnableInEditmode |
|
|
|
|
eModifierTypeFlag_AcceptsCVs,
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
/* copyData */ copyData,
|
2011-03-05 10:29:10 +00:00
|
|
|
/* deformVerts */ NULL,
|
|
|
|
/* deformMatrices */ NULL,
|
|
|
|
/* deformVertsEM */ NULL,
|
|
|
|
/* deformMatricesEM */ NULL,
|
2010-04-11 22:12:30 +00:00
|
|
|
/* applyModifier */ applyModifier,
|
2013-05-02 14:42:05 +00:00
|
|
|
/* applyModifierEM */ NULL,
|
2010-04-11 22:12:30 +00:00
|
|
|
/* initData */ initData,
|
2011-03-05 10:29:10 +00:00
|
|
|
/* requiredDataMask */ NULL,
|
|
|
|
/* freeData */ NULL,
|
|
|
|
/* isDisabled */ NULL,
|
2010-04-11 22:12:30 +00:00
|
|
|
/* updateDepgraph */ updateDepgraph,
|
2011-03-05 10:29:10 +00:00
|
|
|
/* dependsOnTime */ NULL,
|
|
|
|
/* dependsOnNormals */ NULL,
|
2010-04-11 22:12:30 +00:00
|
|
|
/* foreachObjectLink */ foreachObjectLink,
|
2011-03-05 10:29:10 +00:00
|
|
|
/* foreachIDLink */ NULL,
|
2011-08-12 18:11:22 +00:00
|
|
|
/* foreachTexLink */ NULL,
|
2010-04-11 22:12:30 +00:00
|
|
|
};
|