fix for crash when a register script sets material colors, also made some changes...
[blender.git] / source / blender / modifiers / intern / MOD_smooth.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 "DNA_meshdata_types.h"
34
35 #include "BLI_math.h"
36
37 #include "BKE_cdderivedmesh.h"
38 #include "BKE_particle.h"
39 #include "BKE_deform.h"
40
41 #include "MEM_guardedalloc.h"
42
43 #include "MOD_modifiertypes.h"
44 #include "MOD_util.h"
45
46
47 static void initData(ModifierData *md)
48 {
49         SmoothModifierData *smd = (SmoothModifierData*) md;
50
51         smd->fac = 0.5f;
52         smd->repeat = 1;
53         smd->flag = MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z;
54         smd->defgrp_name[0] = '\0';
55 }
56
57 static void copyData(ModifierData *md, ModifierData *target)
58 {
59         SmoothModifierData *smd = (SmoothModifierData*) md;
60         SmoothModifierData *tsmd = (SmoothModifierData*) target;
61
62         tsmd->fac = smd->fac;
63         tsmd->repeat = smd->repeat;
64         tsmd->flag = smd->flag;
65         strncpy(tsmd->defgrp_name, smd->defgrp_name, 32);
66 }
67
68 static int isDisabled(ModifierData *md, int useRenderParams)
69 {
70         SmoothModifierData *smd = (SmoothModifierData*) md;
71         short flag;
72
73         flag = smd->flag & (MOD_SMOOTH_X|MOD_SMOOTH_Y|MOD_SMOOTH_Z);
74
75         /* disable if modifier is off for X, Y and Z or if factor is 0 */
76         if((smd->fac == 0.0f) || flag == 0) return 1;
77
78         return 0;
79 }
80
81 static CustomDataMask requiredDataMask(Object *ob, ModifierData *md)
82 {
83         SmoothModifierData *smd = (SmoothModifierData *)md;
84         CustomDataMask dataMask = 0;
85
86         /* ask for vertexgroups if we need them */
87         if(smd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT);
88
89         return dataMask;
90 }
91
92 static void smoothModifier_do(
93                                   SmoothModifierData *smd, Object *ob, DerivedMesh *dm,
94          float (*vertexCos)[3], int numVerts)
95 {
96         MDeformVert *dvert = NULL;
97         MEdge *medges = NULL;
98
99         int i, j, numDMEdges, defgrp_index;
100         unsigned char *uctmp;
101         float *ftmp, fac, facm;
102
103         ftmp = (float*)MEM_callocN(3*sizeof(float)*numVerts,
104                 "smoothmodifier_f");
105         if (!ftmp) return;
106         uctmp = (unsigned char*)MEM_callocN(sizeof(unsigned char)*numVerts,
107                  "smoothmodifier_uc");
108         if (!uctmp) {
109                 if (ftmp) MEM_freeN(ftmp);
110                 return;
111         }
112
113         fac = smd->fac;
114         facm = 1 - fac;
115
116         medges = dm->getEdgeArray(dm);
117         numDMEdges = dm->getNumEdges(dm);
118
119         defgrp_index = defgroup_name_index(ob, smd->defgrp_name);
120
121         if (defgrp_index >= 0)
122                 dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
123
124         /* NOTICE: this can be optimized a little bit by moving the
125         * if (dvert) out of the loop, if needed */
126         for (j = 0; j < smd->repeat; j++) {
127                 for (i = 0; i < numDMEdges; i++) {
128                         float fvec[3];
129                         float *v1, *v2;
130                         unsigned int idx1, idx2;
131
132                         idx1 = medges[i].v1;
133                         idx2 = medges[i].v2;
134
135                         v1 = vertexCos[idx1];
136                         v2 = vertexCos[idx2];
137
138                         fvec[0] = (v1[0] + v2[0]) / 2.0;
139                         fvec[1] = (v1[1] + v2[1]) / 2.0;
140                         fvec[2] = (v1[2] + v2[2]) / 2.0;
141
142                         v1 = &ftmp[idx1*3];
143                         v2 = &ftmp[idx2*3];
144
145                         if (uctmp[idx1] < 255) {
146                                 uctmp[idx1]++;
147                                 add_v3_v3v3(v1, v1, fvec);
148                         }
149                         if (uctmp[idx2] < 255) {
150                                 uctmp[idx2]++;
151                                 add_v3_v3v3(v2, v2, fvec);
152                         }
153                 }
154
155                 if (dvert) {
156                         for (i = 0; i < numVerts; i++) {
157                                 MDeformWeight *dw = NULL;
158                                 float f, fm, facw, *fp, *v;
159                                 int k;
160                                 short flag = smd->flag;
161
162                                 v = vertexCos[i];
163                                 fp = &ftmp[i*3];
164
165                                 for (k = 0; k < dvert[i].totweight; ++k) {
166                                         if(dvert[i].dw[k].def_nr == defgrp_index) {
167                                                 dw = &dvert[i].dw[k];
168                                                 break;
169                                         }
170                                 }
171                                 if (!dw) continue;
172
173                                 f = fac * dw->weight;
174                                 fm = 1.0f - f;
175
176                                 /* fp is the sum of uctmp[i] verts, so must be averaged */
177                                 facw = 0.0f;
178                                 if (uctmp[i]) 
179                                         facw = f / (float)uctmp[i];
180
181                                 if (flag & MOD_SMOOTH_X)
182                                         v[0] = fm * v[0] + facw * fp[0];
183                                 if (flag & MOD_SMOOTH_Y)
184                                         v[1] = fm * v[1] + facw * fp[1];
185                                 if (flag & MOD_SMOOTH_Z)
186                                         v[2] = fm * v[2] + facw * fp[2];
187                         }
188                 }
189                 else { /* no vertex group */
190                         for (i = 0; i < numVerts; i++) {
191                                 float facw, *fp, *v;
192                                 short flag = smd->flag;
193
194                                 v = vertexCos[i];
195                                 fp = &ftmp[i*3];
196
197                                 /* fp is the sum of uctmp[i] verts, so must be averaged */
198                                 facw = 0.0f;
199                                 if (uctmp[i]) 
200                                         facw = fac / (float)uctmp[i];
201
202                                 if (flag & MOD_SMOOTH_X)
203                                         v[0] = facm * v[0] + facw * fp[0];
204                                 if (flag & MOD_SMOOTH_Y)
205                                         v[1] = facm * v[1] + facw * fp[1];
206                                 if (flag & MOD_SMOOTH_Z)
207                                         v[2] = facm * v[2] + facw * fp[2];
208                         }
209
210                 }
211
212                 memset(ftmp, 0, 3*sizeof(float)*numVerts);
213                 memset(uctmp, 0, sizeof(unsigned char)*numVerts);
214         }
215
216         MEM_freeN(ftmp);
217         MEM_freeN(uctmp);
218 }
219
220 static void deformVerts(
221                                            ModifierData *md, Object *ob, DerivedMesh *derivedData,
222            float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc)
223 {
224         DerivedMesh *dm= get_dm(md->scene, ob, NULL, derivedData, NULL, 0);
225
226         smoothModifier_do((SmoothModifierData *)md, ob, dm,
227                            vertexCos, numVerts);
228
229         if(dm != derivedData)
230                 dm->release(dm);
231 }
232
233 static void deformVertsEM(
234                                          ModifierData *md, Object *ob, struct EditMesh *editData,
235           DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
236 {
237         DerivedMesh *dm= get_dm(md->scene, ob, editData, derivedData, NULL, 0);
238
239         smoothModifier_do((SmoothModifierData *)md, ob, dm,
240                            vertexCos, numVerts);
241
242         if(dm != derivedData)
243                 dm->release(dm);
244 }
245
246
247 ModifierTypeInfo modifierType_Smooth = {
248         /* name */              "Smooth",
249         /* structName */        "SmoothModifierData",
250         /* structSize */        sizeof(SmoothModifierData),
251         /* type */              eModifierTypeType_OnlyDeform,
252         /* flags */             eModifierTypeFlag_AcceptsMesh
253                                                         | eModifierTypeFlag_SupportsEditmode,
254
255         /* copyData */          copyData,
256         /* deformVerts */       deformVerts,
257         /* deformVertsEM */     deformVertsEM,
258         /* deformMatricesEM */  0,
259         /* applyModifier */     0,
260         /* applyModifierEM */   0,
261         /* initData */          initData,
262         /* requiredDataMask */  requiredDataMask,
263         /* freeData */          0,
264         /* isDisabled */        isDisabled,
265         /* updateDepgraph */    0,
266         /* dependsOnTime */     0,
267         /* foreachObjectLink */ 0,
268         /* foreachIDLink */     0,
269 };