alternative to joe's commit r36451.
[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 |= (1 << CD_MDEFORMVERT);
89         dataMask |= (1 << CD_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 updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
144                            Object *UNUSED(ob), DagNode *obNode)
145 {
146         WarpModifierData *wmd = (WarpModifierData*) md;
147
148         if(wmd->object_from && wmd->object_to) {
149                 DagNode *fromNode = dag_get_node(forest, wmd->object_from);
150                 DagNode *toNode = dag_get_node(forest, wmd->object_to);
151
152                 dag_add_relation(forest, fromNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier1");
153                 dag_add_relation(forest, toNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier2");
154         }
155
156         if((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object) {
157                 DagNode *curNode = dag_get_node(forest, wmd->map_object);
158                 dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier3");
159         }
160 }
161
162 static void warpModifier_do(WarpModifierData *wmd, Object *ob,
163                             DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
164 {
165         float obinv[4][4];
166         float mat_from[4][4];
167         float mat_from_inv[4][4];
168         float mat_to[4][4];
169         float mat_unit[4][4];
170         float mat_final[4][4];
171
172         float tmat[4][4];
173
174         float strength = wmd->strength;
175         float fac = 1.0f, weight;
176         int i;
177         int defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
178         MDeformVert *dv= NULL;
179
180         float (*tex_co)[3]= NULL;
181
182         if(!(wmd->object_from && wmd->object_to))
183                 return;
184
185         if(wmd->curfalloff==NULL) /* should never happen, but bad lib linking could cause it */
186                 wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
187
188         invert_m4_m4(obinv, ob->obmat);
189
190         mul_m4_m4m4(mat_from, wmd->object_from->obmat, obinv);
191         mul_m4_m4m4(mat_to, wmd->object_to->obmat, obinv);
192
193         invert_m4_m4(tmat, mat_from); // swap?
194         mul_m4_m4m4(mat_final, mat_to, tmat);
195
196         invert_m4_m4(mat_from_inv, mat_from);
197
198         unit_m4(mat_unit);
199
200         if(strength < 0.0f) {
201                 float loc[3];
202                 strength = -strength;
203
204                 /* inverted location is not useful, just use the negative */
205                 copy_v3_v3(loc, mat_final[3]);
206                 invert_m4(mat_final);
207                 negate_v3_v3(mat_final[3], loc);
208
209         }
210         weight= strength;
211
212         if(wmd->texture) {
213                 tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, "warpModifier_do tex_co");
214                 get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);
215         }
216
217         for(i = 0; i < numVerts; i++) {
218                 float *co = vertexCos[i];
219
220                 if(wmd->falloff_type==eWarp_Falloff_None ||
221                         ((fac=len_v3v3(co, mat_from[3])) < wmd->falloff_radius && (fac=(wmd->falloff_radius-fac)/wmd->falloff_radius)) ) {
222
223                         /* skip if no vert group found */
224                         if(defgrp_index >= 0) {
225                                 dv = dm->getVertData(dm, i, CD_MDEFORMVERT);
226
227                                 if(dv) {
228                                         weight = defvert_find_weight(dv, defgrp_index) * wmd->strength;
229                                         if(weight <= 0.0f)
230                                                 continue;
231                                 }
232                         }
233
234
235                         /* closely match PROP_SMOOTH and similar */
236                         switch(wmd->falloff_type) {
237                         case eWarp_Falloff_None:
238                                 fac = 1.0f;
239                                 break;
240                         case eWarp_Falloff_Curve:
241                                 fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac);
242                                 break;
243                         case eWarp_Falloff_Sharp:
244                                 fac = fac*fac;
245                                 break;
246                         case eWarp_Falloff_Smooth:
247                                 fac = 3.0f*fac*fac - 2.0f*fac*fac*fac;
248                                 break;
249                         case eWarp_Falloff_Root:
250                                 fac = (float)sqrt(fac);
251                                 break;
252                         case eWarp_Falloff_Linear:
253                                 /* pass */
254                                 break;
255                         case eWarp_Falloff_Const:
256                                 fac = 1.0f;
257                                 break;
258                         case eWarp_Falloff_Sphere:
259                                 fac = (float)sqrt(2*fac - fac * fac);
260                                 break;
261                         }
262
263                         fac *= weight;
264
265                         if(tex_co) {
266                                 TexResult texres;
267                                 texres.nor = NULL;
268                                 get_texture_value(wmd->texture, tex_co[i], &texres);
269                                 fac *= texres.tin;
270                         }
271
272                         /* into the 'from' objects space */
273                         mul_m4_v3(mat_from_inv, co);
274
275                         if(fac >= 1.0f) {
276                                 mul_m4_v3(mat_final, co);
277                         }
278                         else if(fac > 0.0f) {
279                                 if(wmd->flag & MOD_WARP_VOLUME_PRESERVE) {
280                                         /* interpolate the matrix for nicer locations */
281                                         blend_m4_m4m4(tmat, mat_unit, mat_final, fac);
282                                         mul_m4_v3(tmat, co);
283                                 }
284                                 else {
285                                         float tvec[3];
286                                         mul_v3_m4v3(tvec, mat_final, co);
287                                         interp_v3_v3v3(co, co, tvec, fac);
288                                 }
289                         }
290
291                         /* out of the 'from' objects space */
292                         mul_m4_v3(mat_from, co);
293                 }
294         }
295
296         if(tex_co)
297                 MEM_freeN(tex_co);
298
299 }
300
301 static int warp_needs_dm(WarpModifierData *wmd)
302 {
303         return wmd->texture || wmd->defgrp_name[0];
304 }
305
306 static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
307                         float (*vertexCos)[3], int numVerts, int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
308 {
309         DerivedMesh *dm= NULL;
310         int use_dm= warp_needs_dm((WarpModifierData *)md);
311
312         if(use_dm) {
313                 dm= get_cddm(ob, NULL, derivedData, vertexCos);
314         }
315
316         warpModifier_do((WarpModifierData *)md, ob, dm, vertexCos, numVerts);
317
318         if(use_dm) {
319                 if(dm != derivedData) dm->release(dm);
320         }
321 }
322
323 static void deformVertsEM(ModifierData *md, Object *ob, struct EditMesh *editData,
324                           DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
325 {
326         DerivedMesh *dm = derivedData;
327         int use_dm= warp_needs_dm((WarpModifierData *)md);
328
329         if(use_dm) {
330                 if(!derivedData)
331                         dm = CDDM_from_editmesh(editData, ob->data);
332         }
333
334         deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0);
335
336         if(use_dm) {
337                 if(!derivedData) dm->release(dm);
338         }
339 }
340
341
342 ModifierTypeInfo modifierType_Warp = {
343         /* name */              "Warp",
344         /* structName */        "WarpModifierData",
345         /* structSize */        sizeof(WarpModifierData),
346         /* type */              eModifierTypeType_OnlyDeform,
347         /* flags */             eModifierTypeFlag_AcceptsCVs
348                                                         | eModifierTypeFlag_SupportsEditmode,
349         /* copyData */          copyData,
350         /* deformVerts */       deformVerts,
351         /* deformMatrices */    NULL,
352         /* deformVertsEM */     deformVertsEM,
353     /* deformMatricesEM */  NULL,
354         /* applyModifier */     0,
355         /* applyModifierEM */   0,
356         /* initData */          initData,
357         /* requiredDataMask */  requiredDataMask,
358         /* freeData */          freeData,
359         /* isDisabled */        isDisabled,
360         /* updateDepgraph */    updateDepgraph,
361         /* dependsOnTime */     dependsOnTime,
362     /* dependsOnNormals */      NULL,
363         /* foreachObjectLink */ foreachObjectLink,
364         /* foreachIDLink */     foreachIDLink,
365 };