Merging revision 29560:30125 from trunk.
[blender.git] / source / blender / modifiers / intern / MOD_collision.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 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
21 * All rights reserved.
22 *
23 * Contributor(s): Daniel Dunbar
24 *                 Ton Roosendaal,
25 *                 Ben Batt,
26 *                 Brecht Van Lommel,
27 *                 Campbell Barton
28 *
29 * ***** END GPL LICENSE BLOCK *****
30 *
31 */
32
33 #include "DNA_scene_types.h"
34
35 #include "BLI_math.h"
36
37 #include "BKE_collision.h"
38 #include "BKE_cdderivedmesh.h"
39 #include "BKE_global.h"
40 #include "BKE_modifier.h"
41 #include "BKE_object.h"
42 #include "BKE_pointcache.h"
43 #include "BKE_scene.h"
44
45
46 static void initData(ModifierData *md) 
47 {
48         CollisionModifierData *collmd = (CollisionModifierData*) md;
49         
50         collmd->x = NULL;
51         collmd->xnew = NULL;
52         collmd->current_x = NULL;
53         collmd->current_xnew = NULL;
54         collmd->current_v = NULL;
55         collmd->time = -1000;
56         collmd->numverts = 0;
57         collmd->bvhtree = NULL;
58 }
59
60 static void freeData(ModifierData *md)
61 {
62         CollisionModifierData *collmd = (CollisionModifierData*) md;
63         
64         if (collmd) 
65         {
66                 if(collmd->bvhtree)
67                         BLI_bvhtree_free(collmd->bvhtree);
68                 if(collmd->x)
69                         MEM_freeN(collmd->x);
70                 if(collmd->xnew)
71                         MEM_freeN(collmd->xnew);
72                 if(collmd->current_x)
73                         MEM_freeN(collmd->current_x);
74                 if(collmd->current_xnew)
75                         MEM_freeN(collmd->current_xnew);
76                 if(collmd->current_v)
77                         MEM_freeN(collmd->current_v);
78                 if(collmd->mfaces)
79                         MEM_freeN(collmd->mfaces);
80                 
81                 collmd->x = NULL;
82                 collmd->xnew = NULL;
83                 collmd->current_x = NULL;
84                 collmd->current_xnew = NULL;
85                 collmd->current_v = NULL;
86                 collmd->time = -1000;
87                 collmd->numverts = 0;
88                 collmd->bvhtree = NULL;
89                 collmd->mfaces = NULL;
90         }
91 }
92
93 static int dependsOnTime(ModifierData *md)
94 {
95         return 1;
96 }
97
98 static void deformVerts(
99                                           ModifierData *md, Object *ob, DerivedMesh *derivedData,
100            float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc)
101 {
102         CollisionModifierData *collmd = (CollisionModifierData*) md;
103         DerivedMesh *dm = NULL;
104         float current_time = 0;
105         unsigned int numverts = 0, i = 0;
106         MVert *tempVert = NULL;
107         
108         /* if possible use/create DerivedMesh */
109         if(derivedData) dm = CDDM_copy(derivedData);
110         else if(ob->type==OB_MESH) dm = CDDM_from_mesh(ob->data, ob);
111         
112         if(!ob->pd)
113         {
114                 printf("CollisionModifier deformVerts: Should not happen!\n");
115                 return;
116         }
117         
118         if(dm)
119         {
120                 CDDM_apply_vert_coords(dm, vertexCos);
121                 CDDM_calc_normals(dm);
122                 
123                 current_time = BKE_curframe(md->scene);
124                 
125                 if(G.rt > 0)
126                         printf("current_time %f, collmd->time %f\n", current_time, collmd->time);
127                 
128                 numverts = dm->getNumVerts ( dm );
129                 
130                 if((current_time > collmd->time)|| (BKE_ptcache_get_continue_physics()))
131                 {       
132                         // check if mesh has changed
133                         if(collmd->x && (numverts != collmd->numverts))
134                                 freeData((ModifierData *)collmd);
135                         
136                         if(collmd->time == -1000) // first time
137                         {
138                                 collmd->x = dm->dupVertArray(dm); // frame start position
139                                 
140                                 for ( i = 0; i < numverts; i++ )
141                                 {
142                                         // we save global positions
143                                         mul_m4_v3( ob->obmat, collmd->x[i].co );
144                                 }
145                                 
146                                 collmd->xnew = MEM_dupallocN(collmd->x); // frame end position
147                                 collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame
148                                 collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
149                                 collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
150
151                                 collmd->numverts = numverts;
152                                 
153                                 collmd->mfaces = dm->dupFaceArray(dm);
154                                 collmd->numfaces = dm->getNumFaces(dm);
155                                 
156                                 // create bounding box hierarchy
157                                 collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft);
158                                 
159                                 collmd->time = current_time;
160                         }
161                         else if(numverts == collmd->numverts)
162                         {
163                                 // put positions to old positions
164                                 tempVert = collmd->x;
165                                 collmd->x = collmd->xnew;
166                                 collmd->xnew = tempVert;
167                                 
168                                 memcpy(collmd->xnew, dm->getVertArray(dm), numverts*sizeof(MVert));
169                                 
170                                 for ( i = 0; i < numverts; i++ )
171                                 {
172                                         // we save global positions
173                                         mul_m4_v3( ob->obmat, collmd->xnew[i].co );
174                                 }
175                                 
176                                 memcpy(collmd->current_xnew, collmd->x, numverts*sizeof(MVert));
177                                 memcpy(collmd->current_x, collmd->x, numverts*sizeof(MVert));
178                                 
179                                 /* check if GUI setting has changed for bvh */
180                                 if(collmd->bvhtree) 
181                                 {
182                                         if(ob->pd->pdef_sboft != BLI_bvhtree_getepsilon(collmd->bvhtree))
183                                         {
184                                                 BLI_bvhtree_free(collmd->bvhtree);
185                                                 collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
186                                         }
187                         
188                                 }
189                                 
190                                 /* happens on file load (ONLY when i decomment changes in readfile.c) */
191                                 if(!collmd->bvhtree)
192                                 {
193                                         collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
194                                 }
195                                 else
196                                 {
197                                         // recalc static bounding boxes
198                                         bvhtree_update_from_mvert ( collmd->bvhtree, collmd->mfaces, collmd->numfaces, collmd->current_x, collmd->current_xnew, collmd->numverts, 1 );
199                                 }
200                                 
201                                 collmd->time = current_time;
202                         }
203                         else if(numverts != collmd->numverts)
204                         {
205                                 freeData((ModifierData *)collmd);
206                         }
207                         
208                 }
209                 else if(current_time < collmd->time)
210                 {       
211                         freeData((ModifierData *)collmd);
212                 }
213                 else
214                 {
215                         if(numverts != collmd->numverts)
216                         {
217                                 freeData((ModifierData *)collmd);
218                         }
219                 }
220         }
221         
222         if(dm)
223                 dm->release(dm);
224 }
225
226
227 ModifierTypeInfo modifierType_Collision = {
228         /* name */              "Collision",
229         /* structName */        "CollisionModifierData",
230         /* structSize */        sizeof(CollisionModifierData),
231         /* type */              eModifierTypeType_OnlyDeform,
232         /* flags */             eModifierTypeFlag_AcceptsMesh
233                                                         | eModifierTypeFlag_Single,
234
235         /* copyData */          0,
236         /* deformVerts */       deformVerts,
237         /* deformVertsEM */     0,
238         /* deformMatricesEM */  0,
239         /* applyModifier */     0,
240         /* applyModifierEM */   0,
241         /* initData */          initData,
242         /* requiredDataMask */  0,
243         /* freeData */          freeData,
244         /* isDisabled */        0,
245         /* updateDepgraph */    0,
246         /* dependsOnTime */     dependsOnTime,
247         /* foreachObjectLink */ 0,
248         /* foreachIDLink */     0,
249 };