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 "BLT_translation.h"
29 
30 #include "DNA_defaults.h"
31 #include "DNA_mesh_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_screen_types.h"
35 
36 #include "MEM_guardedalloc.h"
37 
38 #include "BKE_collision.h"
39 #include "BKE_context.h"
40 #include "BKE_global.h"
41 #include "BKE_lib_id.h"
42 #include "BKE_mesh.h"
43 #include "BKE_mesh_runtime.h"
44 #include "BKE_modifier.h"
45 #include "BKE_pointcache.h"
46 #include "BKE_scene.h"
47 #include "BKE_screen.h"
48 
49 #include "UI_interface.h"
50 #include "UI_resources.h"
51 
52 #include "RNA_access.h"
53 
54 #include "MOD_modifiertypes.h"
55 #include "MOD_ui_common.h"
56 #include "MOD_util.h"
57 
58 #include "BLO_read_write.h"
59 
60 #include "DEG_depsgraph_query.h"
61 
initData(ModifierData * md)62 static void initData(ModifierData *md)
63 {
64   CollisionModifierData *collmd = (CollisionModifierData *)md;
65 
66   BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(collmd, modifier));
67 
68   MEMCPY_STRUCT_AFTER(collmd, DNA_struct_default_get(CollisionModifierData), modifier);
69 }
70 
freeData(ModifierData * md)71 static void freeData(ModifierData *md)
72 {
73   CollisionModifierData *collmd = (CollisionModifierData *)md;
74 
75   if (collmd) { /* Seriously? */
76     if (collmd->bvhtree) {
77       BLI_bvhtree_free(collmd->bvhtree);
78       collmd->bvhtree = NULL;
79     }
80 
81     MEM_SAFE_FREE(collmd->x);
82     MEM_SAFE_FREE(collmd->xnew);
83     MEM_SAFE_FREE(collmd->current_x);
84     MEM_SAFE_FREE(collmd->current_xnew);
85     MEM_SAFE_FREE(collmd->current_v);
86 
87     MEM_SAFE_FREE(collmd->tri);
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 
dependsOnTime(ModifierData * UNUSED (md))96 static bool dependsOnTime(ModifierData *UNUSED(md))
97 {
98   return true;
99 }
100 
deformVerts(ModifierData * md,const ModifierEvalContext * ctx,Mesh * mesh,float (* vertexCos)[3],int numVerts)101 static void deformVerts(ModifierData *md,
102                         const ModifierEvalContext *ctx,
103                         Mesh *mesh,
104                         float (*vertexCos)[3],
105                         int numVerts)
106 {
107   CollisionModifierData *collmd = (CollisionModifierData *)md;
108   Mesh *mesh_src;
109   MVert *tempVert = NULL;
110   Object *ob = ctx->object;
111 
112   if (mesh == NULL) {
113     mesh_src = MOD_deform_mesh_eval_get(ob, NULL, NULL, NULL, numVerts, false, false);
114   }
115   else {
116     /* Not possible to use get_mesh() in this case as we'll modify its vertices
117      * and get_mesh() would return 'mesh' directly. */
118     mesh_src = (Mesh *)BKE_id_copy_ex(NULL, (ID *)mesh, NULL, LIB_ID_COPY_LOCALIZE);
119   }
120 
121   if (!ob->pd) {
122     printf("CollisionModifier deformVerts: Should not happen!\n");
123     return;
124   }
125 
126   if (mesh_src) {
127     float current_time = 0;
128     uint mvert_num = 0;
129 
130     BKE_mesh_vert_coords_apply(mesh_src, vertexCos);
131     BKE_mesh_calc_normals(mesh_src);
132 
133     current_time = DEG_get_ctime(ctx->depsgraph);
134 
135     if (G.debug & G_DEBUG_SIMDATA) {
136       printf("current_time %f, collmd->time_xnew %f\n", current_time, collmd->time_xnew);
137     }
138 
139     mvert_num = mesh_src->totvert;
140 
141     if (current_time < collmd->time_xnew) {
142       freeData((ModifierData *)collmd);
143     }
144     else if (current_time == collmd->time_xnew) {
145       if (mvert_num != collmd->mvert_num) {
146         freeData((ModifierData *)collmd);
147       }
148     }
149 
150     /* check if mesh has changed */
151     if (collmd->x && (mvert_num != collmd->mvert_num)) {
152       freeData((ModifierData *)collmd);
153     }
154 
155     if (collmd->time_xnew == -1000) { /* first time */
156 
157       collmd->x = MEM_dupallocN(mesh_src->mvert); /* frame start position */
158 
159       for (uint i = 0; i < mvert_num; i++) {
160         /* we save global positions */
161         mul_m4_v3(ob->obmat, collmd->x[i].co);
162       }
163 
164       collmd->xnew = MEM_dupallocN(collmd->x);          // frame end position
165       collmd->current_x = MEM_dupallocN(collmd->x);     // inter-frame
166       collmd->current_xnew = MEM_dupallocN(collmd->x);  // inter-frame
167       collmd->current_v = MEM_dupallocN(collmd->x);     // inter-frame
168 
169       collmd->mvert_num = mvert_num;
170 
171       {
172         const MLoop *mloop = mesh_src->mloop;
173         const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh_src);
174         collmd->tri_num = BKE_mesh_runtime_looptri_len(mesh_src);
175         MVertTri *tri = MEM_mallocN(sizeof(*tri) * collmd->tri_num, __func__);
176         BKE_mesh_runtime_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num);
177         collmd->tri = tri;
178       }
179 
180       /* create bounding box hierarchy */
181       collmd->bvhtree = bvhtree_build_from_mvert(
182           collmd->x, collmd->tri, collmd->tri_num, ob->pd->pdef_sboft);
183 
184       collmd->time_x = collmd->time_xnew = current_time;
185       collmd->is_static = true;
186     }
187     else if (mvert_num == collmd->mvert_num) {
188       /* put positions to old positions */
189       tempVert = collmd->x;
190       collmd->x = collmd->xnew;
191       collmd->xnew = tempVert;
192       collmd->time_x = collmd->time_xnew;
193 
194       memcpy(collmd->xnew, mesh_src->mvert, mvert_num * sizeof(MVert));
195 
196       bool is_static = true;
197 
198       for (uint i = 0; i < mvert_num; i++) {
199         /* we save global positions */
200         mul_m4_v3(ob->obmat, collmd->xnew[i].co);
201 
202         /* detect motion */
203         is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co);
204       }
205 
206       memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert));
207       memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert));
208 
209       /* check if GUI setting has changed for bvh */
210       if (collmd->bvhtree) {
211         if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
212           BLI_bvhtree_free(collmd->bvhtree);
213           collmd->bvhtree = bvhtree_build_from_mvert(
214               collmd->current_x, collmd->tri, collmd->tri_num, ob->pd->pdef_sboft);
215         }
216       }
217 
218       /* happens on file load (ONLY when i decomment changes in readfile.c) */
219       if (!collmd->bvhtree) {
220         collmd->bvhtree = bvhtree_build_from_mvert(
221             collmd->current_x, collmd->tri, collmd->tri_num, ob->pd->pdef_sboft);
222       }
223       else if (!collmd->is_static || !is_static) {
224         /* recalc static bounding boxes */
225         bvhtree_update_from_mvert(collmd->bvhtree,
226                                   collmd->current_x,
227                                   collmd->current_xnew,
228                                   collmd->tri,
229                                   collmd->tri_num,
230                                   true);
231       }
232 
233       collmd->is_static = is_static;
234       collmd->time_xnew = current_time;
235     }
236     else if (mvert_num != collmd->mvert_num) {
237       freeData((ModifierData *)collmd);
238     }
239   }
240 
241   if (!ELEM(mesh_src, NULL, mesh)) {
242     BKE_id_free(NULL, mesh_src);
243   }
244 }
245 
updateDepsgraph(ModifierData * UNUSED (md),const ModifierUpdateDepsgraphContext * ctx)246 static void updateDepsgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgraphContext *ctx)
247 {
248   DEG_add_modifier_to_transform_relation(ctx->node, "Collision Modifier");
249 }
250 
panel_draw(const bContext * UNUSED (C),Panel * panel)251 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
252 {
253   uiLayout *layout = panel->layout;
254 
255   PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
256 
257   uiItemL(layout, IFACE_("Settings are inside the Physics tab"), ICON_NONE);
258 
259   modifier_panel_end(layout, ptr);
260 }
261 
panelRegister(ARegionType * region_type)262 static void panelRegister(ARegionType *region_type)
263 {
264   modifier_panel_register(region_type, eModifierType_Collision, panel_draw);
265 }
266 
blendRead(BlendDataReader * UNUSED (reader),ModifierData * md)267 static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
268 {
269   CollisionModifierData *collmd = (CollisionModifierData *)md;
270 #if 0
271       // TODO: CollisionModifier should use pointcache
272       // + have proper reset events before enabling this
273       collmd->x = newdataadr(fd, collmd->x);
274       collmd->xnew = newdataadr(fd, collmd->xnew);
275       collmd->mfaces = newdataadr(fd, collmd->mfaces);
276 
277       collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x");
278       collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew");
279       collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v");
280 #endif
281 
282   collmd->x = NULL;
283   collmd->xnew = NULL;
284   collmd->current_x = NULL;
285   collmd->current_xnew = NULL;
286   collmd->current_v = NULL;
287   collmd->time_x = collmd->time_xnew = -1000;
288   collmd->mvert_num = 0;
289   collmd->tri_num = 0;
290   collmd->is_static = false;
291   collmd->bvhtree = NULL;
292   collmd->tri = NULL;
293 }
294 
295 ModifierTypeInfo modifierType_Collision = {
296     /* name */ "Collision",
297     /* structName */ "CollisionModifierData",
298     /* structSize */ sizeof(CollisionModifierData),
299     /* srna */ &RNA_CollisionModifier,
300     /* type */ eModifierTypeType_OnlyDeform,
301     /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_Single,
302     /* icon */ ICON_MOD_PHYSICS,
303 
304     /* copyData */ NULL,
305 
306     /* deformVerts */ deformVerts,
307     /* deformMatrices */ NULL,
308     /* deformVertsEM */ NULL,
309     /* deformMatricesEM */ NULL,
310     /* modifyMesh */ NULL,
311     /* modifyHair */ NULL,
312     /* modifyPointCloud */ NULL,
313     /* modifyVolume */ NULL,
314 
315     /* initData */ initData,
316     /* requiredDataMask */ NULL,
317     /* freeData */ freeData,
318     /* isDisabled */ NULL,
319     /* updateDepsgraph */ updateDepsgraph,
320     /* dependsOnTime */ dependsOnTime,
321     /* dependsOnNormals */ NULL,
322     /* foreachIDLink */ NULL,
323     /* foreachTexLink */ NULL,
324     /* freeRuntimeData */ NULL,
325     /* panelRegister */ panelRegister,
326     /* blendWrite */ NULL,
327     /* blendRead */ blendRead,
328 };
329