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