Files
test/source/blender/modifiers/intern/MOD_collision.cc
Brecht Van Lommel ee1a460f42 Revert "Refactor: Add and use MEMCPY_STRUCT_AFTER_CHECKED"
Needs more review, see #138830.

This reverts commit 5ac631d02b.
2025-05-20 17:32:49 +02:00

308 lines
9.3 KiB
C++

/* SPDX-FileCopyrightText: 2005 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup modifiers
*/
#include "BLI_utildefines.h"
#include "BLI_kdopbvh.hh"
#include "BLI_math_matrix.h"
#include "BLI_math_vector.h"
#include "BLT_translation.hh"
#include "DNA_defaults.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "MEM_guardedalloc.h"
#include "BKE_collision.h"
#include "BKE_global.hh"
#include "BKE_mesh.hh"
#include "BKE_modifier.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "RNA_prototypes.hh"
#include "MOD_ui_common.hh"
#include "DEG_depsgraph_query.hh"
static void init_data(ModifierData *md)
{
CollisionModifierData *collmd = (CollisionModifierData *)md;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(collmd, modifier));
MEMCPY_STRUCT_AFTER(collmd, DNA_struct_default_get(CollisionModifierData), modifier);
}
static void free_data(ModifierData *md)
{
CollisionModifierData *collmd = (CollisionModifierData *)md;
if (collmd) { /* Seriously? */
if (collmd->bvhtree) {
BLI_bvhtree_free(collmd->bvhtree);
collmd->bvhtree = nullptr;
}
MEM_SAFE_FREE(collmd->x);
MEM_SAFE_FREE(collmd->xnew);
MEM_SAFE_FREE(collmd->current_x);
MEM_SAFE_FREE(collmd->current_xnew);
MEM_SAFE_FREE(collmd->current_v);
MEM_SAFE_FREE(collmd->vert_tris);
collmd->time_x = collmd->time_xnew = -1000;
collmd->mvert_num = 0;
collmd->tri_num = 0;
collmd->is_static = false;
}
}
static bool depends_on_time(Scene * /*scene*/, ModifierData * /*md*/)
{
return true;
}
static void deform_verts(ModifierData *md,
const ModifierEvalContext *ctx,
Mesh *mesh,
blender::MutableSpan<blender::float3> positions)
{
CollisionModifierData *collmd = (CollisionModifierData *)md;
Object *ob = ctx->object;
/* If collision is disabled, free the stale data and exit. */
if (!ob->pd || !ob->pd->deflect) {
if (!ob->pd) {
printf("CollisionModifier: collision settings are missing!\n");
}
free_data(md);
return;
}
if (mesh) {
float current_time = 0;
int mvert_num = 0;
mesh->vert_positions_for_write().copy_from(positions);
mesh->tag_positions_changed();
current_time = DEG_get_ctime(ctx->depsgraph);
if (G.debug & G_DEBUG_SIMDATA) {
printf("current_time %f, collmd->time_xnew %f\n", current_time, collmd->time_xnew);
}
mvert_num = mesh->verts_num;
if (current_time < collmd->time_xnew) {
free_data((ModifierData *)collmd);
}
else if (current_time == collmd->time_xnew) {
if (mvert_num != collmd->mvert_num) {
free_data((ModifierData *)collmd);
}
}
/* check if mesh has changed */
if (collmd->x && (mvert_num != collmd->mvert_num)) {
free_data((ModifierData *)collmd);
}
if (collmd->time_xnew == -1000) { /* first time */
mvert_num = mesh->verts_num;
collmd->x = MEM_malloc_arrayN<float[3]>(size_t(mvert_num), __func__);
blender::MutableSpan(reinterpret_cast<blender::float3 *>(collmd->x), mvert_num)
.copy_from(mesh->vert_positions());
for (uint i = 0; i < mvert_num; i++) {
/* we save global positions */
mul_m4_v3(ob->object_to_world().ptr(), collmd->x[i]);
}
collmd->xnew = static_cast<float(*)[3]>(MEM_dupallocN(collmd->x)); /* Frame end position. */
collmd->current_x = static_cast<float(*)[3]>(MEM_dupallocN(collmd->x)); /* Inter-frame. */
collmd->current_xnew = static_cast<float(*)[3]>(MEM_dupallocN(collmd->x)); /* Inter-frame. */
collmd->current_v = static_cast<float(*)[3]>(MEM_dupallocN(collmd->x)); /* Inter-frame. */
collmd->mvert_num = mvert_num;
{
const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
collmd->tri_num = corner_tris.size();
int(*vert_tris)[3] = MEM_malloc_arrayN<int[3]>(collmd->tri_num, __func__);
blender::bke::mesh::vert_tris_from_corner_tris(
mesh->corner_verts(),
corner_tris,
{reinterpret_cast<blender::int3 *>(vert_tris), collmd->tri_num});
collmd->vert_tris = vert_tris;
}
/* create bounding box hierarchy */
collmd->bvhtree = bvhtree_build_from_mvert(
collmd->x,
reinterpret_cast<blender::int3 *>(collmd->vert_tris),
collmd->tri_num,
ob->pd->pdef_sboft);
collmd->time_x = collmd->time_xnew = current_time;
collmd->is_static = true;
}
else if (mvert_num == collmd->mvert_num) {
/* put positions to old positions */
float(*temp)[3] = collmd->x;
collmd->x = collmd->xnew;
collmd->xnew = temp;
collmd->time_x = collmd->time_xnew;
memcpy(collmd->xnew, mesh->vert_positions().data(), mvert_num * sizeof(float[3]));
bool is_static = true;
for (uint i = 0; i < mvert_num; i++) {
/* we save global positions */
mul_m4_v3(ob->object_to_world().ptr(), collmd->xnew[i]);
/* detect motion */
is_static = is_static && equals_v3v3(collmd->x[i], collmd->xnew[i]);
}
memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(float[3]));
memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(float[3]));
/* check if GUI setting has changed for bvh */
if (collmd->bvhtree) {
if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
BLI_bvhtree_free(collmd->bvhtree);
collmd->bvhtree = bvhtree_build_from_mvert(
collmd->current_x,
reinterpret_cast<const blender::int3 *>(collmd->vert_tris),
collmd->tri_num,
ob->pd->pdef_sboft);
}
}
/* Happens on file load (ONLY when I un-comment changes in `readfile.cc`). */
if (!collmd->bvhtree) {
collmd->bvhtree = bvhtree_build_from_mvert(
collmd->current_x,
reinterpret_cast<const blender::int3 *>(collmd->vert_tris),
collmd->tri_num,
ob->pd->pdef_sboft);
}
else if (!collmd->is_static || !is_static) {
/* recalc static bounding boxes */
bvhtree_update_from_mvert(collmd->bvhtree,
collmd->current_x,
collmd->current_xnew,
reinterpret_cast<const blender::int3 *>(collmd->vert_tris),
collmd->tri_num,
true);
}
collmd->is_static = is_static;
collmd->time_xnew = current_time;
}
else if (mvert_num != collmd->mvert_num) {
free_data((ModifierData *)collmd);
}
}
}
static void update_depsgraph(ModifierData * /*md*/, const ModifierUpdateDepsgraphContext *ctx)
{
DEG_add_depends_on_transform_relation(ctx->node, "Collision Modifier");
}
static void panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
layout->label(RPT_("Settings are inside the Physics tab"), ICON_NONE);
modifier_error_message_draw(layout, ptr);
}
static void panel_register(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_Collision, panel_draw);
}
static void blend_read(BlendDataReader * /*reader*/, ModifierData *md)
{
CollisionModifierData *collmd = (CollisionModifierData *)md;
#if 0
/* TODO: #CollisionModifier should use point-cache
* + have proper reset events before enabling this. */
collmd->x = newdataadr(fd, collmd->x);
collmd->xnew = newdataadr(fd, collmd->xnew);
collmd->mfaces = newdataadr(fd, collmd->mfaces);
collmd->current_x = MEM_calloc_arrayN<float[3]>(collmd->mvert_num, "current_x");
collmd->current_xnew = MEM_calloc_arrayN<float[3]>(collmd->mvert_num, "current_xnew");
collmd->current_v = MEM_calloc_arrayN<float[3]>(collmd->mvert_num, "current_v");
#endif
collmd->x = nullptr;
collmd->xnew = nullptr;
collmd->current_x = nullptr;
collmd->current_xnew = nullptr;
collmd->current_v = nullptr;
collmd->time_x = collmd->time_xnew = -1000;
collmd->mvert_num = 0;
collmd->tri_num = 0;
collmd->is_static = false;
collmd->bvhtree = nullptr;
collmd->vert_tris = nullptr;
}
ModifierTypeInfo modifierType_Collision = {
/*idname*/ "Collision",
/*name*/ N_("Collision"),
/*struct_name*/ "CollisionModifierData",
/*struct_size*/ sizeof(CollisionModifierData),
/*srna*/ &RNA_CollisionModifier,
/*type*/ ModifierTypeType::OnlyDeform,
/*flags*/ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_Single,
/*icon*/ ICON_MOD_PHYSICS,
/*copy_data*/ nullptr,
/*deform_verts*/ deform_verts,
/*deform_matrices*/ nullptr,
/*deform_verts_EM*/ nullptr,
/*deform_matrices_EM*/ nullptr,
/*modify_mesh*/ nullptr,
/*modify_geometry_set*/ nullptr,
/*init_data*/ init_data,
/*required_data_mask*/ nullptr,
/*free_data*/ free_data,
/*is_disabled*/ nullptr,
/*update_depsgraph*/ update_depsgraph,
/*depends_on_time*/ depends_on_time,
/*depends_on_normals*/ nullptr,
/*foreach_ID_link*/ nullptr,
/*foreach_tex_link*/ nullptr,
/*free_runtime_data*/ nullptr,
/*panel_register*/ panel_register,
/*blend_write*/ nullptr,
/*blend_read*/ blend_read,
/*foreach_cache*/ nullptr,
};