Blender V2.61 - r43446

MOD_array.c

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