Extract common modifier parameters into ModifierEvalContext struct
[blender.git] / source / blender / modifiers / intern / MOD_collision.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_collision.c
32  *  \ingroup modifiers
33  */
34
35 #include "DNA_object_types.h"
36 #include "DNA_meshdata_types.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLI_math.h"
41 #include "BLI_utildefines.h"
42
43 #include "BKE_collision.h"
44 #include "BKE_cdderivedmesh.h"
45 #include "BKE_global.h"
46 #include "BKE_modifier.h"
47 #include "BKE_pointcache.h"
48 #include "BKE_scene.h"
49
50 #include "MOD_modifiertypes.h"
51
52 static void initData(ModifierData *md) 
53 {
54         CollisionModifierData *collmd = (CollisionModifierData *) md;
55         
56         collmd->x = NULL;
57         collmd->xnew = NULL;
58         collmd->current_x = NULL;
59         collmd->current_xnew = NULL;
60         collmd->current_v = NULL;
61         collmd->time_x = collmd->time_xnew = -1000;
62         collmd->mvert_num = 0;
63         collmd->tri_num = 0;
64         collmd->is_static = false;
65         collmd->bvhtree = NULL;
66 }
67
68 static void freeData(ModifierData *md)
69 {
70         CollisionModifierData *collmd = (CollisionModifierData *) md;
71         
72         if (collmd) {
73                 if (collmd->bvhtree) {
74                         BLI_bvhtree_free(collmd->bvhtree);
75                         collmd->bvhtree = NULL;
76                 }
77
78                 MEM_SAFE_FREE(collmd->x);
79                 MEM_SAFE_FREE(collmd->xnew);
80                 MEM_SAFE_FREE(collmd->current_x);
81                 MEM_SAFE_FREE(collmd->current_xnew);
82                 MEM_SAFE_FREE(collmd->current_v);
83
84                 if (collmd->tri) {
85                         MEM_freeN((void *)collmd->tri);
86                         collmd->tri = NULL;
87                 }
88
89                 collmd->time_x = collmd->time_xnew = -1000;
90                 collmd->mvert_num = 0;
91                 collmd->tri_num = 0;
92                 collmd->is_static = false;
93         }
94 }
95
96 static bool dependsOnTime(ModifierData *UNUSED(md))
97 {
98         return true;
99 }
100
101 static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx,
102                         DerivedMesh *derivedData,
103                         float (*vertexCos)[3],
104                         int UNUSED(numVerts))
105 {
106         CollisionModifierData *collmd = (CollisionModifierData *) md;
107         DerivedMesh *dm = NULL;
108         MVert *tempVert = NULL;
109         Object *ob = ctx->object;
110         
111         /* if possible use/create DerivedMesh */
112         if (derivedData) dm = CDDM_copy(derivedData);
113         else if (ob->type == OB_MESH) dm = CDDM_from_mesh(ob->data);
114         
115         if (!ob->pd) {
116                 printf("CollisionModifier deformVerts: Should not happen!\n");
117                 return;
118         }
119         
120         if (dm) {
121                 float current_time = 0;
122                 unsigned int mvert_num = 0;
123
124                 CDDM_apply_vert_coords(dm, vertexCos);
125                 CDDM_calc_normals(dm);
126                 
127                 current_time = BKE_scene_frame_get(md->scene);
128                 
129                 if (G.debug_value > 0)
130                         printf("current_time %f, collmd->time_xnew %f\n", current_time, collmd->time_xnew);
131                 
132                 mvert_num = dm->getNumVerts(dm);
133                 
134                 if (current_time > collmd->time_xnew) {
135                         unsigned int i;
136
137                         /* check if mesh has changed */
138                         if (collmd->x && (mvert_num != collmd->mvert_num))
139                                 freeData((ModifierData *)collmd);
140
141                         if (collmd->time_xnew == -1000) { /* first time */
142
143                                 collmd->x = dm->dupVertArray(dm); /* frame start position */
144
145                                 for (i = 0; i < mvert_num; i++) {
146                                         /* we save global positions */
147                                         mul_m4_v3(ob->obmat, collmd->x[i].co);
148                                 }
149                                 
150                                 collmd->xnew = MEM_dupallocN(collmd->x); // frame end position
151                                 collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame
152                                 collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
153                                 collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
154
155                                 collmd->mvert_num = mvert_num;
156
157                                 collmd->tri_num = dm->getNumLoopTri(dm);
158                                 {
159                                         const MLoop *mloop = dm->getLoopArray(dm);
160                                         const MLoopTri *looptri = dm->getLoopTriArray(dm);
161                                         MVertTri *tri = MEM_malloc_arrayN(collmd->tri_num, sizeof(*tri), __func__);
162                                         DM_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num);
163                                         collmd->tri = tri;
164                                 }
165
166                                 /* create bounding box hierarchy */
167                                 collmd->bvhtree = bvhtree_build_from_mvert(
168                                         collmd->x,
169                                         collmd->tri, collmd->tri_num,
170                                         ob->pd->pdef_sboft);
171
172                                 collmd->time_x = collmd->time_xnew = current_time;
173                                 collmd->is_static = true;
174                         }
175                         else if (mvert_num == collmd->mvert_num) {
176                                 /* put positions to old positions */
177                                 tempVert = collmd->x;
178                                 collmd->x = collmd->xnew;
179                                 collmd->xnew = tempVert;
180                                 collmd->time_x = collmd->time_xnew;
181
182                                 memcpy(collmd->xnew, dm->getVertArray(dm), mvert_num * sizeof(MVert));
183
184                                 bool is_static = true;
185
186                                 for (i = 0; i < mvert_num; i++) {
187                                         /* we save global positions */
188                                         mul_m4_v3(ob->obmat, collmd->xnew[i].co);
189
190                                         /* detect motion */
191                                         is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co);
192                                 }
193
194                                 memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert));
195                                 memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert));
196
197                                 /* check if GUI setting has changed for bvh */
198                                 if (collmd->bvhtree) {
199                                         if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
200                                                 BLI_bvhtree_free(collmd->bvhtree);
201                                                 collmd->bvhtree = bvhtree_build_from_mvert(
202                                                         collmd->current_x,
203                                                         collmd->tri, collmd->tri_num,
204                                                         ob->pd->pdef_sboft);
205                                         }
206                         
207                                 }
208                                 
209                                 /* happens on file load (ONLY when i decomment changes in readfile.c) */
210                                 if (!collmd->bvhtree) {
211                                         collmd->bvhtree = bvhtree_build_from_mvert(
212                                                 collmd->current_x,
213                                                 collmd->tri, collmd->tri_num,
214                                                 ob->pd->pdef_sboft);
215                                 }
216                                 else if (!collmd->is_static || !is_static) {
217                                         /* recalc static bounding boxes */
218                                         bvhtree_update_from_mvert(
219                                                 collmd->bvhtree,
220                                                 collmd->current_x, collmd->current_xnew,
221                                                 collmd->tri, collmd->tri_num,
222                                                 true);
223                                 }
224
225                                 collmd->is_static = is_static;
226                                 collmd->time_xnew = current_time;
227                         }
228                         else if (mvert_num != collmd->mvert_num) {
229                                 freeData((ModifierData *)collmd);
230                         }
231                         
232                 }
233                 else if (current_time < collmd->time_xnew) {
234                         freeData((ModifierData *)collmd);
235                 }
236                 else {
237                         if (mvert_num != collmd->mvert_num) {
238                                 freeData((ModifierData *)collmd);
239                         }
240                 }
241         }
242         
243         if (dm)
244                 dm->release(dm);
245 }
246
247
248 ModifierTypeInfo modifierType_Collision = {
249         /* name */              "Collision",
250         /* structName */        "CollisionModifierData",
251         /* structSize */        sizeof(CollisionModifierData),
252         /* type */              eModifierTypeType_OnlyDeform,
253         /* flags */             eModifierTypeFlag_AcceptsMesh |
254                                 eModifierTypeFlag_Single,
255
256         /* copyData */          NULL,
257
258         /* deformVerts_DM */    deformVerts,
259         /* deformMatrices_DM */ NULL,
260         /* deformVertsEM_DM */  NULL,
261         /* deformMatricesEM_DM*/NULL,
262         /* applyModifier_DM */  NULL,
263         /* applyModifierEM_DM */NULL,
264
265         /* deformVerts */       NULL,
266         /* deformMatrices */    NULL,
267         /* deformVertsEM */     NULL,
268         /* deformMatricesEM */  NULL,
269         /* applyModifier */     NULL,
270         /* applyModifierEM */   NULL,
271
272         /* initData */          initData,
273         /* requiredDataMask */  NULL,
274         /* freeData */          freeData,
275         /* isDisabled */        NULL,
276         /* updateDepsgraph */   NULL,
277         /* dependsOnTime */     dependsOnTime,
278         /* dependsOnNormals */  NULL,
279         /* foreachObjectLink */ NULL,
280         /* foreachIDLink */     NULL,
281         /* foreachTexLink */    NULL,
282 };