Notes:
* blenderbuttons and ICON_SNAP_PEEL_OBJECT were not merged.
This commit is contained in:
Brecht Van Lommel
2009-04-20 15:06:46 +00:00
554 changed files with 36035 additions and 27044 deletions

View File

@@ -18,6 +18,7 @@ subject to the following restrictions:
#include "CcdPhysicsEnvironment.h"
#include "CcdPhysicsController.h"
#include "CcdGraphicController.h"
#include <algorithm>
#include "btBulletDynamicsCommon.h"
@@ -32,6 +33,10 @@ subject to the following restrictions:
#include "PHY_IMotionState.h"
#include "KX_GameObject.h"
#include "RAS_MeshObject.h"
#include "RAS_Polygon.h"
#include "RAS_TexVert.h"
#define CCD_CONSTRAINT_DISABLE_LINKED_COLLISION 0x80
@@ -46,7 +51,9 @@ btRaycastVehicle::btVehicleTuning gTuning;
#endif //NEW_BULLET_VEHICLE_SUPPORT
#include "LinearMath/btAabbUtil2.h"
#include "MT_Matrix4x4.h"
#include "MT_Vector3.h"
#include "GL/glew.h"
#ifdef WIN32
void DrawRasterizerLine(const float* from,const float* to,int color);
@@ -316,8 +323,10 @@ static void DrawAabb(btIDebugDraw* debugDrawer,const btVector3& from,const btVec
CcdPhysicsEnvironment::CcdPhysicsEnvironment(btDispatcher* dispatcher,btOverlappingPairCache* pairCache)
:m_numIterations(10),
CcdPhysicsEnvironment::CcdPhysicsEnvironment(bool useDbvtCulling,btDispatcher* dispatcher,btOverlappingPairCache* pairCache)
:m_cullingCache(NULL),
m_cullingTree(NULL),
m_numIterations(10),
m_scalingPropagated(false),
m_numTimeSubSteps(1),
m_ccdMode(0),
@@ -350,6 +359,11 @@ m_ownDispatcher(NULL)
//m_broadphase = new btAxisSweep3(btVector3(-1000,-1000,-1000),btVector3(1000,1000,1000));
//m_broadphase = new btSimpleBroadphase();
m_broadphase = new btDbvtBroadphase();
// avoid any collision in the culling tree
if (useDbvtCulling) {
m_cullingCache = new btNullPairCache();
m_cullingTree = new btDbvtBroadphase(m_cullingCache);
}
m_filterCallback = new CcdOverlapFilterCallBack(this);
m_broadphase->getOverlappingPairCache()->setOverlapFilterCallback(m_filterCallback);
@@ -364,7 +378,6 @@ m_ownDispatcher(NULL)
m_gravity = btVector3(0.f,-10.f,0.f);
m_dynamicsWorld->setGravity(m_gravity);
}
void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl)
@@ -558,6 +571,41 @@ void CcdPhysicsEnvironment::refreshCcdPhysicsController(CcdPhysicsController* ct
}
}
void CcdPhysicsEnvironment::addCcdGraphicController(CcdGraphicController* ctrl)
{
if (m_cullingTree)
{
btVector3 minAabb;
btVector3 maxAabb;
ctrl->getAabb(minAabb, maxAabb);
ctrl->setBroadphaseHandle(m_cullingTree->createProxy(
minAabb,
maxAabb,
INVALID_SHAPE_PROXYTYPE, // this parameter is not used
ctrl,
0, // this object does not collision with anything
0,
NULL, // dispatcher => this parameter is not used
0));
assert(ctrl->getBroadphaseHandle());
}
}
void CcdPhysicsEnvironment::removeCcdGraphicController(CcdGraphicController* ctrl)
{
if (m_cullingTree)
{
btBroadphaseProxy* bp = ctrl->getBroadphaseHandle();
if (bp)
{
m_cullingTree->destroyProxy(bp,NULL);
ctrl->setBroadphaseHandle(0);
}
}
}
void CcdPhysicsEnvironment::beginFrame()
{
@@ -593,10 +641,10 @@ bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep)
(*it)->SynchronizeMotionStates(timeStep);
}
for (it=m_controllers.begin(); it!=m_controllers.end(); it++)
{
(*it)->SynchronizeMotionStates(timeStep);
}
//for (it=m_controllers.begin(); it!=m_controllers.end(); it++)
//{
// (*it)->SynchronizeMotionStates(timeStep);
//}
for (i=0;i<m_wrapperVehicles.size();i++)
{
@@ -618,9 +666,10 @@ class ClosestRayResultCallbackNotMe : public btCollisionWorld::ClosestRayResultC
public:
ClosestRayResultCallbackNotMe(const btVector3& rayFromWorld,const btVector3& rayToWorld,btCollisionObject* owner,btCollisionObject* parent)
:btCollisionWorld::ClosestRayResultCallback(rayFromWorld,rayToWorld),
m_owner(owner)
m_owner(owner),
m_parent(parent)
{
}
virtual bool needsCollision(btBroadphaseProxy* proxy0) const
@@ -668,7 +717,7 @@ void CcdPhysicsEnvironment::processFhSprings(double curTime,float timeStep)
//btVector3 rayToWorld = rayFromWorld + body->getCenterOfMassTransform().getBasis() * rayDirLocal;
//ray always points down the z axis in world space...
btVector3 rayToWorld = rayFromWorld + rayDirLocal;
ClosestRayResultCallbackNotMe resultCallback(rayFromWorld,rayToWorld,body,parentBody);
m_dynamicsWorld->rayTest(rayFromWorld,rayToWorld,resultCallback);
@@ -1146,7 +1195,578 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallbac
return result.m_controller;
}
// Handles occlusion culling.
// The implementation is based on the CDTestFramework
struct OcclusionBuffer
{
struct WriteOCL
{
static inline bool Process(btScalar& q,btScalar v) { if(q<v) q=v;return(false); }
static inline void Occlusion(bool& flag) { flag = true; }
};
struct QueryOCL
{
static inline bool Process(btScalar& q,btScalar v) { return(q<=v); }
static inline void Occlusion(bool& flag) { }
};
btScalar* m_buffer;
size_t m_bufferSize;
bool m_initialized;
bool m_occlusion;
int m_sizes[2];
btScalar m_scales[2];
btScalar m_offsets[2];
btScalar m_wtc[16]; // world to clip transform
btScalar m_mtc[16]; // model to clip transform
// constructor: size=largest dimension of the buffer.
// Buffer size depends on aspect ratio
OcclusionBuffer()
{
m_initialized=false;
m_occlusion = false;
m_buffer == NULL;
m_bufferSize = 0;
}
// multiplication of column major matrices: m=m1*m2
template<typename T1, typename T2>
void CMmat4mul(btScalar* m, const T1* m1, const T2* m2)
{
m[ 0] = btScalar(m1[ 0]*m2[ 0]+m1[ 4]*m2[ 1]+m1[ 8]*m2[ 2]+m1[12]*m2[ 3]);
m[ 1] = btScalar(m1[ 1]*m2[ 0]+m1[ 5]*m2[ 1]+m1[ 9]*m2[ 2]+m1[13]*m2[ 3]);
m[ 2] = btScalar(m1[ 2]*m2[ 0]+m1[ 6]*m2[ 1]+m1[10]*m2[ 2]+m1[14]*m2[ 3]);
m[ 3] = btScalar(m1[ 3]*m2[ 0]+m1[ 7]*m2[ 1]+m1[11]*m2[ 2]+m1[15]*m2[ 3]);
m[ 4] = btScalar(m1[ 0]*m2[ 4]+m1[ 4]*m2[ 5]+m1[ 8]*m2[ 6]+m1[12]*m2[ 7]);
m[ 5] = btScalar(m1[ 1]*m2[ 4]+m1[ 5]*m2[ 5]+m1[ 9]*m2[ 6]+m1[13]*m2[ 7]);
m[ 6] = btScalar(m1[ 2]*m2[ 4]+m1[ 6]*m2[ 5]+m1[10]*m2[ 6]+m1[14]*m2[ 7]);
m[ 7] = btScalar(m1[ 3]*m2[ 4]+m1[ 7]*m2[ 5]+m1[11]*m2[ 6]+m1[15]*m2[ 7]);
m[ 8] = btScalar(m1[ 0]*m2[ 8]+m1[ 4]*m2[ 9]+m1[ 8]*m2[10]+m1[12]*m2[11]);
m[ 9] = btScalar(m1[ 1]*m2[ 8]+m1[ 5]*m2[ 9]+m1[ 9]*m2[10]+m1[13]*m2[11]);
m[10] = btScalar(m1[ 2]*m2[ 8]+m1[ 6]*m2[ 9]+m1[10]*m2[10]+m1[14]*m2[11]);
m[11] = btScalar(m1[ 3]*m2[ 8]+m1[ 7]*m2[ 9]+m1[11]*m2[10]+m1[15]*m2[11]);
m[12] = btScalar(m1[ 0]*m2[12]+m1[ 4]*m2[13]+m1[ 8]*m2[14]+m1[12]*m2[15]);
m[13] = btScalar(m1[ 1]*m2[12]+m1[ 5]*m2[13]+m1[ 9]*m2[14]+m1[13]*m2[15]);
m[14] = btScalar(m1[ 2]*m2[12]+m1[ 6]*m2[13]+m1[10]*m2[14]+m1[14]*m2[15]);
m[15] = btScalar(m1[ 3]*m2[12]+m1[ 7]*m2[13]+m1[11]*m2[14]+m1[15]*m2[15]);
}
void setup(int size)
{
m_initialized=false;
m_occlusion=false;
// compute the size of the buffer
GLint v[4];
GLdouble m[16],p[16];
int maxsize;
double ratio;
glGetIntegerv(GL_VIEWPORT,v);
maxsize = (v[2] > v[3]) ? v[2] : v[3];
assert(maxsize > 0);
ratio = 1.0/(2*maxsize);
// ensure even number
m_sizes[0] = 2*((int)(size*v[2]*ratio+0.5));
m_sizes[1] = 2*((int)(size*v[3]*ratio+0.5));
m_scales[0]=btScalar(m_sizes[0]/2);
m_scales[1]=btScalar(m_sizes[1]/2);
m_offsets[0]=m_scales[0]+0.5f;
m_offsets[1]=m_scales[1]+0.5f;
// prepare matrix
// at this time of the rendering, the modelview matrix is the
// world to camera transformation and the projection matrix is
// camera to clip transformation. combine both so that
glGetDoublev(GL_MODELVIEW_MATRIX,m);
glGetDoublev(GL_PROJECTION_MATRIX,p);
CMmat4mul(m_wtc,p,m);
}
void initialize()
{
size_t newsize = (m_sizes[0]*m_sizes[1])*sizeof(btScalar);
if (m_buffer)
{
// see if we can reuse
if (newsize > m_bufferSize)
{
free(m_buffer);
m_buffer = NULL;
m_bufferSize = 0;
}
}
if (!m_buffer)
{
m_buffer = (btScalar*)calloc(1, newsize);
m_bufferSize = newsize;
} else
{
// buffer exists already, just clears it
memset(m_buffer, 0, newsize);
}
// memory allocate must succeed
assert(m_buffer != NULL);
m_initialized = true;
m_occlusion = false;
}
void SetModelMatrix(double *fl)
{
CMmat4mul(m_mtc,m_wtc,fl);
if (!m_initialized)
initialize();
}
// transform a segment in world coordinate to clip coordinate
void transformW(const btVector3& x, btVector4& t)
{
t[0] = x[0]*m_wtc[0]+x[1]*m_wtc[4]+x[2]*m_wtc[8]+m_wtc[12];
t[1] = x[0]*m_wtc[1]+x[1]*m_wtc[5]+x[2]*m_wtc[9]+m_wtc[13];
t[2] = x[0]*m_wtc[2]+x[1]*m_wtc[6]+x[2]*m_wtc[10]+m_wtc[14];
t[3] = x[0]*m_wtc[3]+x[1]*m_wtc[7]+x[2]*m_wtc[11]+m_wtc[15];
}
void transformM(const float* x, btVector4& t)
{
t[0] = x[0]*m_mtc[0]+x[1]*m_mtc[4]+x[2]*m_mtc[8]+m_mtc[12];
t[1] = x[0]*m_mtc[1]+x[1]*m_mtc[5]+x[2]*m_mtc[9]+m_mtc[13];
t[2] = x[0]*m_mtc[2]+x[1]*m_mtc[6]+x[2]*m_mtc[10]+m_mtc[14];
t[3] = x[0]*m_mtc[3]+x[1]*m_mtc[7]+x[2]*m_mtc[11]+m_mtc[15];
}
// convert polygon to device coordinates
static bool project(btVector4* p,int n)
{
for(int i=0;i<n;++i)
{
const btScalar iw=1/p[i][3];
p[i][2]=1/p[i][3];
p[i][0]*=p[i][2];
p[i][1]*=p[i][2];
}
return(true);
}
// pi: closed polygon in clip coordinate, NP = number of segments
// po: same polygon with clipped segments removed
template <const int NP>
static int clip(const btVector4* pi,btVector4* po)
{
btScalar s[2*NP];
btVector4 pn[2*NP];
int i, j, m, n, ni;
// deal with near clipping
for(i=0, m=0;i<NP;++i)
{
s[i]=pi[i][2]+pi[i][3];
if(s[i]<0) m+=1<<i;
}
if(m==((1<<NP)-1))
return(0);
if(m!=0)
{
for(i=NP-1,j=0,n=0;j<NP;i=j++)
{
const btVector4& a=pi[i];
const btVector4& b=pi[j];
const btScalar t=s[i]/(a[3]+a[2]-b[3]-b[2]);
if((t>0)&&(t<1))
{
pn[n][0] = a[0]+(b[0]-a[0])*t;
pn[n][1] = a[1]+(b[1]-a[1])*t;
pn[n][2] = a[2]+(b[2]-a[2])*t;
pn[n][3] = a[3]+(b[3]-a[3])*t;
++n;
}
if(s[j]>0) pn[n++]=b;
}
// ready to test far clipping, start from the modified polygon
pi = pn;
ni = n;
} else
{
// no clipping on the near plane, keep same vector
ni = NP;
}
// now deal with far clipping
for(i=0, m=0;i<ni;++i)
{
s[i]=pi[i][2]-pi[i][3];
if(s[i]>0) m+=1<<i;
}
if(m==((1<<ni)-1))
return(0);
if(m!=0)
{
for(i=ni-1,j=0,n=0;j<ni;i=j++)
{
const btVector4& a=pi[i];
const btVector4& b=pi[j];
const btScalar t=s[i]/(a[2]-a[3]-b[2]+b[3]);
if((t>0)&&(t<1))
{
po[n][0] = a[0]+(b[0]-a[0])*t;
po[n][1] = a[1]+(b[1]-a[1])*t;
po[n][2] = a[2]+(b[2]-a[2])*t;
po[n][3] = a[3]+(b[3]-a[3])*t;
++n;
}
if(s[j]<0) po[n++]=b;
}
return(n);
}
for(int i=0;i<ni;++i) po[i]=pi[i];
return(ni);
}
// write or check a triangle to buffer. a,b,c in device coordinates (-1,+1)
template <typename POLICY>
inline bool draw( const btVector4& a,
const btVector4& b,
const btVector4& c,
const float face,
const btScalar minarea)
{
const btScalar a2=cross(b-a,c-a)[2];
if((face*a2)<0.f || btFabs(a2)<minarea)
return false;
// further down we are normally going to write to the Zbuffer, mark it so
POLICY::Occlusion(m_occlusion);
int x[3], y[3], ib=1, ic=2;
btScalar z[3];
x[0]=(int)(a.x()*m_scales[0]+m_offsets[0]);
y[0]=(int)(a.y()*m_scales[1]+m_offsets[1]);
z[0]=a.z();
if (a2 < 0.f)
{
// negative aire is possible with double face => must
// change the order of b and c otherwise the algorithm doesn't work
ib=2;
ic=1;
}
x[ib]=(int)(b.x()*m_scales[0]+m_offsets[0]);
x[ic]=(int)(c.x()*m_scales[0]+m_offsets[0]);
y[ib]=(int)(b.y()*m_scales[1]+m_offsets[1]);
y[ic]=(int)(c.y()*m_scales[1]+m_offsets[1]);
z[ib]=b.z();
z[ic]=c.z();
const int mix=btMax(0,btMin(x[0],btMin(x[1],x[2])));
const int mxx=btMin(m_sizes[0],1+btMax(x[0],btMax(x[1],x[2])));
const int miy=btMax(0,btMin(y[0],btMin(y[1],y[2])));
const int mxy=btMin(m_sizes[1],1+btMax(y[0],btMax(y[1],y[2])));
const int width=mxx-mix;
const int height=mxy-miy;
if ((width*height) <= 1)
{
// degenerated in at most one single pixel
btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
// use for loop to detect the case where width or height == 0
for(int iy=miy;iy<mxy;++iy)
{
for(int ix=mix;ix<mxx;++ix)
{
if(POLICY::Process(*scan,z[0]))
return(true);
if(POLICY::Process(*scan,z[1]))
return(true);
if(POLICY::Process(*scan,z[2]))
return(true);
}
}
} else if (width == 1)
{
// Degenerated in at least 2 vertical lines
// The algorithm below doesn't work when face has a single pixel width
// We cannot use general formulas because the plane is degenerated.
// We have to interpolate along the 3 edges that overlaps and process each pixel.
// sort the y coord to make formula simpler
int ytmp;
btScalar ztmp;
if (y[0] > y[1]) { ytmp=y[1];y[1]=y[0];y[0]=ytmp;ztmp=z[1];z[1]=z[0];z[0]=ztmp; }
if (y[0] > y[2]) { ytmp=y[2];y[2]=y[0];y[0]=ytmp;ztmp=z[2];z[2]=z[0];z[0]=ztmp; }
if (y[1] > y[2]) { ytmp=y[2];y[2]=y[1];y[1]=ytmp;ztmp=z[2];z[2]=z[1];z[1]=ztmp; }
int dy[]={ y[0]-y[1],
y[1]-y[2],
y[2]-y[0]};
btScalar dzy[3];
dzy[0] = (dy[0]) ? (z[0]-z[1])/dy[0] : btScalar(0.f);
dzy[1] = (dy[1]) ? (z[1]-z[2])/dy[1] : btScalar(0.f);
dzy[2] = (dy[2]) ? (z[2]-z[0])/dy[2] : btScalar(0.f);
btScalar v[3] = { dzy[0]*(miy-y[0])+z[0],
dzy[1]*(miy-y[1])+z[1],
dzy[2]*(miy-y[2])+z[2] };
dy[0] = y[1]-y[0];
dy[1] = y[0]-y[1];
dy[2] = y[2]-y[0];
btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
for(int iy=miy;iy<mxy;++iy)
{
if(dy[0] >= 0 && POLICY::Process(*scan,v[0]))
return(true);
if(dy[1] >= 0 && POLICY::Process(*scan,v[1]))
return(true);
if(dy[2] >= 0 && POLICY::Process(*scan,v[2]))
return(true);
scan+=m_sizes[0];
v[0] += dzy[0]; v[1] += dzy[1]; v[2] += dzy[2];
dy[0]--; dy[1]++, dy[2]--;
}
} else if (height == 1)
{
// Degenerated in at least 2 horizontal lines
// The algorithm below doesn't work when face has a single pixel width
// We cannot use general formulas because the plane is degenerated.
// We have to interpolate along the 3 edges that overlaps and process each pixel.
int xtmp;
btScalar ztmp;
if (x[0] > x[1]) { xtmp=x[1];x[1]=x[0];x[0]=xtmp;ztmp=z[1];z[1]=z[0];z[0]=ztmp; }
if (x[0] > x[2]) { xtmp=x[2];x[2]=x[0];x[0]=xtmp;ztmp=z[2];z[2]=z[0];z[0]=ztmp; }
if (x[1] > x[2]) { xtmp=x[2];x[2]=x[1];x[1]=xtmp;ztmp=z[2];z[2]=z[1];z[1]=ztmp; }
int dx[]={ x[0]-x[1],
x[1]-x[2],
x[2]-x[0]};
btScalar dzx[3];
dzx[0] = (dx[0]) ? (z[0]-z[1])/dx[0] : btScalar(0.f);
dzx[1] = (dx[1]) ? (z[1]-z[2])/dx[1] : btScalar(0.f);
dzx[2] = (dx[2]) ? (z[2]-z[0])/dx[2] : btScalar(0.f);
btScalar v[3] = { dzx[0]*(mix-x[0])+z[0],
dzx[1]*(mix-x[1])+z[1],
dzx[2]*(mix-x[2])+z[2] };
dx[0] = x[1]-x[0];
dx[1] = x[0]-x[1];
dx[2] = x[2]-x[0];
btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
for(int ix=mix;ix<mxx;++ix)
{
if(dx[0] >= 0 && POLICY::Process(*scan,v[0]))
return(true);
if(dx[1] >= 0 && POLICY::Process(*scan,v[1]))
return(true);
if(dx[2] >= 0 && POLICY::Process(*scan,v[2]))
return(true);
scan++;
v[0] += dzx[0]; v[1] += dzx[1]; v[2] += dzx[2];
dx[0]--; dx[1]++, dx[2]--;
}
} else
{
// general case
const int dx[]={ y[0]-y[1],
y[1]-y[2],
y[2]-y[0]};
const int dy[]={ x[1]-x[0]-dx[0]*width,
x[2]-x[1]-dx[1]*width,
x[0]-x[2]-dx[2]*width};
const int a=x[2]*y[0]+x[0]*y[1]-x[2]*y[1]-x[0]*y[2]+x[1]*y[2]-x[1]*y[0];
const btScalar ia=1/(btScalar)a;
const btScalar dzx=ia*(y[2]*(z[1]-z[0])+y[1]*(z[0]-z[2])+y[0]*(z[2]-z[1]));
const btScalar dzy=ia*(x[2]*(z[0]-z[1])+x[0]*(z[1]-z[2])+x[1]*(z[2]-z[0]))-(dzx*width);
int c[]={ miy*x[1]+mix*y[0]-x[1]*y[0]-mix*y[1]+x[0]*y[1]-miy*x[0],
miy*x[2]+mix*y[1]-x[2]*y[1]-mix*y[2]+x[1]*y[2]-miy*x[1],
miy*x[0]+mix*y[2]-x[0]*y[2]-mix*y[0]+x[2]*y[0]-miy*x[2]};
btScalar v=ia*((z[2]*c[0])+(z[0]*c[1])+(z[1]*c[2]));
btScalar* scan=&m_buffer[miy*m_sizes[0]];
for(int iy=miy;iy<mxy;++iy)
{
for(int ix=mix;ix<mxx;++ix)
{
if((c[0]>=0)&&(c[1]>=0)&&(c[2]>=0))
{
if(POLICY::Process(scan[ix],v))
return(true);
}
c[0]+=dx[0];c[1]+=dx[1];c[2]+=dx[2];v+=dzx;
}
c[0]+=dy[0];c[1]+=dy[1];c[2]+=dy[2];v+=dzy;
scan+=m_sizes[0];
}
}
return(false);
}
// clip than write or check a polygon
template <const int NP,typename POLICY>
inline bool clipDraw( const btVector4* p,
const float face,
btScalar minarea)
{
btVector4 o[NP*2];
int n=clip<NP>(p,o);
bool earlyexit=false;
if (n)
{
project(o,n);
for(int i=2;i<n && !earlyexit;++i)
{
earlyexit|=draw<POLICY>(o[0],o[i-1],o[i],face,minarea);
}
}
return(earlyexit);
}
// add a triangle (in model coordinate)
// face = 0.f if face is double side,
// = 1.f if face is single sided and scale is positive
// = -1.f if face is single sided and scale is negative
void appendOccluderM(const float* a,
const float* b,
const float* c,
const float face)
{
btVector4 p[3];
transformM(a,p[0]);
transformM(b,p[1]);
transformM(c,p[2]);
clipDraw<3,WriteOCL>(p,face,btScalar(0.f));
}
// add a quad (in model coordinate)
void appendOccluderM(const float* a,
const float* b,
const float* c,
const float* d,
const float face)
{
btVector4 p[4];
transformM(a,p[0]);
transformM(b,p[1]);
transformM(c,p[2]);
transformM(d,p[3]);
clipDraw<4,WriteOCL>(p,face,btScalar(0.f));
}
// query occluder for a box (c=center, e=extend) in world coordinate
inline bool queryOccluderW( const btVector3& c,
const btVector3& e)
{
if (!m_occlusion)
// no occlusion yet, no need to check
return true;
btVector4 x[8];
transformW(btVector3(c[0]-e[0],c[1]-e[1],c[2]-e[2]),x[0]);
transformW(btVector3(c[0]+e[0],c[1]-e[1],c[2]-e[2]),x[1]);
transformW(btVector3(c[0]+e[0],c[1]+e[1],c[2]-e[2]),x[2]);
transformW(btVector3(c[0]-e[0],c[1]+e[1],c[2]-e[2]),x[3]);
transformW(btVector3(c[0]-e[0],c[1]-e[1],c[2]+e[2]),x[4]);
transformW(btVector3(c[0]+e[0],c[1]-e[1],c[2]+e[2]),x[5]);
transformW(btVector3(c[0]+e[0],c[1]+e[1],c[2]+e[2]),x[6]);
transformW(btVector3(c[0]-e[0],c[1]+e[1],c[2]+e[2]),x[7]);
for(int i=0;i<8;++i)
{
// the box is clipped, it's probably a large box, don't waste our time to check
if((x[i][2]+x[i][3])<=0) return(true);
}
static const int d[]={ 1,0,3,2,
4,5,6,7,
4,7,3,0,
6,5,1,2,
7,6,2,3,
5,4,0,1};
for(int i=0;i<(sizeof(d)/sizeof(d[0]));)
{
const btVector4 p[]={ x[d[i++]],
x[d[i++]],
x[d[i++]],
x[d[i++]]};
if(clipDraw<4,QueryOCL>(p,1.f,0.f))
return(true);
}
return(false);
}
};
struct DbvtCullingCallback : btDbvt::ICollide
{
PHY_CullingCallback m_clientCallback;
void* m_userData;
OcclusionBuffer *m_ocb;
DbvtCullingCallback(PHY_CullingCallback clientCallback, void* userData)
{
m_clientCallback = clientCallback;
m_userData = userData;
m_ocb = NULL;
}
bool Descent(const btDbvtNode* node)
{
return(m_ocb->queryOccluderW(node->volume.Center(),node->volume.Extents()));
}
void Process(const btDbvtNode* node,btScalar depth)
{
Process(node);
}
void Process(const btDbvtNode* leaf)
{
btBroadphaseProxy* proxy=(btBroadphaseProxy*)leaf->data;
// the client object is a graphic controller
CcdGraphicController* ctrl = static_cast<CcdGraphicController*>(proxy->m_clientObject);
KX_ClientObjectInfo* info = (KX_ClientObjectInfo*)ctrl->getNewClientInfo();
if (m_ocb)
{
// means we are doing occlusion culling. Check if this object is an occluders
KX_GameObject* gameobj = KX_GameObject::GetClientObject(info);
if (gameobj && gameobj->GetOccluder())
{
double* fl = gameobj->GetOpenGLMatrixPtr()->getPointer();
// this will create the occlusion buffer if not already done
// and compute the transformation from model local space to clip space
m_ocb->SetModelMatrix(fl);
float face = (gameobj->IsNegativeScaling()) ? -1.0f : 1.0f;
// walk through the meshes and for each add to buffer
for (int i=0; i<gameobj->GetMeshCount(); i++)
{
RAS_MeshObject* meshobj = gameobj->GetMesh(i);
const float *v1, *v2, *v3, *v4;
int polycount = meshobj->NumPolygons();
for (int j=0; j<polycount; j++)
{
RAS_Polygon* poly = meshobj->GetPolygon(j);
switch (poly->VertexCount())
{
case 3:
v1 = poly->GetVertex(0)->getXYZ();
v2 = poly->GetVertex(1)->getXYZ();
v3 = poly->GetVertex(2)->getXYZ();
m_ocb->appendOccluderM(v1,v2,v3,((poly->IsTwoside())?0.f:face));
break;
case 4:
v1 = poly->GetVertex(0)->getXYZ();
v2 = poly->GetVertex(1)->getXYZ();
v3 = poly->GetVertex(2)->getXYZ();
v4 = poly->GetVertex(3)->getXYZ();
m_ocb->appendOccluderM(v1,v2,v3,v4,((poly->IsTwoside())?0.f:face));
break;
}
}
}
}
}
if (info)
(*m_clientCallback)(info, m_userData);
}
};
static OcclusionBuffer gOcb;
bool CcdPhysicsEnvironment::cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes, int occlusionRes)
{
if (!m_cullingTree)
return false;
DbvtCullingCallback dispatcher(callback, userData);
btVector3 planes_n[6];
btScalar planes_o[6];
if (nplanes > 6)
nplanes = 6;
for (int i=0; i<nplanes; i++)
{
planes_n[i].setValue(planes[i][0], planes[i][1], planes[i][2]);
planes_o[i] = planes[i][3];
}
// if occlusionRes != 0 => occlusion culling
if (occlusionRes)
{
gOcb.setup(occlusionRes);
dispatcher.m_ocb = &gOcb;
// occlusion culling, the direction of the view is taken from the first plan which MUST be the near plane
btDbvt::collideOCL(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,planes_n[0],nplanes,dispatcher);
btDbvt::collideOCL(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,planes_n[0],nplanes,dispatcher);
}else
{
btDbvt::collideKDOP(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,nplanes,dispatcher);
btDbvt::collideKDOP(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,nplanes,dispatcher);
}
return true;
}
int CcdPhysicsEnvironment::getNumContactPoints()
{
@@ -1211,6 +1831,13 @@ CcdPhysicsEnvironment::~CcdPhysicsEnvironment()
if (NULL != m_broadphase)
delete m_broadphase;
if (NULL != m_cullingTree)
delete m_cullingTree;
if (NULL != m_cullingCache)
delete m_cullingCache;
}
@@ -1465,8 +2092,8 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::CreateSphereController(float radi
{
CcdConstructionInfo cinfo;
// memory leak! The shape is not deleted by Bullet and we cannot add it to the KX_Scene.m_shapes list
cinfo.m_collisionShape = new btSphereShape(radius);
memset(&cinfo, 0, sizeof(cinfo)); /* avoid uninitialized values */
cinfo.m_collisionShape = new btSphereShape(radius); // memory leak! The shape is not deleted by Bullet and we cannot add it to the KX_Scene.m_shapes list
cinfo.m_MotionState = 0;
cinfo.m_physicsEnv = this;
// declare this object as Dyamic rather then static!!
@@ -1925,7 +2552,7 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl
PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float coneradius,float coneheight)
{
CcdConstructionInfo cinfo;
memset(&cinfo, 0, sizeof(cinfo)); /* avoid uninitialized values */
// we don't need a CcdShapeConstructionInfo for this shape:
// it is simple enough for the standard copy constructor (see CcdPhysicsController::GetReplica)
cinfo.m_collisionShape = new btConeShape(coneradius,coneheight);