1476c79216903a6ec28ec0b436e856c96f1f6ded
[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
36 #include "DNA_scene_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_meshdata_types.h"
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_math.h"
43 #include "BLI_utildefines.h"
44
45
46 #include "BKE_collision.h"
47 #include "BKE_cdderivedmesh.h"
48 #include "BKE_global.h"
49 #include "BKE_modifier.h"
50 #include "BKE_object.h"
51 #include "BKE_pointcache.h"
52 #include "BKE_scene.h"
53
54 #include "MOD_util.h"
55
56 static void initData(ModifierData *md) 
57 {
58         CollisionModifierData *collmd = (CollisionModifierData*) md;
59         
60         collmd->x = NULL;
61         collmd->xnew = NULL;
62         collmd->current_x = NULL;
63         collmd->current_xnew = NULL;
64         collmd->current_v = NULL;
65         collmd->time_x = collmd->time_xnew = -1000;
66         collmd->numverts = 0;
67         collmd->bvhtree = NULL;
68 }
69
70 static void freeData(ModifierData *md)
71 {
72         CollisionModifierData *collmd = (CollisionModifierData*) md;
73         
74         if (collmd) 
75         {
76                 if(collmd->bvhtree)
77                         BLI_bvhtree_free(collmd->bvhtree);
78                 if(collmd->x)
79                         MEM_freeN(collmd->x);
80                 if(collmd->xnew)
81                         MEM_freeN(collmd->xnew);
82                 if(collmd->current_x)
83                         MEM_freeN(collmd->current_x);
84                 if(collmd->current_xnew)
85                         MEM_freeN(collmd->current_xnew);
86                 if(collmd->current_v)
87                         MEM_freeN(collmd->current_v);
88                 if(collmd->mfaces)
89                         MEM_freeN(collmd->mfaces);
90                 
91                 collmd->x = NULL;
92                 collmd->xnew = NULL;
93                 collmd->current_x = NULL;
94                 collmd->current_xnew = NULL;
95                 collmd->current_v = NULL;
96                 collmd->time_x = collmd->time_xnew = -1000;
97                 collmd->numverts = 0;
98                 collmd->bvhtree = NULL;
99                 collmd->mfaces = NULL;
100         }
101 }
102
103 static int dependsOnTime(ModifierData *UNUSED(md))
104 {
105         return 1;
106 }
107
108 static void deformVerts(ModifierData *md, Object *ob,
109                                                 DerivedMesh *derivedData,
110                                                 float (*vertexCos)[3],
111                                                 int UNUSED(numVerts),
112                                                 int UNUSED(useRenderParams),
113                                                 int UNUSED(isFinalCalc))
114 {
115         CollisionModifierData *collmd = (CollisionModifierData*) md;
116         DerivedMesh *dm = NULL;
117         MVert *tempVert = NULL;
118         
119         /* if possible use/create DerivedMesh */
120         if(derivedData) dm = CDDM_copy(derivedData);
121         else if(ob->type==OB_MESH) dm = CDDM_from_mesh(ob->data, ob);
122         
123         if(!ob->pd)
124         {
125                 printf("CollisionModifier deformVerts: Should not happen!\n");
126                 return;
127         }
128         
129         if(dm)
130         {
131                 float current_time = 0;
132                 unsigned int numverts = 0;
133
134                 CDDM_apply_vert_coords(dm, vertexCos);
135                 CDDM_calc_normals(dm);
136                 
137                 current_time = BKE_curframe(md->scene);
138                 
139                 if(G.rt > 0)
140                         printf("current_time %f, collmd->time_xnew %f\n", current_time, collmd->time_xnew);
141                 
142                 numverts = dm->getNumVerts ( dm );
143                 
144                 if((current_time > collmd->time_xnew)|| (BKE_ptcache_get_continue_physics()))
145                 {
146                         unsigned int i;
147
148                         // check if mesh has changed
149                         if(collmd->x && (numverts != collmd->numverts))
150                                 freeData((ModifierData *)collmd);
151                         
152                         if(collmd->time_xnew == -1000) // first time
153                         {
154                                 collmd->x = dm->dupVertArray(dm); // frame start position
155                                 
156                                 for ( i = 0; i < numverts; i++ )
157                                 {
158                                         // we save global positions
159                                         mul_m4_v3( ob->obmat, collmd->x[i].co );
160                                 }
161                                 
162                                 collmd->xnew = MEM_dupallocN(collmd->x); // frame end position
163                                 collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame
164                                 collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
165                                 collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
166
167                                 collmd->numverts = numverts;
168                                 
169                                 DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
170
171                                 collmd->mfaces = dm->dupTessFaceArray(dm);
172                                 collmd->numfaces = dm->getNumTessFaces(dm);
173                                 
174                                 // create bounding box hierarchy
175                                 collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft);
176                                 
177                                 collmd->time_x = collmd->time_xnew = current_time;
178                         }
179                         else if(numverts == collmd->numverts)
180                         {
181                                 // put positions to old positions
182                                 tempVert = collmd->x;
183                                 collmd->x = collmd->xnew;
184                                 collmd->xnew = tempVert;
185                                 collmd->time_x = collmd->time_xnew;
186                                 
187                                 memcpy(collmd->xnew, dm->getVertArray(dm), numverts*sizeof(MVert));
188                                 
189                                 for ( i = 0; i < numverts; i++ )
190                                 {
191                                         // we save global positions
192                                         mul_m4_v3( ob->obmat, collmd->xnew[i].co );
193                                 }
194                                 
195                                 memcpy(collmd->current_xnew, collmd->x, numverts*sizeof(MVert));
196                                 memcpy(collmd->current_x, collmd->x, numverts*sizeof(MVert));
197                                 
198                                 /* check if GUI setting has changed for bvh */
199                                 if(collmd->bvhtree) 
200                                 {
201                                         if(ob->pd->pdef_sboft != BLI_bvhtree_getepsilon(collmd->bvhtree))
202                                         {
203                                                 BLI_bvhtree_free(collmd->bvhtree);
204                                                 collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, 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                                 {
212                                         collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
213                                 }
214                                 else
215                                 {
216                                         // recalc static bounding boxes
217                                         bvhtree_update_from_mvert ( collmd->bvhtree, collmd->mfaces, collmd->numfaces, collmd->current_x, collmd->current_xnew, collmd->numverts, 1 );
218                                 }
219                                 
220                                 collmd->time_xnew = current_time;
221                         }
222                         else if(numverts != collmd->numverts)
223                         {
224                                 freeData((ModifierData *)collmd);
225                         }
226                         
227                 }
228                 else if(current_time < collmd->time_xnew)
229                 {       
230                         freeData((ModifierData *)collmd);
231                 }
232                 else
233                 {
234                         if(numverts != collmd->numverts)
235                         {
236                                 freeData((ModifierData *)collmd);
237                         }
238                 }
239         }
240         
241         if(dm)
242                 dm->release(dm);
243 }
244
245
246 ModifierTypeInfo modifierType_Collision = {
247         /* name */              "Collision",
248         /* structName */        "CollisionModifierData",
249         /* structSize */        sizeof(CollisionModifierData),
250         /* type */              eModifierTypeType_OnlyDeform,
251         /* flags */             eModifierTypeFlag_AcceptsMesh
252                                                         | eModifierTypeFlag_Single,
253
254         /* copyData */          NULL,
255         /* deformVerts */       deformVerts,
256         /* deformMatrices */    NULL,
257         /* deformVertsEM */     NULL,
258         /* deformMatricesEM */  NULL,
259         /* applyModifier */     NULL,
260         /* applyModifierEM */   NULL,
261         /* initData */          initData,
262         /* requiredDataMask */  NULL,
263         /* freeData */          freeData,
264         /* isDisabled */        NULL,
265         /* updateDepgraph */    NULL,
266         /* dependsOnTime */     dependsOnTime,
267         /* dependsOnNormals */  NULL,
268         /* foreachObjectLink */ NULL,
269         /* foreachIDLink */     NULL,
270         /* foreachTexLink */    NULL,
271 };