Blender  V2.59
MOD_array.c
Go to the documentation of this file.
00001 /*
00002 * $Id: MOD_array.c 36276 2011-04-21 15:53:30Z campbellbarton $
00003 *
00004 * ***** BEGIN GPL LICENSE BLOCK *****
00005 *
00006 * This program is free software; you can redistribute it and/or
00007 * modify it under the terms of the GNU General Public License
00008 * as published by the Free Software Foundation; either version 2
00009 * of the License, or (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU General Public License
00017 * along with this program; if not, write to the Free Software  Foundation,
00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 *
00020 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
00021 * All rights reserved.
00022 *
00023 * Contributor(s): Daniel Dunbar
00024 *                 Ton Roosendaal,
00025 *                 Ben Batt,
00026 *                 Brecht Van Lommel,
00027 *                 Campbell Barton
00028 *
00029 * ***** END GPL LICENSE BLOCK *****
00030 *
00031 */
00032 
00038 /* Array modifier: duplicates the object multiple times along an axis */
00039 
00040 #include "MEM_guardedalloc.h"
00041 
00042 #include "BLI_math.h"
00043 #include "BLI_utildefines.h"
00044 #include "BLI_ghash.h"
00045 #include "BLI_edgehash.h"
00046 
00047 #include "DNA_curve_types.h"
00048 #include "DNA_meshdata_types.h"
00049 #include "DNA_object_types.h"
00050 
00051 #include "BKE_cdderivedmesh.h"
00052 #include "BKE_displist.h"
00053 #include "BKE_mesh.h"
00054 #include "BKE_modifier.h"
00055 #include "BKE_object.h"
00056 
00057 #include "depsgraph_private.h"
00058 
00059 #include "MOD_util.h"
00060 
00061 static void initData(ModifierData *md)
00062 {
00063         ArrayModifierData *amd = (ArrayModifierData*) md;
00064 
00065         /* default to 2 duplicates distributed along the x-axis by an
00066         offset of 1 object-width
00067         */
00068         amd->start_cap = amd->end_cap = amd->curve_ob = amd->offset_ob = NULL;
00069         amd->count = 2;
00070         amd->offset[0] = amd->offset[1] = amd->offset[2] = 0;
00071         amd->scale[0] = 1;
00072         amd->scale[1] = amd->scale[2] = 0;
00073         amd->length = 0;
00074         amd->merge_dist = 0.01;
00075         amd->fit_type = MOD_ARR_FIXEDCOUNT;
00076         amd->offset_type = MOD_ARR_OFF_RELATIVE;
00077         amd->flags = 0;
00078 }
00079 
00080 static void copyData(ModifierData *md, ModifierData *target)
00081 {
00082         ArrayModifierData *amd = (ArrayModifierData*) md;
00083         ArrayModifierData *tamd = (ArrayModifierData*) target;
00084 
00085         tamd->start_cap = amd->start_cap;
00086         tamd->end_cap = amd->end_cap;
00087         tamd->curve_ob = amd->curve_ob;
00088         tamd->offset_ob = amd->offset_ob;
00089         tamd->count = amd->count;
00090         copy_v3_v3(tamd->offset, amd->offset);
00091         copy_v3_v3(tamd->scale, amd->scale);
00092         tamd->length = amd->length;
00093         tamd->merge_dist = amd->merge_dist;
00094         tamd->fit_type = amd->fit_type;
00095         tamd->offset_type = amd->offset_type;
00096         tamd->flags = amd->flags;
00097 }
00098 
00099 static void foreachObjectLink(
00100                                                 ModifierData *md, Object *ob,
00101          void (*walk)(void *userData, Object *ob, Object **obpoin),
00102                 void *userData)
00103 {
00104         ArrayModifierData *amd = (ArrayModifierData*) md;
00105 
00106         walk(userData, ob, &amd->start_cap);
00107         walk(userData, ob, &amd->end_cap);
00108         walk(userData, ob, &amd->curve_ob);
00109         walk(userData, ob, &amd->offset_ob);
00110 }
00111 
00112 static void updateDepgraph(ModifierData *md, DagForest *forest,
00113         struct Scene *UNUSED(scene), Object *UNUSED(ob), DagNode *obNode)
00114 {
00115         ArrayModifierData *amd = (ArrayModifierData*) md;
00116 
00117         if (amd->start_cap) {
00118                 DagNode *curNode = dag_get_node(forest, amd->start_cap);
00119 
00120                 dag_add_relation(forest, curNode, obNode,
00121                                  DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
00122         }
00123         if (amd->end_cap) {
00124                 DagNode *curNode = dag_get_node(forest, amd->end_cap);
00125 
00126                 dag_add_relation(forest, curNode, obNode,
00127                                  DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
00128         }
00129         if (amd->curve_ob) {
00130                 DagNode *curNode = dag_get_node(forest, amd->curve_ob);
00131 
00132                 dag_add_relation(forest, curNode, obNode,
00133                                  DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
00134         }
00135         if (amd->offset_ob) {
00136                 DagNode *curNode = dag_get_node(forest, amd->offset_ob);
00137 
00138                 dag_add_relation(forest, curNode, obNode,
00139                                  DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
00140         }
00141 }
00142 
00143 static float vertarray_size(MVert *mvert, int numVerts, int axis)
00144 {
00145         int i;
00146         float min_co, max_co;
00147 
00148         /* if there are no vertices, width is 0 */
00149         if(numVerts == 0) return 0;
00150 
00151         /* find the minimum and maximum coordinates on the desired axis */
00152         min_co = max_co = mvert->co[axis];
00153         ++mvert;
00154         for(i = 1; i < numVerts; ++i, ++mvert) {
00155                 if(mvert->co[axis] < min_co) min_co = mvert->co[axis];
00156                 if(mvert->co[axis] > max_co) max_co = mvert->co[axis];
00157         }
00158 
00159         return max_co - min_co;
00160 }
00161 
00162 /* XXX This function fixes bad merging code, in some cases removing vertices creates indices > maxvert */
00163 
00164 static int test_index_face_maxvert(MFace *mface, CustomData *fdata, int mfindex, int nr, int maxvert)
00165 {
00166         if(mface->v1 >= maxvert) {
00167                 // printf("bad index in array\n");
00168                 mface->v1= maxvert - 1;
00169         }
00170         if(mface->v2 >= maxvert) {
00171                 // printf("bad index in array\n");
00172                 mface->v2= maxvert - 1;
00173         }
00174         if(mface->v3 >= maxvert) {
00175                 // printf("bad index in array\n");
00176                 mface->v3= maxvert - 1;
00177         }
00178         if(mface->v4 >= maxvert) {
00179                 // printf("bad index in array\n");
00180                 mface->v4= maxvert - 1;
00181         }
00182         
00183         return test_index_face(mface, fdata, mfindex, nr);
00184 }
00185 
00186 typedef struct IndexMapEntry {
00187         /* the new vert index that this old vert index maps to */
00188         int new;
00189         /* -1 if this vert isn't merged, otherwise the old vert index it
00190         * should be replaced with
00191         */
00192         int merge;
00193         /* 1 if this vert's first copy is merged with the last copy of its
00194         * merge target, otherwise 0
00195         */
00196         short merge_final;
00197 } IndexMapEntry;
00198 
00199 /* indexMap - an array of IndexMap entries
00200  * oldIndex - the old index to map
00201  * copyNum - the copy number to map to (original = 0, first copy = 1, etc.)
00202  */
00203 static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum)
00204 {
00205         if(indexMap[oldIndex].merge < 0) {
00206                 /* vert wasn't merged, so use copy of this vert */
00207                 return indexMap[oldIndex].new + copyNum;
00208         } else if(indexMap[oldIndex].merge == oldIndex) {
00209                 /* vert was merged with itself */
00210                 return indexMap[oldIndex].new;
00211         } else {
00212                 /* vert was merged with another vert */
00213                 /* follow the chain of merges to the end, or until we've passed
00214                 * a number of vertices equal to the copy number
00215                 */
00216                 if(copyNum <= 0)
00217                         return indexMap[oldIndex].new;
00218                 else
00219                         return calc_mapping(indexMap, indexMap[oldIndex].merge,
00220                                                 copyNum - 1);
00221         }
00222 }
00223 
00224 static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
00225                                           struct Scene *scene, Object *ob, DerivedMesh *dm,
00226            int initFlags)
00227 {
00228         int i, j;
00229         /* offset matrix */
00230         float offset[4][4];
00231         float final_offset[4][4];
00232         float tmp_mat[4][4];
00233         float length = amd->length;
00234         int count = amd->count;
00235         int numVerts, numEdges, numFaces;
00236         int maxVerts, maxEdges, maxFaces;
00237         int finalVerts, finalEdges, finalFaces;
00238         DerivedMesh *result, *start_cap = NULL, *end_cap = NULL;
00239         MVert *mvert, *src_mvert;
00240         MEdge *medge;
00241         MFace *mface;
00242 
00243         IndexMapEntry *indexMap;
00244 
00245         EdgeHash *edges;
00246 
00247         /* need to avoid infinite recursion here */
00248         if(amd->start_cap && amd->start_cap != ob)
00249                 start_cap = amd->start_cap->derivedFinal;
00250         if(amd->end_cap && amd->end_cap != ob)
00251                 end_cap = amd->end_cap->derivedFinal;
00252 
00253         unit_m4(offset);
00254 
00255         indexMap = MEM_callocN(sizeof(*indexMap) * dm->getNumVerts(dm),
00256                                    "indexmap");
00257 
00258         src_mvert = dm->getVertArray(dm);
00259 
00260         maxVerts = dm->getNumVerts(dm);
00261 
00262         if(amd->offset_type & MOD_ARR_OFF_CONST)
00263                 add_v3_v3(offset[3], amd->offset);
00264         if(amd->offset_type & MOD_ARR_OFF_RELATIVE) {
00265                 for(j = 0; j < 3; j++)
00266                         offset[3][j] += amd->scale[j] * vertarray_size(src_mvert,
00267                                         maxVerts, j);
00268         }
00269 
00270         if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
00271                 float obinv[4][4];
00272                 float result_mat[4][4];
00273 
00274                 if(ob)
00275                         invert_m4_m4(obinv, ob->obmat);
00276                 else
00277                         unit_m4(obinv);
00278 
00279                 mul_serie_m4(result_mat, offset,
00280                                  obinv, amd->offset_ob->obmat,
00281          NULL, NULL, NULL, NULL, NULL);
00282                 copy_m4_m4(offset, result_mat);
00283         }
00284 
00285         if(amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
00286                 Curve *cu = amd->curve_ob->data;
00287                 if(cu) {
00288                         float tmp_mat[3][3];
00289                         float scale;
00290                         
00291                         object_to_mat3(amd->curve_ob, tmp_mat);
00292                         scale = mat3_to_scale(tmp_mat);
00293                                 
00294                         if(!cu->path) {
00295                                 cu->flag |= CU_PATH; // needed for path & bevlist
00296                                 makeDispListCurveTypes(scene, amd->curve_ob, 0);
00297                         }
00298                         if(cu->path)
00299                                 length = scale*cu->path->totdist;
00300                 }
00301         }
00302 
00303         /* calculate the maximum number of copies which will fit within the
00304         prescribed length */
00305         if(amd->fit_type == MOD_ARR_FITLENGTH
00306                   || amd->fit_type == MOD_ARR_FITCURVE) {
00307                 float dist = sqrt(dot_v3v3(offset[3], offset[3]));
00308 
00309                 if(dist > 1e-6f)
00310                         /* this gives length = first copy start to last copy end
00311                         add a tiny offset for floating point rounding errors */
00312                         count = (length + 1e-6f) / dist;
00313                 else
00314                         /* if the offset has no translation, just make one copy */
00315                         count = 1;
00316         }
00317 
00318         if(count < 1)
00319                 count = 1;
00320 
00321         /* allocate memory for count duplicates (including original) plus
00322                   * start and end caps
00323         */
00324         finalVerts = dm->getNumVerts(dm) * count;
00325         finalEdges = dm->getNumEdges(dm) * count;
00326         finalFaces = dm->getNumFaces(dm) * count;
00327         if(start_cap) {
00328                 finalVerts += start_cap->getNumVerts(start_cap);
00329                 finalEdges += start_cap->getNumEdges(start_cap);
00330                 finalFaces += start_cap->getNumFaces(start_cap);
00331         }
00332         if(end_cap) {
00333                 finalVerts += end_cap->getNumVerts(end_cap);
00334                 finalEdges += end_cap->getNumEdges(end_cap);
00335                 finalFaces += end_cap->getNumFaces(end_cap);
00336         }
00337         result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces);
00338 
00339         /* calculate the offset matrix of the final copy (for merging) */
00340         unit_m4(final_offset);
00341 
00342         for(j=0; j < count - 1; j++) {
00343                 mul_m4_m4m4(tmp_mat, final_offset, offset);
00344                 copy_m4_m4(final_offset, tmp_mat);
00345         }
00346 
00347         numVerts = numEdges = numFaces = 0;
00348         mvert = CDDM_get_verts(result);
00349 
00350         for (i = 0; i < maxVerts; i++) {
00351                 indexMap[i].merge = -1; /* default to no merge */
00352                 indexMap[i].merge_final = 0; /* default to no merge */
00353         }
00354 
00355         for (i = 0; i < maxVerts; i++) {
00356                 MVert *inMV;
00357                 MVert *mv = &mvert[numVerts];
00358                 MVert *mv2;
00359                 float co[3];
00360 
00361                 inMV = &src_mvert[i];
00362 
00363                 DM_copy_vert_data(dm, result, i, numVerts, 1);
00364                 *mv = *inMV;
00365                 numVerts++;
00366 
00367                 indexMap[i].new = numVerts - 1;
00368 
00369                 copy_v3_v3(co, mv->co);
00370                 
00371                 /* Attempts to merge verts from one duplicate with verts from the
00372                           * next duplicate which are closer than amd->merge_dist.
00373                           * Only the first such vert pair is merged.
00374                           * If verts are merged in the first duplicate pair, they are merged
00375                           * in all pairs.
00376                 */
00377                 if((count > 1) && (amd->flags & MOD_ARR_MERGE)) {
00378                         float tmp_co[3];
00379                         mul_v3_m4v3(tmp_co, offset, mv->co);
00380 
00381                         for(j = 0; j < maxVerts; j++) {
00382                                 /* if vertex already merged, don't use it */
00383                                 if( indexMap[j].merge != -1 ) continue;
00384 
00385                                 inMV = &src_mvert[j];
00386                                 /* if this vert is within merge limit, merge */
00387                                 if(compare_len_v3v3(tmp_co, inMV->co, amd->merge_dist)) {
00388                                         indexMap[i].merge = j;
00389 
00390                                         /* test for merging with final copy of merge target */
00391                                         if(amd->flags & MOD_ARR_MERGEFINAL) {
00392                                                 copy_v3_v3(tmp_co, inMV->co);
00393                                                 inMV = &src_mvert[i];
00394                                                 mul_m4_v3(final_offset, tmp_co);
00395                                                 if(compare_len_v3v3(tmp_co, inMV->co, amd->merge_dist))
00396                                                         indexMap[i].merge_final = 1;
00397                                         }
00398                                         break;
00399                                 }
00400                         }
00401                 }
00402 
00403                 /* if no merging, generate copies of this vert */
00404                 if(indexMap[i].merge < 0) {
00405                         for(j=0; j < count - 1; j++) {
00406                                 mv2 = &mvert[numVerts];
00407 
00408                                 DM_copy_vert_data(result, result, numVerts - 1, numVerts, 1);
00409                                 *mv2 = *mv;
00410                                 numVerts++;
00411 
00412                                 mul_m4_v3(offset, co);
00413                                 copy_v3_v3(mv2->co, co);
00414                         }
00415                 } else if(indexMap[i].merge != i && indexMap[i].merge_final) {
00416                         /* if this vert is not merging with itself, and it is merging
00417                                   * with the final copy of its merge target, remove the first copy
00418                         */
00419                         numVerts--;
00420                         DM_free_vert_data(result, numVerts, 1);
00421                 }
00422         }
00423 
00424         /* make a hashtable so we can avoid duplicate edges from merging */
00425         edges = BLI_edgehash_new();
00426 
00427         maxEdges = dm->getNumEdges(dm);
00428         medge = CDDM_get_edges(result);
00429         for(i = 0; i < maxEdges; i++) {
00430                 MEdge inMED;
00431                 MEdge med;
00432                 MEdge *med2;
00433                 int vert1, vert2;
00434 
00435                 dm->getEdge(dm, i, &inMED);
00436 
00437                 med = inMED;
00438                 med.v1 = indexMap[inMED.v1].new;
00439                 med.v2 = indexMap[inMED.v2].new;
00440 
00441                 /* if vertices are to be merged with the final copies of their
00442                           * merge targets, calculate that final copy
00443                 */
00444                 if(indexMap[inMED.v1].merge_final) {
00445                         med.v1 = calc_mapping(indexMap, indexMap[inMED.v1].merge,
00446                         count - 1);
00447                 }
00448                 if(indexMap[inMED.v2].merge_final) {
00449                         med.v2 = calc_mapping(indexMap, indexMap[inMED.v2].merge,
00450                         count - 1);
00451                 }
00452 
00453                 if(med.v1 == med.v2) continue;
00454 
00455                 /* XXX Unfortunately the calc_mapping returns sometimes numVerts... leads to bad crashes */
00456                 if(med.v1 >= numVerts)
00457                         med.v1= numVerts-1;
00458                 if(med.v2 >= numVerts)
00459                         med.v2= numVerts-1;
00460 
00461                 if (initFlags) {
00462                         med.flag |= ME_EDGEDRAW | ME_EDGERENDER;
00463                 }
00464 
00465                 if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) {
00466                         DM_copy_edge_data(dm, result, i, numEdges, 1);
00467                         medge[numEdges] = med;
00468                         numEdges++;
00469 
00470                         BLI_edgehash_insert(edges, med.v1, med.v2, NULL);
00471                 }
00472 
00473                 for(j = 1; j < count; j++)
00474                 {
00475                         vert1 = calc_mapping(indexMap, inMED.v1, j);
00476                         vert2 = calc_mapping(indexMap, inMED.v2, j);
00477 
00478                         /* edge could collapse to single point after mapping */
00479                         if(vert1 == vert2) continue;
00480 
00481                         /* XXX Unfortunately the calc_mapping returns sometimes numVerts... leads to bad crashes */
00482                         if(vert1 >= numVerts)
00483                                 vert1= numVerts-1;
00484                         if(vert2 >= numVerts)
00485                                 vert2= numVerts-1;
00486 
00487                         /* avoid duplicate edges */
00488                         if(!BLI_edgehash_haskey(edges, vert1, vert2)) {
00489                                 med2 = &medge[numEdges];
00490 
00491                                 DM_copy_edge_data(dm, result, i, numEdges, 1);
00492                                 *med2 = med;
00493                                 numEdges++;
00494 
00495                                 med2->v1 = vert1;
00496                                 med2->v2 = vert2;
00497 
00498                                 BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL);
00499                         }
00500                 }
00501         }
00502 
00503         maxFaces = dm->getNumFaces(dm);
00504         mface = CDDM_get_faces(result);
00505         for (i=0; i < maxFaces; i++) {
00506                 MFace inMF;
00507                 MFace *mf = &mface[numFaces];
00508 
00509                 dm->getFace(dm, i, &inMF);
00510 
00511                 DM_copy_face_data(dm, result, i, numFaces, 1);
00512                 *mf = inMF;
00513 
00514                 mf->v1 = indexMap[inMF.v1].new;
00515                 mf->v2 = indexMap[inMF.v2].new;
00516                 mf->v3 = indexMap[inMF.v3].new;
00517                 if(inMF.v4)
00518                         mf->v4 = indexMap[inMF.v4].new;
00519 
00520                 /* if vertices are to be merged with the final copies of their
00521                           * merge targets, calculate that final copy
00522                 */
00523                 if(indexMap[inMF.v1].merge_final)
00524                         mf->v1 = calc_mapping(indexMap, indexMap[inMF.v1].merge, count-1);
00525                 if(indexMap[inMF.v2].merge_final)
00526                         mf->v2 = calc_mapping(indexMap, indexMap[inMF.v2].merge, count-1);
00527                 if(indexMap[inMF.v3].merge_final)
00528                         mf->v3 = calc_mapping(indexMap, indexMap[inMF.v3].merge, count-1);
00529                 if(inMF.v4 && indexMap[inMF.v4].merge_final)
00530                         mf->v4 = calc_mapping(indexMap, indexMap[inMF.v4].merge, count-1);
00531 
00532                 if(test_index_face_maxvert(mf, &result->faceData, numFaces, inMF.v4?4:3, numVerts) < 3)
00533                         continue;
00534 
00535                 numFaces++;
00536 
00537                 /* if the face has fewer than 3 vertices, don't create it */
00538                 if(mf->v3 == 0 || (mf->v1 && (mf->v1 == mf->v3 || mf->v1 == mf->v4))) {
00539                         numFaces--;
00540                         DM_free_face_data(result, numFaces, 1);
00541                 }
00542 
00543                 for(j = 1; j < count; j++)
00544                 {
00545                         MFace *mf2 = &mface[numFaces];
00546 
00547                         DM_copy_face_data(dm, result, i, numFaces, 1);
00548                         *mf2 = *mf;
00549 
00550                         mf2->v1 = calc_mapping(indexMap, inMF.v1, j);
00551                         mf2->v2 = calc_mapping(indexMap, inMF.v2, j);
00552                         mf2->v3 = calc_mapping(indexMap, inMF.v3, j);
00553                         if (inMF.v4)
00554                                 mf2->v4 = calc_mapping(indexMap, inMF.v4, j);
00555 
00556                         numFaces++;
00557 
00558                         /* if the face has fewer than 3 vertices, don't create it */
00559                         if(test_index_face_maxvert(mf2, &result->faceData, numFaces-1, inMF.v4?4:3, numVerts) < 3) {
00560                                 numFaces--;
00561                                 DM_free_face_data(result, numFaces, 1);
00562                         }
00563                 }
00564         }
00565 
00566         /* add start and end caps */
00567         if(start_cap) {
00568                 float startoffset[4][4];
00569                 MVert *cap_mvert;
00570                 MEdge *cap_medge;
00571                 MFace *cap_mface;
00572                 int *origindex;
00573                 int *vert_map;
00574                 int capVerts, capEdges, capFaces;
00575 
00576                 capVerts = start_cap->getNumVerts(start_cap);
00577                 capEdges = start_cap->getNumEdges(start_cap);
00578                 capFaces = start_cap->getNumFaces(start_cap);
00579                 cap_mvert = start_cap->getVertArray(start_cap);
00580                 cap_medge = start_cap->getEdgeArray(start_cap);
00581                 cap_mface = start_cap->getFaceArray(start_cap);
00582 
00583                 invert_m4_m4(startoffset, offset);
00584 
00585                 vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
00586                 "arrayModifier_doArray vert_map");
00587 
00588                 origindex = result->getVertDataArray(result, CD_ORIGINDEX);
00589                 for(i = 0; i < capVerts; i++) {
00590                         MVert *mv = &cap_mvert[i];
00591                         short merged = 0;
00592 
00593                         if(amd->flags & MOD_ARR_MERGE) {
00594                                 float tmp_co[3];
00595                                 MVert *in_mv;
00596                                 int j;
00597 
00598                                 copy_v3_v3(tmp_co, mv->co);
00599                                 mul_m4_v3(startoffset, tmp_co);
00600 
00601                                 for(j = 0; j < maxVerts; j++) {
00602                                         in_mv = &src_mvert[j];
00603                                         /* if this vert is within merge limit, merge */
00604                                         if(compare_len_v3v3(tmp_co, in_mv->co, amd->merge_dist)) {
00605                                                 vert_map[i] = calc_mapping(indexMap, j, 0);
00606                                                 merged = 1;
00607                                                 break;
00608                                         }
00609                                 }
00610                         }
00611 
00612                         if(!merged) {
00613                                 DM_copy_vert_data(start_cap, result, i, numVerts, 1);
00614                                 mvert[numVerts] = *mv;
00615                                 mul_m4_v3(startoffset, mvert[numVerts].co);
00616                                 origindex[numVerts] = ORIGINDEX_NONE;
00617 
00618                                 vert_map[i] = numVerts;
00619 
00620                                 numVerts++;
00621                         }
00622                 }
00623                 origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
00624                 for(i = 0; i < capEdges; i++) {
00625                         int v1, v2;
00626 
00627                         v1 = vert_map[cap_medge[i].v1];
00628                         v2 = vert_map[cap_medge[i].v2];
00629 
00630                         if(!BLI_edgehash_haskey(edges, v1, v2)) {
00631                                 DM_copy_edge_data(start_cap, result, i, numEdges, 1);
00632                                 medge[numEdges] = cap_medge[i];
00633                                 medge[numEdges].v1 = v1;
00634                                 medge[numEdges].v2 = v2;
00635                                 origindex[numEdges] = ORIGINDEX_NONE;
00636 
00637                                 numEdges++;
00638                         }
00639                 }
00640                 origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
00641                 for(i = 0; i < capFaces; i++) {
00642                         DM_copy_face_data(start_cap, result, i, numFaces, 1);
00643                         mface[numFaces] = cap_mface[i];
00644                         mface[numFaces].v1 = vert_map[mface[numFaces].v1];
00645                         mface[numFaces].v2 = vert_map[mface[numFaces].v2];
00646                         mface[numFaces].v3 = vert_map[mface[numFaces].v3];
00647                         if(mface[numFaces].v4) {
00648                                 mface[numFaces].v4 = vert_map[mface[numFaces].v4];
00649 
00650                                 test_index_face_maxvert(&mface[numFaces], &result->faceData,
00651                                 numFaces, 4, numVerts);
00652                         }
00653                         else
00654                         {
00655                                 test_index_face(&mface[numFaces], &result->faceData,
00656                                 numFaces, 3);
00657                         }
00658 
00659                         origindex[numFaces] = ORIGINDEX_NONE;
00660 
00661                         numFaces++;
00662                 }
00663 
00664                 MEM_freeN(vert_map);
00665                 start_cap->release(start_cap);
00666         }
00667 
00668         if(end_cap) {
00669                 float endoffset[4][4];
00670                 MVert *cap_mvert;
00671                 MEdge *cap_medge;
00672                 MFace *cap_mface;
00673                 int *origindex;
00674                 int *vert_map;
00675                 int capVerts, capEdges, capFaces;
00676 
00677                 capVerts = end_cap->getNumVerts(end_cap);
00678                 capEdges = end_cap->getNumEdges(end_cap);
00679                 capFaces = end_cap->getNumFaces(end_cap);
00680                 cap_mvert = end_cap->getVertArray(end_cap);
00681                 cap_medge = end_cap->getEdgeArray(end_cap);
00682                 cap_mface = end_cap->getFaceArray(end_cap);
00683 
00684                 mul_m4_m4m4(endoffset, final_offset, offset);
00685 
00686                 vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
00687                 "arrayModifier_doArray vert_map");
00688 
00689                 origindex = result->getVertDataArray(result, CD_ORIGINDEX);
00690                 for(i = 0; i < capVerts; i++) {
00691                         MVert *mv = &cap_mvert[i];
00692                         short merged = 0;
00693 
00694                         if(amd->flags & MOD_ARR_MERGE) {
00695                                 float tmp_co[3];
00696                                 MVert *in_mv;
00697                                 int j;
00698 
00699                                 copy_v3_v3(tmp_co, mv->co);
00700                                 mul_m4_v3(offset, tmp_co);
00701 
00702                                 for(j = 0; j < maxVerts; j++) {
00703                                         in_mv = &src_mvert[j];
00704                                         /* if this vert is within merge limit, merge */
00705                                         if(compare_len_v3v3(tmp_co, in_mv->co, amd->merge_dist)) {
00706                                                 vert_map[i] = calc_mapping(indexMap, j, count - 1);
00707                                                 merged = 1;
00708                                                 break;
00709                                         }
00710                                 }
00711                         }
00712 
00713                         if(!merged) {
00714                                 DM_copy_vert_data(end_cap, result, i, numVerts, 1);
00715                                 mvert[numVerts] = *mv;
00716                                 mul_m4_v3(endoffset, mvert[numVerts].co);
00717                                 origindex[numVerts] = ORIGINDEX_NONE;
00718 
00719                                 vert_map[i] = numVerts;
00720 
00721                                 numVerts++;
00722                         }
00723                 }
00724                 origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
00725                 for(i = 0; i < capEdges; i++) {
00726                         int v1, v2;
00727 
00728                         v1 = vert_map[cap_medge[i].v1];
00729                         v2 = vert_map[cap_medge[i].v2];
00730 
00731                         if(!BLI_edgehash_haskey(edges, v1, v2)) {
00732                                 DM_copy_edge_data(end_cap, result, i, numEdges, 1);
00733                                 medge[numEdges] = cap_medge[i];
00734                                 medge[numEdges].v1 = v1;
00735                                 medge[numEdges].v2 = v2;
00736                                 origindex[numEdges] = ORIGINDEX_NONE;
00737 
00738                                 numEdges++;
00739                         }
00740                 }
00741                 origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
00742                 for(i = 0; i < capFaces; i++) {
00743                         DM_copy_face_data(end_cap, result, i, numFaces, 1);
00744                         mface[numFaces] = cap_mface[i];
00745                         mface[numFaces].v1 = vert_map[mface[numFaces].v1];
00746                         mface[numFaces].v2 = vert_map[mface[numFaces].v2];
00747                         mface[numFaces].v3 = vert_map[mface[numFaces].v3];
00748                         if(mface[numFaces].v4) {
00749                                 mface[numFaces].v4 = vert_map[mface[numFaces].v4];
00750 
00751                                 test_index_face(&mface[numFaces], &result->faceData,
00752                                 numFaces, 4);
00753                         }
00754                         else
00755                         {
00756                                 test_index_face(&mface[numFaces], &result->faceData,
00757                                 numFaces, 3);
00758                         }
00759                         origindex[numFaces] = ORIGINDEX_NONE;
00760 
00761                         numFaces++;
00762                 }
00763 
00764                 MEM_freeN(vert_map);
00765                 end_cap->release(end_cap);
00766         }
00767 
00768         BLI_edgehash_free(edges, NULL);
00769         MEM_freeN(indexMap);
00770 
00771         CDDM_lower_num_verts(result, numVerts);
00772         CDDM_lower_num_edges(result, numEdges);
00773         CDDM_lower_num_faces(result, numFaces);
00774 
00775         return result;
00776 }
00777 
00778 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
00779                                                 DerivedMesh *dm,
00780                                                 int UNUSED(useRenderParams),
00781                                                 int UNUSED(isFinalCalc))
00782 {
00783         DerivedMesh *result;
00784         ArrayModifierData *amd = (ArrayModifierData*) md;
00785 
00786         result = arrayModifier_doArray(amd, md->scene, ob, dm, 0);
00787 
00788         if(result != dm)
00789                 CDDM_calc_normals(result);
00790 
00791         return result;
00792 }
00793 
00794 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
00795                                                 struct EditMesh *UNUSED(editData),
00796                                                 DerivedMesh *dm)
00797 {
00798         return applyModifier(md, ob, dm, 0, 1);
00799 }
00800 
00801 
00802 ModifierTypeInfo modifierType_Array = {
00803         /* name */              "Array",
00804         /* structName */        "ArrayModifierData",
00805         /* structSize */        sizeof(ArrayModifierData),
00806         /* type */              eModifierTypeType_Constructive,
00807         /* flags */             eModifierTypeFlag_AcceptsMesh
00808                                                         | eModifierTypeFlag_SupportsMapping
00809                                                         | eModifierTypeFlag_SupportsEditmode
00810                                                         | eModifierTypeFlag_EnableInEditmode
00811                                                         | eModifierTypeFlag_AcceptsCVs,
00812 
00813         /* copyData */          copyData,
00814         /* deformVerts */       NULL,
00815         /* deformMatrices */    NULL,
00816         /* deformVertsEM */     NULL,
00817         /* deformMatricesEM */  NULL,
00818         /* applyModifier */     applyModifier,
00819         /* applyModifierEM */   applyModifierEM,
00820         /* initData */          initData,
00821         /* requiredDataMask */  NULL,
00822         /* freeData */          NULL,
00823         /* isDisabled */        NULL,
00824         /* updateDepgraph */    updateDepgraph,
00825         /* dependsOnTime */     NULL,
00826         /* dependsOnNormals */  NULL,
00827         /* foreachObjectLink */ foreachObjectLink,
00828         /* foreachIDLink */     NULL,
00829 };