371a33ebfc69c95702ade3cb9a859c19f7c4b77c
[blender.git] / source / blender / modifiers / intern / MOD_collision.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software  Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup modifiers
22  */
23
24 #include "BLI_utildefines.h"
25
26 #include "BLI_math.h"
27
28 #include "DNA_object_types.h"
29 #include "DNA_mesh_types.h"
30 #include "DNA_meshdata_types.h"
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BKE_collision.h"
35 #include "BKE_global.h"
36 #include "BKE_library.h"
37 #include "BKE_mesh.h"
38 #include "BKE_mesh_runtime.h"
39 #include "BKE_modifier.h"
40 #include "BKE_pointcache.h"
41 #include "BKE_scene.h"
42
43 #include "MOD_modifiertypes.h"
44 #include "MOD_util.h"
45
46 #include "DEG_depsgraph_query.h"
47
48 static void initData(ModifierData *md)
49 {
50         CollisionModifierData *collmd = (CollisionModifierData *) md;
51
52         collmd->x = NULL;
53         collmd->xnew = NULL;
54         collmd->current_x = NULL;
55         collmd->current_xnew = NULL;
56         collmd->current_v = NULL;
57         collmd->time_x = collmd->time_xnew = -1000;
58         collmd->mvert_num = 0;
59         collmd->tri_num = 0;
60         collmd->is_static = false;
61         collmd->bvhtree = NULL;
62 }
63
64 static void freeData(ModifierData *md)
65 {
66         CollisionModifierData *collmd = (CollisionModifierData *) md;
67
68         if (collmd) {  /* Seriously? */
69                 if (collmd->bvhtree) {
70                         BLI_bvhtree_free(collmd->bvhtree);
71                         collmd->bvhtree = NULL;
72                 }
73
74                 MEM_SAFE_FREE(collmd->x);
75                 MEM_SAFE_FREE(collmd->xnew);
76                 MEM_SAFE_FREE(collmd->current_x);
77                 MEM_SAFE_FREE(collmd->current_xnew);
78                 MEM_SAFE_FREE(collmd->current_v);
79
80                 MEM_SAFE_FREE(collmd->tri);
81
82                 collmd->time_x = collmd->time_xnew = -1000;
83                 collmd->mvert_num = 0;
84                 collmd->tri_num = 0;
85                 collmd->is_static = false;
86         }
87 }
88
89 static bool dependsOnTime(ModifierData *UNUSED(md))
90 {
91         return true;
92 }
93
94 static void deformVerts(
95         ModifierData *md, const ModifierEvalContext *ctx,
96         Mesh *mesh,
97         float (*vertexCos)[3],
98         int numVerts)
99 {
100         CollisionModifierData *collmd = (CollisionModifierData *) md;
101         Mesh *mesh_src;
102         MVert *tempVert = NULL;
103         Object *ob = ctx->object;
104
105         if (mesh == NULL) {
106                 mesh_src = MOD_deform_mesh_eval_get(ob, NULL, NULL, NULL, numVerts, false, false);
107         }
108         else {
109                 /* Not possible to use get_mesh() in this case as we'll modify its vertices
110                  * and get_mesh() would return 'mesh' directly. */
111                 BKE_id_copy_ex(NULL, (ID *)mesh, (ID **)&mesh_src, LIB_ID_COPY_LOCALIZE);
112         }
113
114         if (!ob->pd) {
115                 printf("CollisionModifier deformVerts: Should not happen!\n");
116                 return;
117         }
118
119         if (mesh_src) {
120                 float current_time = 0;
121                 unsigned int mvert_num = 0;
122
123                 BKE_mesh_apply_vert_coords(mesh_src, vertexCos);
124                 BKE_mesh_calc_normals(mesh_src);
125
126                 current_time = DEG_get_ctime(ctx->depsgraph);
127
128                 if (G.debug & G_DEBUG_SIMDATA) {
129                         printf("current_time %f, collmd->time_xnew %f\n", current_time, collmd->time_xnew);
130                 }
131
132                 mvert_num = mesh_src->totvert;
133
134                 if (current_time < collmd->time_xnew) {
135                         freeData((ModifierData *)collmd);
136                 }
137                 else if (current_time == collmd->time_xnew) {
138                         if (mvert_num != collmd->mvert_num) {
139                                 freeData((ModifierData *)collmd);
140                         }
141                 }
142
143                 /* check if mesh has changed */
144                 if (collmd->x && (mvert_num != collmd->mvert_num))
145                         freeData((ModifierData *)collmd);
146
147                 if (collmd->time_xnew == -1000) { /* first time */
148
149                         collmd->x = MEM_dupallocN(mesh_src->mvert); /* frame start position */
150
151                         for (uint i = 0; i < mvert_num; i++) {
152                                 /* we save global positions */
153                                 mul_m4_v3(ob->obmat, collmd->x[i].co);
154                         }
155
156                         collmd->xnew = MEM_dupallocN(collmd->x); // frame end position
157                         collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame
158                         collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
159                         collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
160
161                         collmd->mvert_num = mvert_num;
162
163                         {
164                                 const MLoop *mloop = mesh_src->mloop;
165                                 const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh_src);
166                                 collmd->tri_num = BKE_mesh_runtime_looptri_len(mesh_src);
167                                 MVertTri *tri = MEM_mallocN(sizeof(*tri) * collmd->tri_num, __func__);
168                                 BKE_mesh_runtime_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num);
169                                 collmd->tri = tri;
170                         }
171
172                         /* create bounding box hierarchy */
173                         collmd->bvhtree = bvhtree_build_from_mvert(
174                                 collmd->x,
175                                 collmd->tri, collmd->tri_num,
176                                 ob->pd->pdef_sboft);
177
178                         collmd->time_x = collmd->time_xnew = current_time;
179                         collmd->is_static = true;
180                 }
181                 else if (mvert_num == collmd->mvert_num) {
182                         /* put positions to old positions */
183                         tempVert = collmd->x;
184                         collmd->x = collmd->xnew;
185                         collmd->xnew = tempVert;
186                         collmd->time_x = collmd->time_xnew;
187
188                         memcpy(collmd->xnew, mesh_src->mvert, mvert_num * sizeof(MVert));
189
190                         bool is_static = true;
191
192                         for (uint i = 0; i < mvert_num; i++) {
193                                 /* we save global positions */
194                                 mul_m4_v3(ob->obmat, collmd->xnew[i].co);
195
196                                 /* detect motion */
197                                 is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co);
198                         }
199
200                         memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert));
201                         memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert));
202
203                         /* check if GUI setting has changed for bvh */
204                         if (collmd->bvhtree) {
205                                 if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
206                                         BLI_bvhtree_free(collmd->bvhtree);
207                                         collmd->bvhtree = bvhtree_build_from_mvert(
208                                                 collmd->current_x,
209                                                 collmd->tri, collmd->tri_num,
210                                                 ob->pd->pdef_sboft);
211                                 }
212                         }
213
214                         /* happens on file load (ONLY when i decomment changes in readfile.c) */
215                         if (!collmd->bvhtree) {
216                                 collmd->bvhtree = bvhtree_build_from_mvert(
217                                         collmd->current_x,
218                                         collmd->tri, collmd->tri_num,
219                                         ob->pd->pdef_sboft);
220                         }
221                         else if (!collmd->is_static || !is_static) {
222                                 /* recalc static bounding boxes */
223                                 bvhtree_update_from_mvert(
224                                         collmd->bvhtree,
225                                         collmd->current_x, collmd->current_xnew,
226                                         collmd->tri, collmd->tri_num,
227                                         true);
228                         }
229
230                         collmd->is_static = is_static;
231                         collmd->time_xnew = current_time;
232                 }
233                 else if (mvert_num != collmd->mvert_num) {
234                         freeData((ModifierData *)collmd);
235                 }
236         }
237
238         if (mesh_src != mesh) {
239                 BKE_id_free(NULL, mesh_src);
240         }
241 }
242
243
244 ModifierTypeInfo modifierType_Collision = {
245         /* name */              "Collision",
246         /* structName */        "CollisionModifierData",
247         /* structSize */        sizeof(CollisionModifierData),
248         /* type */              eModifierTypeType_OnlyDeform,
249         /* flags */             eModifierTypeFlag_AcceptsMesh |
250                                 eModifierTypeFlag_Single,
251
252         /* copyData */          NULL,
253
254         /* deformVerts */       deformVerts,
255         /* deformMatrices */    NULL,
256         /* deformVertsEM */     NULL,
257         /* deformMatricesEM */  NULL,
258         /* applyModifier */     NULL,
259
260         /* initData */          initData,
261         /* requiredDataMask */  NULL,
262         /* freeData */          freeData,
263         /* isDisabled */        NULL,
264         /* updateDepsgraph */   NULL,
265         /* dependsOnTime */     dependsOnTime,
266         /* dependsOnNormals */  NULL,
267         /* foreachObjectLink */ NULL,
268         /* foreachIDLink */     NULL,
269         /* foreachTexLink */    NULL,
270         /* freeRuntimeData */   NULL,
271 };