fix for crash when a register script sets material colors, also made some changes...
[blender.git] / source / blender / modifiers / intern / MOD_build.c
1 /*
2 * $Id$
3 *
4 * ***** BEGIN GPL LICENSE BLOCK *****
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software  Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
21 * All rights reserved.
22 *
23 * Contributor(s): Daniel Dunbar
24 *                 Ton Roosendaal,
25 *                 Ben Batt,
26 *                 Brecht Van Lommel,
27 *                 Campbell Barton
28 *
29 * ***** END GPL LICENSE BLOCK *****
30 *
31 */
32
33 #include "BLI_rand.h"
34 #include "BLI_ghash.h"
35
36 #include "DNA_scene_types.h"
37 #include "DNA_meshdata_types.h"
38
39 #include "BKE_cdderivedmesh.h"
40 #include "BKE_mesh.h"
41 #include "BKE_modifier.h"
42 #include "BKE_object.h"
43 #include "BKE_particle.h"
44
45
46 static void initData(ModifierData *md)
47 {
48         BuildModifierData *bmd = (BuildModifierData*) md;
49
50         bmd->start = 1.0;
51         bmd->length = 100.0;
52 }
53
54 static void copyData(ModifierData *md, ModifierData *target)
55 {
56         BuildModifierData *bmd = (BuildModifierData*) md;
57         BuildModifierData *tbmd = (BuildModifierData*) target;
58
59         tbmd->start = bmd->start;
60         tbmd->length = bmd->length;
61         tbmd->randomize = bmd->randomize;
62         tbmd->seed = bmd->seed;
63 }
64
65 static int dependsOnTime(ModifierData *md)
66 {
67         return 1;
68 }
69
70 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
71                 DerivedMesh *derivedData,
72   int useRenderParams, int isFinalCalc)
73 {
74         DerivedMesh *dm = derivedData;
75         DerivedMesh *result;
76         BuildModifierData *bmd = (BuildModifierData*) md;
77         int i;
78         int numFaces, numEdges;
79         int maxVerts, maxEdges, maxFaces;
80         int *vertMap, *edgeMap, *faceMap;
81         float frac;
82         GHashIterator *hashIter;
83         /* maps vert indices in old mesh to indices in new mesh */
84         GHash *vertHash = BLI_ghash_new(BLI_ghashutil_inthash,
85                                         BLI_ghashutil_intcmp);
86         /* maps edge indices in new mesh to indices in old mesh */
87         GHash *edgeHash = BLI_ghash_new(BLI_ghashutil_inthash,
88                                         BLI_ghashutil_intcmp);
89
90         maxVerts = dm->getNumVerts(dm);
91         vertMap = MEM_callocN(sizeof(*vertMap) * maxVerts,
92                                   "build modifier vertMap");
93         for(i = 0; i < maxVerts; ++i) vertMap[i] = i;
94
95         maxEdges = dm->getNumEdges(dm);
96         edgeMap = MEM_callocN(sizeof(*edgeMap) * maxEdges,
97                                   "build modifier edgeMap");
98         for(i = 0; i < maxEdges; ++i) edgeMap[i] = i;
99
100         maxFaces = dm->getNumFaces(dm);
101         faceMap = MEM_callocN(sizeof(*faceMap) * maxFaces,
102                                   "build modifier faceMap");
103         for(i = 0; i < maxFaces; ++i) faceMap[i] = i;
104
105         if (ob) {
106                 frac = bsystem_time(md->scene, ob, md->scene->r.cfra,
107                                         bmd->start - 1.0f) / bmd->length;
108         } else {
109                 frac = md->scene->r.cfra - bmd->start / bmd->length;
110         }
111         CLAMP(frac, 0.0, 1.0);
112
113         numFaces = dm->getNumFaces(dm) * frac;
114         numEdges = dm->getNumEdges(dm) * frac;
115
116         /* if there's at least one face, build based on faces */
117         if(numFaces) {
118                 int maxEdges;
119
120                 if(bmd->randomize)
121                         BLI_array_randomize(faceMap, sizeof(*faceMap),
122                                                 maxFaces, bmd->seed);
123
124                 /* get the set of all vert indices that will be in the final mesh,
125                 * mapped to the new indices
126                 */
127                 for(i = 0; i < numFaces; ++i) {
128                         MFace mf;
129                         dm->getFace(dm, faceMap[i], &mf);
130
131                         if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)))
132                                 BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v1),
133                                         SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
134                         if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v2)))
135                                 BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v2),
136                                         SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
137                         if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v3)))
138                                 BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v3),
139                                         SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
140                         if(mf.v4 && !BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v4)))
141                                 BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v4),
142                                         SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
143                 }
144
145                 /* get the set of edges that will be in the new mesh (i.e. all edges
146                 * that have both verts in the new mesh)
147                 */
148                 maxEdges = dm->getNumEdges(dm);
149                 for(i = 0; i < maxEdges; ++i) {
150                         MEdge me;
151                         dm->getEdge(dm, i, &me);
152
153                         if(BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1))
154                                                 && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2)))
155                                 BLI_ghash_insert(edgeHash,
156                                         SET_INT_IN_POINTER(BLI_ghash_size(edgeHash)), SET_INT_IN_POINTER(i));
157                 }
158         } else if(numEdges) {
159                 if(bmd->randomize)
160                         BLI_array_randomize(edgeMap, sizeof(*edgeMap),
161                                                 maxEdges, bmd->seed);
162
163                 /* get the set of all vert indices that will be in the final mesh,
164                 * mapped to the new indices
165                 */
166                 for(i = 0; i < numEdges; ++i) {
167                         MEdge me;
168                         dm->getEdge(dm, edgeMap[i], &me);
169
170                         if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)))
171                                 BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me.v1),
172                                         SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
173                         if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2)))
174                                 BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me.v2),
175                                         SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
176                 }
177
178                 /* get the set of edges that will be in the new mesh
179                 */
180                 for(i = 0; i < numEdges; ++i) {
181                         MEdge me;
182                         dm->getEdge(dm, edgeMap[i], &me);
183
184                         BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(BLI_ghash_size(edgeHash)),
185                                          SET_INT_IN_POINTER(edgeMap[i]));
186                 }
187         } else {
188                 int numVerts = dm->getNumVerts(dm) * frac;
189
190                 if(bmd->randomize)
191                         BLI_array_randomize(vertMap, sizeof(*vertMap),
192                                                 maxVerts, bmd->seed);
193
194                 /* get the set of all vert indices that will be in the final mesh,
195                 * mapped to the new indices
196                 */
197                 for(i = 0; i < numVerts; ++i)
198                         BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(vertMap[i]), SET_INT_IN_POINTER(i));
199         }
200
201         /* now we know the number of verts, edges and faces, we can create
202         * the mesh
203         */
204         result = CDDM_from_template(dm, BLI_ghash_size(vertHash),
205                                         BLI_ghash_size(edgeHash), numFaces);
206
207         /* copy the vertices across */
208         for(hashIter = BLI_ghashIterator_new(vertHash);
209                    !BLI_ghashIterator_isDone(hashIter);
210                    BLI_ghashIterator_step(hashIter)) {
211                            MVert source;
212                            MVert *dest;
213                            int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
214                            int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
215
216                            dm->getVert(dm, oldIndex, &source);
217                            dest = CDDM_get_vert(result, newIndex);
218
219                            DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
220                            *dest = source;
221                    }
222                    BLI_ghashIterator_free(hashIter);
223
224                    /* copy the edges across, remapping indices */
225                    for(i = 0; i < BLI_ghash_size(edgeHash); ++i) {
226                            MEdge source;
227                            MEdge *dest;
228                            int oldIndex = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(i)));
229
230                            dm->getEdge(dm, oldIndex, &source);
231                            dest = CDDM_get_edge(result, i);
232
233                            source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
234                            source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
235
236                            DM_copy_edge_data(dm, result, oldIndex, i, 1);
237                            *dest = source;
238                    }
239
240                    /* copy the faces across, remapping indices */
241                    for(i = 0; i < numFaces; ++i) {
242                            MFace source;
243                            MFace *dest;
244                            int orig_v4;
245
246                            dm->getFace(dm, faceMap[i], &source);
247                            dest = CDDM_get_face(result, i);
248
249                            orig_v4 = source.v4;
250
251                            source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
252                            source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
253                            source.v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v3)));
254                            if(source.v4)
255                                    source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4)));
256
257                            DM_copy_face_data(dm, result, faceMap[i], i, 1);
258                            *dest = source;
259
260                            test_index_face(dest, &result->faceData, i, (orig_v4 ? 4 : 3));
261                    }
262
263                    CDDM_calc_normals(result);
264
265                    BLI_ghash_free(vertHash, NULL, NULL);
266                    BLI_ghash_free(edgeHash, NULL, NULL);
267
268                    MEM_freeN(vertMap);
269                    MEM_freeN(edgeMap);
270                    MEM_freeN(faceMap);
271
272                    return result;
273 }
274
275
276 ModifierTypeInfo modifierType_Build = {
277         /* name */              "Build",
278         /* structName */        "BuildModifierData",
279         /* structSize */        sizeof(BuildModifierData),
280         /* type */              eModifierTypeType_Nonconstructive,
281         /* flags */             eModifierTypeFlag_AcceptsMesh
282                                                         | eModifierTypeFlag_AcceptsCVs,
283         /* copyData */          copyData,
284         /* deformVerts */       0,
285         /* deformVertsEM */     0,
286         /* deformMatricesEM */  0,
287         /* applyModifier */     applyModifier,
288         /* applyModifierEM */   0,
289         /* initData */          initData,
290         /* requiredDataMask */  0,
291         /* freeData */          0,
292         /* isDisabled */        0,
293         /* updateDepgraph */    0,
294         /* dependsOnTime */     dependsOnTime,
295         /* foreachObjectLink */ 0,
296         /* foreachIDLink */     0,
297 };