Fix: GUI cache reset should work again, same goes for collision modifier (enabled through 'deflection' panel

This commit is contained in:
2007-11-29 12:29:32 +00:00
parent 087a549e55
commit 543f38c20a
9 changed files with 300 additions and 164 deletions

View File

@@ -72,10 +72,10 @@ typedef struct ClothVertex {
} ClothVertex;
typedef struct ClothSpring {
int ij; /* Pij from the paper, one end of the spring. */
int kl; /* Pkl from the paper, one end of the spring. */
unsigned int ij; /* Pij from the paper, one end of the spring. */
unsigned int kl; /* Pkl from the paper, one end of the spring. */
float restlen; /* The original length of the spring. */
int matrix_index; /* needed for implicit solver (fast lookup) */
unsigned int matrix_index; /* needed for implicit solver (fast lookup) */
int type; /* types defined in BKE_cloth.h ("springType") */
int flags; /* defined in BKE_cloth.h, e.g. deactivated due to tearing */
float dfdx[3][3];
@@ -152,6 +152,7 @@ typedef enum
CLOTH_SPRING_TYPE_STRUCTURAL = 0,
CLOTH_SPRING_TYPE_SHEAR,
CLOTH_SPRING_TYPE_BENDING,
CLOTH_SPRING_TYPE_COLLISION,
} CLOTH_SPRING_TYPES;
/* SPRING FLAGS */

View File

@@ -37,11 +37,13 @@
#include <math.h>
#include <stdlib.h>
#include <string.h>
/* types */
#include "BLI_linklist.h"
#include "BKE_DerivedMesh.h"
#include "BKE_object.h"
#include "BKE_DerivedMesh.h"
#include "DNA_modifier_types.h"
// used in kdop.c and collision.c
typedef struct CollisionTree
@@ -82,6 +84,8 @@ typedef struct CollisionPair
{
int point_indexA[4], point_indexB[4];
float vector[3];
float normal[3]; // has to be calculated from vector
float distance;
float pa[3], pb[3];
}
CollisionPair;
@@ -115,6 +119,10 @@ LinkNode *BLI_linklist_append_fast (LinkNode **listp, void *ptr);
// defined in collisions.c
void collision_move_object(CollisionModifierData *collmd, float step, float prevstep);
// interface for collision functions
void collisions_compute_barycentric (float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3);
void interpolateOnTriangle(float to[3], float v1[3], float v2[3], float v3[3], double w1, double w2, double w3);
/////////////////////////////////////////////////
#endif

View File

@@ -1009,6 +1009,7 @@ static void cloth_from_mesh (Object *ob, ClothModifierData *clmd, DerivedMesh *d
***************************************************************************************/
// be carefull: implicit solver has to be resettet when using this one!
// --> only for implicit handling of this spring!
int cloth_add_spring ( ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type)
{
Cloth *cloth = clmd->clothObject;

View File

@@ -71,7 +71,6 @@
#include "Bullet-C-Api.h"
// step is limited from 0 (frame start position) to 1 (frame end position)
void collision_move_object(CollisionModifierData *collmd, float step, float prevstep)
{
@@ -83,6 +82,7 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev
VECSUB(tv, collmd->xnew[i].co, collmd->x[i].co);
VECADDS(collmd->current_x[i].co, collmd->x[i].co, tv, prevstep);
VECADDS(collmd->current_xnew[i].co, collmd->x[i].co, tv, step);
VECSUB(collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co);
}
}

View File

@@ -63,6 +63,8 @@
#include "BKE_global.h"
#include "BIF_editdeform.h"
#include "Bullet-C-Api.h"
#ifdef _WIN32
#include <windows.h>
static LARGE_INTEGER _itstart, _itend;
@@ -1123,6 +1125,17 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
}
if(s->type == CLOTH_SPRING_TYPE_COLLISION)
{
if(length < L)
{
mul_fvector_S(stretch_force, dir, (100.0*(length-L)));
VECADD(s->f, s->f, stretch_force);
}
return;
}
// calculate force of structural + shear springs
if(s->type != CLOTH_SPRING_TYPE_BENDING)
{
@@ -1415,6 +1428,19 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase
{
effectors= pdInitEffectors(ob,NULL);
// clear constraint matrix from collisions
if(clmd->coll_parms->flags & CLOTH_COLLISIONSETTINGS_FLAG_ENABLED)
{
for(i = 0; i < id->S[0].vcount; i++)
{
if(!(verts [id->S[i].r].goal >= SOFTGOALSNAP))
{
id->S[0].vcount = i-1;
break;
}
}
}
// calculate
cloth_calc_force(clmd, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step );
@@ -1553,122 +1579,148 @@ void implicit_set_positions (ClothModifierData *clmd)
memcpy(id->V, cloth->v, sizeof(lfVector) * numverts);
}
int collisions_collision_response_static(ClothModifierData *clmd, ClothModifierData *coll_clmd)
unsigned int implicit_getcreate_S_index(ClothModifierData *clmd, unsigned int index)
{
/*
Cloth *cloth = clmd->clothObject;
Implicit_Data *id = cloth->implicit;
unsigned int i = 0, pinned = 0;
pinned = id->S[0].vcount;
for(i = 0; i < pinned; i++)
{
if(id->S[i].r == index)
{
return index;
}
}
// create new PINNED entry in constraint matrix
id->S[0].vcount++;
id->S[pinned].c = id->S[pinned].r = index;
return pinned;
}
int collisions_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd, CollisionPair *collpair )
{
unsigned int i = 0;
int result = 0;
LinkNode *search = NULL;
CollPair *collpair = NULL;
Cloth *cloth1, *cloth2;
Cloth *cloth1 = NULL;
float w1, w2, w3, u1, u2, u3;
float v1[3], v2[3], relativeVelocity[3];
float magrelVel;
float magrelVel = 0.0;
float epsilon = clmd->coll_parms->epsilon;
cloth1 = clmd->clothObject;
cloth2 = coll_clmd->clothObject;
if(!collpair)
return 0;
// TODO: check distance & calc normal
// calc distance + normal
collpair->distance = plNearestPoints(
cloth1->current_xold[collpair->point_indexA[0]],
cloth1->current_xold[collpair->point_indexA[1]],
cloth1->current_xold[collpair->point_indexA[2]],
collmd->current_x[collpair->point_indexB[0]].co,
collmd->current_x[collpair->point_indexB[1]].co,
collmd->current_x[collpair->point_indexB[2]].co,
collpair->pa,collpair->pb,collpair->vector);
if (collpair->distance > (epsilon + ALMOST_ZERO))
{
return 0;
}
// search = clmd->coll_parms.collision_list;
while(search)
{
collpair = search->link;
// compute barycentric coordinates for both collision points
collisions_compute_barycentric(collpair->pa,
cloth1->verts[collpair->ap1].txold,
cloth1->verts[collpair->ap2].txold,
cloth1->verts[collpair->ap3].txold,
&w1, &w2, &w3);
collisions_compute_barycentric(collpair->pb,
cloth2->verts[collpair->bp1].txold,
cloth2->verts[collpair->bp2].txold,
cloth2->verts[collpair->bp3].txold,
&u1, &u2, &u3);
// Calculate relative "velocity".
interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3);
interpolateOnTriangle(v2, cloth2->verts[collpair->bp1].tv, cloth2->verts[collpair->bp2].tv, cloth2->verts[collpair->bp3].tv, u1, u2, u3);
VECSUB(relativeVelocity, v1, v2);
// Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal').
magrelVel = INPR(relativeVelocity, collpair->normal);
// printf("magrelVel: %f\n", magrelVel);
// Calculate masses of points.
// If v_n_mag < 0 the edges are approaching each other.
if(magrelVel < -ALMOST_ZERO)
{
// Calculate Impulse magnitude to stop all motion in normal direction.
// const double I_mag = v_n_mag / (1/m1 + 1/m2);
float magnitude_i = magrelVel / 2.0f; // TODO implement masses
float tangential[3], magtangent, magnormal, collvel[3];
float vrel_t_pre[3];
float vrel_t[3];
double impulse;
float epsilon = clmd->coll_parms.epsilon;
float overlap = (epsilon + ALMOST_ZERO-collpair->distance);
// calculateFrictionImpulse(tangential, relativeVelocity, collpair->normal, magrelVel, clmd->coll_parms.friction*0.01, magrelVel);
// magtangent = INPR(tangential, tangential);
// Apply friction impulse.
if (magtangent < -ALMOST_ZERO)
{
// printf("friction applied: %f\n", magtangent);
// TODO check original code
}
// compute barycentric coordinates for both collision points
collisions_compute_barycentric (collpair->pa,
cloth1->current_xold[collpair->point_indexA[0]],
cloth1->current_xold[collpair->point_indexA[1]],
cloth1->current_xold[collpair->point_indexA[2]],
&w1, &w2, &w3 );
impulse = -2.0f * magrelVel / ( 1.0 + w1*w1 + w2*w2 + w3*w3);
// printf("impulse: %f\n", impulse);
// face A
VECADDMUL(cloth1->verts[collpair->ap1].impulse, collpair->normal, w1 * impulse);
cloth1->verts[collpair->ap1].impulse_count++;
VECADDMUL(cloth1->verts[collpair->ap2].impulse, collpair->normal, w2 * impulse);
cloth1->verts[collpair->ap2].impulse_count++;
VECADDMUL(cloth1->verts[collpair->ap3].impulse, collpair->normal, w3 * impulse);
cloth1->verts[collpair->ap3].impulse_count++;
// face B
VECADDMUL(cloth2->verts[collpair->bp1].impulse, collpair->normal, u1 * impulse);
cloth2->verts[collpair->bp1].impulse_count++;
VECADDMUL(cloth2->verts[collpair->bp2].impulse, collpair->normal, u2 * impulse);
cloth2->verts[collpair->bp2].impulse_count++;
VECADDMUL(cloth2->verts[collpair->bp3].impulse, collpair->normal, u3 * impulse);
cloth2->verts[collpair->bp3].impulse_count++;
result = 1;
collisions_compute_barycentric (collpair->pb,
collmd->current_x[collpair->point_indexB[0]].co,
collmd->current_x[collpair->point_indexB[1]].co,
collmd->current_x[collpair->point_indexB[2]].co,
&u1, &u2, &u3 );
// Calculate relative "velocity".
interpolateOnTriangle ( v1, cloth1->current_v[collpair->point_indexA[0]], cloth1->current_v[collpair->point_indexA[1]], cloth1->current_v[collpair->point_indexA[2]], w1, w2, w3 );
interpolateOnTriangle ( v2, collmd->current_v[collpair->point_indexB[0]].co, collmd->current_v[collpair->point_indexB[1]].co, collmd->current_v[collpair->point_indexB[2]].co, u1, u2, u3 );
VECSUB ( relativeVelocity, v1, v2 );
// Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal').
magrelVel = INPR ( relativeVelocity, collpair->normal );
// printf("magrelVel: %f\n", magrelVel);
// Calculate masses of points.
// If v_n_mag < 0 the edges are approaching each other.
if ( magrelVel < -ALMOST_ZERO )
{
// Calculate Impulse magnitude to stop all motion in normal direction.
// const double I_mag = v_n_mag / (1/m1 + 1/m2);
float magnitude_i = magrelVel / 2.0f; // TODO implement masses
float tangential[3], magtangent, magnormal, collvel[3];
float vrel_t_pre[3];
float vrel_t[3];
double impulse;
float overlap = ( epsilon + ALMOST_ZERO-collpair->distance );
// calculateFrictionImpulse(tangential, relativeVelocity, collpair->normal, magrelVel, clmd->coll_parms.friction*0.01, magrelVel);
// magtangent = INPR(tangential, tangential);
// Apply friction impulse.
if ( magtangent < -ALMOST_ZERO )
{
// printf("friction applied: %f\n", magtangent);
// TODO check original code
}
impulse = -2.0f * magrelVel / ( 1.0 + w1*w1 + w2*w2 + w3*w3 );
// printf("impulse: %f\n", impulse);
// face A
VECADDMUL ( cloth1->verts[collpair->point_indexA[0]].impulse, collpair->normal, w1 * impulse );
cloth1->verts[collpair->point_indexA[0]].impulse_count++;
VECADDMUL ( cloth1->verts[collpair->point_indexA[1]].impulse, collpair->normal, w2 * impulse );
cloth1->verts[collpair->point_indexA[1]].impulse_count++;
VECADDMUL ( cloth1->verts[collpair->point_indexA[2]].impulse, collpair->normal, w3 * impulse );
cloth1->verts[collpair->point_indexA[2]].impulse_count++;
// face B
/*
VECADDMUL ( collmd->verts[collpair->point_indexB[0]].impulse, collpair->normal, u1 * impulse );
collmd->verts[collpair->point_indexB[0]].impulse_count++;
VECADDMUL ( collmd->verts[collpair->point_indexB[1]].impulse, collpair->normal, u2 * impulse );
collmd->verts[collpair->point_indexB[1]].impulse_count++;
VECADDMUL ( collmd->verts[collpair->point_indexB[2]].impulse, collpair->normal, u3 * impulse );
collmd->verts[collpair->point_indexB[2]].impulse_count++;
*/
// printf("magnitude_i: %f\n", magnitude_i); // negative before collision in my case
// Apply the impulse and increase impulse counters.
}
search = search->next;
}
result = 1;
// printf("magnitude_i: %f\n", magnitude_i); // negative before collision in my case
// Apply the impulse and increase impulse counters.
}
return result;
*/
return 0;
}
@@ -2087,10 +2139,11 @@ int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep,
Object *ob2 = NULL;
BVH *bvh1 = NULL, *bvh2 = NULL, *self_bvh;
LinkNode *collision_list = NULL;
unsigned int i = 0, j = 0;
unsigned int i = 0, j = 0, index;
int collisions = 0, count = 0;
float (*current_x)[3];
Implicit_Data *id = NULL;
/*
if (!(((Cloth *)clmd->clothObject)->tree))
{
printf("No BVH found\n");
@@ -2100,65 +2153,77 @@ int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep,
cloth = clmd->clothObject;
bvh1 = cloth->tree;
self_bvh = cloth->selftree;
id = cloth->implicit;
////////////////////////////////////////////////////////////
// static collisions
////////////////////////////////////////////////////////////
// update cloth bvh
bvh_update_from_float3(bvh1, cloth->current_xold, cloth->numverts, cloth->current_x, 0); // 0 means STATIC, 1 means MOVING (see later in this function)
/*
bvh_update_from_float3 ( bvh1, cloth->current_xold, cloth->numverts, cloth->current_x, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function)
// check all collision objects
for (base = G.scene->base.first; base; base = base->next)
for ( base = G.scene->base.first; base; base = base->next )
{
ob2 = base->object;
collmd = (CollisionModifierData *) modifiers_findByType (ob2, eModifierType_Collision);
if (!collmd)
continue;
ob2 = base->object;
collmd = ( CollisionModifierData * ) modifiers_findByType ( ob2, eModifierType_Collision );
if ( !collmd )
continue;
// check if there is a bounding volume hierarchy
if (collmd->tree)
{
bvh2 = collmd->tree;
if ( collmd->tree )
{
bvh2 = collmd->tree;
// update position + bvh of collision object
collision_move_object(collmd, step, prevstep);
bvh_update_from_mvert(collmd->tree, collmd->current_x, collmd->numverts, NULL, 0);
// fill collision list
collisions += bvh_traverse(bvh1->root, bvh2->root, &collision_list);
collision_move_object ( collmd, step, prevstep );
bvh_update_from_mvert ( collmd->tree, collmd->current_x, collmd->numverts, NULL, 0 );
// fill collision list
collisions += bvh_traverse ( bvh1->root, bvh2->root, &collision_list );
// call static collision response
if ( collision_list )
{
LinkNode *search = collision_list;
while ( search )
{
collisions_collision_response_static(clmd, collmd, (CollisionPair *)search->link);
search = search->next;
}
}
// free collision list
if(collision_list)
{
LinkNode *search = collision_list;
while(search)
{
CollisionPair *coll_pair = search->link;
MEM_freeN(coll_pair);
search = search->next;
}
BLI_linklist_free(collision_list,NULL);
if ( collision_list )
{
LinkNode *search = collision_list;
collision_list = NULL;
}
}
}
while ( search )
{
CollisionPair *coll_pair = search->link;
MEM_freeN ( coll_pair );
search = search->next;
}
BLI_linklist_free ( collision_list,NULL );
collision_list = NULL;
}
}
}
//////////////////////////////////////////////
// update velocities + positions
//////////////////////////////////////////////
for(i = 0; i < cloth->numverts; i++)
{
VECADD(cloth->current_x[i], cloth->current_xold[i], cloth->current_v[i]);
}
VECADD(cloth->current_x[i], cloth->current_xold[i], cloth->current_v[i]);
}
//////////////////////////////////////////////
*/
*/
/*
// fill collision list
collisions += bvh_traverse(self_bvh->root, self_bvh->root, &collision_list);
@@ -2235,7 +2300,7 @@ int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep,
collisions = 1;
count = 0;
current_x = cloth->current_x; // needed for openMP
/*
// #pragma omp parallel for private(i,j, collisions) shared(current_x)
// for ( count = 0; count < 6; count++ )
{
@@ -2275,8 +2340,6 @@ int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep,
{
float correction = ((mindistance1 + mindistance2)) - length;
printf("correction: %f\n", correction);
if ( ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) && ( cloth->verts [i].goal >= SOFTGOALSNAP ) )
{
VecMulf ( temp, -correction );
@@ -2289,10 +2352,24 @@ int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep,
}
else
{
unsigned int pinned = id->S[0].vcount;
printf("correction: %f\n", correction);
VecMulf ( temp, -correction*0.5 );
VECADD ( current_x[j], current_x[j], temp );
VECSUB ( cloth->current_v[j], cloth->current_x[j], cloth->current_xold[j] );
index = implicit_getcreate_S_index(clmd, j);
id->S[index].pinned = 1;
VECSUB ( current_x[i], current_x[i], temp );
VECSUB ( cloth->current_v[i], cloth->current_x[i], cloth->current_xold[i] );
index = implicit_getcreate_S_index(clmd, i);
id->S[index].pinned = 1;
cloth_add_spring (clmd, i, j, mindistance1 + mindistance2, CLOTH_SPRING_TYPE_COLLISION);
}
collisions = 1;
@@ -2300,16 +2377,18 @@ int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep,
}
}
}
*/
//////////////////////////////////////////////
// SELFCOLLISIONS: update velocities
//////////////////////////////////////////////
/*
for ( i = 0; i < cloth->numverts; i++ )
{
VECSUB ( cloth->current_v[i], cloth->current_x[i], cloth->current_xold[i] );
}
*/
//////////////////////////////////////////////
return 1;
return 0;
}

