I made multitude of fixes based on the comments provided online:
[blender.git] / source / blender / modifiers / intern / MOD_warp.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 * Contributor(s): Campbell Barton
21 *
22 * ***** END GPL LICENSE BLOCK *****
23 *
24 */
25
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_math.h"
31 #include "BLI_utildefines.h"
32
33 #include "BKE_cdderivedmesh.h"
34 #include "BKE_modifier.h"
35 #include "BKE_deform.h"
36 #include "BKE_texture.h"
37 #include "BKE_colortools.h"
38
39 #include "DNA_object_types.h"
40 #include "DNA_meshdata_types.h"
41
42 #include "depsgraph_private.h"
43
44 #include "RE_shader_ext.h"
45
46 #include "MOD_util.h"
47
48
49 static void initData(ModifierData *md)
50 {
51         WarpModifierData *wmd = (WarpModifierData*) md;
52
53         wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
54         wmd->texture = NULL;
55         wmd->strength = 1.0f;
56         wmd->falloff_radius = 1.0f;
57         wmd->falloff_type = eWarp_Falloff_Smooth;
58         wmd->flag = 0;
59 }
60
61 static void copyData(ModifierData *md, ModifierData *target)
62 {
63         WarpModifierData *wmd = (WarpModifierData*) md;
64         WarpModifierData *twmd = (WarpModifierData*) target;
65
66         twmd->object_from = wmd->object_from;
67         twmd->object_to = wmd->object_to;
68
69         twmd->strength = wmd->strength;
70         twmd->falloff_radius = wmd->falloff_radius;
71         twmd->falloff_type = wmd->falloff_type;
72         strncpy(twmd->defgrp_name, wmd->defgrp_name, sizeof(twmd->defgrp_name));
73         twmd->curfalloff = curvemapping_copy(wmd->curfalloff);
74
75         /* map info */
76         twmd->texture = wmd->texture;
77         twmd->map_object = wmd->map_object;
78         strncpy(twmd->uvlayer_name, wmd->uvlayer_name, sizeof(twmd->uvlayer_name));
79         twmd->texmapping= wmd->texmapping;
80 }
81
82 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
83 {
84         WarpModifierData *wmd = (WarpModifierData *)md;
85         CustomDataMask dataMask = 0;
86
87         /* ask for vertexgroups if we need them */
88         if(wmd->defgrp_name[0]) dataMask |= (CD_MASK_MDEFORMVERT);
89         dataMask |= (CD_MASK_MDEFORMVERT);
90
91         /* ask for UV coordinates if we need them */
92         if(wmd->texmapping == MOD_DISP_MAP_UV) dataMask |= (1 << CD_MTFACE);
93
94         return dataMask;
95 }
96
97 static int dependsOnTime(ModifierData *md)
98 {
99         WarpModifierData *wmd = (WarpModifierData *)md;
100
101         if(wmd->texture) {
102                 return BKE_texture_dependsOnTime(wmd->texture);
103         }
104         else {
105                 return 0;
106         }
107 }
108
109 static void freeData(ModifierData *md)
110 {
111         WarpModifierData *wmd = (WarpModifierData *) md;
112         curvemapping_free(wmd->curfalloff);
113 }
114
115
116 static int isDisabled(ModifierData *md, int UNUSED(userRenderParams))
117 {
118         WarpModifierData *wmd = (WarpModifierData*) md;
119
120         return !(wmd->object_from && wmd->object_to);
121 }
122
123 static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
124 {
125         WarpModifierData *wmd = (WarpModifierData*) md;
126
127         walk(userData, ob, &wmd->object_from);
128         walk(userData, ob, &wmd->object_to);
129         walk(userData, ob, &wmd->map_object);
130 }
131
132 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
133 {
134         WarpModifierData *wmd = (WarpModifierData*) md;
135
136         walk(userData, ob, (ID **)&wmd->texture);
137
138         walk(userData, ob, (ID **)&wmd->object_from);
139         walk(userData, ob, (ID **)&wmd->object_to);
140         walk(userData, ob, (ID **)&wmd->map_object);
141 }
142
143 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
144 {
145         walk(userData, ob, md, "texture");
146 }
147
148 static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
149                            Object *UNUSED(ob), DagNode *obNode)
150 {
151         WarpModifierData *wmd = (WarpModifierData*) md;
152
153         if(wmd->object_from && wmd->object_to) {
154                 DagNode *fromNode = dag_get_node(forest, wmd->object_from);
155                 DagNode *toNode = dag_get_node(forest, wmd->object_to);
156
157                 dag_add_relation(forest, fromNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier1");
158                 dag_add_relation(forest, toNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier2");
159         }
160
161         if((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object) {
162                 DagNode *curNode = dag_get_node(forest, wmd->map_object);
163                 dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier3");
164         }
165 }
166
167 static void warpModifier_do(WarpModifierData *wmd, Object *ob,
168                             DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
169 {
170         float obinv[4][4];
171         float mat_from[4][4];
172         float mat_from_inv[4][4];
173         float mat_to[4][4];
174         float mat_unit[4][4];
175         float mat_final[4][4];
176
177         float tmat[4][4];
178
179         float strength = wmd->strength;
180         float fac = 1.0f, weight;
181         int i;
182         int defgrp_index;
183         MDeformVert *dvert, *dv= NULL;
184
185         float (*tex_co)[3]= NULL;
186
187         if(!(wmd->object_from && wmd->object_to))
188                 return;
189
190         modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);
191
192         if(wmd->curfalloff==NULL) /* should never happen, but bad lib linking could cause it */
193                 wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
194
195         invert_m4_m4(obinv, ob->obmat);
196
197         mul_m4_m4m4(mat_from, wmd->object_from->obmat, obinv);
198         mul_m4_m4m4(mat_to, wmd->object_to->obmat, obinv);
199
200         invert_m4_m4(tmat, mat_from); // swap?
201         mul_m4_m4m4(mat_final, mat_to, tmat);
202
203         invert_m4_m4(mat_from_inv, mat_from);
204
205         unit_m4(mat_unit);
206
207         if(strength < 0.0f) {
208                 float loc[3];
209                 strength = -strength;
210
211                 /* inverted location is not useful, just use the negative */
212                 copy_v3_v3(loc, mat_final[3]);
213                 invert_m4(mat_final);
214                 negate_v3_v3(mat_final[3], loc);
215
216         }
217         weight= strength;
218
219         if(wmd->texture) {
220                 tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, "warpModifier_do tex_co");
221                 get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);
222         }
223
224         for(i = 0; i < numVerts; i++) {
225                 float *co = vertexCos[i];
226
227                 if(wmd->falloff_type==eWarp_Falloff_None ||
228                         ((fac=len_v3v3(co, mat_from[3])) < wmd->falloff_radius && (fac=(wmd->falloff_radius-fac)/wmd->falloff_radius)) ) {
229
230                         /* skip if no vert group found */
231                         if(dvert && defgrp_index >= 0) {
232                                 dv = &dvert[i];
233
234                                 if(dv) {
235                                         weight = defvert_find_weight(dv, defgrp_index) * wmd->strength;
236                                         if(weight <= 0.0f)
237                                                 continue;
238                                 }
239                         }
240
241
242                         /* closely match PROP_SMOOTH and similar */
243                         switch(wmd->falloff_type) {
244                         case eWarp_Falloff_None:
245                                 fac = 1.0f;
246                                 break;
247                         case eWarp_Falloff_Curve:
248                                 fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac);
249                                 break;
250                         case eWarp_Falloff_Sharp:
251                                 fac = fac*fac;
252                                 break;
253                         case eWarp_Falloff_Smooth:
254                                 fac = 3.0f*fac*fac - 2.0f*fac*fac*fac;
255                                 break;
256                         case eWarp_Falloff_Root:
257                                 fac = (float)sqrt(fac);
258                                 break;
259                         case eWarp_Falloff_Linear:
260                                 /* pass */
261                                 break;
262                         case eWarp_Falloff_Const:
263                                 fac = 1.0f;
264                                 break;
265                         case eWarp_Falloff_Sphere:
266                                 fac = (float)sqrt(2*fac - fac * fac);
267                                 break;
268                         }
269
270                         fac *= weight;
271
272                         if(tex_co) {
273                                 TexResult texres;
274                                 texres.nor = NULL;
275                                 get_texture_value(wmd->texture, tex_co[i], &texres);
276                                 fac *= texres.tin;
277                         }
278
279                         /* into the 'from' objects space */
280                         mul_m4_v3(mat_from_inv, co);
281
282                         if(fac >= 1.0f) {
283                                 mul_m4_v3(mat_final, co);
284                         }
285                         else if(fac > 0.0f) {
286                                 if(wmd->flag & MOD_WARP_VOLUME_PRESERVE) {
287                                         /* interpolate the matrix for nicer locations */
288                                         blend_m4_m4m4(tmat, mat_unit, mat_final, fac);
289                                         mul_m4_v3(tmat, co);
290                                 }
291                                 else {
292                                         float tvec[3];
293                                         mul_v3_m4v3(tvec, mat_final, co);
294                                         interp_v3_v3v3(co, co, tvec, fac);
295                                 }
296                         }
297
298                         /* out of the 'from' objects space */
299                         mul_m4_v3(mat_from, co);
300                 }
301         }
302
303         if(tex_co)
304                 MEM_freeN(tex_co);
305
306 }
307
308 static int warp_needs_dm(WarpModifierData *wmd)
309 {
310         return wmd->texture || wmd->defgrp_name[0];
311 }
312
313 static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
314                         float (*vertexCos)[3], int numVerts, int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
315 {
316         DerivedMesh *dm= NULL;
317         int use_dm= warp_needs_dm((WarpModifierData *)md);
318
319         if(use_dm) {
320                 dm= get_cddm(ob, NULL, derivedData, vertexCos);
321         }
322
323         warpModifier_do((WarpModifierData *)md, ob, dm, vertexCos, numVerts);
324
325         if(use_dm) {
326                 if(dm != derivedData) dm->release(dm);
327         }
328 }
329
330 static void deformVertsEM(ModifierData *md, Object *ob, struct EditMesh *editData,
331                           DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
332 {
333         DerivedMesh *dm = derivedData;
334         int use_dm= warp_needs_dm((WarpModifierData *)md);
335
336         if(use_dm) {
337                 if(!derivedData)
338                         dm = CDDM_from_editmesh(editData, ob->data);
339         }
340
341         deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0);
342
343         if(use_dm) {
344                 if(!derivedData) dm->release(dm);
345         }
346 }
347
348
349 ModifierTypeInfo modifierType_Warp = {
350         /* name */              "Warp",
351         /* structName */        "WarpModifierData",
352         /* structSize */        sizeof(WarpModifierData),
353         /* type */              eModifierTypeType_OnlyDeform,
354         /* flags */             eModifierTypeFlag_AcceptsCVs
355                                                         | eModifierTypeFlag_SupportsEditmode,
356         /* copyData */          copyData,
357         /* deformVerts */       deformVerts,
358         /* deformMatrices */    NULL,
359         /* deformVertsEM */     deformVertsEM,
360         /* deformMatricesEM */  NULL,
361         /* applyModifier */     0,
362         /* applyModifierEM */   0,
363         /* initData */          initData,
364         /* requiredDataMask */  requiredDataMask,
365         /* freeData */          freeData,
366         /* isDisabled */        isDisabled,
367         /* updateDepgraph */    updateDepgraph,
368         /* dependsOnTime */     dependsOnTime,
369         /* dependsOnNormals */  NULL,
370         /* foreachObjectLink */ foreachObjectLink,
371         /* foreachIDLink */     foreachIDLink,
372         /* foreachTexLink */    foreachTexLink,
373 };