Mesh Modifiers: refactor copying using a generic function
[blender.git] / source / blender / modifiers / intern / MOD_hook.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  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Daniel Dunbar
22  *                 Ton Roosendaal,
23  *                 Ben Batt,
24  *                 Brecht Van Lommel,
25  *                 Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  *
29  */
30
31 /** \file blender/modifiers/intern/MOD_hook.c
32  *  \ingroup modifiers
33  */
34
35
36 #include "DNA_mesh_types.h"
37 #include "DNA_meshdata_types.h"
38 #include "DNA_object_types.h"
39
40 #include "BLI_math.h"
41 #include "BLI_utildefines.h"
42 #include "BLI_string.h"
43
44 #include "BKE_action.h"
45 #include "BKE_cdderivedmesh.h"
46 #include "BKE_modifier.h"
47 #include "BKE_deform.h"
48
49
50 #include "depsgraph_private.h"
51 #include "MEM_guardedalloc.h"
52
53 #include "MOD_util.h"
54
55 static void initData(ModifierData *md) 
56 {
57         HookModifierData *hmd = (HookModifierData *) md;
58
59         hmd->force = 1.0;
60 }
61
62 static void copyData(ModifierData *md, ModifierData *target)
63 {
64         HookModifierData *hmd = (HookModifierData *) md;
65         HookModifierData *thmd = (HookModifierData *) target;
66
67         modifier_copyData_generic(md, target);
68
69         thmd->indexar = MEM_dupallocN(hmd->indexar);
70 }
71
72 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
73 {
74         HookModifierData *hmd = (HookModifierData *)md;
75         CustomDataMask dataMask = 0;
76
77         /* ask for vertexgroups if we need them */
78         if (hmd->name[0]) dataMask |= CD_MASK_MDEFORMVERT;
79         if (hmd->indexar) dataMask |= CD_MASK_ORIGINDEX;
80
81         return dataMask;
82 }
83
84 static void freeData(ModifierData *md)
85 {
86         HookModifierData *hmd = (HookModifierData *) md;
87
88         if (hmd->indexar) MEM_freeN(hmd->indexar);
89 }
90
91 static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
92 {
93         HookModifierData *hmd = (HookModifierData *) md;
94
95         return !hmd->object;
96 }
97
98 static void foreachObjectLink(
99         ModifierData *md, Object *ob,
100         void (*walk)(void *userData, Object *ob, Object **obpoin),
101         void *userData)
102 {
103         HookModifierData *hmd = (HookModifierData *) md;
104
105         walk(userData, ob, &hmd->object);
106 }
107
108 static void updateDepgraph(ModifierData *md, DagForest *forest,
109                            struct Scene *UNUSED(scene),
110                            Object *UNUSED(ob),
111                            DagNode *obNode)
112 {
113         HookModifierData *hmd = (HookModifierData *) md;
114
115         if (hmd->object) {
116                 DagNode *curNode = dag_get_node(forest, hmd->object);
117                 
118                 if (hmd->subtarget[0])
119                         dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Hook Modifier");
120                 else
121                         dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, "Hook Modifier");
122         }
123 }
124
125 static float hook_falloff(const float co_1[3], const float co_2[3], const float falloff_squared, float fac)
126 {
127         if (falloff_squared) {
128                 float len_squared = len_squared_v3v3(co_1, co_2);
129                 if (len_squared > falloff_squared) {
130                         return 0.0f;
131                 }
132                 else if (len_squared > 0.0f) {
133                         return fac * (1.0f - (len_squared / falloff_squared));
134                 }
135         }
136
137         return fac;
138 }
139
140 static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
141                            float (*vertexCos)[3], int numVerts)
142 {
143         bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
144         float vec[3], mat[4][4], dmat[4][4];
145         int i, *index_pt;
146         const float falloff_squared = hmd->falloff * hmd->falloff; /* for faster comparisons */
147         
148         MDeformVert *dvert;
149         int defgrp_index, max_dvert;
150         
151         /* get world-space matrix of target, corrected for the space the verts are in */
152         if (hmd->subtarget[0] && pchan) {
153                 /* bone target if there's a matching pose-channel */
154                 mul_m4_m4m4(dmat, hmd->object->obmat, pchan->pose_mat);
155         }
156         else {
157                 /* just object target */
158                 copy_m4_m4(dmat, hmd->object->obmat);
159         }
160         invert_m4_m4(ob->imat, ob->obmat);
161         mul_serie_m4(mat, ob->imat, dmat, hmd->parentinv,
162                      NULL, NULL, NULL, NULL, NULL);
163
164         modifier_get_vgroup(ob, dm, hmd->name, &dvert, &defgrp_index);
165         max_dvert = (dvert) ? numVerts : 0;
166
167         /* Regarding index range checking below.
168          *
169          * This should always be true and I don't generally like 
170          * "paranoid" style code like this, but old files can have
171          * indices that are out of range because old blender did
172          * not correct them on exit editmode. - zr
173          */
174         
175         if (hmd->force == 0.0f) {
176                 /* do nothing, avoid annoying checks in the loop */
177         }
178         else if (hmd->indexar) { /* vertex indices? */
179                 const float fac_orig = hmd->force;
180                 float fac;
181                 const int *origindex_ar;
182                 
183                 /* if DerivedMesh is present and has original index data, use it */
184                 if (dm && (origindex_ar = dm->getVertDataArray(dm, CD_ORIGINDEX))) {
185                         for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) {
186                                 if (*index_pt < numVerts) {
187                                         int j;
188                                         
189                                         for (j = 0; j < numVerts; j++) {
190                                                 if (origindex_ar[j] == *index_pt) {
191                                                         float *co = vertexCos[j];
192                                                         if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
193                                                                 if (dvert)
194                                                                         fac *= defvert_find_weight(dvert + j, defgrp_index);
195                                                                 
196                                                                 if (fac) {
197                                                                         mul_v3_m4v3(vec, mat, co);
198                                                                         interp_v3_v3v3(co, co, vec, fac);
199                                                                 }
200                                                         }
201                                                 }
202                                         }
203                                 }
204                         }
205                 }
206                 else { /* missing dm or ORIGINDEX */
207                         for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) {
208                                 if (*index_pt < numVerts) {
209                                         float *co = vertexCos[*index_pt];
210                                         if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
211                                                 if (dvert)
212                                                         fac *= defvert_find_weight(dvert + (*index_pt), defgrp_index);
213                                                 
214                                                 if (fac) {
215                                                         mul_v3_m4v3(vec, mat, co);
216                                                         interp_v3_v3v3(co, co, vec, fac);
217                                                 }
218                                         }
219                                 }
220                         }
221                 }
222         }
223         else if (dvert) {  /* vertex group hook */
224                 const float fac_orig = hmd->force;
225                 
226                 for (i = 0; i < max_dvert; i++, dvert++) {
227                         float fac;
228                         float *co = vertexCos[i];
229                         
230                         if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
231                                 fac *= defvert_find_weight(dvert, defgrp_index);
232                                 if (fac) {
233                                         mul_v3_m4v3(vec, mat, co);
234                                         interp_v3_v3v3(co, co, vec, fac);
235                                 }
236                         }
237                 }
238         }
239 }
240
241 static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
242                         float (*vertexCos)[3], int numVerts,
243                         ModifierApplyFlag UNUSED(flag))
244 {
245         HookModifierData *hmd = (HookModifierData *) md;
246         DerivedMesh *dm = derivedData;
247         /* We need a valid dm for meshes when a vgroup is set... */
248         if (!dm && ob->type == OB_MESH && hmd->name[0] != '\0')
249                 dm = get_dm(ob, NULL, dm, NULL, false, false);
250
251         deformVerts_do(hmd, ob, dm, vertexCos, numVerts);
252
253         if (derivedData != dm)
254                 dm->release(dm);
255 }
256
257 static void deformVertsEM(ModifierData *md, Object *ob, struct BMEditMesh *editData,
258                           DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
259 {
260         HookModifierData *hmd = (HookModifierData *) md;
261         DerivedMesh *dm = derivedData;
262         /* We need a valid dm for meshes when a vgroup is set... */
263         if (!dm && ob->type == OB_MESH && hmd->name[0] != '\0')
264                 dm = get_dm(ob, editData, dm, NULL, false, false);
265
266         deformVerts_do(hmd, ob, dm, vertexCos, numVerts);
267
268         if (derivedData != dm)
269                 dm->release(dm);
270 }
271
272
273 ModifierTypeInfo modifierType_Hook = {
274         /* name */              "Hook",
275         /* structName */        "HookModifierData",
276         /* structSize */        sizeof(HookModifierData),
277         /* type */              eModifierTypeType_OnlyDeform,
278         /* flags */             eModifierTypeFlag_AcceptsCVs |
279                                 eModifierTypeFlag_SupportsEditmode,
280         /* copyData */          copyData,
281         /* deformVerts */       deformVerts,
282         /* deformMatrices */    NULL,
283         /* deformVertsEM */     deformVertsEM,
284         /* deformMatricesEM */  NULL,
285         /* applyModifier */     NULL,
286         /* applyModifierEM */   NULL,
287         /* initData */          initData,
288         /* requiredDataMask */  requiredDataMask,
289         /* freeData */          freeData,
290         /* isDisabled */        isDisabled,
291         /* updateDepgraph */    updateDepgraph,
292         /* dependsOnTime */     NULL,
293         /* dependsOnNormals */  NULL,
294         /* foreachObjectLink */ foreachObjectLink,
295         /* foreachIDLink */     NULL,
296         /* foreachTexLink */    NULL,
297 };