View File

@@ -5068,6 +5068,7 @@ static void collisionModifier_initData(ModifierData *md)
collmd->xnew = NULL;
collmd->current_x = NULL;
collmd->current_xnew = NULL;
collmd->current_v = NULL;
collmd->time = -1;
collmd->numverts = 0;
collmd->tree = NULL;
@@ -5089,11 +5090,14 @@ static void collisionModifier_freeData(ModifierData *md)
MEM_freeN(collmd->current_x);
if(collmd->current_xnew)
MEM_freeN(collmd->current_xnew);
if(collmd->current_v)
MEM_freeN(collmd->current_v);
collmd->x = NULL;
collmd->xnew = NULL;
collmd->current_x = NULL;
collmd->current_xnew = NULL;
collmd->current_v = NULL;
collmd->time = -1;
collmd->numverts = 0;
collmd->tree = NULL;
@@ -5155,6 +5159,8 @@ static void collisionModifier_deformVerts(
collmd->xnew = MEM_dupallocN(collmd->x); // frame end position
collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame
collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
collmd->numverts = numverts;
// TODO: epsilon

View File

@@ -358,6 +358,7 @@ typedef struct CollisionModifierData {
struct MVert *xnew; /* position at the end of the frame */
struct MVert *current_xnew; /* new position at the actual inter-frame step */
struct MVert *current_x; /* position at the actual inter-frame step */
struct MVert *current_v; /* position at the actual inter-frame step */
unsigned int numverts;
float time;

View File

@@ -1494,14 +1494,6 @@ static void modifiers_convertToReal(void *ob_v, void *md_v)
BIF_undo_push("Modifier convert to real");
}
static void modifiers_pointCacheClearModifier(void *ob_v, void *md_v)
{
Object *ob = ob_v;
ModifierData *md = md_v;
int stack_index = modifiers_indexInObject(ob_v, md_v);
PTCache_id_clear((ID *)ob, CFRA, stack_index);
}
static void build_uvlayer_menu_vars(CustomData *data, char **menu_string,
int *uvlayer_tmp, char *uvlayer_name)
{

View File

@@ -48,6 +48,7 @@
#include "BKE_action.h"
#include "BKE_cloth.h"
#include "BKE_collisions.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_library.h"
@@ -2966,6 +2967,30 @@ void do_effects_panels(unsigned short event)
}
allqueue(REDRAWVIEW3D, 0);
break;
case B_CLOTH_CLEARCACHEALL:
{
ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
if(clmd)
{
CFRA= 1;
update_for_newframe_muted();
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
cloth_clear_cache(ob, clmd, 2);
allqueue(REDRAWBUTSOBJECT, 0);
allqueue(REDRAWVIEW3D, 0);
}
}
break;
case B_CLOTH_RENEW:
{
ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
if(clmd)
{
do_object_panels(B_CLOTH_CLEARCACHEALL);
cloth_free_modifier (clmd);
}
}
break;
default:
if(event>=B_SELEFFECT && event<B_SELEFFECT+MAX_EFFECT) {
ob= OBACT;
@@ -3002,10 +3027,31 @@ static void field_testTexture(char *name, ID **idpp)
}
*idpp = 0;
}
/* Panel for collision */
static void object_collision__enabletoggle ( void *ob_v, void *arg2 )
{
Object *ob = ob_v;
ModifierData *md = modifiers_findByType ( ob, eModifierType_Collision );
if ( !md )
{
md = modifier_new ( eModifierType_Collision );
BLI_addhead ( &ob->modifiers, md );
}
else
{
BLI_remlink ( &ob->modifiers, md );
modifier_free ( md );
allqueue(REDRAWBUTSEDIT, 0);
}
}
/* Panels for particle interaction settings */
static void object_panel_deflection(Object *ob)
{
uiBlock *block;
uiBut *but;
block= uiNewBlock(&curarea->uiblocks, "object_panel_deflection", UI_EMBOSS, UI_HELV, curarea->win);
if(uiNewPanel(curarea, block, "Deflection", "Physics", 0, 0, 318, 204)==0) return;
@@ -3025,7 +3071,9 @@ static void object_panel_deflection(Object *ob)
if(ob->pd && ob->type==OB_MESH) {
PartDeflect *pd= ob->pd;
uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",160,160,150,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision");
but = uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",160,160,150,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision");
uiButSetFunc(but, object_collision__enabletoggle, ob, NULL);
if(pd->deflect) {
uiDefBut(block, LABEL, 0, "Particles", 160,140,75,20, NULL, 0.0, 0, 0, 0, "");
uiDefButBitS(block, TOG, PDEFLE_KILL_PART, B_DIFF, "Kill",235,140,75,20, &pd->flag, 0, 0, 0, 0, "Kill collided particles");