soc-2008-mxcurioni: FRS_glBlendEquation files

This commit is contained in:
Maxime Curioni 2008-09-28 18:43:51 +00:00
parent 5812c494a5
commit bb8477ec57
67 changed files with 18788 additions and 17 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,548 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///btDbvtBroadphase implementation by Nathanael Presson
#include "btDbvtBroadphase.h"
//
// Profiling
//
#if DBVT_BP_PROFILE||DBVT_BP_ENABLE_BENCHMARK
#include <stdio.h>
#endif
#if DBVT_BP_PROFILE
struct ProfileScope
{
__forceinline ProfileScope(btClock& clock,unsigned long& value) :
m_clock(&clock),m_value(&value),m_base(clock.getTimeMicroseconds())
{
}
__forceinline ~ProfileScope()
{
(*m_value)+=m_clock->getTimeMicroseconds()-m_base;
}
btClock* m_clock;
unsigned long* m_value;
unsigned long m_base;
};
#define SPC(_value_) ProfileScope spc_scope(m_clock,_value_)
#else
#define SPC(_value_)
#endif
//
// Helpers
//
//
template <typename T>
static inline void listappend(T* item,T*& list)
{
item->links[0]=0;
item->links[1]=list;
if(list) list->links[0]=item;
list=item;
}
//
template <typename T>
static inline void listremove(T* item,T*& list)
{
if(item->links[0]) item->links[0]->links[1]=item->links[1]; else list=item->links[1];
if(item->links[1]) item->links[1]->links[0]=item->links[0];
}
//
template <typename T>
static inline int listcount(T* root)
{
int n=0;
while(root) { ++n;root=root->links[1]; }
return(n);
}
//
template <typename T>
static inline void clear(T& value)
{
static const struct ZeroDummy : T {} zerodummy;
value=zerodummy;
}
//
// Colliders
//
/* Tree collider */
struct btDbvtTreeCollider : btDbvt::ICollide
{
btDbvtBroadphase* pbp;
btDbvtProxy* proxy;
btDbvtTreeCollider(btDbvtBroadphase* p) : pbp(p) {}
void Process(const btDbvtNode* na,const btDbvtNode* nb)
{
if(na!=nb)
{
btDbvtProxy* pa=(btDbvtProxy*)na->data;
btDbvtProxy* pb=(btDbvtProxy*)nb->data;
#if DBVT_BP_SORTPAIRS
if(pa>pb) btSwap(pa,pb);
#endif
pbp->m_paircache->addOverlappingPair(pa,pb);
++pbp->m_newpairs;
}
}
void Process(const btDbvtNode* n)
{
Process(n,proxy->leaf);
}
};
//
// btDbvtBroadphase
//
//
btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache)
{
m_deferedcollide = false;
m_needcleanup = true;
m_releasepaircache = (paircache!=0)?false:true;
m_prediction = 1/(btScalar)2;
m_stageCurrent = 0;
m_fixedleft = 0;
m_fupdates = 1;
m_dupdates = 0;
m_cupdates = 10;
m_newpairs = 1;
m_updates_call = 0;
m_updates_done = 0;
m_updates_ratio = 0;
m_paircache = paircache?
paircache :
new(btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache();
m_gid = 0;
m_pid = 0;
m_cid = 0;
for(int i=0;i<=STAGECOUNT;++i)
{
m_stageRoots[i]=0;
}
#if DBVT_BP_PROFILE
clear(m_profiling);
#endif
}
//
btDbvtBroadphase::~btDbvtBroadphase()
{
if(m_releasepaircache)
{
m_paircache->~btOverlappingPairCache();
btAlignedFree(m_paircache);
}
}
//
btBroadphaseProxy* btDbvtBroadphase::createProxy( const btVector3& aabbMin,
const btVector3& aabbMax,
int /*shapeType*/,
void* userPtr,
short int collisionFilterGroup,
short int collisionFilterMask,
btDispatcher* /*dispatcher*/,
void* /*multiSapProxy*/)
{
btDbvtProxy* proxy=new(btAlignedAlloc(sizeof(btDbvtProxy),16)) btDbvtProxy( userPtr,
collisionFilterGroup,
collisionFilterMask);
proxy->aabb = btDbvtVolume::FromMM(aabbMin,aabbMax);
proxy->stage = m_stageCurrent;
proxy->m_uniqueId = ++m_gid;
proxy->leaf = m_sets[0].insert(proxy->aabb,proxy);
listappend(proxy,m_stageRoots[m_stageCurrent]);
if(!m_deferedcollide)
{
btDbvtTreeCollider collider(this);
collider.proxy=proxy;
btDbvt::collideTV(m_sets[0].m_root,proxy->aabb,collider);
btDbvt::collideTV(m_sets[1].m_root,proxy->aabb,collider);
}
return(proxy);
}
//
void btDbvtBroadphase::destroyProxy( btBroadphaseProxy* absproxy,
btDispatcher* dispatcher)
{
btDbvtProxy* proxy=(btDbvtProxy*)absproxy;
if(proxy->stage==STAGECOUNT)
m_sets[1].remove(proxy->leaf);
else
m_sets[0].remove(proxy->leaf);
listremove(proxy,m_stageRoots[proxy->stage]);
m_paircache->removeOverlappingPairsContainingProxy(proxy,dispatcher);
btAlignedFree(proxy);
m_needcleanup=true;
}
//
void btDbvtBroadphase::setAabb( btBroadphaseProxy* absproxy,
const btVector3& aabbMin,
const btVector3& aabbMax,
btDispatcher* /*dispatcher*/)
{
btDbvtProxy* proxy=(btDbvtProxy*)absproxy;
ATTRIBUTE_ALIGNED16(btDbvtVolume) aabb=btDbvtVolume::FromMM(aabbMin,aabbMax);
#if DBVT_BP_PREVENTFALSEUPDATE
if(NotEqual(aabb,proxy->leaf->volume))
#endif
{
bool docollide=false;
if(proxy->stage==STAGECOUNT)
{/* fixed -> dynamic set */
m_sets[1].remove(proxy->leaf);
proxy->leaf=m_sets[0].insert(aabb,proxy);
docollide=true;
}
else
{/* dynamic set */
++m_updates_call;
if(Intersect(proxy->leaf->volume,aabb))
{/* Moving */
const btVector3 delta=aabbMin-proxy->aabb.Mins();
btVector3 velocity(aabb.Extents()*m_prediction);
if(delta[0]<0) velocity[0]=-velocity[0];
if(delta[1]<0) velocity[1]=-velocity[1];
if(delta[2]<0) velocity[2]=-velocity[2];
if (
#ifdef DBVT_BP_MARGIN
m_sets[0].update(proxy->leaf,aabb,velocity,DBVT_BP_MARGIN)
#else
m_sets[0].update(proxy->leaf,aabb,velocity)
#endif
)
{
++m_updates_done;
docollide=true;
}
}
else
{/* Teleporting */
m_sets[0].update(proxy->leaf,aabb);
++m_updates_done;
docollide=true;
}
}
listremove(proxy,m_stageRoots[proxy->stage]);
proxy->aabb = aabb;
proxy->stage = m_stageCurrent;
listappend(proxy,m_stageRoots[m_stageCurrent]);
if(docollide)
{
m_needcleanup=true;
if(!m_deferedcollide)
{
btDbvtTreeCollider collider(this);
btDbvt::collideTT(m_sets[1].m_root,proxy->leaf,collider);
btDbvt::collideTT(m_sets[0].m_root,proxy->leaf,collider);
}
}
}
}
//
void btDbvtBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher)
{
collide(dispatcher);
#if DBVT_BP_PROFILE
if(0==(m_pid%DBVT_BP_PROFILING_RATE))
{
printf("fixed(%u) dynamics(%u) pairs(%u)\r\n",m_sets[1].m_leaves,m_sets[0].m_leaves,m_paircache->getNumOverlappingPairs());
unsigned int total=m_profiling.m_total;
if(total<=0) total=1;
printf("ddcollide: %u%% (%uus)\r\n",(50+m_profiling.m_ddcollide*100)/total,m_profiling.m_ddcollide/DBVT_BP_PROFILING_RATE);
printf("fdcollide: %u%% (%uus)\r\n",(50+m_profiling.m_fdcollide*100)/total,m_profiling.m_fdcollide/DBVT_BP_PROFILING_RATE);
printf("cleanup: %u%% (%uus)\r\n",(50+m_profiling.m_cleanup*100)/total,m_profiling.m_cleanup/DBVT_BP_PROFILING_RATE);
printf("total: %uus\r\n",total/DBVT_BP_PROFILING_RATE);
const unsigned long sum=m_profiling.m_ddcollide+
m_profiling.m_fdcollide+
m_profiling.m_cleanup;
printf("leaked: %u%% (%uus)\r\n",100-((50+sum*100)/total),(total-sum)/DBVT_BP_PROFILING_RATE);
printf("job counts: %u%%\r\n",(m_profiling.m_jobcount*100)/((m_sets[0].m_leaves+m_sets[1].m_leaves)*DBVT_BP_PROFILING_RATE));
clear(m_profiling);
m_clock.reset();
}
#endif
}
//
void btDbvtBroadphase::collide(btDispatcher* dispatcher)
{
SPC(m_profiling.m_total);
/* optimize */
m_sets[0].optimizeIncremental(1+(m_sets[0].m_leaves*m_dupdates)/100);
if(m_fixedleft)
{
const int count=1+(m_sets[1].m_leaves*m_fupdates)/100;
m_sets[1].optimizeIncremental(1+(m_sets[1].m_leaves*m_fupdates)/100);
m_fixedleft=btMax<int>(0,m_fixedleft-count);
}
/* dynamic -> fixed set */
m_stageCurrent=(m_stageCurrent+1)%STAGECOUNT;
btDbvtProxy* current=m_stageRoots[m_stageCurrent];
if(current)
{
btDbvtTreeCollider collider(this);
do {
btDbvtProxy* next=current->links[1];
listremove(current,m_stageRoots[current->stage]);
listappend(current,m_stageRoots[STAGECOUNT]);
#if DBVT_BP_ACCURATESLEEPING
m_paircache->removeOverlappingPairsContainingProxy(current,dispatcher);
collider.proxy=current;
btDbvt::collideTV(m_sets[0].m_root,current->aabb,collider);
btDbvt::collideTV(m_sets[1].m_root,current->aabb,collider);
#endif
m_sets[0].remove(current->leaf);
current->leaf = m_sets[1].insert(current->aabb,current);
current->stage = STAGECOUNT;
current = next;
} while(current);
m_fixedleft=m_sets[1].m_leaves;
m_needcleanup=true;
}
/* collide dynamics */
{
btDbvtTreeCollider collider(this);
if(m_deferedcollide)
{
SPC(m_profiling.m_fdcollide);
btDbvt::collideTT(m_sets[0].m_root,m_sets[1].m_root,collider);
}
if(m_deferedcollide)
{
SPC(m_profiling.m_ddcollide);
btDbvt::collideTT(m_sets[0].m_root,m_sets[0].m_root,collider);
}
}
/* clean up */
if(m_needcleanup)
{
SPC(m_profiling.m_cleanup);
btBroadphasePairArray& pairs=m_paircache->getOverlappingPairArray();
if(pairs.size()>0)
{
const int ci=pairs.size();
int ni=btMin(ci,btMax<int>(m_newpairs,(ci*m_cupdates)/100));
for(int i=0;i<ni;++i)
{
btBroadphasePair& p=pairs[(m_cid+i)%ci];
btDbvtProxy* pa=(btDbvtProxy*)p.m_pProxy0;
btDbvtProxy* pb=(btDbvtProxy*)p.m_pProxy1;
if(!Intersect(pa->leaf->volume,pb->leaf->volume))
{
#if DBVT_BP_SORTPAIRS
if(pa>pb) btSwap(pa,pb);
#endif
m_paircache->removeOverlappingPair(pa,pb,dispatcher);
--ni;--i;
}
}
if(pairs.size()>0) m_cid=(m_cid+ni)%pairs.size(); else m_cid=0;
}
}
++m_pid;
m_newpairs=1;
m_needcleanup=false;
if(m_updates_call>0)
{ m_updates_ratio=m_updates_done/(btScalar)m_updates_call; }
else
{ m_updates_ratio=0; }
m_updates_done/=2;
m_updates_call/=2;
}
//
void btDbvtBroadphase::optimize()
{
m_sets[0].optimizeTopDown();
m_sets[1].optimizeTopDown();
}
//
btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache()
{
return(m_paircache);
}
//
const btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache() const
{
return(m_paircache);
}
//
void btDbvtBroadphase::getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const
{
ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds;
if(!m_sets[0].empty())
if(!m_sets[1].empty()) Merge( m_sets[0].m_root->volume,
m_sets[1].m_root->volume,bounds);
else
bounds=m_sets[0].m_root->volume;
else if(!m_sets[1].empty()) bounds=m_sets[1].m_root->volume;
else
bounds=btDbvtVolume::FromCR(btVector3(0,0,0),0);
aabbMin=bounds.Mins();
aabbMax=bounds.Maxs();
}
//
void btDbvtBroadphase::printStats()
{}
//
#if DBVT_BP_ENABLE_BENCHMARK
struct btBroadphaseBenchmark
{
struct Experiment
{
const char* name;
int object_count;
int update_count;
int spawn_count;
int iterations;
btScalar speed;
btScalar amplitude;
};
struct Object
{
btVector3 center;
btVector3 extents;
btBroadphaseProxy* proxy;
btScalar time;
void update(btScalar speed,btScalar amplitude,btBroadphaseInterface* pbi)
{
time += speed;
center[0] = btCos(time*(btScalar)2.17)*amplitude+
btSin(time)*amplitude/2;
center[1] = btCos(time*(btScalar)1.38)*amplitude+
btSin(time)*amplitude;
center[2] = btSin(time*(btScalar)0.777)*amplitude;
pbi->setAabb(proxy,center-extents,center+extents,0);
}
};
static int UnsignedRand(int range=RAND_MAX-1) { return(rand()%(range+1)); }
static btScalar UnitRand() { return(UnsignedRand(16384)/(btScalar)16384); }
static void OutputTime(const char* name,btClock& c,unsigned count=0)
{
const unsigned long us=c.getTimeMicroseconds();
const unsigned long ms=(us+500)/1000;
const btScalar sec=us/(btScalar)(1000*1000);
if(count>0)
printf("%s : %u us (%u ms), %.2f/s\r\n",name,us,ms,count/sec);
else
printf("%s : %u us (%u ms)\r\n",name,us,ms);
}
};
void btDbvtBroadphase::benchmark(btBroadphaseInterface* pbi)
{
static const btBroadphaseBenchmark::Experiment experiments[]=
{
{"1024o.10%",1024,10,0,8192,(btScalar)0.005,(btScalar)100},
/*{"4096o.10%",4096,10,0,8192,(btScalar)0.005,(btScalar)100},
{"8192o.10%",8192,10,0,8192,(btScalar)0.005,(btScalar)100},*/
};
static const int nexperiments=sizeof(experiments)/sizeof(experiments[0]);
btAlignedObjectArray<btBroadphaseBenchmark::Object*> objects;
btClock wallclock;
/* Begin */
for(int iexp=0;iexp<nexperiments;++iexp)
{
const btBroadphaseBenchmark::Experiment& experiment=experiments[iexp];
const int object_count=experiment.object_count;
const int update_count=(object_count*experiment.update_count)/100;
const int spawn_count=(object_count*experiment.spawn_count)/100;
const btScalar speed=experiment.speed;
const btScalar amplitude=experiment.amplitude;
printf("Experiment #%u '%s':\r\n",iexp,experiment.name);
printf("\tObjects: %u\r\n",object_count);
printf("\tUpdate: %u\r\n",update_count);
printf("\tSpawn: %u\r\n",spawn_count);
printf("\tSpeed: %f\r\n",speed);
printf("\tAmplitude: %f\r\n",amplitude);
srand(180673);
/* Create objects */
wallclock.reset();
objects.reserve(object_count);
for(int i=0;i<object_count;++i)
{
btBroadphaseBenchmark::Object* po=new btBroadphaseBenchmark::Object();
po->center[0]=btBroadphaseBenchmark::UnitRand()*50;
po->center[1]=btBroadphaseBenchmark::UnitRand()*50;
po->center[2]=btBroadphaseBenchmark::UnitRand()*50;
po->extents[0]=btBroadphaseBenchmark::UnitRand()*2+2;
po->extents[1]=btBroadphaseBenchmark::UnitRand()*2+2;
po->extents[2]=btBroadphaseBenchmark::UnitRand()*2+2;
po->time=btBroadphaseBenchmark::UnitRand()*2000;
po->proxy=pbi->createProxy(po->center-po->extents,po->center+po->extents,0,po,1,1,0,0);
objects.push_back(po);
}
btBroadphaseBenchmark::OutputTime("\tInitialization",wallclock);
/* First update */
wallclock.reset();
for(int i=0;i<objects.size();++i)
{
objects[i]->update(speed,amplitude,pbi);
}
btBroadphaseBenchmark::OutputTime("\tFirst update",wallclock);
/* Updates */
wallclock.reset();
for(int i=0;i<experiment.iterations;++i)
{
for(int j=0;j<update_count;++j)
{
objects[j]->update(speed,amplitude,pbi);
}
pbi->calculateOverlappingPairs(0);
}
btBroadphaseBenchmark::OutputTime("\tUpdate",wallclock,experiment.iterations);
/* Clean up */
wallclock.reset();
for(int i=0;i<objects.size();++i)
{
pbi->destroyProxy(objects[i]->proxy,0);
delete objects[i];
}
objects.resize(0);
btBroadphaseBenchmark::OutputTime("\tRelease",wallclock);
}
}
#else
void btDbvtBroadphase::benchmark(btBroadphaseInterface*)
{}
#endif
#if DBVT_BP_PROFILE
#undef SPC
#endif

@ -0,0 +1,116 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///btDbvtBroadphase implementation by Nathanael Presson
#ifndef BT_DBVT_BROADPHASE_H
#define BT_DBVT_BROADPHASE_H
#include "BulletCollision/BroadphaseCollision/btDbvt.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
//
// Compile time config
//
#define DBVT_BP_PROFILE 0
#define DBVT_BP_SORTPAIRS 1
#define DBVT_BP_PREVENTFALSEUPDATE 0
#define DBVT_BP_ACCURATESLEEPING 0
#define DBVT_BP_ENABLE_BENCHMARK 0
#define DBVT_BP_MARGIN (btScalar)0.05
#if DBVT_BP_PROFILE
#define DBVT_BP_PROFILING_RATE 256
#include "LinearMath/btQuickprof.h"
#endif
//
// btDbvtProxy
//
struct btDbvtProxy : btBroadphaseProxy
{
/* Fields */
btDbvtAabbMm aabb;
btDbvtNode* leaf;
btDbvtProxy* links[2];
int stage;
/* ctor */
btDbvtProxy(void* userPtr,short int collisionFilterGroup, short int collisionFilterMask) :
btBroadphaseProxy(userPtr,collisionFilterGroup,collisionFilterMask)
{
links[0]=links[1]=0;
}
};
typedef btAlignedObjectArray<btDbvtProxy*> btDbvtProxyArray;
///The btDbvtBroadphase implements a broadphase using two dynamic AABB bounding volume hierarchies/trees (see btDbvt).
///One tree is used for static/non-moving objects, and another tree is used for dynamic objects. Objects can move from one tree to the other.
///This is a very fast broadphase, especially for very dynamic worlds where many objects are moving. Its insert/add and remove of objects is generally faster than the sweep and prune broadphases btAxisSweep3 and bt32BitAxisSweep3.
struct btDbvtBroadphase : btBroadphaseInterface
{
/* Config */
enum {
DYNAMIC_SET = 0, /* Dynamic set index */
FIXED_SET = 1, /* Fixed set index */
STAGECOUNT = 2 /* Number of stages */
};
/* Fields */
btDbvt m_sets[2]; // Dbvt sets
btDbvtProxy* m_stageRoots[STAGECOUNT+1]; // Stages list
btOverlappingPairCache* m_paircache; // Pair cache
btScalar m_prediction; // Velocity prediction
int m_stageCurrent; // Current stage
int m_fupdates; // % of fixed updates per frame
int m_dupdates; // % of dynamic updates per frame
int m_cupdates; // % of cleanup updates per frame
int m_newpairs; // Number of pairs created
int m_fixedleft; // Fixed optimization left
unsigned m_updates_call; // Number of updates call
unsigned m_updates_done; // Number of updates done
btScalar m_updates_ratio; // m_updates_done/m_updates_call
int m_pid; // Parse id
int m_cid; // Cleanup index
int m_gid; // Gen id
bool m_releasepaircache; // Release pair cache on delete
bool m_deferedcollide; // Defere dynamic/static collision to collide call
bool m_needcleanup; // Need to run cleanup?
#if DBVT_BP_PROFILE
btClock m_clock;
struct {
unsigned long m_total;
unsigned long m_ddcollide;
unsigned long m_fdcollide;
unsigned long m_cleanup;
unsigned long m_jobcount;
} m_profiling;
#endif
/* Methods */
btDbvtBroadphase(btOverlappingPairCache* paircache=0);
~btDbvtBroadphase();
void collide(btDispatcher* dispatcher);
void optimize();
/* btBroadphaseInterface Implementation */
btBroadphaseProxy* createProxy(const btVector3& aabbMin,const btVector3& aabbMax,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy);
void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher);
void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher);
void calculateOverlappingPairs(btDispatcher* dispatcher);
btOverlappingPairCache* getOverlappingPairCache();
const btOverlappingPairCache* getOverlappingPairCache() const;
void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const;
void printStats();
static void benchmark(btBroadphaseInterface*);
};
#endif

@ -0,0 +1,466 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btMultiSapBroadphase.h"
#include "btSimpleBroadphase.h"
#include "LinearMath/btAabbUtil2.h"
#include "btQuantizedBvh.h"
/// btSapBroadphaseArray m_sapBroadphases;
/// btOverlappingPairCache* m_overlappingPairs;
extern int gOverlappingPairs;
/*
class btMultiSapSortedOverlappingPairCache : public btSortedOverlappingPairCache
{
public:
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
return btSortedOverlappingPairCache::addOverlappingPair((btBroadphaseProxy*)proxy0->m_multiSapParentProxy,(btBroadphaseProxy*)proxy1->m_multiSapParentProxy);
}
};
*/
btMultiSapBroadphase::btMultiSapBroadphase(int /*maxProxies*/,btOverlappingPairCache* pairCache)
:m_overlappingPairs(pairCache),
m_optimizedAabbTree(0),
m_ownsPairCache(false),
m_invalidPair(0)
{
if (!m_overlappingPairs)
{
m_ownsPairCache = true;
void* mem = btAlignedAlloc(sizeof(btSortedOverlappingPairCache),16);
m_overlappingPairs = new (mem)btSortedOverlappingPairCache();
}
struct btMultiSapOverlapFilterCallback : public btOverlapFilterCallback
{
virtual ~btMultiSapOverlapFilterCallback()
{}
// return true when pairs need collision
virtual bool needBroadphaseCollision(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1) const
{
btBroadphaseProxy* multiProxy0 = (btBroadphaseProxy*)childProxy0->m_multiSapParentProxy;
btBroadphaseProxy* multiProxy1 = (btBroadphaseProxy*)childProxy1->m_multiSapParentProxy;
bool collides = (multiProxy0->m_collisionFilterGroup & multiProxy1->m_collisionFilterMask) != 0;
collides = collides && (multiProxy1->m_collisionFilterGroup & multiProxy0->m_collisionFilterMask);
return collides;
}
};
void* mem = btAlignedAlloc(sizeof(btMultiSapOverlapFilterCallback),16);
m_filterCallback = new (mem)btMultiSapOverlapFilterCallback();
m_overlappingPairs->setOverlapFilterCallback(m_filterCallback);
// mem = btAlignedAlloc(sizeof(btSimpleBroadphase),16);
// m_simpleBroadphase = new (mem) btSimpleBroadphase(maxProxies,m_overlappingPairs);
}
btMultiSapBroadphase::~btMultiSapBroadphase()
{
if (m_ownsPairCache)
{
m_overlappingPairs->~btOverlappingPairCache();
btAlignedFree(m_overlappingPairs);
}
}
void btMultiSapBroadphase::buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax)
{
m_optimizedAabbTree = new btQuantizedBvh();
m_optimizedAabbTree->setQuantizationValues(bvhAabbMin,bvhAabbMax);
QuantizedNodeArray& nodes = m_optimizedAabbTree->getLeafNodeArray();
for (int i=0;i<m_sapBroadphases.size();i++)
{
btQuantizedBvhNode node;
btVector3 aabbMin,aabbMax;
m_sapBroadphases[i]->getBroadphaseAabb(aabbMin,aabbMax);
m_optimizedAabbTree->quantize(&node.m_quantizedAabbMin[0],aabbMin,0);
m_optimizedAabbTree->quantize(&node.m_quantizedAabbMax[0],aabbMax,1);
int partId = 0;
node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | i;
nodes.push_back(node);
}
m_optimizedAabbTree->buildInternal();
}
btBroadphaseProxy* btMultiSapBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* /*ignoreMe*/)
{
//void* ignoreMe -> we could think of recursive multi-sap, if someone is interested
void* mem = btAlignedAlloc(sizeof(btMultiSapProxy),16);
btMultiSapProxy* proxy = new (mem)btMultiSapProxy(aabbMin, aabbMax,shapeType,userPtr, collisionFilterGroup,collisionFilterMask);
m_multiSapProxies.push_back(proxy);
///this should deal with inserting/removal into child broadphases
setAabb(proxy,aabbMin,aabbMax,dispatcher);
return proxy;
}
void btMultiSapBroadphase::destroyProxy(btBroadphaseProxy* /*proxy*/,btDispatcher* /*dispatcher*/)
{
///not yet
btAssert(0);
}
void btMultiSapBroadphase::addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase)
{
void* mem = btAlignedAlloc(sizeof(btBridgeProxy),16);
btBridgeProxy* bridgeProxyRef = new(mem) btBridgeProxy;
bridgeProxyRef->m_childProxy = childProxy;
bridgeProxyRef->m_childBroadphase = childBroadphase;
parentMultiSapProxy->m_bridgeProxies.push_back(bridgeProxyRef);
}
bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax);
bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax)
{
return
amin.getX() >= bmin.getX() && amax.getX() <= bmax.getX() &&
amin.getY() >= bmin.getY() && amax.getY() <= bmax.getY() &&
amin.getZ() >= bmin.getZ() && amax.getZ() <= bmax.getZ();
}
//#include <stdio.h>
void btMultiSapBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)
{
btMultiSapProxy* multiProxy = static_cast<btMultiSapProxy*>(proxy);
multiProxy->m_aabbMin = aabbMin;
multiProxy->m_aabbMax = aabbMax;
// bool fullyContained = false;
// bool alreadyInSimple = false;
struct MyNodeOverlapCallback : public btNodeOverlapCallback
{
btMultiSapBroadphase* m_multiSap;
btMultiSapProxy* m_multiProxy;
btDispatcher* m_dispatcher;
MyNodeOverlapCallback(btMultiSapBroadphase* multiSap,btMultiSapProxy* multiProxy,btDispatcher* dispatcher)
:m_multiSap(multiSap),
m_multiProxy(multiProxy),
m_dispatcher(dispatcher)
{
}
virtual void processNode(int /*nodeSubPart*/, int broadphaseIndex)
{
btBroadphaseInterface* childBroadphase = m_multiSap->getBroadphaseArray()[broadphaseIndex];
int containingBroadphaseIndex = -1;
//already found?
for (int i=0;i<m_multiProxy->m_bridgeProxies.size();i++)
{
if (m_multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase)
{
containingBroadphaseIndex = i;
break;
}
}
if (containingBroadphaseIndex<0)
{
//add it
btBroadphaseProxy* childProxy = childBroadphase->createProxy(m_multiProxy->m_aabbMin,m_multiProxy->m_aabbMax,m_multiProxy->m_shapeType,m_multiProxy->m_clientObject,m_multiProxy->m_collisionFilterGroup,m_multiProxy->m_collisionFilterMask, m_dispatcher,m_multiProxy);
m_multiSap->addToChildBroadphase(m_multiProxy,childProxy,childBroadphase);
}
}
};
MyNodeOverlapCallback myNodeCallback(this,multiProxy,dispatcher);
m_optimizedAabbTree->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax);
int i;
for ( i=0;i<multiProxy->m_bridgeProxies.size();i++)
{
btVector3 worldAabbMin,worldAabbMax;
multiProxy->m_bridgeProxies[i]->m_childBroadphase->getBroadphaseAabb(worldAabbMin,worldAabbMax);
bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax);
if (!overlapsBroadphase)
{
//remove it now
btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[i];
btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy;
bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher);
multiProxy->m_bridgeProxies.swap( i,multiProxy->m_bridgeProxies.size()-1);
multiProxy->m_bridgeProxies.pop_back();
}
}
/*
if (1)
{
//find broadphase that contain this multiProxy
int numChildBroadphases = getBroadphaseArray().size();
for (int i=0;i<numChildBroadphases;i++)
{
btBroadphaseInterface* childBroadphase = getBroadphaseArray()[i];
btVector3 worldAabbMin,worldAabbMax;
childBroadphase->getBroadphaseAabb(worldAabbMin,worldAabbMax);
bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax);
// fullyContained = fullyContained || boxIsContainedWithinBox(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax);
int containingBroadphaseIndex = -1;
//if already contains this
for (int i=0;i<multiProxy->m_bridgeProxies.size();i++)
{
if (multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase)
{
containingBroadphaseIndex = i;
}
alreadyInSimple = alreadyInSimple || (multiProxy->m_bridgeProxies[i]->m_childBroadphase == m_simpleBroadphase);
}
if (overlapsBroadphase)
{
if (containingBroadphaseIndex<0)
{
btBroadphaseProxy* childProxy = childBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher);
childProxy->m_multiSapParentProxy = multiProxy;
addToChildBroadphase(multiProxy,childProxy,childBroadphase);
}
} else
{
if (containingBroadphaseIndex>=0)
{
//remove
btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[containingBroadphaseIndex];
btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy;
bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher);
multiProxy->m_bridgeProxies.swap( containingBroadphaseIndex,multiProxy->m_bridgeProxies.size()-1);
multiProxy->m_bridgeProxies.pop_back();
}
}
}
///If we are in no other child broadphase, stick the proxy in the global 'simple' broadphase (brute force)
///hopefully we don't end up with many entries here (can assert/provide feedback on stats)
if (0)//!multiProxy->m_bridgeProxies.size())
{
///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision
///this is needed to be able to calculate the aabb overlap
btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher);
childProxy->m_multiSapParentProxy = multiProxy;
addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase);
}
}
if (!multiProxy->m_bridgeProxies.size())
{
///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision
///this is needed to be able to calculate the aabb overlap
btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher);
childProxy->m_multiSapParentProxy = multiProxy;
addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase);
}
*/
//update
for ( i=0;i<multiProxy->m_bridgeProxies.size();i++)
{
btBridgeProxy* bridgeProxyRef = multiProxy->m_bridgeProxies[i];
bridgeProxyRef->m_childBroadphase->setAabb(bridgeProxyRef->m_childProxy,aabbMin,aabbMax,dispatcher);
}
}
bool stopUpdating=false;
class btMultiSapBroadphasePairSortPredicate
{
public:
bool operator() ( const btBroadphasePair& a1, const btBroadphasePair& b1 )
{
btMultiSapBroadphase::btMultiSapProxy* aProxy0 = a1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy0->m_multiSapParentProxy : 0;
btMultiSapBroadphase::btMultiSapProxy* aProxy1 = a1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy1->m_multiSapParentProxy : 0;
btMultiSapBroadphase::btMultiSapProxy* bProxy0 = b1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy0->m_multiSapParentProxy : 0;
btMultiSapBroadphase::btMultiSapProxy* bProxy1 = b1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy1->m_multiSapParentProxy : 0;
return aProxy0 > bProxy0 ||
(aProxy0 == bProxy0 && aProxy1 > bProxy1) ||
(aProxy0 == bProxy0 && aProxy1 == bProxy1 && a1.m_algorithm > b1.m_algorithm);
}
};
///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb
void btMultiSapBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher)
{
// m_simpleBroadphase->calculateOverlappingPairs(dispatcher);
if (!stopUpdating && getOverlappingPairCache()->hasDeferredRemoval())
{
btBroadphasePairArray& overlappingPairArray = getOverlappingPairCache()->getOverlappingPairArray();
// quicksort(overlappingPairArray,0,overlappingPairArray.size());
overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate());
//perform a sort, to find duplicates and to sort 'invalid' pairs to the end
// overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate());
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair);
m_invalidPair = 0;
int i;
btBroadphasePair previousPair;
previousPair.m_pProxy0 = 0;
previousPair.m_pProxy1 = 0;
previousPair.m_algorithm = 0;
for (i=0;i<overlappingPairArray.size();i++)
{
btBroadphasePair& pair = overlappingPairArray[i];
btMultiSapProxy* aProxy0 = pair.m_pProxy0 ? (btMultiSapProxy*)pair.m_pProxy0->m_multiSapParentProxy : 0;
btMultiSapProxy* aProxy1 = pair.m_pProxy1 ? (btMultiSapProxy*)pair.m_pProxy1->m_multiSapParentProxy : 0;
btMultiSapProxy* bProxy0 = previousPair.m_pProxy0 ? (btMultiSapProxy*)previousPair.m_pProxy0->m_multiSapParentProxy : 0;
btMultiSapProxy* bProxy1 = previousPair.m_pProxy1 ? (btMultiSapProxy*)previousPair.m_pProxy1->m_multiSapParentProxy : 0;
bool isDuplicate = (aProxy0 == bProxy0) && (aProxy1 == bProxy1);
previousPair = pair;
bool needsRemoval = false;
if (!isDuplicate)
{
bool hasOverlap = testAabbOverlap(pair.m_pProxy0,pair.m_pProxy1);
if (hasOverlap)
{
needsRemoval = false;//callback->processOverlap(pair);
} else
{
needsRemoval = true;
}
} else
{
//remove duplicate
needsRemoval = true;
//should have no algorithm
btAssert(!pair.m_algorithm);
}
if (needsRemoval)
{
getOverlappingPairCache()->cleanOverlappingPair(pair,dispatcher);
// m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1);
// m_overlappingPairArray.pop_back();
pair.m_pProxy0 = 0;
pair.m_pProxy1 = 0;
m_invalidPair++;
gOverlappingPairs--;
}
}
///if you don't like to skip the invalid pairs in the array, execute following code:
#define CLEAN_INVALID_PAIRS 1
#ifdef CLEAN_INVALID_PAIRS
//perform a sort, to sort 'invalid' pairs to the end
//overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate());
overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate());
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair);
m_invalidPair = 0;
#endif//CLEAN_INVALID_PAIRS
//printf("overlappingPairArray.size()=%d\n",overlappingPairArray.size());
}
}
bool btMultiSapBroadphase::testAabbOverlap(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1)
{
btMultiSapProxy* multiSapProxy0 = (btMultiSapProxy*)childProxy0->m_multiSapParentProxy;
btMultiSapProxy* multiSapProxy1 = (btMultiSapProxy*)childProxy1->m_multiSapParentProxy;
return TestAabbAgainstAabb2(multiSapProxy0->m_aabbMin,multiSapProxy0->m_aabbMax,
multiSapProxy1->m_aabbMin,multiSapProxy1->m_aabbMax);
}
void btMultiSapBroadphase::printStats()
{
/* printf("---------------------------------\n");
printf("btMultiSapBroadphase.h\n");
printf("numHandles = %d\n",m_multiSapProxies.size());
//find broadphase that contain this multiProxy
int numChildBroadphases = getBroadphaseArray().size();
for (int i=0;i<numChildBroadphases;i++)
{
btBroadphaseInterface* childBroadphase = getBroadphaseArray()[i];
childBroadphase->printStats();
}
*/
}

@ -0,0 +1,144 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_MULTI_SAP_BROADPHASE
#define BT_MULTI_SAP_BROADPHASE
#include "btBroadphaseInterface.h"
#include "LinearMath/btAlignedObjectArray.h"
#include "btOverlappingPairCache.h"
class btBroadphaseInterface;
class btSimpleBroadphase;
typedef btAlignedObjectArray<btBroadphaseInterface*> btSapBroadphaseArray;
///The btMultiSapBroadphase is a broadphase that contains multiple SAP broadphases.
///The user can add SAP broadphases that cover the world. A btBroadphaseProxy can be in multiple child broadphases at the same time.
///A btQuantizedBvh acceleration structures finds overlapping SAPs for each btBroadphaseProxy.
///See http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=328
///and http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1329
class btMultiSapBroadphase :public btBroadphaseInterface
{
btSapBroadphaseArray m_sapBroadphases;
btSimpleBroadphase* m_simpleBroadphase;
btOverlappingPairCache* m_overlappingPairs;
class btQuantizedBvh* m_optimizedAabbTree;
bool m_ownsPairCache;
btOverlapFilterCallback* m_filterCallback;
int m_invalidPair;
struct btBridgeProxy
{
btBroadphaseProxy* m_childProxy;
btBroadphaseInterface* m_childBroadphase;
};
public:
struct btMultiSapProxy : public btBroadphaseProxy
{
///array with all the entries that this proxy belongs to
btAlignedObjectArray<btBridgeProxy*> m_bridgeProxies;
btVector3 m_aabbMin;
btVector3 m_aabbMax;
int m_shapeType;
/* void* m_userPtr;
short int m_collisionFilterGroup;
short int m_collisionFilterMask;
*/
btMultiSapProxy(const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask)
:btBroadphaseProxy(userPtr,collisionFilterGroup,collisionFilterMask),
m_aabbMin(aabbMin),
m_aabbMax(aabbMax),
m_shapeType(shapeType)
{
m_multiSapParentProxy =this;
}
};
protected:
btAlignedObjectArray<btMultiSapProxy*> m_multiSapProxies;
public:
btMultiSapBroadphase(int maxProxies = 16384,btOverlappingPairCache* pairCache=0);
btSapBroadphaseArray& getBroadphaseArray()
{
return m_sapBroadphases;
}
const btSapBroadphaseArray& getBroadphaseArray() const
{
return m_sapBroadphases;
}
virtual ~btMultiSapBroadphase();
virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy);
virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher);
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher);
void addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase);
///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb
virtual void calculateOverlappingPairs(btDispatcher* dispatcher);
bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1);
virtual btOverlappingPairCache* getOverlappingPairCache()
{
return m_overlappingPairs;
}
virtual const btOverlappingPairCache* getOverlappingPairCache() const
{
return m_overlappingPairs;
}
///getAabb returns the axis aligned bounding box in the 'global' coordinate frame
///will add some transform later
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const
{
aabbMin.setValue(-1e30f,-1e30f,-1e30f);
aabbMax.setValue(1e30f,1e30f,1e30f);
}
void buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax);
virtual void printStats();
void quicksort (btBroadphasePairArray& a, int lo, int hi);
};
#endif //BT_MULTI_SAP_BROADPHASE

@ -0,0 +1,40 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef OVERLAPPING_PAIR_CALLBACK_H
#define OVERLAPPING_PAIR_CALLBACK_H
class btDispatcher;
struct btBroadphasePair;
///The btOverlappingPairCallback class is an additional optional broadphase user callback for adding/removing overlapping pairs, similar interface to btOverlappingPairCache.
class btOverlappingPairCallback
{
public:
virtual ~btOverlappingPairCallback()
{
}
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) = 0;
virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher) = 0;
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy0,btDispatcher* dispatcher) = 0;
};
#endif //OVERLAPPING_PAIR_CALLBACK_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,486 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef QUANTIZED_BVH_H
#define QUANTIZED_BVH_H
//#define DEBUG_CHECK_DEQUANTIZATION 1
#ifdef DEBUG_CHECK_DEQUANTIZATION
#ifdef __SPU__
#define printf spu_printf
#endif //__SPU__
#include <stdio.h>
#include <stdlib.h>
#endif //DEBUG_CHECK_DEQUANTIZATION
#include "LinearMath/btVector3.h"
#include "LinearMath/btAlignedAllocator.h"
//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrf__m128.asp
//Note: currently we have 16 bytes per quantized node
#define MAX_SUBTREE_SIZE_IN_BYTES 2048
// 10 gives the potential for 1024 parts, with at most 2^21 (2097152) (minus one
// actually) triangles each (since the sign bit is reserved
#define MAX_NUM_PARTS_IN_BITS 10
///btQuantizedBvhNode is a compressed aabb node, 16 bytes.
///Node can be used for leafnode or internal node. Leafnodes can point to 32-bit triangle index (non-negative range).
ATTRIBUTE_ALIGNED16 (struct) btQuantizedBvhNode
{
BT_DECLARE_ALIGNED_ALLOCATOR();
//12 bytes
unsigned short int m_quantizedAabbMin[3];
unsigned short int m_quantizedAabbMax[3];
//4 bytes
int m_escapeIndexOrTriangleIndex;
bool isLeafNode() const
{
//skipindex is negative (internal node), triangleindex >=0 (leafnode)
return (m_escapeIndexOrTriangleIndex >= 0);
}
int getEscapeIndex() const
{
btAssert(!isLeafNode());
return -m_escapeIndexOrTriangleIndex;
}
int getTriangleIndex() const
{
btAssert(isLeafNode());
// Get only the lower bits where the triangle index is stored
return (m_escapeIndexOrTriangleIndex&~((~0)<<(31-MAX_NUM_PARTS_IN_BITS)));
}
int getPartId() const
{
btAssert(isLeafNode());
// Get only the highest bits where the part index is stored
return (m_escapeIndexOrTriangleIndex>>(31-MAX_NUM_PARTS_IN_BITS));
}
}
;
/// btOptimizedBvhNode contains both internal and leaf node information.
/// Total node size is 44 bytes / node. You can use the compressed version of 16 bytes.
ATTRIBUTE_ALIGNED16 (struct) btOptimizedBvhNode
{
BT_DECLARE_ALIGNED_ALLOCATOR();
//32 bytes
btVector3 m_aabbMinOrg;
btVector3 m_aabbMaxOrg;
//4
int m_escapeIndex;
//8
//for child nodes
int m_subPart;
int m_triangleIndex;
int m_padding[5];//bad, due to alignment
};
///btBvhSubtreeInfo provides info to gather a subtree of limited size
ATTRIBUTE_ALIGNED16(class) btBvhSubtreeInfo
{
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
//12 bytes
unsigned short int m_quantizedAabbMin[3];
unsigned short int m_quantizedAabbMax[3];
//4 bytes, points to the root of the subtree
int m_rootNodeIndex;
//4 bytes
int m_subtreeSize;
int m_padding[3];
btBvhSubtreeInfo()
{
//memset(&m_padding[0], 0, sizeof(m_padding));
}
void setAabbFromQuantizeNode(const btQuantizedBvhNode& quantizedNode)
{
m_quantizedAabbMin[0] = quantizedNode.m_quantizedAabbMin[0];
m_quantizedAabbMin[1] = quantizedNode.m_quantizedAabbMin[1];
m_quantizedAabbMin[2] = quantizedNode.m_quantizedAabbMin[2];
m_quantizedAabbMax[0] = quantizedNode.m_quantizedAabbMax[0];
m_quantizedAabbMax[1] = quantizedNode.m_quantizedAabbMax[1];
m_quantizedAabbMax[2] = quantizedNode.m_quantizedAabbMax[2];
}
}
;
class btNodeOverlapCallback
{
public:
virtual ~btNodeOverlapCallback() {};
virtual void processNode(int subPart, int triangleIndex) = 0;
};
#include "LinearMath/btAlignedAllocator.h"
#include "LinearMath/btAlignedObjectArray.h"
///for code readability:
typedef btAlignedObjectArray<btOptimizedBvhNode> NodeArray;
typedef btAlignedObjectArray<btQuantizedBvhNode> QuantizedNodeArray;
typedef btAlignedObjectArray<btBvhSubtreeInfo> BvhSubtreeInfoArray;
///The btQuantizedBvh class stores an AABB tree that can be quickly traversed on CPU and Cell SPU.
///It is used by the btBvhTriangleMeshShape as midphase, and by the btMultiSapBroadphase.
///It is recommended to use quantization for better performance and lower memory requirements.
ATTRIBUTE_ALIGNED16(class) btQuantizedBvh
{
protected:
NodeArray m_leafNodes;
NodeArray m_contiguousNodes;
QuantizedNodeArray m_quantizedLeafNodes;
QuantizedNodeArray m_quantizedContiguousNodes;
int m_curNodeIndex;
//quantization data
bool m_useQuantization;
btVector3 m_bvhAabbMin;
btVector3 m_bvhAabbMax;
btVector3 m_bvhQuantization;
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
enum btTraversalMode
{
TRAVERSAL_STACKLESS = 0,
TRAVERSAL_STACKLESS_CACHE_FRIENDLY,
TRAVERSAL_RECURSIVE
};
protected:
btTraversalMode m_traversalMode;
BvhSubtreeInfoArray m_SubtreeHeaders;
//This is only used for serialization so we don't have to add serialization directly to btAlignedObjectArray
int m_subtreeHeaderCount;
///two versions, one for quantized and normal nodes. This allows code-reuse while maintaining readability (no template/macro!)
///this might be refactored into a virtual, it is usually not calculated at run-time
void setInternalNodeAabbMin(int nodeIndex, const btVector3& aabbMin)
{
if (m_useQuantization)
{
quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] ,aabbMin,0);
} else
{
m_contiguousNodes[nodeIndex].m_aabbMinOrg = aabbMin;
}
}
void setInternalNodeAabbMax(int nodeIndex,const btVector3& aabbMax)
{
if (m_useQuantization)
{
quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0],aabbMax,1);
} else
{
m_contiguousNodes[nodeIndex].m_aabbMaxOrg = aabbMax;
}
}
btVector3 getAabbMin(int nodeIndex) const
{
if (m_useQuantization)
{
return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMin[0]);
}
//non-quantized
return m_leafNodes[nodeIndex].m_aabbMinOrg;
}
btVector3 getAabbMax(int nodeIndex) const
{
if (m_useQuantization)
{
return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMax[0]);
}
//non-quantized
return m_leafNodes[nodeIndex].m_aabbMaxOrg;
}
void setInternalNodeEscapeIndex(int nodeIndex, int escapeIndex)
{
if (m_useQuantization)
{
m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = -escapeIndex;
}
else
{
m_contiguousNodes[nodeIndex].m_escapeIndex = escapeIndex;
}
}
void mergeInternalNodeAabb(int nodeIndex,const btVector3& newAabbMin,const btVector3& newAabbMax)
{
if (m_useQuantization)
{
unsigned short int quantizedAabbMin[3];
unsigned short int quantizedAabbMax[3];
quantize(quantizedAabbMin,newAabbMin,0);
quantize(quantizedAabbMax,newAabbMax,1);
for (int i=0;i<3;i++)
{
if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] > quantizedAabbMin[i])
m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] = quantizedAabbMin[i];
if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] < quantizedAabbMax[i])
m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] = quantizedAabbMax[i];
}
} else
{
//non-quantized
m_contiguousNodes[nodeIndex].m_aabbMinOrg.setMin(newAabbMin);
m_contiguousNodes[nodeIndex].m_aabbMaxOrg.setMax(newAabbMax);
}
}
void swapLeafNodes(int firstIndex,int secondIndex);
void assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex);
protected:
void buildTree (int startIndex,int endIndex);
int calcSplittingAxis(int startIndex,int endIndex);
int sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis);
void walkStacklessTree(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const;
void walkStacklessQuantizedTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex,int endNodeIndex) const;
void walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const;
///tree traversal designed for small-memory processors like PS3 SPU
void walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const;
///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal
void walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode,btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const;
///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal
void walkRecursiveQuantizedTreeAgainstQuantizedTree(const btQuantizedBvhNode* treeNodeA,const btQuantizedBvhNode* treeNodeB,btNodeOverlapCallback* nodeCallback) const;
#define USE_BANCHLESS 1
#ifdef USE_BANCHLESS
//This block replaces the block below and uses no branches, and replaces the 8 bit return with a 32 bit return for improved performance (~3x on XBox 360)
SIMD_FORCE_INLINE unsigned testQuantizedAabbAgainstQuantizedAabb(unsigned short int* aabbMin1,unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) const
{
return static_cast<unsigned int>(btSelect((unsigned)((aabbMin1[0] <= aabbMax2[0]) & (aabbMax1[0] >= aabbMin2[0])
& (aabbMin1[2] <= aabbMax2[2]) & (aabbMax1[2] >= aabbMin2[2])
& (aabbMin1[1] <= aabbMax2[1]) & (aabbMax1[1] >= aabbMin2[1])),
1, 0));
}
#else
SIMD_FORCE_INLINE bool testQuantizedAabbAgainstQuantizedAabb(unsigned short int* aabbMin1,unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) const
{
bool overlap = true;
overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? false : overlap;
overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? false : overlap;
overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? false : overlap;
return overlap;
}
#endif //USE_BANCHLESS
void updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex);
public:
btQuantizedBvh();
virtual ~btQuantizedBvh();
///***************************************** expert/internal use only *************************
void setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin=btScalar(1.0));
QuantizedNodeArray& getLeafNodeArray() { return m_quantizedLeafNodes; }
///buildInternal is expert use only: assumes that setQuantizationValues and LeafNodeArray are initialized
void buildInternal();
///***************************************** expert/internal use only *************************
void reportAabbOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const;
void reportRayOverlappingNodex (btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget) const;
void reportBoxCastOverlappingNodex(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin,const btVector3& aabbMax) const;
SIMD_FORCE_INLINE void quantize(unsigned short* out, const btVector3& point,int isMax) const
{
btAssert(m_useQuantization);
btAssert(point.getX() <= m_bvhAabbMax.getX());
btAssert(point.getY() <= m_bvhAabbMax.getY());
btAssert(point.getZ() <= m_bvhAabbMax.getZ());
btAssert(point.getX() >= m_bvhAabbMin.getX());
btAssert(point.getY() >= m_bvhAabbMin.getY());
btAssert(point.getZ() >= m_bvhAabbMin.getZ());
btVector3 v = (point - m_bvhAabbMin) * m_bvhQuantization;
///Make sure rounding is done in a way that unQuantize(quantizeWithClamp(...)) is conservative
///end-points always set the first bit, so that they are sorted properly (so that neighbouring AABBs overlap properly)
///todo: double-check this
if (isMax)
{
out[0] = (unsigned short) (((unsigned short)(v.getX()+btScalar(1.)) | 1));
out[1] = (unsigned short) (((unsigned short)(v.getY()+btScalar(1.)) | 1));
out[2] = (unsigned short) (((unsigned short)(v.getZ()+btScalar(1.)) | 1));
} else
{
out[0] = (unsigned short) (((unsigned short)(v.getX()) & 0xfffe));
out[1] = (unsigned short) (((unsigned short)(v.getY()) & 0xfffe));
out[2] = (unsigned short) (((unsigned short)(v.getZ()) & 0xfffe));
}
#ifdef DEBUG_CHECK_DEQUANTIZATION
btVector3 newPoint = unQuantize(out);
if (isMax)
{
if (newPoint.getX() < point.getX())
{
printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX());
}
if (newPoint.getY() < point.getY())
{
printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY());
}
if (newPoint.getZ() < point.getZ())
{
printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ());
}
} else
{
if (newPoint.getX() > point.getX())
{
printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX());
}
if (newPoint.getY() > point.getY())
{
printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY());
}
if (newPoint.getZ() > point.getZ())
{
printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ());
}
}
#endif //DEBUG_CHECK_DEQUANTIZATION
}
SIMD_FORCE_INLINE void quantizeWithClamp(unsigned short* out, const btVector3& point2,int isMax) const
{
btAssert(m_useQuantization);
btVector3 clampedPoint(point2);
clampedPoint.setMax(m_bvhAabbMin);
clampedPoint.setMin(m_bvhAabbMax);
quantize(out,clampedPoint,isMax);
}
SIMD_FORCE_INLINE btVector3 unQuantize(const unsigned short* vecIn) const
{
btVector3 vecOut;
vecOut.setValue(
(btScalar)(vecIn[0]) / (m_bvhQuantization.getX()),
(btScalar)(vecIn[1]) / (m_bvhQuantization.getY()),
(btScalar)(vecIn[2]) / (m_bvhQuantization.getZ()));
vecOut += m_bvhAabbMin;
return vecOut;
}
///setTraversalMode let's you choose between stackless, recursive or stackless cache friendly tree traversal. Note this is only implemented for quantized trees.
void setTraversalMode(btTraversalMode traversalMode)
{
m_traversalMode = traversalMode;
}
SIMD_FORCE_INLINE QuantizedNodeArray& getQuantizedNodeArray()
{
return m_quantizedContiguousNodes;
}
SIMD_FORCE_INLINE BvhSubtreeInfoArray& getSubtreeInfoArray()
{
return m_SubtreeHeaders;
}
/////Calculate space needed to store BVH for serialization
unsigned calculateSerializeBufferSize();
/// Data buffer MUST be 16 byte aligned
virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian);
///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place'
static btQuantizedBvh *deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian);
static unsigned int getAlignmentSerializationPadding();
SIMD_FORCE_INLINE bool isQuantized()
{
return m_useQuantization;
}
private:
// Special "copy" constructor that allows for in-place deserialization
// Prevents btVector3's default constructor from being called, but doesn't inialize much else
// ownsMemory should most likely be false if deserializing, and if you are not, don't call this (it also changes the function signature, which we need)
btQuantizedBvh(btQuantizedBvh &other, bool ownsMemory);
}
;
#endif //QUANTIZED_BVH_H

@ -0,0 +1,85 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btBoxBoxCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
#include "BulletCollision/CollisionShapes/btBoxShape.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "btBoxBoxDetector.h"
#define USE_PERSISTENT_CONTACTS 1
btBoxBoxCollisionAlgorithm::btBoxBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* obj0,btCollisionObject* obj1)
: btCollisionAlgorithm(ci),
m_ownManifold(false),
m_manifoldPtr(mf)
{
if (!m_manifoldPtr && m_dispatcher->needsCollision(obj0,obj1))
{
m_manifoldPtr = m_dispatcher->getNewManifold(obj0,obj1);
m_ownManifold = true;
}
}
btBoxBoxCollisionAlgorithm::~btBoxBoxCollisionAlgorithm()
{
if (m_ownManifold)
{
if (m_manifoldPtr)
m_dispatcher->releaseManifold(m_manifoldPtr);
}
}
void btBoxBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
{
if (!m_manifoldPtr)
return;
btCollisionObject* col0 = body0;
btCollisionObject* col1 = body1;
btBoxShape* box0 = (btBoxShape*)col0->getCollisionShape();
btBoxShape* box1 = (btBoxShape*)col1->getCollisionShape();
/// report a contact. internally this will be kept persistent, and contact reduction is done
resultOut->setPersistentManifold(m_manifoldPtr);
#ifndef USE_PERSISTENT_CONTACTS
m_manifoldPtr->clearManifold();
#endif //USE_PERSISTENT_CONTACTS
btDiscreteCollisionDetectorInterface::ClosestPointInput input;
input.m_maximumDistanceSquared = 1e30f;
input.m_transformA = body0->getWorldTransform();
input.m_transformB = body1->getWorldTransform();
btBoxBoxDetector detector(box0,box1);
detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw);
#ifdef USE_PERSISTENT_CONTACTS
// refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added
if (m_ownManifold)
{
resultOut->refreshContactPoints();
}
#endif //USE_PERSISTENT_CONTACTS
}
btScalar btBoxBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/,btCollisionObject* /*body1*/,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/)
{
//not yet
return 1.f;
}

@ -0,0 +1,66 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BOX_BOX__COLLISION_ALGORITHM_H
#define BOX_BOX__COLLISION_ALGORITHM_H
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "BulletCollision/BroadphaseCollision/btDispatcher.h"
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h"
class btPersistentManifold;
///box-box collision detection
class btBoxBoxCollisionAlgorithm : public btCollisionAlgorithm
{
bool m_ownManifold;
btPersistentManifold* m_manifoldPtr;
public:
btBoxBoxCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci)
: btCollisionAlgorithm(ci) {}
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
btBoxBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1);
virtual ~btBoxBoxCollisionAlgorithm();
virtual void getAllContactManifolds(btManifoldArray& manifoldArray)
{
if (m_manifoldPtr && m_ownManifold)
{
manifoldArray.push_back(m_manifoldPtr);
}
}
struct CreateFunc :public btCollisionAlgorithmCreateFunc
{
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{
int bbsize = sizeof(btBoxBoxCollisionAlgorithm);
void* ptr = ci.m_dispatcher1->allocateCollisionAlgorithm(bbsize);
return new(ptr) btBoxBoxCollisionAlgorithm(0,ci,body0,body1);
}
};
};
#endif //BOX_BOX__COLLISION_ALGORITHM_H

@ -0,0 +1,683 @@
/*
* Box-Box collision detection re-distributed under the ZLib license with permission from Russell L. Smith
* Original version is from Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.
* All rights reserved. Email: russ@q12.org Web: www.q12.org
Bullet Continuous Collision Detection and Physics Library
Bullet is Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///ODE box-box collision detection is adapted to work with Bullet
#include "btBoxBoxDetector.h"
#include "BulletCollision/CollisionShapes/btBoxShape.h"
#include <float.h>
#include <string.h>
btBoxBoxDetector::btBoxBoxDetector(btBoxShape* box1,btBoxShape* box2)
: m_box1(box1),
m_box2(box2)
{
}
// given two boxes (p1,R1,side1) and (p2,R2,side2), collide them together and
// generate contact points. this returns 0 if there is no contact otherwise
// it returns the number of contacts generated.
// `normal' returns the contact normal.
// `depth' returns the maximum penetration depth along that normal.
// `return_code' returns a number indicating the type of contact that was
// detected:
// 1,2,3 = box 2 intersects with a face of box 1
// 4,5,6 = box 1 intersects with a face of box 2
// 7..15 = edge-edge contact
// `maxc' is the maximum number of contacts allowed to be generated, i.e.
// the size of the `contact' array.
// `contact' and `skip' are the contact array information provided to the
// collision functions. this function only fills in the position and depth
// fields.
struct dContactGeom;
#define dDOTpq(a,b,p,q) ((a)[0]*(b)[0] + (a)[p]*(b)[q] + (a)[2*(p)]*(b)[2*(q)])
#define dInfinity FLT_MAX
/*PURE_INLINE btScalar dDOT (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,1); }
PURE_INLINE btScalar dDOT13 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,3); }
PURE_INLINE btScalar dDOT31 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,3,1); }
PURE_INLINE btScalar dDOT33 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,3,3); }
*/
static btScalar dDOT (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,1); }
static btScalar dDOT44 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,4,4); }
static btScalar dDOT41 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,4,1); }
static btScalar dDOT14 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,4); }
#define dMULTIPLYOP1_331(A,op,B,C) \
{\
(A)[0] op dDOT41((B),(C)); \
(A)[1] op dDOT41((B+1),(C)); \
(A)[2] op dDOT41((B+2),(C)); \
}
#define dMULTIPLYOP0_331(A,op,B,C) \
{ \
(A)[0] op dDOT((B),(C)); \
(A)[1] op dDOT((B+4),(C)); \
(A)[2] op dDOT((B+8),(C)); \
}
#define dMULTIPLY1_331(A,B,C) dMULTIPLYOP1_331(A,=,B,C)
#define dMULTIPLY0_331(A,B,C) dMULTIPLYOP0_331(A,=,B,C)
typedef btScalar dMatrix3[4*3];
void dLineClosestApproach (const btVector3& pa, const btVector3& ua,
const btVector3& pb, const btVector3& ub,
btScalar *alpha, btScalar *beta);
void dLineClosestApproach (const btVector3& pa, const btVector3& ua,
const btVector3& pb, const btVector3& ub,
btScalar *alpha, btScalar *beta)
{
btVector3 p;
p[0] = pb[0] - pa[0];
p[1] = pb[1] - pa[1];
p[2] = pb[2] - pa[2];
btScalar uaub = dDOT(ua,ub);
btScalar q1 = dDOT(ua,p);
btScalar q2 = -dDOT(ub,p);
btScalar d = 1-uaub*uaub;
if (d <= btScalar(0.0001f)) {
// @@@ this needs to be made more robust
*alpha = 0;
*beta = 0;
}
else {
d = 1.f/d;
*alpha = (q1 + uaub*q2)*d;
*beta = (uaub*q1 + q2)*d;
}
}
// find all the intersection points between the 2D rectangle with vertices
// at (+/-h[0],+/-h[1]) and the 2D quadrilateral with vertices (p[0],p[1]),
// (p[2],p[3]),(p[4],p[5]),(p[6],p[7]).
//
// the intersection points are returned as x,y pairs in the 'ret' array.
// the number of intersection points is returned by the function (this will
// be in the range 0 to 8).
static int intersectRectQuad2 (btScalar h[2], btScalar p[8], btScalar ret[16])
{
// q (and r) contain nq (and nr) coordinate points for the current (and
// chopped) polygons
int nq=4,nr=0;
btScalar buffer[16];
btScalar *q = p;
btScalar *r = ret;
for (int dir=0; dir <= 1; dir++) {
// direction notation: xy[0] = x axis, xy[1] = y axis
for (int sign=-1; sign <= 1; sign += 2) {
// chop q along the line xy[dir] = sign*h[dir]
btScalar *pq = q;
btScalar *pr = r;
nr = 0;
for (int i=nq; i > 0; i--) {
// go through all points in q and all lines between adjacent points
if (sign*pq[dir] < h[dir]) {
// this point is inside the chopping line
pr[0] = pq[0];
pr[1] = pq[1];
pr += 2;
nr++;
if (nr & 8) {
q = r;
goto done;
}
}
btScalar *nextq = (i > 1) ? pq+2 : q;
if ((sign*pq[dir] < h[dir]) ^ (sign*nextq[dir] < h[dir])) {
// this line crosses the chopping line
pr[1-dir] = pq[1-dir] + (nextq[1-dir]-pq[1-dir]) /
(nextq[dir]-pq[dir]) * (sign*h[dir]-pq[dir]);
pr[dir] = sign*h[dir];
pr += 2;
nr++;
if (nr & 8) {
q = r;
goto done;
}
}
pq += 2;
}
q = r;
r = (q==ret) ? buffer : ret;
nq = nr;
}
}
done:
if (q != ret) memcpy (ret,q,nr*2*sizeof(btScalar));
return nr;
}
#define M__PI 3.14159265f
// given n points in the plane (array p, of size 2*n), generate m points that
// best represent the whole set. the definition of 'best' here is not
// predetermined - the idea is to select points that give good box-box
// collision detection behavior. the chosen point indexes are returned in the
// array iret (of size m). 'i0' is always the first entry in the array.
// n must be in the range [1..8]. m must be in the range [1..n]. i0 must be
// in the range [0..n-1].
void cullPoints2 (int n, btScalar p[], int m, int i0, int iret[]);
void cullPoints2 (int n, btScalar p[], int m, int i0, int iret[])
{
// compute the centroid of the polygon in cx,cy
int i,j;
btScalar a,cx,cy,q;
if (n==1) {
cx = p[0];
cy = p[1];
}
else if (n==2) {
cx = btScalar(0.5)*(p[0] + p[2]);
cy = btScalar(0.5)*(p[1] + p[3]);
}
else {
a = 0;
cx = 0;
cy = 0;
for (i=0; i<(n-1); i++) {
q = p[i*2]*p[i*2+3] - p[i*2+2]*p[i*2+1];
a += q;
cx += q*(p[i*2]+p[i*2+2]);
cy += q*(p[i*2+1]+p[i*2+3]);
}
q = p[n*2-2]*p[1] - p[0]*p[n*2-1];
a = 1.f/(btScalar(3.0)*(a+q));
cx = a*(cx + q*(p[n*2-2]+p[0]));
cy = a*(cy + q*(p[n*2-1]+p[1]));
}
// compute the angle of each point w.r.t. the centroid
btScalar A[8];
for (i=0; i<n; i++) A[i] = btAtan2(p[i*2+1]-cy,p[i*2]-cx);
// search for points that have angles closest to A[i0] + i*(2*pi/m).
int avail[8];
for (i=0; i<n; i++) avail[i] = 1;
avail[i0] = 0;
iret[0] = i0;
iret++;
for (j=1; j<m; j++) {
a = btScalar(j)*(2*M__PI/m) + A[i0];
if (a > M__PI) a -= 2*M__PI;
btScalar maxdiff=1e9,diff;
#if defined(DEBUG) || defined (_DEBUG)
*iret = i0; // iret is not allowed to keep this value
#endif
for (i=0; i<n; i++) {
if (avail[i]) {
diff = btFabs (A[i]-a);
if (diff > M__PI) diff = 2*M__PI - diff;
if (diff < maxdiff) {
maxdiff = diff;
*iret = i;
}
}
}
#if defined(DEBUG) || defined (_DEBUG)
btAssert (*iret != i0); // ensure iret got set
#endif
avail[*iret] = 0;
iret++;
}
}
int dBoxBox2 (const btVector3& p1, const dMatrix3 R1,
const btVector3& side1, const btVector3& p2,
const dMatrix3 R2, const btVector3& side2,
btVector3& normal, btScalar *depth, int *return_code,
int maxc, dContactGeom * /*contact*/, int /*skip*/,btDiscreteCollisionDetectorInterface::Result& output);
int dBoxBox2 (const btVector3& p1, const dMatrix3 R1,
const btVector3& side1, const btVector3& p2,
const dMatrix3 R2, const btVector3& side2,
btVector3& normal, btScalar *depth, int *return_code,
int maxc, dContactGeom * /*contact*/, int /*skip*/,btDiscreteCollisionDetectorInterface::Result& output)
{
const btScalar fudge_factor = btScalar(1.05);
btVector3 p,pp,normalC;
const btScalar *normalR = 0;
btScalar A[3],B[3],R11,R12,R13,R21,R22,R23,R31,R32,R33,
Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33,s,s2,l;
int i,j,invert_normal,code;
// get vector from centers of box 1 to box 2, relative to box 1
p = p2 - p1;
dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1
// get side lengths / 2
A[0] = side1[0]*btScalar(0.5);
A[1] = side1[1]*btScalar(0.5);
A[2] = side1[2]*btScalar(0.5);
B[0] = side2[0]*btScalar(0.5);
B[1] = side2[1]*btScalar(0.5);
B[2] = side2[2]*btScalar(0.5);
// Rij is R1'*R2, i.e. the relative rotation between R1 and R2
R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2);
R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2);
R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2);
Q11 = btFabs(R11); Q12 = btFabs(R12); Q13 = btFabs(R13);
Q21 = btFabs(R21); Q22 = btFabs(R22); Q23 = btFabs(R23);
Q31 = btFabs(R31); Q32 = btFabs(R32); Q33 = btFabs(R33);
// for all 15 possible separating axes:
// * see if the axis separates the boxes. if so, return 0.
// * find the depth of the penetration along the separating axis (s2)
// * if this is the largest depth so far, record it.
// the normal vector will be set to the separating axis with the smallest
// depth. note: normalR is set to point to a column of R1 or R2 if that is
// the smallest depth normal so far. otherwise normalR is 0 and normalC is
// set to a vector relative to body 1. invert_normal is 1 if the sign of
// the normal should be flipped.
#define TST(expr1,expr2,norm,cc) \
s2 = btFabs(expr1) - (expr2); \
if (s2 > 0) return 0; \
if (s2 > s) { \
s = s2; \
normalR = norm; \
invert_normal = ((expr1) < 0); \
code = (cc); \
}
s = -dInfinity;
invert_normal = 0;
code = 0;
// separating axis = u1,u2,u3
TST (pp[0],(A[0] + B[0]*Q11 + B[1]*Q12 + B[2]*Q13),R1+0,1);
TST (pp[1],(A[1] + B[0]*Q21 + B[1]*Q22 + B[2]*Q23),R1+1,2);
TST (pp[2],(A[2] + B[0]*Q31 + B[1]*Q32 + B[2]*Q33),R1+2,3);
// separating axis = v1,v2,v3
TST (dDOT41(R2+0,p),(A[0]*Q11 + A[1]*Q21 + A[2]*Q31 + B[0]),R2+0,4);
TST (dDOT41(R2+1,p),(A[0]*Q12 + A[1]*Q22 + A[2]*Q32 + B[1]),R2+1,5);
TST (dDOT41(R2+2,p),(A[0]*Q13 + A[1]*Q23 + A[2]*Q33 + B[2]),R2+2,6);
// note: cross product axes need to be scaled when s is computed.
// normal (n1,n2,n3) is relative to box 1.
#undef TST
#define TST(expr1,expr2,n1,n2,n3,cc) \
s2 = btFabs(expr1) - (expr2); \
if (s2 > 0) return 0; \
l = btSqrt((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \
if (l > 0) { \
s2 /= l; \
if (s2*fudge_factor > s) { \
s = s2; \
normalR = 0; \
normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \
invert_normal = ((expr1) < 0); \
code = (cc); \
} \
}
// separating axis = u1 x (v1,v2,v3)
TST(pp[2]*R21-pp[1]*R31,(A[1]*Q31+A[2]*Q21+B[1]*Q13+B[2]*Q12),0,-R31,R21,7);
TST(pp[2]*R22-pp[1]*R32,(A[1]*Q32+A[2]*Q22+B[0]*Q13+B[2]*Q11),0,-R32,R22,8);
TST(pp[2]*R23-pp[1]*R33,(A[1]*Q33+A[2]*Q23+B[0]*Q12+B[1]*Q11),0,-R33,R23,9);
// separating axis = u2 x (v1,v2,v3)
TST(pp[0]*R31-pp[2]*R11,(A[0]*Q31+A[2]*Q11+B[1]*Q23+B[2]*Q22),R31,0,-R11,10);
TST(pp[0]*R32-pp[2]*R12,(A[0]*Q32+A[2]*Q12+B[0]*Q23+B[2]*Q21),R32,0,-R12,11);
TST(pp[0]*R33-pp[2]*R13,(A[0]*Q33+A[2]*Q13+B[0]*Q22+B[1]*Q21),R33,0,-R13,12);
// separating axis = u3 x (v1,v2,v3)
TST(pp[1]*R11-pp[0]*R21,(A[0]*Q21+A[1]*Q11+B[1]*Q33+B[2]*Q32),-R21,R11,0,13);
TST(pp[1]*R12-pp[0]*R22,(A[0]*Q22+A[1]*Q12+B[0]*Q33+B[2]*Q31),-R22,R12,0,14);
TST(pp[1]*R13-pp[0]*R23,(A[0]*Q23+A[1]*Q13+B[0]*Q32+B[1]*Q31),-R23,R13,0,15);
#undef TST
if (!code) return 0;
// if we get to this point, the boxes interpenetrate. compute the normal
// in global coordinates.
if (normalR) {
normal[0] = normalR[0];
normal[1] = normalR[4];
normal[2] = normalR[8];
}
else {
dMULTIPLY0_331 (normal,R1,normalC);
}
if (invert_normal) {
normal[0] = -normal[0];
normal[1] = -normal[1];
normal[2] = -normal[2];
}
*depth = -s;
// compute contact point(s)
if (code > 6) {
// an edge from box 1 touches an edge from box 2.
// find a point pa on the intersecting edge of box 1
btVector3 pa;
btScalar sign;
for (i=0; i<3; i++) pa[i] = p1[i];
for (j=0; j<3; j++) {
sign = (dDOT14(normal,R1+j) > 0) ? btScalar(1.0) : btScalar(-1.0);
for (i=0; i<3; i++) pa[i] += sign * A[j] * R1[i*4+j];
}
// find a point pb on the intersecting edge of box 2
btVector3 pb;
for (i=0; i<3; i++) pb[i] = p2[i];
for (j=0; j<3; j++) {
sign = (dDOT14(normal,R2+j) > 0) ? btScalar(-1.0) : btScalar(1.0);
for (i=0; i<3; i++) pb[i] += sign * B[j] * R2[i*4+j];
}
btScalar alpha,beta;
btVector3 ua,ub;
for (i=0; i<3; i++) ua[i] = R1[((code)-7)/3 + i*4];
for (i=0; i<3; i++) ub[i] = R2[((code)-7)%3 + i*4];
dLineClosestApproach (pa,ua,pb,ub,&alpha,&beta);
for (i=0; i<3; i++) pa[i] += ua[i]*alpha;
for (i=0; i<3; i++) pb[i] += ub[i]*beta;
{
//contact[0].pos[i] = btScalar(0.5)*(pa[i]+pb[i]);
//contact[0].depth = *depth;
btVector3 pointInWorld;
#ifdef USE_CENTER_POINT
for (i=0; i<3; i++)
pointInWorld[i] = (pa[i]+pb[i])*btScalar(0.5);
output.addContactPoint(-normal,pointInWorld,-*depth);
#else
output.addContactPoint(-normal,pb,-*depth);
#endif //
*return_code = code;
}
return 1;
}
// okay, we have a face-something intersection (because the separating
// axis is perpendicular to a face). define face 'a' to be the reference
// face (i.e. the normal vector is perpendicular to this) and face 'b' to be
// the incident face (the closest face of the other box).
const btScalar *Ra,*Rb,*pa,*pb,*Sa,*Sb;
if (code <= 3) {
Ra = R1;
Rb = R2;
pa = p1;
pb = p2;
Sa = A;
Sb = B;
}
else {
Ra = R2;
Rb = R1;
pa = p2;
pb = p1;
Sa = B;
Sb = A;
}
// nr = normal vector of reference face dotted with axes of incident box.
// anr = absolute values of nr.
btVector3 normal2,nr,anr;
if (code <= 3) {
normal2[0] = normal[0];
normal2[1] = normal[1];
normal2[2] = normal[2];
}
else {
normal2[0] = -normal[0];
normal2[1] = -normal[1];
normal2[2] = -normal[2];
}
dMULTIPLY1_331 (nr,Rb,normal2);
anr[0] = btFabs (nr[0]);
anr[1] = btFabs (nr[1]);
anr[2] = btFabs (nr[2]);
// find the largest compontent of anr: this corresponds to the normal
// for the indident face. the other axis numbers of the indicent face
// are stored in a1,a2.
int lanr,a1,a2;
if (anr[1] > anr[0]) {
if (anr[1] > anr[2]) {
a1 = 0;
lanr = 1;
a2 = 2;
}
else {
a1 = 0;
a2 = 1;
lanr = 2;
}
}
else {
if (anr[0] > anr[2]) {
lanr = 0;
a1 = 1;
a2 = 2;
}
else {
a1 = 0;
a2 = 1;
lanr = 2;
}
}
// compute center point of incident face, in reference-face coordinates
btVector3 center;
if (nr[lanr] < 0) {
for (i=0; i<3; i++) center[i] = pb[i] - pa[i] + Sb[lanr] * Rb[i*4+lanr];
}
else {
for (i=0; i<3; i++) center[i] = pb[i] - pa[i] - Sb[lanr] * Rb[i*4+lanr];
}
// find the normal and non-normal axis numbers of the reference box
int codeN,code1,code2;
if (code <= 3) codeN = code-1; else codeN = code-4;
if (codeN==0) {
code1 = 1;
code2 = 2;
}
else if (codeN==1) {
code1 = 0;
code2 = 2;
}
else {
code1 = 0;
code2 = 1;
}
// find the four corners of the incident face, in reference-face coordinates
btScalar quad[8]; // 2D coordinate of incident face (x,y pairs)
btScalar c1,c2,m11,m12,m21,m22;
c1 = dDOT14 (center,Ra+code1);
c2 = dDOT14 (center,Ra+code2);
// optimize this? - we have already computed this data above, but it is not
// stored in an easy-to-index format. for now it's quicker just to recompute
// the four dot products.
m11 = dDOT44 (Ra+code1,Rb+a1);
m12 = dDOT44 (Ra+code1,Rb+a2);
m21 = dDOT44 (Ra+code2,Rb+a1);
m22 = dDOT44 (Ra+code2,Rb+a2);
{
btScalar k1 = m11*Sb[a1];
btScalar k2 = m21*Sb[a1];
btScalar k3 = m12*Sb[a2];
btScalar k4 = m22*Sb[a2];
quad[0] = c1 - k1 - k3;
quad[1] = c2 - k2 - k4;
quad[2] = c1 - k1 + k3;
quad[3] = c2 - k2 + k4;
quad[4] = c1 + k1 + k3;
quad[5] = c2 + k2 + k4;
quad[6] = c1 + k1 - k3;
quad[7] = c2 + k2 - k4;
}
// find the size of the reference face
btScalar rect[2];
rect[0] = Sa[code1];
rect[1] = Sa[code2];
// intersect the incident and reference faces
btScalar ret[16];
int n = intersectRectQuad2 (rect,quad,ret);
if (n < 1) return 0; // this should never happen
// convert the intersection points into reference-face coordinates,
// and compute the contact position and depth for each point. only keep
// those points that have a positive (penetrating) depth. delete points in
// the 'ret' array as necessary so that 'point' and 'ret' correspond.
btScalar point[3*8]; // penetrating contact points
btScalar dep[8]; // depths for those points
btScalar det1 = 1.f/(m11*m22 - m12*m21);
m11 *= det1;
m12 *= det1;
m21 *= det1;
m22 *= det1;
int cnum = 0; // number of penetrating contact points found
for (j=0; j < n; j++) {
btScalar k1 = m22*(ret[j*2]-c1) - m12*(ret[j*2+1]-c2);
btScalar k2 = -m21*(ret[j*2]-c1) + m11*(ret[j*2+1]-c2);
for (i=0; i<3; i++) point[cnum*3+i] =
center[i] + k1*Rb[i*4+a1] + k2*Rb[i*4+a2];
dep[cnum] = Sa[codeN] - dDOT(normal2,point+cnum*3);
if (dep[cnum] >= 0) {
ret[cnum*2] = ret[j*2];
ret[cnum*2+1] = ret[j*2+1];
cnum++;
}
}
if (cnum < 1) return 0; // this should never happen
// we can't generate more contacts than we actually have
if (maxc > cnum) maxc = cnum;
if (maxc < 1) maxc = 1;
if (cnum <= maxc) {
// we have less contacts than we need, so we use them all
for (j=0; j < cnum; j++) {
//AddContactPoint...
//dContactGeom *con = CONTACT(contact,skip*j);
//for (i=0; i<3; i++) con->pos[i] = point[j*3+i] + pa[i];
//con->depth = dep[j];
btVector3 pointInWorld;
for (i=0; i<3; i++)
pointInWorld[i] = point[j*3+i] + pa[i];
output.addContactPoint(-normal,pointInWorld,-dep[j]);
}
}
else {
// we have more contacts than are wanted, some of them must be culled.
// find the deepest point, it is always the first contact.
int i1 = 0;
btScalar maxdepth = dep[0];
for (i=1; i<cnum; i++) {
if (dep[i] > maxdepth) {
maxdepth = dep[i];
i1 = i;
}
}
int iret[8];
cullPoints2 (cnum,ret,maxc,i1,iret);
for (j=0; j < maxc; j++) {
// dContactGeom *con = CONTACT(contact,skip*j);
// for (i=0; i<3; i++) con->pos[i] = point[iret[j]*3+i] + pa[i];
// con->depth = dep[iret[j]];
btVector3 posInWorld;
for (i=0; i<3; i++)
posInWorld[i] = point[iret[j]*3+i] + pa[i];
output.addContactPoint(-normal,posInWorld,-dep[iret[j]]);
}
cnum = maxc;
}
*return_code = code;
return cnum;
}
void btBoxBoxDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* /*debugDraw*/,bool /*swapResults*/)
{
const btTransform& transformA = input.m_transformA;
const btTransform& transformB = input.m_transformB;
int skip = 0;
dContactGeom *contact = 0;
dMatrix3 R1;
dMatrix3 R2;
for (int j=0;j<3;j++)
{
R1[0+4*j] = transformA.getBasis()[j].x();
R2[0+4*j] = transformB.getBasis()[j].x();
R1[1+4*j] = transformA.getBasis()[j].y();
R2[1+4*j] = transformB.getBasis()[j].y();
R1[2+4*j] = transformA.getBasis()[j].z();
R2[2+4*j] = transformB.getBasis()[j].z();
}
btVector3 normal;
btScalar depth;
int return_code;
int maxc = 4;
dBoxBox2 (transformA.getOrigin(),
R1,
2.f*m_box1->getHalfExtentsWithMargin(),
transformB.getOrigin(),
R2,
2.f*m_box2->getHalfExtentsWithMargin(),
normal, &depth, &return_code,
maxc, contact, skip,
output
);
}

@ -0,0 +1,44 @@
/*
* Box-Box collision detection re-distributed under the ZLib license with permission from Russell L. Smith
* Original version is from Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.
* All rights reserved. Email: russ@q12.org Web: www.q12.org
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BOX_BOX_DETECTOR_H
#define BOX_BOX_DETECTOR_H
class btBoxShape;
#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h"
/// btBoxBoxDetector wraps the ODE box-box collision detector
/// re-distributed under the Zlib license with permission from Russell L. Smith
struct btBoxBoxDetector : public btDiscreteCollisionDetectorInterface
{
btBoxShape* m_box1;
btBoxShape* m_box2;
public:
btBoxBoxDetector(btBoxShape* box1,btBoxShape* box2);
virtual ~btBoxBoxDetector() {};
virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults=false);
};
#endif //BT_BOX_BOX_DETECTOR_H

@ -0,0 +1,47 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_COLLISION_CONFIGURATION
#define BT_COLLISION_CONFIGURATION
struct btCollisionAlgorithmCreateFunc;
class btStackAlloc;
class btPoolAllocator;
///btCollisionConfiguration allows to configure Bullet collision detection
///stack allocator size, default collision algorithms and persistent manifold pool size
///todo: describe the meaning
class btCollisionConfiguration
{
public:
virtual ~btCollisionConfiguration()
{
}
///memory pools
virtual btPoolAllocator* getPersistentManifoldPool() = 0;
virtual btPoolAllocator* getCollisionAlgorithmPool() = 0;
virtual btStackAlloc* getStackAllocator() = 0;
virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) =0;
};
#endif //BT_COLLISION_CONFIGURATION

@ -0,0 +1,108 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btConvexPlaneCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/CollisionShapes/btConvexShape.h"
#include "BulletCollision/CollisionShapes/btStaticPlaneShape.h"
//#include <stdio.h>
btConvexPlaneCollisionAlgorithm::btConvexPlaneCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped)
: btCollisionAlgorithm(ci),
m_ownManifold(false),
m_manifoldPtr(mf),
m_isSwapped(isSwapped)
{
btCollisionObject* convexObj = m_isSwapped? col1 : col0;
btCollisionObject* planeObj = m_isSwapped? col0 : col1;
if (!m_manifoldPtr && m_dispatcher->needsCollision(convexObj,planeObj))
{
m_manifoldPtr = m_dispatcher->getNewManifold(convexObj,planeObj);
m_ownManifold = true;
}
}
btConvexPlaneCollisionAlgorithm::~btConvexPlaneCollisionAlgorithm()
{
if (m_ownManifold)
{
if (m_manifoldPtr)
m_dispatcher->releaseManifold(m_manifoldPtr);
}
}
void btConvexPlaneCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
{
(void)dispatchInfo;
(void)resultOut;
if (!m_manifoldPtr)
return;
btCollisionObject* convexObj = m_isSwapped? body1 : body0;
btCollisionObject* planeObj = m_isSwapped? body0: body1;
btConvexShape* convexShape = (btConvexShape*) convexObj->getCollisionShape();
btStaticPlaneShape* planeShape = (btStaticPlaneShape*) planeObj->getCollisionShape();
bool hasCollision = false;
const btVector3& planeNormal = planeShape->getPlaneNormal();
const btScalar& planeConstant = planeShape->getPlaneConstant();
btTransform planeInConvex;
planeInConvex= convexObj->getWorldTransform().inverse() * planeObj->getWorldTransform();
btTransform convexInPlaneTrans;
convexInPlaneTrans= planeObj->getWorldTransform().inverse() * convexObj->getWorldTransform();
btVector3 vtx = convexShape->localGetSupportingVertex(planeInConvex.getBasis()*-planeNormal);
btVector3 vtxInPlane = convexInPlaneTrans(vtx);
btScalar distance = (planeNormal.dot(vtxInPlane) - planeConstant);
btVector3 vtxInPlaneProjected = vtxInPlane - distance*planeNormal;
btVector3 vtxInPlaneWorld = planeObj->getWorldTransform() * vtxInPlaneProjected;
hasCollision = distance < m_manifoldPtr->getContactBreakingThreshold();
resultOut->setPersistentManifold(m_manifoldPtr);
if (hasCollision)
{
/// report a contact. internally this will be kept persistent, and contact reduction is done
btVector3 normalOnSurfaceB = planeObj->getWorldTransform().getBasis() * planeNormal;
btVector3 pOnB = vtxInPlaneWorld;
resultOut->addContactPoint(normalOnSurfaceB,pOnB,distance);
}
if (m_ownManifold)
{
if (m_manifoldPtr->getNumContacts())
{
resultOut->refreshContactPoints();
}
}
}
btScalar btConvexPlaneCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
{
(void)resultOut;
(void)dispatchInfo;
(void)col0;
(void)col1;
//not yet
return btScalar(1.);
}

@ -0,0 +1,71 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef CONVEX_PLANE_COLLISION_ALGORITHM_H
#define CONVEX_PLANE_COLLISION_ALGORITHM_H
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h"
class btPersistentManifold;
#include "btCollisionDispatcher.h"
#include "LinearMath/btVector3.h"
/// btSphereBoxCollisionAlgorithm provides sphere-box collision detection.
/// Other features are frame-coherency (persistent data) and collision response.
class btConvexPlaneCollisionAlgorithm : public btCollisionAlgorithm
{
bool m_ownManifold;
btPersistentManifold* m_manifoldPtr;
bool m_isSwapped;
public:
btConvexPlaneCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped);
virtual ~btConvexPlaneCollisionAlgorithm();
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual void getAllContactManifolds(btManifoldArray& manifoldArray)
{
if (m_manifoldPtr && m_ownManifold)
{
manifoldArray.push_back(m_manifoldPtr);
}
}
struct CreateFunc :public btCollisionAlgorithmCreateFunc
{
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexPlaneCollisionAlgorithm));
if (!m_swapped)
{
return new(mem) btConvexPlaneCollisionAlgorithm(0,ci,body0,body1,false);
} else
{
return new(mem) btConvexPlaneCollisionAlgorithm(0,ci,body0,body1,true);
}
}
};
};
#endif //CONVEX_PLANE_COLLISION_ALGORITHM_H

@ -0,0 +1,291 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btDefaultCollisionConfiguration.h"
#include "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h"
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM
#include "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h"
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM
#include "BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h"
#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
#include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h"
#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h"
#include "LinearMath/btStackAlloc.h"
#include "LinearMath/btPoolAllocator.h"
btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo)
//btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(btStackAlloc* stackAlloc,btPoolAllocator* persistentManifoldPool,btPoolAllocator* collisionAlgorithmPool)
{
void* mem = btAlignedAlloc(sizeof(btVoronoiSimplexSolver),16);
m_simplexSolver = new (mem)btVoronoiSimplexSolver();
#define USE_EPA 1
#ifdef USE_EPA
mem = btAlignedAlloc(sizeof(btGjkEpaPenetrationDepthSolver),16);
m_pdSolver = new (mem)btGjkEpaPenetrationDepthSolver;
#else
mem = btAlignedAlloc(sizeof(btMinkowskiPenetrationDepthSolver),16);
m_pdSolver = new (mem)btMinkowskiPenetrationDepthSolver;
#endif//USE_EPA
//default CreationFunctions, filling the m_doubleDispatch table
mem = btAlignedAlloc(sizeof(btConvexConvexAlgorithm::CreateFunc),16);
m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_simplexSolver,m_pdSolver);
mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16);
m_convexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16);
m_swappedConvexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::SwappedCreateFunc;
mem = btAlignedAlloc(sizeof(btCompoundCollisionAlgorithm::CreateFunc),16);
m_compoundCreateFunc = new (mem)btCompoundCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btCompoundCollisionAlgorithm::SwappedCreateFunc),16);
m_swappedCompoundCreateFunc = new (mem)btCompoundCollisionAlgorithm::SwappedCreateFunc;
mem = btAlignedAlloc(sizeof(btEmptyAlgorithm::CreateFunc),16);
m_emptyCreateFunc = new(mem) btEmptyAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btSphereSphereCollisionAlgorithm::CreateFunc),16);
m_sphereSphereCF = new(mem) btSphereSphereCollisionAlgorithm::CreateFunc;
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM
mem = btAlignedAlloc(sizeof(btSphereBoxCollisionAlgorithm::CreateFunc),16);
m_sphereBoxCF = new(mem) btSphereBoxCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btSphereBoxCollisionAlgorithm::CreateFunc),16);
m_boxSphereCF = new (mem)btSphereBoxCollisionAlgorithm::CreateFunc;
m_boxSphereCF->m_swapped = true;
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM
mem = btAlignedAlloc(sizeof(btSphereTriangleCollisionAlgorithm::CreateFunc),16);
m_sphereTriangleCF = new (mem)btSphereTriangleCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btSphereTriangleCollisionAlgorithm::CreateFunc),16);
m_triangleSphereCF = new (mem)btSphereTriangleCollisionAlgorithm::CreateFunc;
m_triangleSphereCF->m_swapped = true;
mem = btAlignedAlloc(sizeof(btBoxBoxCollisionAlgorithm::CreateFunc),16);
m_boxBoxCF = new(mem)btBoxBoxCollisionAlgorithm::CreateFunc;
//convex versus plane
mem = btAlignedAlloc (sizeof(btConvexPlaneCollisionAlgorithm::CreateFunc),16);
m_convexPlaneCF = new (mem) btConvexPlaneCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc (sizeof(btConvexPlaneCollisionAlgorithm::CreateFunc),16);
m_planeConvexCF = new (mem) btConvexPlaneCollisionAlgorithm::CreateFunc;
m_planeConvexCF->m_swapped = true;
///calculate maximum element size, big enough to fit any collision algorithm in the memory pool
int maxSize = sizeof(btConvexConvexAlgorithm);
int maxSize2 = sizeof(btConvexConcaveCollisionAlgorithm);
int maxSize3 = sizeof(btCompoundCollisionAlgorithm);
int maxSize4 = sizeof(btEmptyAlgorithm);
int collisionAlgorithmMaxElementSize = btMax(maxSize,maxSize2);
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize3);
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize4);
if (constructionInfo.m_stackAlloc)
{
m_ownsStackAllocator = false;
this->m_stackAlloc = constructionInfo.m_stackAlloc;
} else
{
m_ownsStackAllocator = true;
void* mem = btAlignedAlloc(sizeof(btStackAlloc),16);
m_stackAlloc = new(mem)btStackAlloc(constructionInfo.m_defaultStackAllocatorSize);
}
if (constructionInfo.m_persistentManifoldPool)
{
m_ownsPersistentManifoldPool = false;
m_persistentManifoldPool = constructionInfo.m_persistentManifoldPool;
} else
{
m_ownsPersistentManifoldPool = true;
void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16);
m_persistentManifoldPool = new (mem) btPoolAllocator(sizeof(btPersistentManifold),constructionInfo.m_defaultMaxPersistentManifoldPoolSize);
}
if (constructionInfo.m_collisionAlgorithmPool)
{
m_ownsCollisionAlgorithmPool = false;
m_collisionAlgorithmPool = constructionInfo.m_collisionAlgorithmPool;
} else
{
m_ownsCollisionAlgorithmPool = true;
void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16);
m_collisionAlgorithmPool = new(mem) btPoolAllocator(collisionAlgorithmMaxElementSize,constructionInfo.m_defaultMaxCollisionAlgorithmPoolSize);
}
}
btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration()
{
if (m_ownsStackAllocator)
{
m_stackAlloc->destroy();
m_stackAlloc->~btStackAlloc();
btAlignedFree(m_stackAlloc);
}
if (m_ownsCollisionAlgorithmPool)
{
m_collisionAlgorithmPool->~btPoolAllocator();
btAlignedFree(m_collisionAlgorithmPool);
}
if (m_ownsPersistentManifoldPool)
{
m_persistentManifoldPool->~btPoolAllocator();
btAlignedFree(m_persistentManifoldPool);
}
m_convexConvexCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_convexConvexCreateFunc);
m_convexConcaveCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_convexConcaveCreateFunc);
m_swappedConvexConcaveCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_swappedConvexConcaveCreateFunc);
m_compoundCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_compoundCreateFunc);
m_swappedCompoundCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_swappedCompoundCreateFunc);
m_emptyCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_emptyCreateFunc);
m_sphereSphereCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_sphereSphereCF);
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM
m_sphereBoxCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_sphereBoxCF);
m_boxSphereCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_boxSphereCF);
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM
m_sphereTriangleCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_sphereTriangleCF);
m_triangleSphereCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_triangleSphereCF);
m_boxBoxCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_boxBoxCF);
m_convexPlaneCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_convexPlaneCF);
m_planeConvexCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_planeConvexCF);
m_simplexSolver->~btVoronoiSimplexSolver();
btAlignedFree(m_simplexSolver);
m_pdSolver->~btConvexPenetrationDepthSolver();
btAlignedFree(m_pdSolver);
}
btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1)
{
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1==SPHERE_SHAPE_PROXYTYPE))
{
return m_sphereSphereCF;
}
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1==BOX_SHAPE_PROXYTYPE))
{
return m_sphereBoxCF;
}
if ((proxyType0 == BOX_SHAPE_PROXYTYPE ) && (proxyType1==SPHERE_SHAPE_PROXYTYPE))
{
return m_boxSphereCF;
}
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE ) && (proxyType1==TRIANGLE_SHAPE_PROXYTYPE))
{
return m_sphereTriangleCF;
}
if ((proxyType0 == TRIANGLE_SHAPE_PROXYTYPE ) && (proxyType1==SPHERE_SHAPE_PROXYTYPE))
{
return m_triangleSphereCF;
}
if ((proxyType0 == BOX_SHAPE_PROXYTYPE) && (proxyType1 == BOX_SHAPE_PROXYTYPE))
{
return m_boxBoxCF;
}
if (btBroadphaseProxy::isConvex(proxyType0) && (proxyType1 == STATIC_PLANE_PROXYTYPE))
{
return m_convexPlaneCF;
}
if (btBroadphaseProxy::isConvex(proxyType1) && (proxyType0 == STATIC_PLANE_PROXYTYPE))
{
return m_planeConvexCF;
}
if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConvex(proxyType1))
{
return m_convexConvexCreateFunc;
}
if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConcave(proxyType1))
{
return m_convexConcaveCreateFunc;
}
if (btBroadphaseProxy::isConvex(proxyType1) && btBroadphaseProxy::isConcave(proxyType0))
{
return m_swappedConvexConcaveCreateFunc;
}
if (btBroadphaseProxy::isCompound(proxyType0))
{
return m_compoundCreateFunc;
} else
{
if (btBroadphaseProxy::isCompound(proxyType1))
{
return m_swappedCompoundCreateFunc;
}
}
//failed to find an algorithm
return m_emptyCreateFunc;
}

@ -0,0 +1,118 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_DEFAULT_COLLISION_CONFIGURATION
#define BT_DEFAULT_COLLISION_CONFIGURATION
#include "btCollisionConfiguration.h"
class btVoronoiSimplexSolver;
class btConvexPenetrationDepthSolver;
struct btDefaultCollisionConstructionInfo
{
btStackAlloc* m_stackAlloc;
btPoolAllocator* m_persistentManifoldPool;
btPoolAllocator* m_collisionAlgorithmPool;
int m_defaultMaxPersistentManifoldPoolSize;
int m_defaultMaxCollisionAlgorithmPoolSize;
int m_defaultStackAllocatorSize;
btDefaultCollisionConstructionInfo()
:m_stackAlloc(0),
m_persistentManifoldPool(0),
m_collisionAlgorithmPool(0),
m_defaultMaxPersistentManifoldPoolSize(65535),
m_defaultMaxCollisionAlgorithmPoolSize(65535),
m_defaultStackAllocatorSize(5*1024*1024)
{
}
};
///btCollisionConfiguration allows to configure Bullet collision detection
///stack allocator, pool memory allocators
///todo: describe the meaning
class btDefaultCollisionConfiguration : public btCollisionConfiguration
{
protected:
int m_persistentManifoldPoolSize;
btStackAlloc* m_stackAlloc;
bool m_ownsStackAllocator;
btPoolAllocator* m_persistentManifoldPool;
bool m_ownsPersistentManifoldPool;
btPoolAllocator* m_collisionAlgorithmPool;
bool m_ownsCollisionAlgorithmPool;
//default simplex/penetration depth solvers
btVoronoiSimplexSolver* m_simplexSolver;
btConvexPenetrationDepthSolver* m_pdSolver;
//default CreationFunctions, filling the m_doubleDispatch table
btCollisionAlgorithmCreateFunc* m_convexConvexCreateFunc;
btCollisionAlgorithmCreateFunc* m_convexConcaveCreateFunc;
btCollisionAlgorithmCreateFunc* m_swappedConvexConcaveCreateFunc;
btCollisionAlgorithmCreateFunc* m_compoundCreateFunc;
btCollisionAlgorithmCreateFunc* m_swappedCompoundCreateFunc;
btCollisionAlgorithmCreateFunc* m_emptyCreateFunc;
btCollisionAlgorithmCreateFunc* m_sphereSphereCF;
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM
btCollisionAlgorithmCreateFunc* m_sphereBoxCF;
btCollisionAlgorithmCreateFunc* m_boxSphereCF;
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM
btCollisionAlgorithmCreateFunc* m_boxBoxCF;
btCollisionAlgorithmCreateFunc* m_sphereTriangleCF;
btCollisionAlgorithmCreateFunc* m_triangleSphereCF;
btCollisionAlgorithmCreateFunc* m_planeConvexCF;
btCollisionAlgorithmCreateFunc* m_convexPlaneCF;
public:
btDefaultCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo = btDefaultCollisionConstructionInfo());
virtual ~btDefaultCollisionConfiguration();
///memory pools
virtual btPoolAllocator* getPersistentManifoldPool()
{
return m_persistentManifoldPool;
}
virtual btPoolAllocator* getCollisionAlgorithmPool()
{
return m_collisionAlgorithmPool;
}
virtual btStackAlloc* getStackAllocator()
{
return m_stackAlloc;
}
virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1);
};
#endif //BT_DEFAULT_COLLISION_CONFIGURATION

@ -0,0 +1,78 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btConvexInternalShape.h"
btConvexInternalShape::btConvexInternalShape()
: m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)),
m_collisionMargin(CONVEX_DISTANCE_MARGIN)
{
}
void btConvexInternalShape::setLocalScaling(const btVector3& scaling)
{
m_localScaling = scaling.absolute();
}
void btConvexInternalShape::getAabbSlow(const btTransform& trans,btVector3&minAabb,btVector3&maxAabb) const
{
btScalar margin = getMargin();
for (int i=0;i<3;i++)
{
btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.));
vec[i] = btScalar(1.);
btVector3 sv = localGetSupportingVertex(vec*trans.getBasis());
btVector3 tmp = trans(sv);
maxAabb[i] = tmp[i]+margin;
vec[i] = btScalar(-1.);
tmp = trans(localGetSupportingVertex(vec*trans.getBasis()));
minAabb[i] = tmp[i]-margin;
}
};
btVector3 btConvexInternalShape::localGetSupportingVertex(const btVector3& vec)const
{
#ifndef __SPU__
btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec);
if ( getMargin()!=btScalar(0.) )
{
btVector3 vecnorm = vec;
if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON))
{
vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.));
}
vecnorm.normalize();
supVertex+= getMargin() * vecnorm;
}
return supVertex;
#else
return btVector3(0,0,0);
#endif //__SPU__
}

@ -0,0 +1,98 @@
#ifndef BT_CONVEX_INTERNAL_SHAPE_H
#define BT_CONVEX_INTERNAL_SHAPE_H
#include "btConvexShape.h"
///The btConvexInternalShape is an internal base class, shared by most convex shape implementations.
class btConvexInternalShape : public btConvexShape
{
protected:
//local scaling. collisionMargin is not scaled !
btVector3 m_localScaling;
btVector3 m_implicitShapeDimensions;
btScalar m_collisionMargin;
btScalar m_padding;
public:
btConvexInternalShape();
virtual ~btConvexInternalShape()
{
}
virtual btVector3 localGetSupportingVertex(const btVector3& vec)const;
#ifndef __SPU__
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec) const= 0;
//notice that the vectors should be unit length
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const= 0;
#endif //#ifndef __SPU__
const btVector3& getImplicitShapeDimensions() const
{
return m_implicitShapeDimensions;
}
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version
void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
{
getAabbSlow(t,aabbMin,aabbMax);
}
virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const;
virtual void setLocalScaling(const btVector3& scaling);
virtual const btVector3& getLocalScaling() const
{
return m_localScaling;
}
const btVector3& getLocalScalingNV() const
{
return m_localScaling;
}
virtual void setMargin(btScalar margin)
{
m_collisionMargin = margin;
}
virtual btScalar getMargin() const
{
return m_collisionMargin;
}
btScalar getMarginNV() const
{
return m_collisionMargin;
}
virtual int getNumPreferredPenetrationDirections() const
{
return 0;
}
virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const
{
(void)penetrationVector;
(void)index;
btAssert(0);
}
};
#endif //BT_CONVEX_INTERNAL_SHAPE_H

@ -0,0 +1,34 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/// This file was created by Alex Silverman
#ifndef MATERIAL_H
#define MATERIAL_H
// Material class to be used by btMultimaterialTriangleMeshShape to store triangle properties
class btMaterial
{
// public members so that materials can change due to world events
public:
btScalar m_friction;
btScalar m_restitution;
int pad[2];
btMaterial(){}
btMaterial(btScalar fric, btScalar rest) { m_friction = fric; m_restitution = rest; }
};
#endif // MATERIAL_H

@ -0,0 +1,45 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/// This file was created by Alex Silverman
#include "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h"
#include "BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h"
//#include "BulletCollision/CollisionShapes/btOptimizedBvh.h"
///Obtains the material for a specific triangle
const btMaterial * btMultimaterialTriangleMeshShape::getMaterialProperties(int partID, int triIndex)
{
const unsigned char * materialBase = 0;
int numMaterials;
PHY_ScalarType materialType;
int materialStride;
const unsigned char * triangleMaterialBase = 0;
int numTriangles;
int triangleMaterialStride;
PHY_ScalarType triangleType;
((btTriangleIndexVertexMaterialArray*)m_meshInterface)->getLockedReadOnlyMaterialBase(&materialBase, numMaterials, materialType, materialStride,
&triangleMaterialBase, numTriangles, triangleMaterialStride, triangleType, partID);
// return the pointer to the place with the friction for the triangle
// TODO: This depends on whether it's a moving mesh or not
// BUG IN GIMPACT
//return (btScalar*)(&materialBase[triangleMaterialBase[(triIndex-1) * triangleMaterialStride] * materialStride]);
int * matInd = (int *)(&(triangleMaterialBase[(triIndex * triangleMaterialStride)]));
btMaterial *matVal = (btMaterial *)(&(materialBase[*matInd * materialStride]));
return (matVal);
}

@ -0,0 +1,124 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/// This file was created by Alex Silverman
#ifndef BVH_TRIANGLE_MATERIAL_MESH_SHAPE_H
#define BVH_TRIANGLE_MATERIAL_MESH_SHAPE_H
#include "btBvhTriangleMeshShape.h"
#include "btMaterial.h"
///The BvhTriangleMaterialMeshShape extends the btBvhTriangleMeshShape. Its main contribution is the interface into a material array, which allows per-triangle friction and restitution.
ATTRIBUTE_ALIGNED16(class) btMultimaterialTriangleMeshShape : public btBvhTriangleMeshShape
{
btAlignedObjectArray <btMaterial*> m_materialList;
int ** m_triangleMaterials;
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
btMultimaterialTriangleMeshShape(): btBvhTriangleMeshShape() {}
btMultimaterialTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh = true):
btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression, buildBvh)
{
btVector3 m_triangle[3];
const unsigned char *vertexbase;
int numverts;
PHY_ScalarType type;
int stride;
const unsigned char *indexbase;
int indexstride;
int numfaces;
PHY_ScalarType indicestype;
//m_materialLookup = (int**)(btAlignedAlloc(sizeof(int*) * meshInterface->getNumSubParts(), 16));
for(int i = 0; i < meshInterface->getNumSubParts(); i++)
{
m_meshInterface->getLockedReadOnlyVertexIndexBase(
&vertexbase,
numverts,
type,
stride,
&indexbase,
indexstride,
numfaces,
indicestype,
i);
//m_materialLookup[i] = (int*)(btAlignedAlloc(sizeof(int) * numfaces, 16));
}
}
///optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb
btMultimaterialTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax, bool buildBvh = true):
btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression, bvhAabbMin, bvhAabbMax, buildBvh)
{
btVector3 m_triangle[3];
const unsigned char *vertexbase;
int numverts;
PHY_ScalarType type;
int stride;
const unsigned char *indexbase;
int indexstride;
int numfaces;
PHY_ScalarType indicestype;
//m_materialLookup = (int**)(btAlignedAlloc(sizeof(int*) * meshInterface->getNumSubParts(), 16));
for(int i = 0; i < meshInterface->getNumSubParts(); i++)
{
m_meshInterface->getLockedReadOnlyVertexIndexBase(
&vertexbase,
numverts,
type,
stride,
&indexbase,
indexstride,
numfaces,
indicestype,
i);
//m_materialLookup[i] = (int*)(btAlignedAlloc(sizeof(int) * numfaces * 2, 16));
}
}
virtual ~btMultimaterialTriangleMeshShape()
{
/*
for(int i = 0; i < m_meshInterface->getNumSubParts(); i++)
{
btAlignedFree(m_materialValues[i]);
m_materialLookup[i] = NULL;
}
btAlignedFree(m_materialValues);
m_materialLookup = NULL;
*/
}
virtual int getShapeType() const
{
return MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE;
}
//debugging
virtual const char* getName()const {return "MULTIMATERIALTRIANGLEMESH";}
///Obtains the material for a specific triangle
const btMaterial * getMaterialProperties(int partID, int triIndex);
}
;
#endif //BVH_TRIANGLE_MATERIAL_MESH_SHAPE_H

@ -0,0 +1,121 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btScaledBvhTriangleMeshShape.h"
btScaledBvhTriangleMeshShape::btScaledBvhTriangleMeshShape(btBvhTriangleMeshShape* childShape,btVector3 localScaling)
:m_bvhTriMeshShape(childShape),
m_localScaling(localScaling)
{
}
btScaledBvhTriangleMeshShape::~btScaledBvhTriangleMeshShape()
{
}
class btScaledTriangleCallback : public btTriangleCallback
{
btTriangleCallback* m_originalCallback;
btVector3 m_localScaling;
public:
btScaledTriangleCallback(btTriangleCallback* originalCallback,btVector3 localScaling)
:m_originalCallback(originalCallback),
m_localScaling(localScaling)
{
}
virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex)
{
btVector3 newTriangle[3];
newTriangle[0] = triangle[0]*m_localScaling;
newTriangle[1] = triangle[1]*m_localScaling;
newTriangle[2] = triangle[2]*m_localScaling;
m_originalCallback->processTriangle(&newTriangle[0],partId,triangleIndex);
}
};
void btScaledBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const
{
btScaledTriangleCallback scaledCallback(callback,m_localScaling);
btVector3 invLocalScaling(1.f/m_localScaling.getX(),1.f/m_localScaling.getY(),1.f/m_localScaling.getZ());
btVector3 scaledAabbMin,scaledAabbMax;
///support negative scaling
scaledAabbMin[0] = m_localScaling.getX() >= 0. ? aabbMin[0] * invLocalScaling[0] : aabbMax[0] * invLocalScaling[0];
scaledAabbMin[1] = m_localScaling.getY() >= 0. ? aabbMin[1] * invLocalScaling[1] : aabbMax[1] * invLocalScaling[1];
scaledAabbMin[2] = m_localScaling.getZ() >= 0. ? aabbMin[2] * invLocalScaling[2] : aabbMax[2] * invLocalScaling[2];
scaledAabbMax[0] = m_localScaling.getX() <= 0. ? aabbMin[0] * invLocalScaling[0] : aabbMax[0] * invLocalScaling[0];
scaledAabbMax[1] = m_localScaling.getY() <= 0. ? aabbMin[1] * invLocalScaling[1] : aabbMax[1] * invLocalScaling[1];
scaledAabbMax[2] = m_localScaling.getZ() <= 0. ? aabbMin[2] * invLocalScaling[2] : aabbMax[2] * invLocalScaling[2];
m_bvhTriMeshShape->processAllTriangles(&scaledCallback,scaledAabbMin,scaledAabbMax);
}
void btScaledBvhTriangleMeshShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const
{
btVector3 localAabbMin = m_bvhTriMeshShape->getLocalAabbMin();
btVector3 localAabbMax = m_bvhTriMeshShape->getLocalAabbMax();
btVector3 tmpLocalAabbMin = localAabbMin * m_localScaling;
btVector3 tmpLocalAabbMax = localAabbMax * m_localScaling;
localAabbMin[0] = (m_localScaling.getX() >= 0.) ? tmpLocalAabbMin[0] : tmpLocalAabbMax[0];
localAabbMin[1] = (m_localScaling.getY() >= 0.) ? tmpLocalAabbMin[1] : tmpLocalAabbMax[1];
localAabbMin[2] = (m_localScaling.getZ() >= 0.) ? tmpLocalAabbMin[2] : tmpLocalAabbMax[2];
localAabbMax[0] = (m_localScaling.getX() <= 0.) ? tmpLocalAabbMin[0] : tmpLocalAabbMax[0];
localAabbMax[1] = (m_localScaling.getY() <= 0.) ? tmpLocalAabbMin[1] : tmpLocalAabbMax[1];
localAabbMax[2] = (m_localScaling.getZ() <= 0.) ? tmpLocalAabbMin[2] : tmpLocalAabbMax[2];
btVector3 localHalfExtents = btScalar(0.5)*(localAabbMax-localAabbMin);
btScalar margin = m_bvhTriMeshShape->getMargin();
localHalfExtents += btVector3(margin,margin,margin);
btVector3 localCenter = btScalar(0.5)*(localAabbMax+localAabbMin);
btMatrix3x3 abs_b = trans.getBasis().absolute();
btPoint3 center = trans(localCenter);
btVector3 extent = btVector3(abs_b[0].dot(localHalfExtents),
abs_b[1].dot(localHalfExtents),
abs_b[2].dot(localHalfExtents));
aabbMin = center - extent;
aabbMax = center + extent;
}
void btScaledBvhTriangleMeshShape::setLocalScaling(const btVector3& scaling)
{
m_localScaling = scaling;
}
const btVector3& btScaledBvhTriangleMeshShape::getLocalScaling() const
{
return m_localScaling;
}
void btScaledBvhTriangleMeshShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{
///don't make this a movable object!
// btAssert(0);
}

@ -0,0 +1,67 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SCALED_BVH_TRIANGLE_MESH_SHAPE_H
#define SCALED_BVH_TRIANGLE_MESH_SHAPE_H
#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h"
///The btScaledBvhTriangleMeshShape allows to instance a scaled version of an existing btBvhTriangleMeshShape.
///Note that each btBvhTriangleMeshShape still can have its own local scaling, independent from this btScaledBvhTriangleMeshShape 'localScaling'
ATTRIBUTE_ALIGNED16(class) btScaledBvhTriangleMeshShape : public btConcaveShape
{
btVector3 m_localScaling;
btBvhTriangleMeshShape* m_bvhTriMeshShape;
public:
btScaledBvhTriangleMeshShape(btBvhTriangleMeshShape* childShape,btVector3 localScaling);
virtual ~btScaledBvhTriangleMeshShape();
virtual int getShapeType() const
{
//use un-used 'FAST_CONCAVE_MESH_PROXYTYPE' for now, later add SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE to btBroadphaseProxy.h
return SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE;
}
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const;
virtual void setLocalScaling(const btVector3& scaling);
virtual const btVector3& getLocalScaling() const;
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const;
btBvhTriangleMeshShape* getChildShape()
{
return m_bvhTriMeshShape;
}
const btBvhTriangleMeshShape* getChildShape() const
{
return m_bvhTriMeshShape;
}
//debugging
virtual const char* getName()const {return "SCALEDBVHTRIANGLEMESH";}
};
#endif //BVH_TRIANGLE_MESH_SHAPE_H

@ -0,0 +1,164 @@
/*
btbtShapeHull implemented by John McCutchan.
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btShapeHull.h"
#include "LinearMath/btConvexHull.h"
#define NUM_UNITSPHERE_POINTS 42
static btVector3 btUnitSpherePoints[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2] =
{
btVector3(btScalar(0.000000) , btScalar(-0.000000),btScalar(-1.000000)),
btVector3(btScalar(0.723608) , btScalar(-0.525725),btScalar(-0.447219)),
btVector3(btScalar(-0.276388) , btScalar(-0.850649),btScalar(-0.447219)),
btVector3(btScalar(-0.894426) , btScalar(-0.000000),btScalar(-0.447216)),
btVector3(btScalar(-0.276388) , btScalar(0.850649),btScalar(-0.447220)),
btVector3(btScalar(0.723608) , btScalar(0.525725),btScalar(-0.447219)),
btVector3(btScalar(0.276388) , btScalar(-0.850649),btScalar(0.447220)),
btVector3(btScalar(-0.723608) , btScalar(-0.525725),btScalar(0.447219)),
btVector3(btScalar(-0.723608) , btScalar(0.525725),btScalar(0.447219)),
btVector3(btScalar(0.276388) , btScalar(0.850649),btScalar(0.447219)),
btVector3(btScalar(0.894426) , btScalar(0.000000),btScalar(0.447216)),
btVector3(btScalar(-0.000000) , btScalar(0.000000),btScalar(1.000000)),
btVector3(btScalar(0.425323) , btScalar(-0.309011),btScalar(-0.850654)),
btVector3(btScalar(-0.162456) , btScalar(-0.499995),btScalar(-0.850654)),
btVector3(btScalar(0.262869) , btScalar(-0.809012),btScalar(-0.525738)),
btVector3(btScalar(0.425323) , btScalar(0.309011),btScalar(-0.850654)),
btVector3(btScalar(0.850648) , btScalar(-0.000000),btScalar(-0.525736)),
btVector3(btScalar(-0.525730) , btScalar(-0.000000),btScalar(-0.850652)),
btVector3(btScalar(-0.688190) , btScalar(-0.499997),btScalar(-0.525736)),
btVector3(btScalar(-0.162456) , btScalar(0.499995),btScalar(-0.850654)),
btVector3(btScalar(-0.688190) , btScalar(0.499997),btScalar(-0.525736)),
btVector3(btScalar(0.262869) , btScalar(0.809012),btScalar(-0.525738)),
btVector3(btScalar(0.951058) , btScalar(0.309013),btScalar(0.000000)),
btVector3(btScalar(0.951058) , btScalar(-0.309013),btScalar(0.000000)),
btVector3(btScalar(0.587786) , btScalar(-0.809017),btScalar(0.000000)),
btVector3(btScalar(0.000000) , btScalar(-1.000000),btScalar(0.000000)),
btVector3(btScalar(-0.587786) , btScalar(-0.809017),btScalar(0.000000)),
btVector3(btScalar(-0.951058) , btScalar(-0.309013),btScalar(-0.000000)),
btVector3(btScalar(-0.951058) , btScalar(0.309013),btScalar(-0.000000)),
btVector3(btScalar(-0.587786) , btScalar(0.809017),btScalar(-0.000000)),
btVector3(btScalar(-0.000000) , btScalar(1.000000),btScalar(-0.000000)),
btVector3(btScalar(0.587786) , btScalar(0.809017),btScalar(-0.000000)),
btVector3(btScalar(0.688190) , btScalar(-0.499997),btScalar(0.525736)),
btVector3(btScalar(-0.262869) , btScalar(-0.809012),btScalar(0.525738)),
btVector3(btScalar(-0.850648) , btScalar(0.000000),btScalar(0.525736)),
btVector3(btScalar(-0.262869) , btScalar(0.809012),btScalar(0.525738)),
btVector3(btScalar(0.688190) , btScalar(0.499997),btScalar(0.525736)),
btVector3(btScalar(0.525730) , btScalar(0.000000),btScalar(0.850652)),
btVector3(btScalar(0.162456) , btScalar(-0.499995),btScalar(0.850654)),
btVector3(btScalar(-0.425323) , btScalar(-0.309011),btScalar(0.850654)),
btVector3(btScalar(-0.425323) , btScalar(0.309011),btScalar(0.850654)),
btVector3(btScalar(0.162456) , btScalar(0.499995),btScalar(0.850654))
};
btShapeHull::btShapeHull (const btConvexShape* shape)
{
m_shape = shape;
m_vertices.clear ();
m_indices.clear();
m_numIndices = 0;
}
btShapeHull::~btShapeHull ()
{
m_indices.clear();
m_vertices.clear ();
}
bool
btShapeHull::buildHull (btScalar /*margin*/)
{
int numSampleDirections = NUM_UNITSPHERE_POINTS;
{
int numPDA = m_shape->getNumPreferredPenetrationDirections();
if (numPDA)
{
for (int i=0;i<numPDA;i++)
{
btVector3 norm;
m_shape->getPreferredPenetrationDirection(i,norm);
btUnitSpherePoints[numSampleDirections] = norm;
numSampleDirections++;
}
}
}
btVector3 supportPoints[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2];
int i;
for (i = 0; i < numSampleDirections; i++)
{
supportPoints[i] = m_shape->localGetSupportingVertex(btUnitSpherePoints[i]);
}
HullDesc hd;
hd.mFlags = QF_TRIANGLES;
hd.mVcount = static_cast<unsigned int>(numSampleDirections);
#ifdef BT_USE_DOUBLE_PRECISION
hd.mVertices = &supportPoints[0];
hd.mVertexStride = sizeof(btVector3);
#else
hd.mVertices = &supportPoints[0];
hd.mVertexStride = sizeof (btVector3);
#endif
HullLibrary hl;
HullResult hr;
if (hl.CreateConvexHull (hd, hr) == QE_FAIL)
{
return false;
}
m_vertices.resize (static_cast<int>(hr.mNumOutputVertices));
for (i = 0; i < static_cast<int>(hr.mNumOutputVertices); i++)
{
m_vertices[i] = hr.m_OutputVertices[i];
}
m_numIndices = hr.mNumIndices;
m_indices.resize(static_cast<int>(m_numIndices));
for (i = 0; i < static_cast<int>(m_numIndices); i++)
{
m_indices[i] = hr.m_Indices[i];
}
// free temporary hull result that we just copied
hl.ReleaseResult (hr);
return true;
}
int
btShapeHull::numTriangles () const
{
return static_cast<int>(m_numIndices / 3);
}
int
btShapeHull::numVertices () const
{
return m_vertices.size ();
}
int
btShapeHull::numIndices () const
{
return static_cast<int>(m_numIndices);
}

@ -0,0 +1,56 @@
/*
btShapeHull implemented by John McCutchan.
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef _SHAPE_HULL_H
#define _SHAPE_HULL_H
#include "LinearMath/btAlignedObjectArray.h"
#include "BulletCollision/CollisionShapes/btConvexShape.h"
///The btShapeHull class takes a btConvexShape, builds a simplified convex hull using btConvexHull and provides triangle indices and vertices.
///It can be useful for to simplify a complex convex object and for visualization of a non-polyhedral convex object.
///It approximates the convex hull using the supporting vertex of 42 directions.
class btShapeHull
{
public:
btShapeHull (const btConvexShape* shape);
~btShapeHull ();
bool buildHull (btScalar margin);
int numTriangles () const;
int numVertices () const;
int numIndices () const;
const btVector3* getVertexPointer() const
{
return &m_vertices[0];
}
const unsigned int* getIndexPointer() const
{
return &m_indices[0];
}
protected:
btAlignedObjectArray<btVector3> m_vertices;
btAlignedObjectArray<unsigned int> m_indices;
unsigned int m_numIndices;
const btConvexShape* m_shape;
};
#endif //_SHAPE_HULL_H

@ -0,0 +1,86 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///This file was created by Alex Silverman
#include "btTriangleIndexVertexMaterialArray.h"
btTriangleIndexVertexMaterialArray::btTriangleIndexVertexMaterialArray(int numTriangles,int* triangleIndexBase,int triangleIndexStride,
int numVertices,btScalar* vertexBase,int vertexStride,
int numMaterials, unsigned char* materialBase, int materialStride,
int* triangleMaterialsBase, int materialIndexStride) :
btTriangleIndexVertexArray(numTriangles, triangleIndexBase, triangleIndexStride, numVertices, vertexBase, vertexStride)
{
btMaterialProperties mat;
mat.m_numMaterials = numMaterials;
mat.m_materialBase = materialBase;
mat.m_materialStride = materialStride;
#ifdef BT_USE_DOUBLE_PRECISION
mat.m_materialType = PHY_DOUBLE;
#else
mat.m_materialType = PHY_FLOAT;
#endif
mat.m_numTriangles = numTriangles;
mat.m_triangleMaterialsBase = (unsigned char *)triangleMaterialsBase;
mat.m_triangleMaterialStride = materialIndexStride;
mat.m_triangleType = PHY_INTEGER;
addMaterialProperties(mat);
}
void btTriangleIndexVertexMaterialArray::getLockedMaterialBase(unsigned char **materialBase, int& numMaterials, PHY_ScalarType& materialType, int& materialStride,
unsigned char ** triangleMaterialBase, int& numTriangles, int& triangleMaterialStride, PHY_ScalarType& triangleType, int subpart)
{
btAssert(subpart< getNumSubParts() );
btMaterialProperties& mats = m_materials[subpart];
numMaterials = mats.m_numMaterials;
(*materialBase) = (unsigned char *) mats.m_materialBase;
#ifdef BT_USE_DOUBLE_PRECISION
materialType = PHY_DOUBLE;
#else
materialType = PHY_FLOAT;
#endif
materialStride = mats.m_materialStride;
numTriangles = mats.m_numTriangles;
(*triangleMaterialBase) = (unsigned char *)mats.m_triangleMaterialsBase;
triangleMaterialStride = mats.m_triangleMaterialStride;
triangleType = mats.m_triangleType;
}
void btTriangleIndexVertexMaterialArray::getLockedReadOnlyMaterialBase(const unsigned char **materialBase, int& numMaterials, PHY_ScalarType& materialType, int& materialStride,
const unsigned char ** triangleMaterialBase, int& numTriangles, int& triangleMaterialStride, PHY_ScalarType& triangleType, int subpart)
{
btMaterialProperties& mats = m_materials[subpart];
numMaterials = mats.m_numMaterials;
(*materialBase) = (const unsigned char *) mats.m_materialBase;
#ifdef BT_USE_DOUBLE_PRECISION
materialType = PHY_DOUBLE;
#else
materialType = PHY_FLOAT;
#endif
materialStride = mats.m_materialStride;
numTriangles = mats.m_numTriangles;
(*triangleMaterialBase) = (const unsigned char *)mats.m_triangleMaterialsBase;
triangleMaterialStride = mats.m_triangleMaterialStride;
triangleType = mats.m_triangleType;
}

@ -0,0 +1,84 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///This file was created by Alex Silverman
#ifndef BT_MULTIMATERIAL_TRIANGLE_INDEX_VERTEX_ARRAY_H
#define BT_MULTIMATERIAL_TRIANGLE_INDEX_VERTEX_ARRAY_H
#include "btTriangleIndexVertexArray.h"
ATTRIBUTE_ALIGNED16( struct) btMaterialProperties
{
///m_materialBase ==========> 2 btScalar values make up one material, friction then restitution
int m_numMaterials;
const unsigned char * m_materialBase;
int m_materialStride;
PHY_ScalarType m_materialType;
///m_numTriangles <=========== This exists in the btIndexedMesh object for the same subpart, but since we're
/// padding the structure, it can be reproduced at no real cost
///m_triangleMaterials =====> 1 integer value makes up one entry
/// eg: m_triangleMaterials[1] = 5; // This will set triangle 2 to use material 5
int m_numTriangles;
const unsigned char * m_triangleMaterialsBase;
int m_triangleMaterialStride;
///m_triangleType <========== Automatically set in addMaterialProperties
PHY_ScalarType m_triangleType;
};
typedef btAlignedObjectArray<btMaterialProperties> MaterialArray;
///Teh btTriangleIndexVertexMaterialArray is built on TriangleIndexVertexArray
///The addition of a material array allows for the utilization of the partID and
///triangleIndex that are returned in the ContactAddedCallback. As with
///TriangleIndexVertexArray, no duplicate is made of the material data, so it
///is the users responsibility to maintain the array during the lifetime of the
///TriangleIndexVertexMaterialArray.
ATTRIBUTE_ALIGNED16(class) btTriangleIndexVertexMaterialArray : public btTriangleIndexVertexArray
{
protected:
MaterialArray m_materials;
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
btTriangleIndexVertexMaterialArray()
{
}
btTriangleIndexVertexMaterialArray(int numTriangles,int* triangleIndexBase,int triangleIndexStride,
int numVertices,btScalar* vertexBase,int vertexStride,
int numMaterials, unsigned char* materialBase, int materialStride,
int* triangleMaterialsBase, int materialIndexStride);
virtual ~btTriangleIndexVertexMaterialArray() {}
void addMaterialProperties(const btMaterialProperties& mat, PHY_ScalarType triangleType = PHY_INTEGER)
{
m_materials.push_back(mat);
m_materials[m_materials.size()-1].m_triangleType = triangleType;
}
virtual void getLockedMaterialBase(unsigned char **materialBase, int& numMaterials, PHY_ScalarType& materialType, int& materialStride,
unsigned char ** triangleMaterialBase, int& numTriangles, int& triangleMaterialStride, PHY_ScalarType& triangleType ,int subpart = 0);
virtual void getLockedReadOnlyMaterialBase(const unsigned char **materialBase, int& numMaterials, PHY_ScalarType& materialType, int& materialStride,
const unsigned char ** triangleMaterialBase, int& numTriangles, int& triangleMaterialStride, PHY_ScalarType& triangleType, int subpart = 0);
}
;
#endif //BT_MULTIMATERIAL_TRIANGLE_INDEX_VERTEX_ARRAY_H

@ -0,0 +1,114 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btUniformScalingShape.h"
btUniformScalingShape::btUniformScalingShape( btConvexShape* convexChildShape,btScalar uniformScalingFactor):
m_childConvexShape(convexChildShape),
m_uniformScalingFactor(uniformScalingFactor)
{
}
btUniformScalingShape::~btUniformScalingShape()
{
}
btVector3 btUniformScalingShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const
{
btVector3 tmpVertex;
tmpVertex = m_childConvexShape->localGetSupportingVertexWithoutMargin(vec);
return tmpVertex*m_uniformScalingFactor;
}
void btUniformScalingShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const
{
m_childConvexShape->batchedUnitVectorGetSupportingVertexWithoutMargin(vectors,supportVerticesOut,numVectors);
int i;
for (i=0;i<numVectors;i++)
{
supportVerticesOut[i] = supportVerticesOut[i] * m_uniformScalingFactor;
}
}
btVector3 btUniformScalingShape::localGetSupportingVertex(const btVector3& vec)const
{
btVector3 tmpVertex;
tmpVertex = m_childConvexShape->localGetSupportingVertex(vec);
return tmpVertex*m_uniformScalingFactor;
}
void btUniformScalingShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{
///this linear upscaling is not realistic, but we don't deal with large mass ratios...
btVector3 tmpInertia;
m_childConvexShape->calculateLocalInertia(mass,tmpInertia);
inertia = tmpInertia * m_uniformScalingFactor;
}
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version
void btUniformScalingShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
{
m_childConvexShape->getAabb(t,aabbMin,aabbMax);
btVector3 aabbCenter = (aabbMax+aabbMin)*btScalar(0.5);
btVector3 scaledAabbHalfExtends = (aabbMax-aabbMin)*btScalar(0.5)*m_uniformScalingFactor;
aabbMin = aabbCenter - scaledAabbHalfExtends;
aabbMax = aabbCenter + scaledAabbHalfExtends;
}
void btUniformScalingShape::getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
{
m_childConvexShape->getAabbSlow(t,aabbMin,aabbMax);
btVector3 aabbCenter = (aabbMax+aabbMin)*btScalar(0.5);
btVector3 scaledAabbHalfExtends = (aabbMax-aabbMin)*btScalar(0.5)*m_uniformScalingFactor;
aabbMin = aabbCenter - scaledAabbHalfExtends;
aabbMax = aabbCenter + scaledAabbHalfExtends;
}
void btUniformScalingShape::setLocalScaling(const btVector3& scaling)
{
m_childConvexShape->setLocalScaling(scaling);
}
const btVector3& btUniformScalingShape::getLocalScaling() const
{
return m_childConvexShape->getLocalScaling();
}
void btUniformScalingShape::setMargin(btScalar margin)
{
m_childConvexShape->setMargin(margin);
}
btScalar btUniformScalingShape::getMargin() const
{
return m_childConvexShape->getMargin() * m_uniformScalingFactor;
}
int btUniformScalingShape::getNumPreferredPenetrationDirections() const
{
return m_childConvexShape->getNumPreferredPenetrationDirections();
}
void btUniformScalingShape::getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const
{
m_childConvexShape->getPreferredPenetrationDirection(index,penetrationVector);
}

@ -0,0 +1,88 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_UNIFORM_SCALING_SHAPE_H
#define BT_UNIFORM_SCALING_SHAPE_H
#include "btConvexShape.h"
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
///The btUniformScalingShape allows to re-use uniform scaled instances of btConvexShape in a memory efficient way.
///Istead of using btUniformScalingShape, it is better to use the non-uniform setLocalScaling method on convex shapes that implement it.
class btUniformScalingShape : public btConvexShape
{
btConvexShape* m_childConvexShape;
btScalar m_uniformScalingFactor;
public:
btUniformScalingShape( btConvexShape* convexChildShape, btScalar uniformScalingFactor);
virtual ~btUniformScalingShape();
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const;
virtual btVector3 localGetSupportingVertex(const btVector3& vec)const;
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const;
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
btScalar getUniformScalingFactor() const
{
return m_uniformScalingFactor;
}
btConvexShape* getChildShape()
{
return m_childConvexShape;
}
const btConvexShape* getChildShape() const
{
return m_childConvexShape;
}
virtual const char* getName()const
{
return "UniformScalingShape";
}
virtual int getShapeType() const { return UNIFORM_SCALING_SHAPE_PROXYTYPE; }
///////////////////////////
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version
void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const;
virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const;
virtual void setLocalScaling(const btVector3& scaling) ;
virtual const btVector3& getLocalScaling() const ;
virtual void setMargin(btScalar margin);
virtual btScalar getMargin() const;
virtual int getNumPreferredPenetrationDirections() const;
virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const;
};
#endif //BT_UNIFORM_SCALING_SHAPE_H

@ -0,0 +1,943 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be appreciated
but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
GJK-EPA collision solver by Nathanael Presson, 2008
*/
#include "BulletCollision/CollisionShapes/btConvexInternalShape.h"
#include "BulletCollision/CollisionShapes/btSphereShape.h"
#include "btGjkEpa2.h"
#if defined(DEBUG) || defined (_DEBUG)
#include <stdio.h> //for debug printf
#ifdef __SPU__
#include <spu_printf.h>
#define printf spu_printf
#endif //__SPU__
#endif
namespace gjkepa2_impl
{
// Config
/* GJK */
#define GJK_MAX_ITERATIONS 128
#define GJK_ACCURARY ((btScalar)0.0001)
#define GJK_MIN_DISTANCE ((btScalar)0.0001)
#define GJK_DUPLICATED_EPS ((btScalar)0.0001)
#define GJK_SIMPLEX2_EPS ((btScalar)0.0)
#define GJK_SIMPLEX3_EPS ((btScalar)0.0)
#define GJK_SIMPLEX4_EPS ((btScalar)0.0)
/* EPA */
#define EPA_MAX_VERTICES 64
#define EPA_MAX_FACES (EPA_MAX_VERTICES*2)
#define EPA_MAX_ITERATIONS 255
#define EPA_ACCURACY ((btScalar)0.0001)
#define EPA_FALLBACK (10*EPA_ACCURACY)
#define EPA_PLANE_EPS ((btScalar)0.00001)
#define EPA_INSIDE_EPS ((btScalar)0.01)
// Shorthands
typedef unsigned int U;
typedef unsigned char U1;
// MinkowskiDiff
struct MinkowskiDiff
{
const btConvexShape* m_shapes[2];
btMatrix3x3 m_toshape1;
btTransform m_toshape0;
btVector3 (btConvexShape::*Ls)(const btVector3&) const;
void EnableMargin(bool enable)
{
if(enable)
Ls=&btConvexShape::localGetSupportingVertex;
else
Ls=&btConvexShape::localGetSupportingVertexWithoutMargin;
}
inline btVector3 Support0(const btVector3& d) const
{
return(((m_shapes[0])->*(Ls))(d));
}
inline btVector3 Support1(const btVector3& d) const
{
return(m_toshape0*((m_shapes[1])->*(Ls))(m_toshape1*d));
}
inline btVector3 Support(const btVector3& d) const
{
return(Support0(d)-Support1(-d));
}
btVector3 Support(const btVector3& d,U index) const
{
if(index)
return(Support1(d));
else
return(Support0(d));
}
};
typedef MinkowskiDiff tShape;
// GJK
struct GJK
{
/* Types */
struct sSV
{
btVector3 d,w;
};
struct sSimplex
{
sSV* c[4];
btScalar p[4];
U rank;
};
struct eStatus { enum _ {
Valid,
Inside,
Failed };};
/* Fields */
tShape m_shape;
btVector3 m_ray;
btScalar m_distance;
sSimplex m_simplices[2];
sSV m_store[4];
sSV* m_free[4];
U m_nfree;
U m_current;
sSimplex* m_simplex;
eStatus::_ m_status;
/* Methods */
GJK()
{
Initialize();
}
void Initialize()
{
m_ray = btVector3(0,0,0);
m_nfree = 0;
m_status = eStatus::Failed;
m_current = 0;
m_distance = 0;
}
eStatus::_ Evaluate(const tShape& shapearg,const btVector3& guess)
{
U iterations=0;
btScalar sqdist=0;
btScalar alpha=0;
btVector3 lastw[4];
U clastw=0;
/* Initialize solver */
m_free[0] = &m_store[0];
m_free[1] = &m_store[1];
m_free[2] = &m_store[2];
m_free[3] = &m_store[3];
m_nfree = 4;
m_current = 0;
m_status = eStatus::Valid;
m_shape = shapearg;
m_distance = 0;
/* Initialize simplex */
m_simplices[0].rank = 0;
m_ray = guess;
const btScalar sqrl= m_ray.length2();
appendvertice(m_simplices[0],sqrl>0?-m_ray:btVector3(1,0,0));
m_simplices[0].p[0] = 1;
m_ray = m_simplices[0].c[0]->w;
sqdist = sqrl;
lastw[0] =
lastw[1] =
lastw[2] =
lastw[3] = m_ray;
/* Loop */
do {
const U next=1-m_current;
sSimplex& cs=m_simplices[m_current];
sSimplex& ns=m_simplices[next];
/* Check zero */
const btScalar rl=m_ray.length();
if(rl<GJK_MIN_DISTANCE)
{/* Touching or inside */
m_status=eStatus::Inside;
break;
}
/* Append new vertice in -'v' direction */
appendvertice(cs,-m_ray);
const btVector3& w=cs.c[cs.rank-1]->w;
bool found=false;
for(U i=0;i<4;++i)
{
if((w-lastw[i]).length2()<GJK_DUPLICATED_EPS)
{ found=true;break; }
}
if(found)
{/* Return old simplex */
removevertice(m_simplices[m_current]);
break;
}
else
{/* Update lastw */
lastw[clastw=(clastw+1)&3]=w;
}
/* Check for termination */
const btScalar omega=dot(m_ray,w)/rl;
alpha=btMax(omega,alpha);
if(((rl-alpha)-(GJK_ACCURARY*rl))<=0)
{/* Return old simplex */
removevertice(m_simplices[m_current]);
break;
}
/* Reduce simplex */
btScalar weights[4];
U mask=0;
switch(cs.rank)
{
case 2: sqdist=projectorigin( cs.c[0]->w,
cs.c[1]->w,
weights,mask);break;
case 3: sqdist=projectorigin( cs.c[0]->w,
cs.c[1]->w,
cs.c[2]->w,
weights,mask);break;
case 4: sqdist=projectorigin( cs.c[0]->w,
cs.c[1]->w,
cs.c[2]->w,
cs.c[3]->w,
weights,mask);break;
}
if(sqdist>=0)
{/* Valid */
ns.rank = 0;
m_ray = btVector3(0,0,0);
m_current = next;
for(U i=0,ni=cs.rank;i<ni;++i)
{
if(mask&(1<<i))
{
ns.c[ns.rank] = cs.c[i];
ns.p[ns.rank++] = weights[i];
m_ray += cs.c[i]->w*weights[i];
}
else
{
m_free[m_nfree++] = cs.c[i];
}
}
if(mask==15) m_status=eStatus::Inside;
}
else
{/* Return old simplex */
removevertice(m_simplices[m_current]);
break;
}
m_status=((++iterations)<GJK_MAX_ITERATIONS)?m_status:eStatus::Failed;
} while(m_status==eStatus::Valid);
m_simplex=&m_simplices[m_current];
switch(m_status)
{
case eStatus::Valid: m_distance=m_ray.length();break;
case eStatus::Inside: m_distance=0;break;
}
return(m_status);
}
bool EncloseOrigin()
{
switch(m_simplex->rank)
{
case 1:
{
for(U i=0;i<3;++i)
{
btVector3 axis=btVector3(0,0,0);
axis[i]=1;
appendvertice(*m_simplex, axis);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
appendvertice(*m_simplex,-axis);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
}
}
break;
case 2:
{
const btVector3 d=m_simplex->c[1]->w-m_simplex->c[0]->w;
for(U i=0;i<3;++i)
{
btVector3 axis=btVector3(0,0,0);
axis[i]=1;
const btVector3 p=cross(d,axis);
if(p.length2()>0)
{
appendvertice(*m_simplex, p);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
appendvertice(*m_simplex,-p);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
}
}
}
break;
case 3:
{
const btVector3 n=cross(m_simplex->c[1]->w-m_simplex->c[0]->w,
m_simplex->c[2]->w-m_simplex->c[0]->w);
if(n.length2()>0)
{
appendvertice(*m_simplex,n);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
appendvertice(*m_simplex,-n);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
}
}
break;
case 4:
{
if(btFabs(det( m_simplex->c[0]->w-m_simplex->c[3]->w,
m_simplex->c[1]->w-m_simplex->c[3]->w,
m_simplex->c[2]->w-m_simplex->c[3]->w))>0)
return(true);
}
break;
}
return(false);
}
/* Internals */
void getsupport(const btVector3& d,sSV& sv) const
{
sv.d = d/d.length();
sv.w = m_shape.Support(sv.d);
}
void removevertice(sSimplex& simplex)
{
m_free[m_nfree++]=simplex.c[--simplex.rank];
}
void appendvertice(sSimplex& simplex,const btVector3& v)
{
simplex.p[simplex.rank]=0;
simplex.c[simplex.rank]=m_free[--m_nfree];
getsupport(v,*simplex.c[simplex.rank++]);
}
static btScalar det(const btVector3& a,const btVector3& b,const btVector3& c)
{
return( a.y()*b.z()*c.x()+a.z()*b.x()*c.y()-
a.x()*b.z()*c.y()-a.y()*b.x()*c.z()+
a.x()*b.y()*c.z()-a.z()*b.y()*c.x());
}
static btScalar projectorigin( const btVector3& a,
const btVector3& b,
btScalar* w,U& m)
{
const btVector3 d=b-a;
const btScalar l=d.length2();
if(l>GJK_SIMPLEX2_EPS)
{
const btScalar t(l>0?-dot(a,d)/l:0);
if(t>=1) { w[0]=0;w[1]=1;m=2;return(b.length2()); }
else if(t<=0) { w[0]=1;w[1]=0;m=1;return(a.length2()); }
else { w[0]=1-(w[1]=t);m=3;return((a+d*t).length2()); }
}
return(-1);
}
static btScalar projectorigin( const btVector3& a,
const btVector3& b,
const btVector3& c,
btScalar* w,U& m)
{
static const U imd3[]={1,2,0};
const btVector3* vt[]={&a,&b,&c};
const btVector3 dl[]={a-b,b-c,c-a};
const btVector3 n=cross(dl[0],dl[1]);
const btScalar l=n.length2();
if(l>GJK_SIMPLEX3_EPS)
{
btScalar mindist=-1;
btScalar subw[2];
U subm;
for(U i=0;i<3;++i)
{
if(dot(*vt[i],cross(dl[i],n))>0)
{
const U j=imd3[i];
const btScalar subd(projectorigin(*vt[i],*vt[j],subw,subm));
if((mindist<0)||(subd<mindist))
{
mindist = subd;
m = static_cast<U>(((subm&1)?1<<i:0)+((subm&2)?1<<j:0));
w[i] = subw[0];
w[j] = subw[1];
w[imd3[j]] = 0;
}
}
}
if(mindist<0)
{
const btScalar d=dot(a,n);
const btScalar s=btSqrt(l);
const btVector3 p=n*(d/l);
mindist = p.length2();
m = 7;
w[0] = (cross(dl[1],b-p)).length()/s;
w[1] = (cross(dl[2],c-p)).length()/s;
w[2] = 1-(w[0]+w[1]);
}
return(mindist);
}
return(-1);
}
static btScalar projectorigin( const btVector3& a,
const btVector3& b,
const btVector3& c,
const btVector3& d,
btScalar* w,U& m)
{
static const U imd3[]={1,2,0};
const btVector3* vt[]={&a,&b,&c,&d};
const btVector3 dl[]={a-d,b-d,c-d};
const btScalar vl=det(dl[0],dl[1],dl[2]);
const bool ng=(vl*dot(a,cross(b-c,a-b)))<=0;
if(ng&&(btFabs(vl)>GJK_SIMPLEX4_EPS))
{
btScalar mindist=-1;
btScalar subw[3];
U subm;
for(U i=0;i<3;++i)
{
const U j=imd3[i];
const btScalar s=vl*dot(d,cross(dl[i],dl[j]));
if(s>0)
{
const btScalar subd=projectorigin(*vt[i],*vt[j],d,subw,subm);
if((mindist<0)||(subd<mindist))
{
mindist = subd;
m = static_cast<U>((subm&1?1<<i:0)+
(subm&2?1<<j:0)+
(subm&4?8:0));
w[i] = subw[0];
w[j] = subw[1];
w[imd3[j]] = 0;
w[3] = subw[2];
}
}
}
if(mindist<0)
{
mindist = 0;
m = 15;
w[0] = det(c,b,d)/vl;
w[1] = det(a,c,d)/vl;
w[2] = det(b,a,d)/vl;
w[3] = 1-(w[0]+w[1]+w[2]);
}
return(mindist);
}
return(-1);
}
};
// EPA
struct EPA
{
/* Types */
typedef GJK::sSV sSV;
struct sFace
{
btVector3 n;
btScalar d;
btScalar p;
sSV* c[3];
sFace* f[3];
sFace* l[2];
U1 e[3];
U1 pass;
};
struct sList
{
sFace* root;
U count;
sList() : root(0),count(0) {}
};
struct sHorizon
{
sFace* cf;
sFace* ff;
U nf;
sHorizon() : cf(0),ff(0),nf(0) {}
};
struct eStatus { enum _ {
Valid,
Touching,
Degenerated,
NonConvex,
InvalidHull,
OutOfFaces,
OutOfVertices,
AccuraryReached,
FallBack,
Failed };};
/* Fields */
eStatus::_ m_status;
GJK::sSimplex m_result;
btVector3 m_normal;
btScalar m_depth;
sSV m_sv_store[EPA_MAX_VERTICES];
sFace m_fc_store[EPA_MAX_FACES];
U m_nextsv;
sList m_hull;
sList m_stock;
/* Methods */
EPA()
{
Initialize();
}
static inline void bind(sFace* fa,U ea,sFace* fb,U eb)
{
fa->e[ea]=(U1)eb;fa->f[ea]=fb;
fb->e[eb]=(U1)ea;fb->f[eb]=fa;
}
static inline void append(sList& list,sFace* face)
{
face->l[0] = 0;
face->l[1] = list.root;
if(list.root) list.root->l[0]=face;
list.root = face;
++list.count;
}
static inline void remove(sList& list,sFace* face)
{
if(face->l[1]) face->l[1]->l[0]=face->l[0];
if(face->l[0]) face->l[0]->l[1]=face->l[1];
if(face==list.root) list.root=face->l[1];
--list.count;
}
void Initialize()
{
m_status = eStatus::Failed;
m_normal = btVector3(0,0,0);
m_depth = 0;
m_nextsv = 0;
for(U i=0;i<EPA_MAX_FACES;++i)
{
append(m_stock,&m_fc_store[EPA_MAX_FACES-i-1]);
}
}
eStatus::_ Evaluate(GJK& gjk,const btVector3& guess)
{
GJK::sSimplex& simplex=*gjk.m_simplex;
if((simplex.rank>1)&&gjk.EncloseOrigin())
{
/* Clean up */
while(m_hull.root)
{
sFace* f = m_hull.root;
remove(m_hull,f);
append(m_stock,f);
}
m_status = eStatus::Valid;
m_nextsv = 0;
/* Orient simplex */
if(gjk.det( simplex.c[0]->w-simplex.c[3]->w,
simplex.c[1]->w-simplex.c[3]->w,
simplex.c[2]->w-simplex.c[3]->w)<0)
{
btSwap(simplex.c[0],simplex.c[1]);
btSwap(simplex.p[0],simplex.p[1]);
}
/* Build initial hull */
sFace* tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true),
newface(simplex.c[1],simplex.c[0],simplex.c[3],true),
newface(simplex.c[2],simplex.c[1],simplex.c[3],true),
newface(simplex.c[0],simplex.c[2],simplex.c[3],true)};
if(m_hull.count==4)
{
sFace* best=findbest();
sFace outer=*best;
U pass=0;
U iterations=0;
bind(tetra[0],0,tetra[1],0);
bind(tetra[0],1,tetra[2],0);
bind(tetra[0],2,tetra[3],0);
bind(tetra[1],1,tetra[3],2);
bind(tetra[1],2,tetra[2],1);
bind(tetra[2],2,tetra[3],1);
m_status=eStatus::Valid;
for(;iterations<EPA_MAX_ITERATIONS;++iterations)
{
if(m_nextsv<EPA_MAX_VERTICES)
{
sHorizon horizon;
sSV* w=&m_sv_store[m_nextsv++];
bool valid=true;
best->pass = (U1)(++pass);
gjk.getsupport(best->n,*w);
const btScalar wdist=dot(best->n,w->w)-best->d;
if(wdist>EPA_ACCURACY)
{
for(U j=0;(j<3)&&valid;++j)
{
valid&=expand( pass,w,
best->f[j],best->e[j],
horizon);
}
if(valid&&(horizon.nf>=3))
{
bind(horizon.cf,1,horizon.ff,2);
remove(m_hull,best);
append(m_stock,best);
best=findbest();
if(best->p>=outer.p) outer=*best;
} else { m_status=eStatus::InvalidHull;break; }
} else { m_status=eStatus::AccuraryReached;break; }
} else { m_status=eStatus::OutOfVertices;break; }
}
const btVector3 projection=outer.n*outer.d;
m_normal = outer.n;
m_depth = outer.d;
m_result.rank = 3;
m_result.c[0] = outer.c[0];
m_result.c[1] = outer.c[1];
m_result.c[2] = outer.c[2];
m_result.p[0] = cross( outer.c[1]->w-projection,
outer.c[2]->w-projection).length();
m_result.p[1] = cross( outer.c[2]->w-projection,
outer.c[0]->w-projection).length();
m_result.p[2] = cross( outer.c[0]->w-projection,
outer.c[1]->w-projection).length();
const btScalar sum=m_result.p[0]+m_result.p[1]+m_result.p[2];
m_result.p[0] /= sum;
m_result.p[1] /= sum;
m_result.p[2] /= sum;
return(m_status);
}
}
/* Fallback */
m_status = eStatus::FallBack;
m_normal = -guess;
const btScalar nl=m_normal.length();
if(nl>0)
m_normal = m_normal/nl;
else
m_normal = btVector3(1,0,0);
m_depth = 0;
m_result.rank=1;
m_result.c[0]=simplex.c[0];
m_result.p[0]=1;
return(m_status);
}
sFace* newface(sSV* a,sSV* b,sSV* c,bool forced)
{
if(m_stock.root)
{
sFace* face=m_stock.root;
remove(m_stock,face);
append(m_hull,face);
face->pass = 0;
face->c[0] = a;
face->c[1] = b;
face->c[2] = c;
face->n = cross(b->w-a->w,c->w-a->w);
const btScalar l=face->n.length();
const bool v=l>EPA_ACCURACY;
face->p = btMin(btMin(
dot(a->w,cross(face->n,a->w-b->w)),
dot(b->w,cross(face->n,b->w-c->w))),
dot(c->w,cross(face->n,c->w-a->w))) /
(v?l:1);
face->p = face->p>=-EPA_INSIDE_EPS?0:face->p;
if(v)
{
face->d = dot(a->w,face->n)/l;
face->n /= l;
if(forced||(face->d>=-EPA_PLANE_EPS))
{
return(face);
} else m_status=eStatus::NonConvex;
} else m_status=eStatus::Degenerated;
remove(m_hull,face);
append(m_stock,face);
return(0);
}
m_status=m_stock.root?eStatus::OutOfVertices:eStatus::OutOfFaces;
return(0);
}
sFace* findbest()
{
sFace* minf=m_hull.root;
btScalar mind=minf->d*minf->d;
btScalar maxp=minf->p;
for(sFace* f=minf->l[1];f;f=f->l[1])
{
const btScalar sqd=f->d*f->d;
if((f->p>=maxp)&&(sqd<mind))
{
minf=f;
mind=sqd;
maxp=f->p;
}
}
return(minf);
}
bool expand(U pass,sSV* w,sFace* f,U e,sHorizon& horizon)
{
static const U i1m3[]={1,2,0};
static const U i2m3[]={2,0,1};
if(f->pass!=pass)
{
const U e1=i1m3[e];
if((dot(f->n,w->w)-f->d)<-EPA_PLANE_EPS)
{
sFace* nf=newface(f->c[e1],f->c[e],w,false);
if(nf)
{
bind(nf,0,f,e);
if(horizon.cf) bind(horizon.cf,1,nf,2); else horizon.ff=nf;
horizon.cf=nf;
++horizon.nf;
return(true);
}
}
else
{
const U e2=i2m3[e];
f->pass = (U1)pass;
if( expand(pass,w,f->f[e1],f->e[e1],horizon)&&
expand(pass,w,f->f[e2],f->e[e2],horizon))
{
remove(m_hull,f);
append(m_stock,f);
return(true);
}
}
}
return(false);
}
};
//
static void Initialize( const btConvexShape* shape0,const btTransform& wtrs0,
const btConvexShape* shape1,const btTransform& wtrs1,
btGjkEpaSolver2::sResults& results,
tShape& shape,
bool withmargins)
{
/* Results */
results.witnesses[0] =
results.witnesses[1] = btVector3(0,0,0);
results.status = btGjkEpaSolver2::sResults::Separated;
/* Shape */
shape.m_shapes[0] = shape0;
shape.m_shapes[1] = shape1;
shape.m_toshape1 = wtrs1.getBasis().transposeTimes(wtrs0.getBasis());
shape.m_toshape0 = wtrs0.inverseTimes(wtrs1);
shape.EnableMargin(withmargins);
}
}
//
// Api
//
using namespace gjkepa2_impl;
//
int btGjkEpaSolver2::StackSizeRequirement()
{
return(sizeof(GJK)+sizeof(EPA));
}
//
bool btGjkEpaSolver2::Distance( const btConvexShape* shape0,
const btTransform& wtrs0,
const btConvexShape* shape1,
const btTransform& wtrs1,
const btVector3& guess,
sResults& results)
{
tShape shape;
Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,guess);
if(gjk_status==GJK::eStatus::Valid)
{
btVector3 w0=btVector3(0,0,0);
btVector3 w1=btVector3(0,0,0);
for(U i=0;i<gjk.m_simplex->rank;++i)
{
const btScalar p=gjk.m_simplex->p[i];
w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p;
w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p;
}
results.witnesses[0] = wtrs0*w0;
results.witnesses[1] = wtrs0*w1;
results.normal = w0-w1;
results.distance = results.normal.length();
results.normal /= results.distance>GJK_MIN_DISTANCE?results.distance:1;
return(true);
}
else
{
results.status = gjk_status==GJK::eStatus::Inside?
sResults::Penetrating :
sResults::GJK_Failed ;
return(false);
}
}
//
bool btGjkEpaSolver2::Penetration( const btConvexShape* shape0,
const btTransform& wtrs0,
const btConvexShape* shape1,
const btTransform& wtrs1,
const btVector3& guess,
sResults& results,
bool usemargins)
{
tShape shape;
Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,usemargins);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,-guess);
switch(gjk_status)
{
case GJK::eStatus::Inside:
{
EPA epa;
EPA::eStatus::_ epa_status=epa.Evaluate(gjk,-guess);
if(epa_status!=EPA::eStatus::Failed)
{
btVector3 w0=btVector3(0,0,0);
for(U i=0;i<epa.m_result.rank;++i)
{
w0+=shape.Support(epa.m_result.c[i]->d,0)*epa.m_result.p[i];
}
results.status = sResults::Penetrating;
results.witnesses[0] = wtrs0*w0;
results.witnesses[1] = wtrs0*(w0-epa.m_normal*epa.m_depth);
results.normal = -epa.m_normal;
results.distance = -epa.m_depth;
return(true);
} else results.status=sResults::EPA_Failed;
}
break;
case GJK::eStatus::Failed:
results.status=sResults::GJK_Failed;
break;
}
return(false);
}
//
btScalar btGjkEpaSolver2::SignedDistance(const btVector3& position,
btScalar margin,
const btConvexShape* shape0,
const btTransform& wtrs0,
sResults& results)
{
tShape shape;
btSphereShape shape1(margin);
btTransform wtrs1(btQuaternion(0,0,0,1),position);
Initialize(shape0,wtrs0,&shape1,wtrs1,results,shape,false);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,btVector3(1,1,1));
if(gjk_status==GJK::eStatus::Valid)
{
btVector3 w0=btVector3(0,0,0);
btVector3 w1=btVector3(0,0,0);
for(U i=0;i<gjk.m_simplex->rank;++i)
{
const btScalar p=gjk.m_simplex->p[i];
w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p;
w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p;
}
results.witnesses[0] = wtrs0*w0;
results.witnesses[1] = wtrs0*w1;
const btVector3 delta= results.witnesses[1]-
results.witnesses[0];
const btScalar margin= shape0->getMargin()+
shape1.getMargin();
const btScalar length= delta.length();
results.normal = delta/length;
results.witnesses[0] += results.normal*margin;
return(length-margin);
}
else
{
if(gjk_status==GJK::eStatus::Inside)
{
if(Penetration(shape0,wtrs0,&shape1,wtrs1,gjk.m_ray,results))
{
const btVector3 delta= results.witnesses[0]-
results.witnesses[1];
const btScalar length= delta.length();
if (length >= SIMD_EPSILON)
results.normal = delta/length;
return(-length);
}
}
}
return(SIMD_INFINITY);
}
//
bool btGjkEpaSolver2::SignedDistance(const btConvexShape* shape0,
const btTransform& wtrs0,
const btConvexShape* shape1,
const btTransform& wtrs1,
const btVector3& guess,
sResults& results)
{
if(!Distance(shape0,wtrs0,shape1,wtrs1,guess,results))
return(Penetration(shape0,wtrs0,shape1,wtrs1,guess,results,false));
else
return(true);
}
/* Symbols cleanup */
#undef GJK_MAX_ITERATIONS
#undef GJK_ACCURARY
#undef GJK_MIN_DISTANCE
#undef GJK_DUPLICATED_EPS
#undef GJK_SIMPLEX2_EPS
#undef GJK_SIMPLEX3_EPS
#undef GJK_SIMPLEX4_EPS
#undef EPA_MAX_VERTICES
#undef EPA_MAX_FACES
#undef EPA_MAX_ITERATIONS
#undef EPA_ACCURACY
#undef EPA_FALLBACK
#undef EPA_PLANE_EPS
#undef EPA_INSIDE_EPS

@ -0,0 +1,71 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be appreciated
but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
GJK-EPA collision solver by Nathanael Presson, 2008
*/
#ifndef _68DA1F85_90B7_4bb0_A705_83B4040A75C6_
#define _68DA1F85_90B7_4bb0_A705_83B4040A75C6_
#include "BulletCollision/CollisionShapes/btConvexShape.h"
///btGjkEpaSolver contributed under zlib by Nathanael Presson
struct btGjkEpaSolver2
{
struct sResults
{
enum eStatus
{
Separated, /* Shapes doesnt penetrate */
Penetrating, /* Shapes are penetrating */
GJK_Failed, /* GJK phase fail, no big issue, shapes are probably just 'touching' */
EPA_Failed /* EPA phase fail, bigger problem, need to save parameters, and debug */
} status;
btVector3 witnesses[2];
btVector3 normal;
btScalar distance;
};
static int StackSizeRequirement();
static bool Distance( const btConvexShape* shape0,const btTransform& wtrs0,
const btConvexShape* shape1,const btTransform& wtrs1,
const btVector3& guess,
sResults& results);
static bool Penetration(const btConvexShape* shape0,const btTransform& wtrs0,
const btConvexShape* shape1,const btTransform& wtrs1,
const btVector3& guess,
sResults& results,
bool usemargins=true);
static btScalar SignedDistance( const btVector3& position,
btScalar margin,
const btConvexShape* shape,
const btTransform& wtrs,
sResults& results);
static bool SignedDistance( const btConvexShape* shape0,const btTransform& wtrs0,
const btConvexShape* shape1,const btTransform& wtrs1,
const btVector3& guess,
sResults& results);
};
#endif

@ -0,0 +1,415 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
Added by Roman Ponomarev (rponom@gmail.com)
April 04, 2008
*/
//-----------------------------------------------------------------------------
#include "btSliderConstraint.h"
#include "BulletDynamics/Dynamics/btRigidBody.h"
#include "LinearMath/btTransformUtil.h"
#include <new>
//-----------------------------------------------------------------------------
void btSliderConstraint::initParams()
{
m_lowerLinLimit = btScalar(1.0);
m_upperLinLimit = btScalar(-1.0);
m_lowerAngLimit = btScalar(0.);
m_upperAngLimit = btScalar(0.);
m_softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
m_restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
m_dampingDirLin = btScalar(0.);
m_softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
m_restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
m_dampingDirAng = btScalar(0.);
m_softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
m_restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
m_dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING;
m_softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
m_restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
m_dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING;
m_softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
m_restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
m_dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING;
m_softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
m_restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
m_dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING;
m_poweredLinMotor = false;
m_targetLinMotorVelocity = btScalar(0.);
m_maxLinMotorForce = btScalar(0.);
m_accumulatedLinMotorImpulse = btScalar(0.0);
m_poweredAngMotor = false;
m_targetAngMotorVelocity = btScalar(0.);
m_maxAngMotorForce = btScalar(0.);
m_accumulatedAngMotorImpulse = btScalar(0.0);
} // btSliderConstraint::initParams()
//-----------------------------------------------------------------------------
btSliderConstraint::btSliderConstraint()
:btTypedConstraint(SLIDER_CONSTRAINT_TYPE),
m_useLinearReferenceFrameA(true)
{
initParams();
} // btSliderConstraint::btSliderConstraint()
//-----------------------------------------------------------------------------
btSliderConstraint::btSliderConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA)
: btTypedConstraint(SLIDER_CONSTRAINT_TYPE, rbA, rbB)
, m_frameInA(frameInA)
, m_frameInB(frameInB),
m_useLinearReferenceFrameA(useLinearReferenceFrameA)
{
initParams();
} // btSliderConstraint::btSliderConstraint()
//-----------------------------------------------------------------------------
void btSliderConstraint::buildJacobian()
{
if(m_useLinearReferenceFrameA)
{
buildJacobianInt(m_rbA, m_rbB, m_frameInA, m_frameInB);
}
else
{
buildJacobianInt(m_rbB, m_rbA, m_frameInB, m_frameInA);
}
} // btSliderConstraint::buildJacobian()
//-----------------------------------------------------------------------------
void btSliderConstraint::buildJacobianInt(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB)
{
//calculate transforms
m_calculatedTransformA = rbA.getCenterOfMassTransform() * frameInA;
m_calculatedTransformB = rbB.getCenterOfMassTransform() * frameInB;
m_realPivotAInW = m_calculatedTransformA.getOrigin();
m_realPivotBInW = m_calculatedTransformB.getOrigin();
m_sliderAxis = m_calculatedTransformA.getBasis().getColumn(0); // along X
m_delta = m_realPivotBInW - m_realPivotAInW;
m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;
m_relPosA = m_projPivotInW - rbA.getCenterOfMassPosition();
m_relPosB = m_realPivotBInW - rbB.getCenterOfMassPosition();
btVector3 normalWorld;
int i;
//linear part
for(i = 0; i < 3; i++)
{
normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
new (&m_jacLin[i]) btJacobianEntry(
rbA.getCenterOfMassTransform().getBasis().transpose(),
rbB.getCenterOfMassTransform().getBasis().transpose(),
m_relPosA,
m_relPosB,
normalWorld,
rbA.getInvInertiaDiagLocal(),
rbA.getInvMass(),
rbB.getInvInertiaDiagLocal(),
rbB.getInvMass()
);
m_jacLinDiagABInv[i] = btScalar(1.) / m_jacLin[i].getDiagonal();
m_depth[i] = m_delta.dot(normalWorld);
}
testLinLimits();
// angular part
for(i = 0; i < 3; i++)
{
normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
new (&m_jacAng[i]) btJacobianEntry(
normalWorld,
rbA.getCenterOfMassTransform().getBasis().transpose(),
rbB.getCenterOfMassTransform().getBasis().transpose(),
rbA.getInvInertiaDiagLocal(),
rbB.getInvInertiaDiagLocal()
);
}
testAngLimits();
btVector3 axisA = m_calculatedTransformA.getBasis().getColumn(0);
m_kAngle = btScalar(1.0 )/ (rbA.computeAngularImpulseDenominator(axisA) + rbB.computeAngularImpulseDenominator(axisA));
// clear accumulator for motors
m_accumulatedLinMotorImpulse = btScalar(0.0);
m_accumulatedAngMotorImpulse = btScalar(0.0);
} // btSliderConstraint::buildJacobianInt()
//-----------------------------------------------------------------------------
void btSliderConstraint::solveConstraint(btScalar timeStep)
{
m_timeStep = timeStep;
if(m_useLinearReferenceFrameA)
{
solveConstraintInt(m_rbA, m_rbB);
}
else
{
solveConstraintInt(m_rbB, m_rbA);
}
} // btSliderConstraint::solveConstraint()
//-----------------------------------------------------------------------------
void btSliderConstraint::solveConstraintInt(btRigidBody& rbA, btRigidBody& rbB)
{
int i;
// linear
btVector3 velA = rbA.getVelocityInLocalPoint(m_relPosA);
btVector3 velB = rbB.getVelocityInLocalPoint(m_relPosB);
btVector3 vel = velA - velB;
for(i = 0; i < 3; i++)
{
const btVector3& normal = m_jacLin[i].m_linearJointAxis;
btScalar rel_vel = normal.dot(vel);
// calculate positional error
btScalar depth = m_depth[i];
// get parameters
btScalar softness = (i) ? m_softnessOrthoLin : (m_solveLinLim ? m_softnessLimLin : m_softnessDirLin);
btScalar restitution = (i) ? m_restitutionOrthoLin : (m_solveLinLim ? m_restitutionLimLin : m_restitutionDirLin);
btScalar damping = (i) ? m_dampingOrthoLin : (m_solveLinLim ? m_dampingLimLin : m_dampingDirLin);
// calcutate and apply impulse
btScalar normalImpulse = softness * (restitution * depth / m_timeStep - damping * rel_vel) * m_jacLinDiagABInv[i];
btVector3 impulse_vector = normal * normalImpulse;
rbA.applyImpulse( impulse_vector, m_relPosA);
rbB.applyImpulse(-impulse_vector, m_relPosB);
if(m_poweredLinMotor && (!i))
{ // apply linear motor
if(m_accumulatedLinMotorImpulse < m_maxLinMotorForce)
{
btScalar desiredMotorVel = m_targetLinMotorVelocity;
btScalar motor_relvel = desiredMotorVel + rel_vel;
normalImpulse = -motor_relvel * m_jacLinDiagABInv[i];
// clamp accumulated impulse
btScalar new_acc = m_accumulatedLinMotorImpulse + btFabs(normalImpulse);
if(new_acc > m_maxLinMotorForce)
{
new_acc = m_maxLinMotorForce;
}
btScalar del = new_acc - m_accumulatedLinMotorImpulse;
if(normalImpulse < btScalar(0.0))
{
normalImpulse = -del;
}
else
{
normalImpulse = del;
}
m_accumulatedLinMotorImpulse = new_acc;
// apply clamped impulse
impulse_vector = normal * normalImpulse;
rbA.applyImpulse( impulse_vector, m_relPosA);
rbB.applyImpulse(-impulse_vector, m_relPosB);
}
}
}
// angular
// get axes in world space
btVector3 axisA = m_calculatedTransformA.getBasis().getColumn(0);
btVector3 axisB = m_calculatedTransformB.getBasis().getColumn(0);
const btVector3& angVelA = rbA.getAngularVelocity();
const btVector3& angVelB = rbB.getAngularVelocity();
btVector3 angVelAroundAxisA = axisA * axisA.dot(angVelA);
btVector3 angVelAroundAxisB = axisB * axisB.dot(angVelB);
btVector3 angAorthog = angVelA - angVelAroundAxisA;
btVector3 angBorthog = angVelB - angVelAroundAxisB;
btVector3 velrelOrthog = angAorthog-angBorthog;
//solve orthogonal angular velocity correction
btScalar len = velrelOrthog.length();
if (len > btScalar(0.00001))
{
btVector3 normal = velrelOrthog.normalized();
btScalar denom = rbA.computeAngularImpulseDenominator(normal) + rbB.computeAngularImpulseDenominator(normal);
velrelOrthog *= (btScalar(1.)/denom) * m_dampingOrthoAng * m_softnessOrthoAng;
}
//solve angular positional correction
btVector3 angularError = axisA.cross(axisB) *(btScalar(1.)/m_timeStep);
btScalar len2 = angularError.length();
if (len2>btScalar(0.00001))
{
btVector3 normal2 = angularError.normalized();
btScalar denom2 = rbA.computeAngularImpulseDenominator(normal2) + rbB.computeAngularImpulseDenominator(normal2);
angularError *= (btScalar(1.)/denom2) * m_restitutionOrthoAng * m_softnessOrthoAng;
}
// apply impulse
rbA.applyTorqueImpulse(-velrelOrthog+angularError);
rbB.applyTorqueImpulse(velrelOrthog-angularError);
btScalar impulseMag;
//solve angular limits
if(m_solveAngLim)
{
impulseMag = (angVelB - angVelA).dot(axisA) * m_dampingLimAng + m_angDepth * m_restitutionLimAng / m_timeStep;
impulseMag *= m_kAngle * m_softnessLimAng;
}
else
{
impulseMag = (angVelB - angVelA).dot(axisA) * m_dampingDirAng + m_angDepth * m_restitutionDirAng / m_timeStep;
impulseMag *= m_kAngle * m_softnessDirAng;
}
btVector3 impulse = axisA * impulseMag;
rbA.applyTorqueImpulse(impulse);
rbB.applyTorqueImpulse(-impulse);
//apply angular motor
if(m_poweredAngMotor)
{
if(m_accumulatedAngMotorImpulse < m_maxAngMotorForce)
{
btVector3 velrel = angVelAroundAxisA - angVelAroundAxisB;
btScalar projRelVel = velrel.dot(axisA);
btScalar desiredMotorVel = m_targetAngMotorVelocity;
btScalar motor_relvel = desiredMotorVel - projRelVel;
btScalar angImpulse = m_kAngle * motor_relvel;
// clamp accumulated impulse
btScalar new_acc = m_accumulatedAngMotorImpulse + btFabs(angImpulse);
if(new_acc > m_maxAngMotorForce)
{
new_acc = m_maxAngMotorForce;
}
btScalar del = new_acc - m_accumulatedAngMotorImpulse;
if(angImpulse < btScalar(0.0))
{
angImpulse = -del;
}
else
{
angImpulse = del;
}
m_accumulatedAngMotorImpulse = new_acc;
// apply clamped impulse
btVector3 motorImp = angImpulse * axisA;
m_rbA.applyTorqueImpulse(motorImp);
m_rbB.applyTorqueImpulse(-motorImp);
}
}
} // btSliderConstraint::solveConstraint()
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void btSliderConstraint::calculateTransforms(void){
if(m_useLinearReferenceFrameA)
{
m_calculatedTransformA = m_rbA.getCenterOfMassTransform() * m_frameInA;
m_calculatedTransformB = m_rbB.getCenterOfMassTransform() * m_frameInB;
}
else
{
m_calculatedTransformA = m_rbB.getCenterOfMassTransform() * m_frameInB;
m_calculatedTransformB = m_rbA.getCenterOfMassTransform() * m_frameInA;
}
m_realPivotAInW = m_calculatedTransformA.getOrigin();
m_realPivotBInW = m_calculatedTransformB.getOrigin();
m_sliderAxis = m_calculatedTransformA.getBasis().getColumn(0); // along X
m_delta = m_realPivotBInW - m_realPivotAInW;
m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;
btVector3 normalWorld;
int i;
//linear part
for(i = 0; i < 3; i++)
{
normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
m_depth[i] = m_delta.dot(normalWorld);
}
} // btSliderConstraint::calculateTransforms()
//-----------------------------------------------------------------------------
void btSliderConstraint::testLinLimits(void)
{
m_solveLinLim = false;
m_linPos = m_depth[0];
if(m_lowerLinLimit <= m_upperLinLimit)
{
if(m_depth[0] > m_upperLinLimit)
{
m_depth[0] -= m_upperLinLimit;
m_solveLinLim = true;
}
else if(m_depth[0] < m_lowerLinLimit)
{
m_depth[0] -= m_lowerLinLimit;
m_solveLinLim = true;
}
else
{
m_depth[0] = btScalar(0.);
}
}
else
{
m_depth[0] = btScalar(0.);
}
} // btSliderConstraint::testLinLimits()
//-----------------------------------------------------------------------------
void btSliderConstraint::testAngLimits(void)
{
m_angDepth = btScalar(0.);
m_solveAngLim = false;
if(m_lowerAngLimit <= m_upperAngLimit)
{
const btVector3 axisA0 = m_calculatedTransformA.getBasis().getColumn(1);
const btVector3 axisA1 = m_calculatedTransformA.getBasis().getColumn(2);
const btVector3 axisB0 = m_calculatedTransformB.getBasis().getColumn(1);
btScalar rot = btAtan2Fast(axisB0.dot(axisA1), axisB0.dot(axisA0));
if(rot < m_lowerAngLimit)
{
m_angDepth = rot - m_lowerAngLimit;
m_solveAngLim = true;
}
else if(rot > m_upperAngLimit)
{
m_angDepth = rot - m_upperAngLimit;
m_solveAngLim = true;
}
}
} // btSliderConstraint::testAngLimits()
//-----------------------------------------------------------------------------
btVector3 btSliderConstraint::getAncorInA(void)
{
btVector3 ancorInA;
ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * btScalar(0.5) * m_sliderAxis;
ancorInA = m_rbA.getCenterOfMassTransform().inverse() * ancorInA;
return ancorInA;
} // btSliderConstraint::getAncorInA()
//-----------------------------------------------------------------------------
btVector3 btSliderConstraint::getAncorInB(void)
{
btVector3 ancorInB;
ancorInB = m_frameInB.getOrigin();
return ancorInB;
} // btSliderConstraint::getAncorInB();

@ -0,0 +1,218 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
Added by Roman Ponomarev (rponom@gmail.com)
April 04, 2008
TODO:
- add clamping od accumulated impulse to improve stability
- add conversion for ODE constraint solver
*/
#ifndef SLIDER_CONSTRAINT_H
#define SLIDER_CONSTRAINT_H
//-----------------------------------------------------------------------------
#include "LinearMath/btVector3.h"
#include "btJacobianEntry.h"
#include "btTypedConstraint.h"
//-----------------------------------------------------------------------------
class btRigidBody;
//-----------------------------------------------------------------------------
#define SLIDER_CONSTRAINT_DEF_SOFTNESS (btScalar(1.0))
#define SLIDER_CONSTRAINT_DEF_DAMPING (btScalar(1.0))
#define SLIDER_CONSTRAINT_DEF_RESTITUTION (btScalar(0.7))
//-----------------------------------------------------------------------------
class btSliderConstraint : public btTypedConstraint
{
protected:
btTransform m_frameInA;
btTransform m_frameInB;
// use frameA fo define limits, if true
bool m_useLinearReferenceFrameA;
// linear limits
btScalar m_lowerLinLimit;
btScalar m_upperLinLimit;
// angular limits
btScalar m_lowerAngLimit;
btScalar m_upperAngLimit;
// softness, restitution and damping for different cases
// DirLin - moving inside linear limits
// LimLin - hitting linear limit
// DirAng - moving inside angular limits
// LimAng - hitting angular limit
// OrthoLin, OrthoAng - against constraint axis
btScalar m_softnessDirLin;
btScalar m_restitutionDirLin;
btScalar m_dampingDirLin;
btScalar m_softnessDirAng;
btScalar m_restitutionDirAng;
btScalar m_dampingDirAng;
btScalar m_softnessLimLin;
btScalar m_restitutionLimLin;
btScalar m_dampingLimLin;
btScalar m_softnessLimAng;
btScalar m_restitutionLimAng;
btScalar m_dampingLimAng;
btScalar m_softnessOrthoLin;
btScalar m_restitutionOrthoLin;
btScalar m_dampingOrthoLin;
btScalar m_softnessOrthoAng;
btScalar m_restitutionOrthoAng;
btScalar m_dampingOrthoAng;
// for interlal use
bool m_solveLinLim;
bool m_solveAngLim;
btJacobianEntry m_jacLin[3];
btScalar m_jacLinDiagABInv[3];
btJacobianEntry m_jacAng[3];
btScalar m_timeStep;
btTransform m_calculatedTransformA;
btTransform m_calculatedTransformB;
btVector3 m_sliderAxis;
btVector3 m_realPivotAInW;
btVector3 m_realPivotBInW;
btVector3 m_projPivotInW;
btVector3 m_delta;
btVector3 m_depth;
btVector3 m_relPosA;
btVector3 m_relPosB;
btScalar m_linPos;
btScalar m_angDepth;
btScalar m_kAngle;
bool m_poweredLinMotor;
btScalar m_targetLinMotorVelocity;
btScalar m_maxLinMotorForce;
btScalar m_accumulatedLinMotorImpulse;
bool m_poweredAngMotor;
btScalar m_targetAngMotorVelocity;
btScalar m_maxAngMotorForce;
btScalar m_accumulatedAngMotorImpulse;
//------------------------
void initParams();
public:
// constructors
btSliderConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA);
btSliderConstraint();
// overrides
virtual void buildJacobian();
virtual void solveConstraint(btScalar timeStep);
// access
const btRigidBody& getRigidBodyA() const { return m_rbA; }
const btRigidBody& getRigidBodyB() const { return m_rbB; }
const btTransform & getCalculatedTransformA() const { return m_calculatedTransformA; }
const btTransform & getCalculatedTransformB() const { return m_calculatedTransformB; }
const btTransform & getFrameOffsetA() const { return m_frameInA; }
const btTransform & getFrameOffsetB() const { return m_frameInB; }
btTransform & getFrameOffsetA() { return m_frameInA; }
btTransform & getFrameOffsetB() { return m_frameInB; }
btScalar getLowerLinLimit() { return m_lowerLinLimit; }
void setLowerLinLimit(btScalar lowerLimit) { m_lowerLinLimit = lowerLimit; }
btScalar getUpperLinLimit() { return m_upperLinLimit; }
void setUpperLinLimit(btScalar upperLimit) { m_upperLinLimit = upperLimit; }
btScalar getLowerAngLimit() { return m_lowerAngLimit; }
void setLowerAngLimit(btScalar lowerLimit) { m_lowerAngLimit = lowerLimit; }
btScalar getUpperAngLimit() { return m_upperAngLimit; }
void setUpperAngLimit(btScalar upperLimit) { m_upperAngLimit = upperLimit; }
bool getUseLinearReferenceFrameA() { return m_useLinearReferenceFrameA; }
btScalar getSoftnessDirLin() { return m_softnessDirLin; }
btScalar getRestitutionDirLin() { return m_restitutionDirLin; }
btScalar getDampingDirLin() { return m_dampingDirLin ; }
btScalar getSoftnessDirAng() { return m_softnessDirAng; }
btScalar getRestitutionDirAng() { return m_restitutionDirAng; }
btScalar getDampingDirAng() { return m_dampingDirAng; }
btScalar getSoftnessLimLin() { return m_softnessLimLin; }
btScalar getRestitutionLimLin() { return m_restitutionLimLin; }
btScalar getDampingLimLin() { return m_dampingLimLin; }
btScalar getSoftnessLimAng() { return m_softnessLimAng; }
btScalar getRestitutionLimAng() { return m_restitutionLimAng; }
btScalar getDampingLimAng() { return m_dampingLimAng; }
btScalar getSoftnessOrthoLin() { return m_softnessOrthoLin; }
btScalar getRestitutionOrthoLin() { return m_restitutionOrthoLin; }
btScalar getDampingOrthoLin() { return m_dampingOrthoLin; }
btScalar getSoftnessOrthoAng() { return m_softnessOrthoAng; }
btScalar getRestitutionOrthoAng() { return m_restitutionOrthoAng; }
btScalar getDampingOrthoAng() { return m_dampingOrthoAng; }
void setSoftnessDirLin(btScalar softnessDirLin) { m_softnessDirLin = softnessDirLin; }
void setRestitutionDirLin(btScalar restitutionDirLin) { m_restitutionDirLin = restitutionDirLin; }
void setDampingDirLin(btScalar dampingDirLin) { m_dampingDirLin = dampingDirLin; }
void setSoftnessDirAng(btScalar softnessDirAng) { m_softnessDirAng = softnessDirAng; }
void setRestitutionDirAng(btScalar restitutionDirAng) { m_restitutionDirAng = restitutionDirAng; }
void setDampingDirAng(btScalar dampingDirAng) { m_dampingDirAng = dampingDirAng; }
void setSoftnessLimLin(btScalar softnessLimLin) { m_softnessLimLin = softnessLimLin; }
void setRestitutionLimLin(btScalar restitutionLimLin) { m_restitutionLimLin = restitutionLimLin; }
void setDampingLimLin(btScalar dampingLimLin) { m_dampingLimLin = dampingLimLin; }
void setSoftnessLimAng(btScalar softnessLimAng) { m_softnessLimAng = softnessLimAng; }
void setRestitutionLimAng(btScalar restitutionLimAng) { m_restitutionLimAng = restitutionLimAng; }
void setDampingLimAng(btScalar dampingLimAng) { m_dampingLimAng = dampingLimAng; }
void setSoftnessOrthoLin(btScalar softnessOrthoLin) { m_softnessOrthoLin = softnessOrthoLin; }
void setRestitutionOrthoLin(btScalar restitutionOrthoLin) { m_restitutionOrthoLin = restitutionOrthoLin; }
void setDampingOrthoLin(btScalar dampingOrthoLin) { m_dampingOrthoLin = dampingOrthoLin; }
void setSoftnessOrthoAng(btScalar softnessOrthoAng) { m_softnessOrthoAng = softnessOrthoAng; }
void setRestitutionOrthoAng(btScalar restitutionOrthoAng) { m_restitutionOrthoAng = restitutionOrthoAng; }
void setDampingOrthoAng(btScalar dampingOrthoAng) { m_dampingOrthoAng = dampingOrthoAng; }
void setPoweredLinMotor(bool onOff) { m_poweredLinMotor = onOff; }
bool getPoweredLinMotor() { return m_poweredLinMotor; }
void setTargetLinMotorVelocity(btScalar targetLinMotorVelocity) { m_targetLinMotorVelocity = targetLinMotorVelocity; }
btScalar getTargetLinMotorVelocity() { return m_targetLinMotorVelocity; }
void setMaxLinMotorForce(btScalar maxLinMotorForce) { m_maxLinMotorForce = maxLinMotorForce; }
btScalar getMaxLinMotorForce() { return m_maxLinMotorForce; }
void setPoweredAngMotor(bool onOff) { m_poweredAngMotor = onOff; }
bool getPoweredAngMotor() { return m_poweredAngMotor; }
void setTargetAngMotorVelocity(btScalar targetAngMotorVelocity) { m_targetAngMotorVelocity = targetAngMotorVelocity; }
btScalar getTargetAngMotorVelocity() { return m_targetAngMotorVelocity; }
void setMaxAngMotorForce(btScalar maxAngMotorForce) { m_maxAngMotorForce = maxAngMotorForce; }
btScalar getMaxAngMotorForce() { return m_maxAngMotorForce; }
btScalar getLinearPos() { return m_linPos; }
// access for ODE solver
bool getSolveLinLimit() { return m_solveLinLim; }
btScalar getLinDepth() { return m_depth[0]; }
bool getSolveAngLimit() { return m_solveAngLim; }
btScalar getAngDepth() { return m_angDepth; }
// internal
void buildJacobianInt(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB);
void solveConstraintInt(btRigidBody& rbA, btRigidBody& rbB);
// shared code used by ODE solver
void calculateTransforms(void);
void testLinLimits(void);
void testAngLimits(void);
// access for PE Solver
btVector3 getAncorInA(void);
btVector3 getAncorInB(void);
};
//-----------------------------------------------------------------------------
#endif //SLIDER_CONSTRAINT_H

@ -0,0 +1,193 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btContinuousDynamicsWorld.h"
#include "LinearMath/btQuickprof.h"
//collision detection
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h"
#include "BulletCollision/CollisionShapes/btCollisionShape.h"
#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h"
//rigidbody & constraints
#include "BulletDynamics/Dynamics/btRigidBody.h"
#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h"
#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h"
#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
#include <stdio.h>
btContinuousDynamicsWorld::btContinuousDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration)
:btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration)
{
}
btContinuousDynamicsWorld::~btContinuousDynamicsWorld()
{
}
void btContinuousDynamicsWorld::internalSingleStepSimulation( btScalar timeStep)
{
startProfiling(timeStep);
///update aabbs information
updateAabbs();
//static int frame=0;
// printf("frame %d\n",frame++);
///apply gravity, predict motion
predictUnconstraintMotion(timeStep);
btDispatcherInfo& dispatchInfo = getDispatchInfo();
dispatchInfo.m_timeStep = timeStep;
dispatchInfo.m_stepCount = 0;
dispatchInfo.m_debugDraw = getDebugDrawer();
///perform collision detection
performDiscreteCollisionDetection();
calculateSimulationIslands();
getSolverInfo().m_timeStep = timeStep;
///solve contact and other joint constraints
solveConstraints(getSolverInfo());
///CallbackTriggers();
calculateTimeOfImpacts(timeStep);
btScalar toi = dispatchInfo.m_timeOfImpact;
// if (toi < 1.f)
// printf("toi = %f\n",toi);
if (toi < 0.f)
printf("toi = %f\n",toi);
///integrate transforms
integrateTransforms(timeStep * toi);
///update vehicle simulation
updateVehicles(timeStep);
updateActivationState( timeStep );
if(0 != m_internalTickCallback) {
(*m_internalTickCallback)(this, timeStep);
}
}
void btContinuousDynamicsWorld::calculateTimeOfImpacts(btScalar timeStep)
{
///these should be 'temporal' aabbs!
updateTemporalAabbs(timeStep);
///'toi' is the global smallest time of impact. However, we just calculate the time of impact for each object individually.
///so we handle the case moving versus static properly, and we cheat for moving versus moving
btScalar toi = 1.f;
btDispatcherInfo& dispatchInfo = getDispatchInfo();
dispatchInfo.m_timeStep = timeStep;
dispatchInfo.m_timeOfImpact = 1.f;
dispatchInfo.m_stepCount = 0;
dispatchInfo.m_dispatchFunc = btDispatcherInfo::DISPATCH_CONTINUOUS;
///calculate time of impact for overlapping pairs
btDispatcher* dispatcher = getDispatcher();
if (dispatcher)
dispatcher->dispatchAllCollisionPairs(m_broadphasePairCache->getOverlappingPairCache(),dispatchInfo,m_dispatcher1);
toi = dispatchInfo.m_timeOfImpact;
dispatchInfo.m_dispatchFunc = btDispatcherInfo::DISPATCH_DISCRETE;
}
void btContinuousDynamicsWorld::updateTemporalAabbs(btScalar timeStep)
{
btVector3 temporalAabbMin,temporalAabbMax;
for ( int i=0;i<m_collisionObjects.size();i++)
{
btCollisionObject* colObj = m_collisionObjects[i];
btRigidBody* body = btRigidBody::upcast(colObj);
if (body)
{
body->getCollisionShape()->getAabb(m_collisionObjects[i]->getWorldTransform(),temporalAabbMin,temporalAabbMax);
const btVector3& linvel = body->getLinearVelocity();
//make the AABB temporal
btScalar temporalAabbMaxx = temporalAabbMax.getX();
btScalar temporalAabbMaxy = temporalAabbMax.getY();
btScalar temporalAabbMaxz = temporalAabbMax.getZ();
btScalar temporalAabbMinx = temporalAabbMin.getX();
btScalar temporalAabbMiny = temporalAabbMin.getY();
btScalar temporalAabbMinz = temporalAabbMin.getZ();
// add linear motion
btVector3 linMotion = linvel*timeStep;
if (linMotion.x() > 0.f)
temporalAabbMaxx += linMotion.x();
else
temporalAabbMinx += linMotion.x();
if (linMotion.y() > 0.f)
temporalAabbMaxy += linMotion.y();
else
temporalAabbMiny += linMotion.y();
if (linMotion.z() > 0.f)
temporalAabbMaxz += linMotion.z();
else
temporalAabbMinz += linMotion.z();
//add conservative angular motion
btScalar angularMotion(0);// = angvel.length() * GetAngularMotionDisc() * timeStep;
btVector3 angularMotion3d(angularMotion,angularMotion,angularMotion);
temporalAabbMin = btVector3(temporalAabbMinx,temporalAabbMiny,temporalAabbMinz);
temporalAabbMax = btVector3(temporalAabbMaxx,temporalAabbMaxy,temporalAabbMaxz);
temporalAabbMin -= angularMotion3d;
temporalAabbMax += angularMotion3d;
m_broadphasePairCache->setAabb(body->getBroadphaseHandle(),temporalAabbMin,temporalAabbMax,m_dispatcher1);
}
}
//update aabb (of all moved objects)
m_broadphasePairCache->calculateOverlappingPairs(m_dispatcher1);
}

@ -0,0 +1,46 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_CONTINUOUS_DYNAMICS_WORLD_H
#define BT_CONTINUOUS_DYNAMICS_WORLD_H
#include "btDiscreteDynamicsWorld.h"
///btContinuousDynamicsWorld adds optional (per object) continuous collision detection for fast moving objects to the btDiscreteDynamicsWorld.
///This copes with fast moving objects that otherwise would tunnel/miss collisions.
///Under construction, don't use yet! Please use btDiscreteDynamicsWorld instead.
class btContinuousDynamicsWorld : public btDiscreteDynamicsWorld
{
void updateTemporalAabbs(btScalar timeStep);
public:
btContinuousDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration);
virtual ~btContinuousDynamicsWorld();
///time stepping with calculation of time of impact for selected fast moving objects
virtual void internalSingleStepSimulation( btScalar timeStep);
virtual void calculateTimeOfImpacts(btScalar timeStep);
virtual btDynamicsWorldType getWorldType() const
{
return BT_CONTINUOUS_DYNAMICS_WORLD;
}
};
#endif //BT_CONTINUOUS_DYNAMICS_WORLD_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,245 @@
/*
Stan Melax Convex Hull Computation
Copyright (c) 2008 Stan Melax http://www.melax.com/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///includes modifications/improvements by John Ratcliff, see BringOutYourDead below.
#ifndef CD_HULL_H
#define CD_HULL_H
#include "LinearMath/btVector3.h"
#include "LinearMath/btAlignedObjectArray.h"
typedef btAlignedObjectArray<unsigned int> TUIntArray;
class HullResult
{
public:
HullResult(void)
{
mPolygons = true;
mNumOutputVertices = 0;
mNumFaces = 0;
mNumIndices = 0;
}
bool mPolygons; // true if indices represents polygons, false indices are triangles
unsigned int mNumOutputVertices; // number of vertices in the output hull
btAlignedObjectArray<btVector3> m_OutputVertices; // array of vertices
unsigned int mNumFaces; // the number of faces produced
unsigned int mNumIndices; // the total number of indices
btAlignedObjectArray<unsigned int> m_Indices; // pointer to indices.
// If triangles, then indices are array indexes into the vertex list.
// If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc..
};
enum HullFlag
{
QF_TRIANGLES = (1<<0), // report results as triangles, not polygons.
QF_REVERSE_ORDER = (1<<1), // reverse order of the triangle indices.
QF_DEFAULT = QF_TRIANGLES
};
class HullDesc
{
public:
HullDesc(void)
{
mFlags = QF_DEFAULT;
mVcount = 0;
mVertices = 0;
mVertexStride = sizeof(btVector3);
mNormalEpsilon = 0.001f;
mMaxVertices = 4096; // maximum number of points to be considered for a convex hull.
mMaxFaces = 4096;
};
HullDesc(HullFlag flag,
unsigned int vcount,
const btVector3 *vertices,
unsigned int stride = sizeof(btVector3))
{
mFlags = flag;
mVcount = vcount;
mVertices = vertices;
mVertexStride = stride;
mNormalEpsilon = btScalar(0.001);
mMaxVertices = 4096;
}
bool HasHullFlag(HullFlag flag) const
{
if ( mFlags & flag ) return true;
return false;
}
void SetHullFlag(HullFlag flag)
{
mFlags|=flag;
}
void ClearHullFlag(HullFlag flag)
{
mFlags&=~flag;
}
unsigned int mFlags; // flags to use when generating the convex hull.
unsigned int mVcount; // number of vertices in the input point cloud
const btVector3 *mVertices; // the array of vertices.
unsigned int mVertexStride; // the stride of each vertex, in bytes.
btScalar mNormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on.
unsigned int mMaxVertices; // maximum number of vertices to be considered for the hull!
unsigned int mMaxFaces;
};
enum HullError
{
QE_OK, // success!
QE_FAIL // failed.
};
class btPlane
{
public:
btVector3 normal;
btScalar dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0
btPlane(const btVector3 &n,btScalar d):normal(n),dist(d){}
btPlane():normal(),dist(0){}
};
class ConvexH
{
public:
class HalfEdge
{
public:
short ea; // the other half of the edge (index into edges list)
unsigned char v; // the vertex at the start of this edge (index into vertices list)
unsigned char p; // the facet on which this edge lies (index into facets list)
HalfEdge(){}
HalfEdge(short _ea,unsigned char _v, unsigned char _p):ea(_ea),v(_v),p(_p){}
};
ConvexH()
{
int i;
i=0;
}
~ConvexH()
{
int i;
i=0;
}
btAlignedObjectArray<btVector3> vertices;
btAlignedObjectArray<HalfEdge> edges;
btAlignedObjectArray<btPlane> facets;
ConvexH(int vertices_size,int edges_size,int facets_size);
};
class int4
{
public:
int x,y,z,w;
int4(){};
int4(int _x,int _y, int _z,int _w){x=_x;y=_y;z=_z;w=_w;}
const int& operator[](int i) const {return (&x)[i];}
int& operator[](int i) {return (&x)[i];}
};
class PHullResult
{
public:
PHullResult(void)
{
mVcount = 0;
mIndexCount = 0;
mFaceCount = 0;
mVertices = 0;
}
unsigned int mVcount;
unsigned int mIndexCount;
unsigned int mFaceCount;
btVector3* mVertices;
TUIntArray m_Indices;
};
///The HullLibrary class can create a convex hull from a collection of vertices, using the ComputeHull method.
///The btShapeHull class uses this HullLibrary to create a approximate convex mesh given a general (non-polyhedral) convex shape.
class HullLibrary
{
btAlignedObjectArray<class Tri*> m_tris;
public:
btAlignedObjectArray<int> m_vertexIndexMapping;
HullError CreateConvexHull(const HullDesc& desc, // describes the input request
HullResult& result); // contains the resulst
HullError ReleaseResult(HullResult &result); // release memory allocated for this result, we are done with it.
private:
bool ComputeHull(unsigned int vcount,const btVector3 *vertices,PHullResult &result,unsigned int vlimit);
class Tri* allocateTriangle(int a,int b,int c);
void deAllocateTriangle(Tri*);
void b2bfix(Tri* s,Tri*t);
void removeb2b(Tri* s,Tri*t);
void checkit(Tri *t);
Tri* extrudable(btScalar epsilon);
int calchull(btVector3 *verts,int verts_count, TUIntArray& tris_out, int &tris_count,int vlimit);
int calchullgen(btVector3 *verts,int verts_count, int vlimit);
int4 FindSimplex(btVector3 *verts,int verts_count,btAlignedObjectArray<int> &allow);
class ConvexH* ConvexHCrop(ConvexH& convex,const btPlane& slice);
void extrude(class Tri* t0,int v);
ConvexH* test_cube();
//BringOutYourDead (John Ratcliff): When you create a convex hull you hand it a large input set of vertices forming a 'point cloud'.
//After the hull is generated it give you back a set of polygon faces which index the *original* point cloud.
//The thing is, often times, there are many 'dead vertices' in the point cloud that are on longer referenced by the hull.
//The routine 'BringOutYourDead' find only the referenced vertices, copies them to an new buffer, and re-indexes the hull so that it is a minimal representation.
void BringOutYourDead(const btVector3* verts,unsigned int vcount, btVector3* overts,unsigned int &ocount,unsigned int* indices,unsigned indexcount);
bool CleanupVertices(unsigned int svcount,
const btVector3* svertices,
unsigned int stride,
unsigned int &vcount, // output number of vertices
btVector3* vertices, // location to store the results.
btScalar normalepsilon,
btVector3& scale);
};
#endif

@ -0,0 +1,303 @@
#ifndef BT_HASH_MAP_H
#define BT_HASH_MAP_H
#include "btAlignedObjectArray.h"
const int BT_HASH_NULL=0xffffffff;
template <class Value>
class btHashKey
{
int m_uid;
public:
btHashKey(int uid)
:m_uid(uid)
{
}
int getUid() const
{
return m_uid;
}
//to our success
SIMD_FORCE_INLINE unsigned int getHash()const
{
int key = m_uid;
// Thomas Wang's hash
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
btHashKey getKey(const Value& value) const
{
return btHashKey(value.getUid());
}
};
template <class Value>
class btHashKeyPtr
{
int m_uid;
public:
btHashKeyPtr(int uid)
:m_uid(uid)
{
}
int getUid() const
{
return m_uid;
}
//to our success
SIMD_FORCE_INLINE unsigned int getHash()const
{
int key = m_uid;
// Thomas Wang's hash
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
btHashKeyPtr getKey(const Value& value) const
{
return btHashKeyPtr(value->getUid());
}
};
///The btHashMap template class implements a generic and lightweight hashmap.
///A basic sample of how to use btHashMap is located in Demos\BasicDemo\main.cpp
template <class Key, class Value>
class btHashMap
{
btAlignedObjectArray<int> m_hashTable;
btAlignedObjectArray<int> m_next;
btAlignedObjectArray<Value> m_valueArray;
void growTables(const Key& key)
{
int newCapacity = m_valueArray.capacity();
if (m_hashTable.size() < newCapacity)
{
//grow hashtable and next table
int curHashtableSize = m_hashTable.size();
m_hashTable.resize(newCapacity);
m_next.resize(newCapacity);
int i;
for (i= 0; i < newCapacity; ++i)
{
m_hashTable[i] = BT_HASH_NULL;
}
for (i = 0; i < newCapacity; ++i)
{
m_next[i] = BT_HASH_NULL;
}
for(i=0;i<curHashtableSize;i++)
{
const Value& value = m_valueArray[i];
int hashValue = key.getKey(value).getHash() & (m_valueArray.capacity()-1); // New hash value with new mask
m_next[i] = m_hashTable[hashValue];
m_hashTable[hashValue] = i;
}
}
}
public:
void insert(const Key& key, const Value& value) {
int hash = key.getHash() & (m_valueArray.capacity()-1);
//don't add it if it is already there
if (find(key))
{
return;
}
int count = m_valueArray.size();
int oldCapacity = m_valueArray.capacity();
m_valueArray.push_back(value);
int newCapacity = m_valueArray.capacity();
if (oldCapacity < newCapacity)
{
growTables(key);
//hash with new capacity
hash = key.getHash() & (m_valueArray.capacity()-1);
}
m_next[count] = m_hashTable[hash];
m_hashTable[hash] = count;
}
void remove(const Key& key) {
int hash = key.getHash() & (m_valueArray.capacity()-1);
int pairIndex = findIndex(key);
if (pairIndex ==BT_HASH_NULL)
{
return;
}
// Remove the pair from the hash table.
int index = m_hashTable[hash];
btAssert(index != BT_HASH_NULL);
int previous = BT_HASH_NULL;
while (index != pairIndex)
{
previous = index;
index = m_next[index];
}
if (previous != BT_HASH_NULL)
{
btAssert(m_next[previous] == pairIndex);
m_next[previous] = m_next[pairIndex];
}
else
{
m_hashTable[hash] = m_next[pairIndex];
}
// We now move the last pair into spot of the
// pair being removed. We need to fix the hash
// table indices to support the move.
int lastPairIndex = m_valueArray.size() - 1;
// If the removed pair is the last pair, we are done.
if (lastPairIndex == pairIndex)
{
m_valueArray.pop_back();
return;
}
// Remove the last pair from the hash table.
const Value* lastValue = &m_valueArray[lastPairIndex];
int lastHash = key.getKey(*lastValue).getHash() & (m_valueArray.capacity()-1);
index = m_hashTable[lastHash];
btAssert(index != BT_HASH_NULL);
previous = BT_HASH_NULL;
while (index != lastPairIndex)
{
previous = index;
index = m_next[index];
}
if (previous != BT_HASH_NULL)
{
btAssert(m_next[previous] == lastPairIndex);
m_next[previous] = m_next[lastPairIndex];
}
else
{
m_hashTable[lastHash] = m_next[lastPairIndex];
}
// Copy the last pair into the remove pair's spot.
m_valueArray[pairIndex] = m_valueArray[lastPairIndex];
// Insert the last pair into the hash table
m_next[pairIndex] = m_hashTable[lastHash];
m_hashTable[lastHash] = pairIndex;
m_valueArray.pop_back();
}
int size() const
{
return m_valueArray.size();
}
const Value* getAtIndex(int index) const
{
btAssert(index < m_valueArray.size());
return &m_valueArray[index];
}
Value* getAtIndex(int index)
{
btAssert(index < m_valueArray.size());
return &m_valueArray[index];
}
Value* operator[](const Key& key) {
return find(key);
}
const Value* find(const Key& key) const
{
int index = findIndex(key);
if (index == BT_HASH_NULL)
{
return NULL;
}
return &m_valueArray[index];
}
Value* find(const Key& key)
{
int index = findIndex(key);
if (index == BT_HASH_NULL)
{
return NULL;
}
return &m_valueArray[index];
}
int findIndex(const Key& key) const
{
int hash = key.getHash() & (m_valueArray.capacity()-1);
if (hash >= m_hashTable.size())
{
return BT_HASH_NULL;
}
int index = m_hashTable[hash];
while ((index != BT_HASH_NULL) && (key.getUid() == key.getKey(m_valueArray[index]).getUid()) == false)
{
index = m_next[index];
}
return index;
}
void clear()
{
m_hashTable.clear();
m_next.clear();
m_valueArray.clear();
}
};
#endif //BT_HASH_MAP_H

@ -0,0 +1,102 @@
/*
Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef _BT_POOL_ALLOCATOR_H
#define _BT_POOL_ALLOCATOR_H
#include "btScalar.h"
#include "btAlignedAllocator.h"
///The btPoolAllocator class allows to efficiently allocate a large pool of objects, instead of dynamically allocating them separately.
class btPoolAllocator
{
int m_elemSize;
int m_maxElements;
int m_freeCount;
void* m_firstFree;
unsigned char* m_pool;
public:
btPoolAllocator(int elemSize, int maxElements)
:m_elemSize(elemSize),
m_maxElements(maxElements)
{
m_pool = (unsigned char*) btAlignedAlloc( static_cast<unsigned int>(m_elemSize*m_maxElements),16);
unsigned char* p = m_pool;
m_firstFree = p;
m_freeCount = m_maxElements;
int count = m_maxElements;
while (--count) {
*(void**)p = (p + m_elemSize);
p += m_elemSize;
}
*(void**)p = 0;
}
~btPoolAllocator()
{
btAlignedFree( m_pool);
}
int getFreeCount() const
{
return m_freeCount;
}
void* allocate(int size)
{
// release mode fix
(void)size;
btAssert(!size || size<=m_elemSize);
btAssert(m_freeCount>0);
void* result = m_firstFree;
m_firstFree = *(void**)m_firstFree;
--m_freeCount;
return result;
}
bool validPtr(void* ptr)
{
if (ptr) {
if (((unsigned char*)ptr >= m_pool && (unsigned char*)ptr < m_pool + m_maxElements * m_elemSize))
{
return true;
}
}
return false;
}
void freeMemory(void* ptr)
{
if (ptr) {
btAssert((unsigned char*)ptr >= m_pool && (unsigned char*)ptr < m_pool + m_maxElements * m_elemSize);
*(void**)ptr = m_firstFree;
m_firstFree = ptr;
++m_freeCount;
}
}
int getElementSize() const
{
return m_elemSize;
}
};
#endif //_BT_POOL_ALLOCATOR_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,301 @@
// --------------------------------------------------------------------------
//
// El'Beem - the visual lattice boltzmann freesurface simulator
// All code distributed as part of El'Beem is covered by the version 2 of the
// GNU General Public License. See the file COPYING for details.
//
// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
//
// control particle classes
//
// --------------------------------------------------------------------------
#ifndef CONTROLPARTICLES_H
#define CONTROLPARTICLES_H
#include "ntl_geometrymodel.h"
// indicator for LBM inclusion
//#ifndef LBMDIM
//#include <NxFoundation.h>
//#include <vector>
//class MultisphGUI;
//#define NORMALIZE(a) a.normalize()
//#define MAGNITUDE(a) a.magnitude()
//#define CROSS(a,b,c) a.cross(b,c)
//#define ABS(a) (a>0. ? (a) : -(a))
//#include "cpdefines.h"
//#else // LBMDIM
// use compatibility defines
//#define NORMALIZE(a) normalize(a)
//#define MAGNITUDE(a) norm(a)
//#define CROSS(a,b,c) a=cross(b,c)
//#endif // LBMDIM
#define MAGNITUDE(a) norm(a)
// math.h compatibility
#define CP_PI ((LbmFloat)3.14159265358979323846)
// project 2d test cases onto plane?
// if not, 3d distance is used for 2d sim as well
#define CP_PROJECT2D 1
// default init for mincpdist, ControlForces::maxDistance
#define CPF_MAXDINIT 10000.
// storage of influence for a fluid cell/particle in lbm/sph
class ControlForces
{
public:
ControlForces() { };
~ControlForces() {};
// attraction force
LbmFloat weightAtt;
LbmVec forceAtt;
// velocity influence
LbmFloat weightVel;
LbmVec forceVel;
// maximal distance influence,
// first is max. distance to first control particle
// second attraction strength
LbmFloat maxDistance;
LbmVec forceMaxd;
LbmFloat compAvWeight;
LbmVec compAv;
void resetForces() {
weightAtt = weightVel = 0.;
maxDistance = CPF_MAXDINIT;
forceAtt = forceVel = forceMaxd = LbmVec(0.,0.,0.);
compAvWeight=0.; compAv=LbmVec(0.);
};
};
// single control particle
class ControlParticle
{
public:
ControlParticle() { reset(); };
~ControlParticle() {};
// control parameters
// position
LbmVec pos;
// size (influences influence radius)
LbmFloat size;
// overall strength of influence
LbmFloat influence;
// rotation axis
LbmVec rotaxis;
// computed values
// velocity
LbmVec vel;
// computed density
LbmFloat density;
LbmFloat densityWeight;
LbmVec avgVel;
LbmVec avgVelAcc;
LbmFloat avgVelWeight;
// init all zero / defaults
void reset();
};
// container for a particle configuration at time t
class ControlParticleSet
{
public:
// time of particle set
LbmFloat time;
// particle positions
std::vector<ControlParticle> particles;
};
// container & management of control particles
class ControlParticles
{
public:
ControlParticles();
~ControlParticles();
// reset datastructures for next influence step
// if motion object is given, particle 1 of second system is used for overall
// position and speed offset
void prepareControl(LbmFloat simtime, LbmFloat dt, ControlParticles *motion);
// post control operations
void finishControl(std::vector<ControlForces> &forces, LbmFloat iatt, LbmFloat ivel, LbmFloat imaxd);
// recalculate
void calculateKernelWeight();
// calculate forces at given position, and modify velocity
// according to timestep (from initControl)
void calculateCpInfluenceOpt (ControlParticle *cp, LbmVec fluidpos, LbmVec fluidvel, ControlForces *force, LbmFloat fillFactor);
void calculateMaxdForce (ControlParticle *cp, LbmVec fluidpos, ControlForces *force);
// no. of particles
inline int getSize() { return (int)_particles.size(); }
int getTotalSize();
// get particle [i]
inline ControlParticle* getParticle(int i){ return &_particles[i]; }
// set influence parameters
void setInfluenceTangential(LbmFloat set) { _influenceTangential=set; }
void setInfluenceAttraction(LbmFloat set) { _influenceAttraction=set; }
void setInfluenceMaxdist(LbmFloat set) { _influenceMaxdist=set; }
// calculate for delta t
void setInfluenceVelocity(LbmFloat set, LbmFloat dt);
// get influence parameters
inline LbmFloat getInfluenceAttraction() { return _influenceAttraction; }
inline LbmFloat getInfluenceTangential() { return _influenceTangential; }
inline LbmFloat getInfluenceVelocity() { return _influenceVelocity; }
inline LbmFloat getInfluenceMaxdist() { return _influenceMaxdist; }
inline LbmFloat getCurrTimestep() { return _currTimestep; }
void setRadiusAtt(LbmFloat set) { _radiusAtt=set; }
inline LbmFloat getRadiusAtt() { return _radiusAtt; }
void setRadiusVel(LbmFloat set) { _radiusVel=set; }
inline LbmFloat getRadiusVel() { return _radiusVel; }
void setRadiusMaxd(LbmFloat set) { _radiusMaxd=set; }
inline LbmFloat getRadiusMaxd() { return _radiusMaxd; }
void setRadiusMinMaxd(LbmFloat set) { _radiusMinMaxd=set; }
inline LbmFloat getRadiusMinMaxd() { return _radiusMinMaxd; }
LbmFloat getControlTimStart();
LbmFloat getControlTimEnd();
// set/get characteristic length (and inverse)
void setCharLength(LbmFloat set) { _charLength=set; _charLengthInv=1./_charLength; }
inline LbmFloat getCharLength() { return _charLength;}
inline LbmFloat getCharLengthInv() { return _charLengthInv;}
// set init parameters
void setInitTimeScale(LbmFloat set) { _initTimeScale = set; };
void setInitMirror(string set) { _initMirror = set; };
string getInitMirror() { return _initMirror; };
void setLastOffset(LbmVec set) { _initLastPartOffset = set; };
void setLastScale(LbmVec set) { _initLastPartScale = set; };
void setOffset(LbmVec set) { _initPartOffset = set; };
void setScale(LbmVec set) { _initPartScale = set; };
// set/get cps params
void setCPSWith(LbmFloat set) { mCPSWidth = set; };
void setCPSTimestep(LbmFloat set) { mCPSTimestep = set; };
void setCPSTimeStart(LbmFloat set) { mCPSTimeStart = set; };
void setCPSTimeEnd(LbmFloat set) { mCPSTimeEnd = set; };
void setCPSMvmWeightFac(LbmFloat set) { mCPSWeightFac = set; };
LbmFloat getCPSWith() { return mCPSWidth; };
LbmFloat getCPSTimestep() { return mCPSTimestep; };
LbmFloat getCPSTimeStart() { return mCPSTimeStart; };
LbmFloat getCPSTimeEnd() { return mCPSTimeEnd; };
LbmFloat getCPSMvmWeightFac() { return mCPSWeightFac; };
void setDebugInit(int set) { mDebugInit = set; };
// set init parameters
void setFluidSpacing(LbmFloat set) { _fluidSpacing = set; };
// load positions & timing from text file
int initFromTextFile(string filename);
int initFromTextFileOld(string filename);
// load positions & timing from gzipped binary file
int initFromBinaryFile(string filename);
int initFromMVCMesh(string filename);
// init an example test case
int initExampleSet();
// init for a given time
void initTime(LbmFloat t, LbmFloat dt);
// blender test init
void initBlenderTest();
int initFromObject(ntlGeometryObjModel *model);
protected:
// sets influence params
friend class MultisphGUI;
// tangential and attraction influence
LbmFloat _influenceTangential, _influenceAttraction;
// direct velocity influence
LbmFloat _influenceVelocity;
// maximal distance influence
LbmFloat _influenceMaxdist;
// influence radii
LbmFloat _radiusAtt, _radiusVel, _radiusMinMaxd, _radiusMaxd;
// currently valid time & timestep
LbmFloat _currTime, _currTimestep;
// all particles
std::vector<ControlParticle> _particles;
// particle sets
std::vector<ControlParticleSet> mPartSets;
// additional parameters for initing particles
LbmFloat _initTimeScale;
LbmVec _initPartOffset;
LbmVec _initPartScale;
LbmVec _initLastPartOffset;
LbmVec _initLastPartScale;
// mirror particles for loading?
string _initMirror;
// row spacing paramter, e.g. use for approximation of kernel area/volume
LbmFloat _fluidSpacing;
// save current kernel weight
LbmFloat _kernelWeight;
// charateristic length in world coordinates for normalizatioon of forces
LbmFloat _charLength, _charLengthInv;
/*! do ani mesh CPS */
void calculateCPS(string filename);
//! ani mesh cps params
ntlVec3Gfx mvCPSStart, mvCPSEnd;
gfxReal mCPSWidth, mCPSTimestep;
gfxReal mCPSTimeStart, mCPSTimeEnd;
gfxReal mCPSWeightFac;
int mDebugInit;
protected:
// apply init transformations
void applyTrafos();
// helper function for init -> swap components everywhere
void swapCoords(int a,int b);
// helper function for init -> mirror time
void mirrorTime();
// helper, init given array
void initTimeArray(LbmFloat t, std::vector<ControlParticle> &parts);
bool checkPointInside(ntlTree *tree, ntlVec3Gfx org, gfxReal &distance);
};
#endif

@ -0,0 +1,25 @@
/******************************************************************************
*
* El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
* All code distributed as part of El'Beem is covered by the version 2 of the
* GNU General Public License. See the file COPYING for details.
* Copyright 2003-2006 Nils Thuerey
*
* Control API header
*/
#include "elbeem.h"
#include "elbeem_control.h"
// add mesh as fluidsim object
int elbeemControlAddSet(struct elbeemControl*) {
return 0;
}
int elbeemControlComputeMesh(struct elbeemMesh*) {
return 0;
}

@ -0,0 +1,62 @@
/******************************************************************************
*
* El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
* All code distributed as part of El'Beem is covered by the version 2 of the
* GNU General Public License. See the file COPYING for details.
* Copyright 2003-2006 Nils Thuerey
*
* Control API header
*/
#ifndef ELBEEMCONTROL_API_H
#define ELBEEMCONTROL_API_H
// a single control particle set
typedef struct elbeemControl {
/* influence forces */
float influenceAttraction;
float *channelInfluenceAttraction;
float channelSizeInfluenceAttraction;
float influenceVelocity;
float *channelInfluenceVelocity;
float channelSizeInfluenceVelocity;
float influenceMaxdist;
float *channelInfluenceMaxdist;
float channelSizeInfluenceMaxdist;
/* influence force radii */
float radiusAttraction;
float *channelRadiusAttraction;
float channelSizeRadiusAttraction;
float radiusVelocity;
float *channelRadiusVelocity;
float channelSizeRadiusVelocity;
float radiusMindist;
float *channelRadiusMindist;
float channelSizeRadiusMindist;
float radiusMaxdist;
float *channelRadiusMaxdist;
float channelSizeRadiusMaxdist;
/* control particle positions/scale */
float offset[3];
float *channelOffset;
float channelSizeOffset;
float scale[3];
float *channelScale;
float channelSizeScale;
} elbeemControl;
// add mesh as fluidsim object
int elbeemControlAddSet(struct elbeemControl*);
// sample & track mesh control particles, TODO add return type...
int elbeemControlComputeMesh(struct elbeemMesh*);
#endif // ELBEEMCONTROL_API_H

@ -0,0 +1,193 @@
/******************************************************************************
*
// El'Beem - the visual lattice boltzmann freesurface simulator
// All code distributed as part of El'Beem is covered by the version 2 of the
// GNU General Public License. See the file COPYING for details.
//
// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
//
*
* Mean Value Mesh Coords class
*
*****************************************************************************/
#include "mvmcoords.h"
#include <algorithm>
using std::vector;
void MeanValueMeshCoords::clear()
{
mVertices.resize(0);
mNumVerts = 0;
}
void MeanValueMeshCoords::calculateMVMCs(vector<ntlVec3Gfx> &reference_vertices, vector<ntlTriangle> &tris,
vector<ntlVec3Gfx> &points, gfxReal numweights)
{
clear();
mvmTransferPoint tds;
int mem = 0;
int i = 0;
mNumVerts = (int)reference_vertices.size();
for (vector<ntlVec3Gfx>::iterator iter = points.begin(); iter != points.end(); ++iter, ++i) {
/*
if(i%(points.size()/10)==1) debMsgStd("MeanValueMeshCoords::calculateMVMCs",DM_MSG,"Computing weights, points: "<<i<<"/"<<points.size(),5 );
*/
tds.lastpos = *iter;
tds.weights.resize(0); // clear
computeWeights(reference_vertices, tris, tds, numweights);
mem += (int)tds.weights.size();
mVertices.push_back(tds);
}
int mbmem = mem * sizeof(mvmFloat) / (1024*1024);
debMsgStd("MeanValueMeshCoords::calculateMVMCs",DM_MSG,"vertices:"<<mNumVerts<<" points:"<<points.size()<<" weights:"<<mem<<", wmem:"<<mbmem<<"MB ",7 );
}
// from: mean value coordinates for closed triangular meshes
// attention: fails if a point is exactly (or very close) to a vertex
void MeanValueMeshCoords::computeWeights(vector<ntlVec3Gfx> &reference_vertices, vector<ntlTriangle>& tris,
mvmTransferPoint& tds, gfxReal numweights)
{
const bool mvmFullDebug=false;
//const ntlVec3Gfx cEPS = 1.0e-6;
const mvmFloat cEPS = 1.0e-14;
//mvmFloat d[3], s[3], phi[3],c[3];
ntlVec3d u[3],c,d,s,phi;
int indices[3];
for (int i = 0; i < (int)reference_vertices.size(); ++i) {
tds.weights.push_back(mvmIndexWeight(i, 0.0));
}
// for each triangle
//for (vector<ntlTriangle>::iterator iter = tris.begin(); iter != tris.end();) {
for(int t=0; t<(int)tris.size(); t++) {
for (int i = 0; i < 3; ++i) { //, ++iter) {
indices[i] = tris[t].getPoints()[i];
u[i] = vec2D(reference_vertices[ indices[i] ]-tds.lastpos);
d[i] = normalize(u[i]); //.normalize();
//assert(d[i] != 0.);
if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","t"<<t<<" i"<<indices[i] //<<" lp"<<tds.lastpos
<<" v"<<reference_vertices[indices[i]]<<" u"<<u[i]<<" ");
// on vertex!
//? if(d[i]<=0.) continue;
}
//for (int i = 0; i < 3; ++i) { errMsg("III"," "<<i <<" i"<<indices[i]<<reference_vertices[ indices[i] ] ); }
// arcsin is not needed, see paper
phi[0] = 2.*asin( (mvmFloat)(0.5* norm(u[1]-u[2]) ) );
phi[1] = 2.*asin( (mvmFloat)(0.5* norm(u[0]-u[2]) ) );
phi[2] = 2.*asin( (mvmFloat)(0.5* norm(u[0]-u[1]) ) );
mvmFloat h = (phi[0] + phi[1] + phi[2])*0.5;
if (M_PI-h < cEPS) {
if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","point on triangle");
tds.weights.resize(0);
tds.weights.push_back( mvmIndexWeight(indices[0], sin(phi[0])*d[1]*d[2]));
tds.weights.push_back( mvmIndexWeight(indices[1], sin(phi[1])*d[0]*d[2]));
tds.weights.push_back( mvmIndexWeight(indices[2], sin(phi[2])*d[1]*d[0]));
break;
}
mvmFloat sinh = 2.*sin(h);
c[0] = (sinh*sin(h-phi[0]))/(sin(phi[1])*sin(phi[2]))-1.;
c[1] = (sinh*sin(h-phi[1]))/(sin(phi[0])*sin(phi[2]))-1.;
c[2] = (sinh*sin(h-phi[2]))/(sin(phi[0])*sin(phi[1]))-1.;
if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","c="<<c<<" phi="<<phi<<" d="<<d);
//if (c[0] > 1. || c[0] < 0. || c[1] > 1. || c[1] < 0. || c[2] > 1. || c[2] < 0.) continue;
s[0] = sqrtf((float)(1.-c[0]*c[0]));
s[1] = sqrtf((float)(1.-c[1]*c[1]));
s[2] = sqrtf((float)(1.-c[2]*c[2]));
if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","s");
if (s[0] <= cEPS || s[1] <= cEPS || s[2] <= cEPS) {
//MSG("position lies outside the triangle on the same plane -> ignore it");
continue;
}
const mvmFloat u0x = u[0][0];
const mvmFloat u0y = u[0][1];
const mvmFloat u0z = u[0][2];
const mvmFloat u1x = u[1][0];
const mvmFloat u1y = u[1][1];
const mvmFloat u1z = u[1][2];
const mvmFloat u2x = u[2][0];
const mvmFloat u2y = u[2][1];
const mvmFloat u2z = u[2][2];
mvmFloat det = u0x*u1y*u2z - u0x*u1z*u2y + u0y*u1z*u2x - u0y*u1x*u2z + u0z*u1x*u2y - u0z*u1y*u2x;
//assert(det != 0.);
if (det < 0.) {
s[0] = -s[0];
s[1] = -s[1];
s[2] = -s[2];
}
tds.weights[indices[0]].weight += (phi[0]-c[1]*phi[2]-c[2]*phi[1])/(d[0]*sin(phi[1])*s[2]);
tds.weights[indices[1]].weight += (phi[1]-c[2]*phi[0]-c[0]*phi[2])/(d[1]*sin(phi[2])*s[0]);
tds.weights[indices[2]].weight += (phi[2]-c[0]*phi[1]-c[1]*phi[0])/(d[2]*sin(phi[0])*s[1]);
if(mvmFullDebug) { errMsg("MeanValueMeshCoords::computeWeights","i"<<indices[0]<<" o"<<tds.weights[indices[0]].weight);
errMsg("MeanValueMeshCoords::computeWeights","i"<<indices[1]<<" o"<<tds.weights[indices[1]].weight);
errMsg("MeanValueMeshCoords::computeWeights","i"<<indices[2]<<" o"<<tds.weights[indices[2]].weight);
errMsg("MeanValueMeshCoords::computeWeights","\n\n\n"); }
}
//sort weights
if((numweights>0.)&& (numweights<1.) ) {
//if( ((int)tds.weights.size() > maxNumWeights) && (maxNumWeights > 0) ) {
int maxNumWeights = (int)(tds.weights.size()*numweights);
if(maxNumWeights<=0) maxNumWeights = 1;
std::sort(tds.weights.begin(), tds.weights.end(), std::greater<mvmIndexWeight>());
// only use maxNumWeights-th largest weights
tds.weights.resize(maxNumWeights);
}
// normalize weights
mvmFloat totalWeight = 0.;
for (vector<mvmIndexWeight>::const_iterator witer = tds.weights.begin();
witer != tds.weights.end(); ++witer) {
totalWeight += witer->weight;
}
mvmFloat invTotalWeight;
if (totalWeight == 0.) {
if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","totalWeight == 0");
invTotalWeight = 0.0;
} else {
invTotalWeight = 1.0/totalWeight;
}
for (vector<mvmIndexWeight>::iterator viter = tds.weights.begin();
viter != tds.weights.end(); ++viter) {
viter->weight *= invTotalWeight;
//assert(finite(viter->weight) != 0);
if(!finite(viter->weight)) viter->weight=0.;
}
}
void MeanValueMeshCoords::transfer(vector<ntlVec3Gfx> &vertices, vector<ntlVec3Gfx>& displacements)
{
displacements.resize(0);
//debMsgStd("MeanValueMeshCoords::transfer",DM_MSG,"vertices:"<<mNumVerts<<" curr_verts:"<<vertices.size()<<" ",7 );
if((int)vertices.size() != mNumVerts) {
errMsg("MeanValueMeshCoords::transfer","Different no of verts: "<<vertices.size()<<" vs "<<mNumVerts);
return;
}
for (vector<mvmTransferPoint>::iterator titer = mVertices.begin(); titer != mVertices.end(); ++titer) {
mvmTransferPoint &tds = *titer;
ntlVec3Gfx newpos(0.0);
for (vector<mvmIndexWeight>::iterator witer = tds.weights.begin();
witer != tds.weights.end(); ++witer) {
newpos += vertices[witer->index] * witer->weight;
//errMsg("transfer","np"<<newpos<<" v"<<vertices[witer->index]<<" w"<< witer->weight);
}
displacements.push_back(newpos);
//displacements.push_back(newpos - tds.lastpos);
//tds.lastpos = newpos;
}
}

@ -0,0 +1,89 @@
/******************************************************************************
*
// El'Beem - the visual lattice boltzmann freesurface simulator
// All code distributed as part of El'Beem is covered by the version 2 of the
// GNU General Public License. See the file COPYING for details.
//
// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
//
*
* Mean Value Mesh Coords class
*
*****************************************************************************/
#ifndef MVMCOORDS_H
#define MVMCOORDS_H
#include "utilities.h"
#include "ntl_ray.h"
#include <vector>
#define mvmFloat double
#ifdef WIN32
#ifndef FREE_WINDOWS
#include "float.h"
#define isnan(n) _isnan(n)
#define finite _finite
#endif
#endif
#ifdef sun
#include "ieeefp.h"
#endif
// weight and triangle index
class mvmIndexWeight {
public:
mvmIndexWeight() : weight(0.0) {}
mvmIndexWeight(int const& i, mvmFloat const& w) :
weight(w), index(i) {}
// for sorting
bool operator> (mvmIndexWeight const& w) const { return this->weight > w.weight; }
bool operator< (mvmIndexWeight const& w) const { return this->weight < w.weight; }
mvmFloat weight;
int index;
};
// transfer point with weights
class mvmTransferPoint {
public:
//! position of transfer point
ntlVec3Gfx lastpos;
//! triangle weights
std::vector<mvmIndexWeight> weights;
};
//! compute mvmcs
class MeanValueMeshCoords {
public:
MeanValueMeshCoords() {}
~MeanValueMeshCoords() {
clear();
}
void clear();
void calculateMVMCs(std::vector<ntlVec3Gfx> &reference_vertices,
std::vector<ntlTriangle> &tris, std::vector<ntlVec3Gfx> &points, gfxReal numweights);
void transfer(std::vector<ntlVec3Gfx> &vertices, std::vector<ntlVec3Gfx>& displacements);
protected:
void computeWeights(std::vector<ntlVec3Gfx> &reference_vertices,
std::vector<ntlTriangle> &tris, mvmTransferPoint& tds, gfxReal numweights);
std::vector<mvmTransferPoint> mVertices;
int mNumVerts;
};
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,182 @@
/******************************************************************************
*
* El'Beem - the visual lattice boltzmann freesurface simulator
* All code distributed as part of El'Beem is covered by the version 2 of the
* GNU General Public License. See the file COPYING for details.
* Copyright 2003-2006 Nils Thuerey
*
* testing extensions
*
*****************************************************************************/
#ifndef LBM_TESTCLASS_H
#define LBM_TESTCLASS_H
//class IsoSurface;
class ParticleObject;
class ControlParticles;
class ControlForces;
//#define NUMGRIDS 2
//#define MAXNUMSWS 10
// farfield modes
#define FARF_3DONLY -1
#define FARF_BOTH 0
#define FARF_SWEONLY 1
// dont reuse 3d vars/init
#define FARF_SEPSWE 2
// relaxation macros for solver_relax.h
// WARNING has to match controlparts.h
#define CPF_ENTRIES 12
#define CPF_FORCE 0
#define CPF_VELWEIGHT 3
#define CPF_VELOCITY 4
#define CPF_FORCEWEIGHT 7
#define CPF_MINCPDIST 8
#define CPF_MINCPDIR 9
#include "controlparticles.h"
#include "ntl_geometrymodel.h"
// get force entry, set=0 is unused anyway
#define LBMGET_FORCE(lev, i,j,k) mpControl->mCpForces[lev][ (LBMGI(lev,i,j,k,0)) ]
// debug mods off...
// same as in src/solver_relax.h!
#define __PRECOLLIDE_MODS(rho,ux,uy,uz, grav) \
ux += (grav)[0]; \
uy += (grav)[1]; \
uz += (grav)[2];
//void testMaxdmod(int i, int j,int k, LbmFloat &ux,LbmFloat &uy,LbmFloat &uz,ControlForces &ff);
#if LBMDIM==3
#define MAXDGRAV \
if(myforce->forceMaxd[0]*ux+myforce->forceMaxd[1]*uy<LBM_EPSILON) { \
ux = v2w*myforce->forceVel[0]+ v2wi*ux; \
uy = v2w*myforce->forceVel[1]+ v2wi*uy; } \
/* movement inverse to g? */ \
if((uz>LBM_EPSILON)&&(uz>myforce->forceVel[2])) { \
uz = v2w*myforce->forceVel[2]+ v2wi*uz; }
#else // LBMDIM==3
#define MAXDGRAV \
if(myforce->forceMaxd[0]*ux<LBM_EPSILON) { \
ux = v2w*myforce->forceVel[0]+ v2wi*ux; } \
/* movement inverse to g? */ \
if((uy>LBM_EPSILON)&&(uy>myforce->forceVel[1])) { \
uy = v2w*myforce->forceVel[1]+ v2wi*uy; }
#endif // LBMDIM==3
// debug modifications of collide vars (testing)
// requires: lev,i,j,k
#define PRECOLLIDE_MODS(rho,ux,uy,uz, grav) \
LbmFloat attforce = 1.; \
if(this->mTForceStrength>0.) { \
ControlForces* myforce = &LBMGET_FORCE(lev,i,j,k); \
const LbmFloat vf = myforce->weightAtt;\
const LbmFloat vw = myforce->weightVel;\
if(vf!=0.) { attforce = MAX(0., 1.-vf); /* TODO FIXME? use ABS(vf) for repulsion force? */ \
ux += myforce->forceAtt[0]; \
uy += myforce->forceAtt[1]; \
uz += myforce->forceAtt[2]; \
\
} else if(( myforce->maxDistance>0.) && ( myforce->maxDistance<CPF_MAXDINIT)) {\
const LbmFloat v2w = mpControl->mCons[0]->mCparts->getInfluenceMaxdist() * \
(myforce->maxDistance-mpControl->mCons[0]->mCparts->getRadiusMinMaxd()) / (mpControl->mCons[0]->mCparts->getRadiusMaxd()-mpControl->mCons[0]->mCparts->getRadiusMinMaxd()); \
const LbmFloat v2wi = 1.-v2w; \
if(v2w>0.){ MAXDGRAV; \
/* errMsg("ERRMDTT","at "<<PRINT_IJK<<" maxd="<<myforce->maxDistance<<", newu"<<PRINT_VEC(ux,uy,uz)<<", org"<<PRINT_VEC(oux,ouy,ouz)<<", fv"<<myforce->forceVel<<" " ); */ \
}\
} \
if(vw>0.) { \
const LbmFloat vwi = 1.-vw;\
const LbmFloat vwd = mpControl->mDiffVelCon;\
ux += vw*(myforce->forceVel[0]-myforce->compAv[0] + vwd*(myforce->compAv[0]-ux) ); \
uy += vw*(myforce->forceVel[1]-myforce->compAv[1] + vwd*(myforce->compAv[1]-uy) ); \
uz += vw*(myforce->forceVel[2]-myforce->compAv[2] + vwd*(myforce->compAv[2]-uz) ); \
/* TODO test!? modify smooth vel by influence of force for each lbm step, to account for force update only each N steps */ \
myforce->compAv = (myforce->forceVel*vw+ myforce->compAv*vwi); \
} \
} \
ux += (grav)[0]*attforce; \
uy += (grav)[1]*attforce; \
uz += (grav)[2]*attforce; \
/* end PRECOLLIDE_MODS */
#define TEST_IF_CHECK \
if((!iffilled)&&(LBMGET_FORCE(lev,i,j,k).weightAtt!=0.)) { \
errMsg("TESTIFFILL"," at "<<PRINT_IJK<<" "<<mass<<" "<<rho); \
iffilled = true; \
if(mass<rho*1.0) mass = rho*1.0; myfrac = 1.0; \
}
// a single set of control particles and params
class LbmControlSet {
public:
LbmControlSet();
~LbmControlSet();
void initCparts();
// control particles
ControlParticles *mCparts;
// control particle overall motion (for easier manual generation)
ControlParticles *mCpmotion;
// cp data file
string mContrPartFile;
string mCpmotionFile;
// cp debug displau
LbmFloat mDebugCpscale, mDebugVelScale, mDebugCompavScale, mDebugAttScale, mDebugMaxdScale, mDebugAvgVelScale;
// params
AnimChannel<float> mcForceAtt;
AnimChannel<float> mcForceVel;
AnimChannel<float> mcForceMaxd;
AnimChannel<float> mcRadiusAtt;
AnimChannel<float> mcRadiusVel;
AnimChannel<float> mcRadiusMind;
AnimChannel<float> mcRadiusMaxd;
AnimChannel<ntlVec3f> mcCpScale;
AnimChannel<ntlVec3f> mcCpOffset;
};
// main control data storage
class LbmControlData
{
public:
LbmControlData();
virtual ~LbmControlData();
// control data
// contorl params
void parseControldataAttrList(AttributeList *attr);
// control strength, set for solver interface
LbmFloat mSetForceStrength;
// cp vars
std::vector<LbmControlSet*> mCons;
// update interval
int mCpUpdateInterval;
// output
string mCpOutfile;
// control particle precomputed influence
std::vector< std::vector<ControlForces> > mCpForces;
std::vector<ControlForces> mCpKernel;
std::vector<ControlForces> mMdKernel;
// activate differential velcon
LbmFloat mDiffVelCon;
// cp debug displau
LbmFloat mDebugCpscale, mDebugVelScale, mDebugCompavScale, mDebugAttScale, mDebugMaxdScale, mDebugAvgVelScale;
};
#endif // LBM_TESTCLASS_H

@ -151,7 +151,7 @@ void *mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset)
} }
/* munmap for windows */ /* munmap for windows */
long munmap(void *ptr, long size) intptr_t munmap(void *ptr, intptr_t size)
{ {
MemMap *mm = mmap_findlink(mmapbase, ptr); MemMap *mm = mmap_findlink(mmapbase, ptr);
if (!mm) { if (!mm) {

@ -45,7 +45,10 @@
#define MAP_FAILED ((void *)-1) #define MAP_FAILED ((void *)-1)
void *mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset); #include "BLO_sys_types.h" // needed for intptr_t
long munmap(void *ptr, long size);
void *mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset);
intptr_t munmap(void *ptr, intptr_t size);
#endif
#endif

@ -118,7 +118,6 @@ install: package
ifneq ($(OS), darwin) ifneq ($(OS), darwin)
@[ ! -d $(OCGDIR)/bin/.blender ] || \ @[ ! -d $(OCGDIR)/bin/.blender ] || \
cp -r $(OCGDIR)/bin/.blender $(DISTDIR) cp -r $(OCGDIR)/bin/.blender $(DISTDIR)
@rm -rf $(DISTDIR)/.svn $(DISTDIR)/*/.svn $(DISTDIR)/*/*/.svn
@cp $(NANBLENDERHOME)/bin/.blender/.Blanguages $(CONFDIR) @cp $(NANBLENDERHOME)/bin/.blender/.Blanguages $(CONFDIR)
@cp $(NANBLENDERHOME)/bin/.blender/.bfont.ttf $(CONFDIR) @cp $(NANBLENDERHOME)/bin/.blender/.bfont.ttf $(CONFDIR)
endif endif
@ -144,8 +143,7 @@ ifneq ($(NOPLUGINS),true)
@cp ../source/blender/blenpluginapi/*.h $(DISTDIR)/plugins/include/ @cp ../source/blender/blenpluginapi/*.h $(DISTDIR)/plugins/include/
@chmod 755 $(DISTDIR)/plugins/bmake @chmod 755 $(DISTDIR)/plugins/bmake
@$(MAKE) -C $(DISTDIR)/plugins all > /dev/null || exit 1; @$(MAKE) -C $(DISTDIR)/plugins all > /dev/null || exit 1;
@rm -fr $(DISTDIR)/plugins/.svn $(DISTDIR)/plugins/*/.svn \ @rm -f $(DISTDIR)/plugins/*/*.o
$(DISTDIR)/plugins/*/*.o
#on OS X the plugins move to the installation directory #on OS X the plugins move to the installation directory
ifneq ($(OS),darwin) ifneq ($(OS),darwin)
@ -158,7 +156,6 @@ endif
@echo "----> Copy python infrastructure" @echo "----> Copy python infrastructure"
@[ ! -d scripts ] || cp -r scripts $(CONFDIR)/scripts @[ ! -d scripts ] || cp -r scripts $(CONFDIR)/scripts
@[ ! -d $(CONFDIR)/scripts ] || rm -fr $(CONFDIR)/scripts/.svn $(CONFDIR)/scripts/*/.svn $(CONFDIR)/scripts/*/*/.svn
ifeq ($(OS),darwin) ifeq ($(OS),darwin)
@echo "----> Move .blender to .app/Contents/MacOS/" @echo "----> Move .blender to .app/Contents/MacOS/"
@ -180,6 +177,8 @@ endif
@[ ! -x $(CONFIG_GUESS)/specific.sh ] || (\ @[ ! -x $(CONFIG_GUESS)/specific.sh ] || (\
echo "**--> Execute specific.sh in $(CONFIG_GUESS)/" && \ echo "**--> Execute specific.sh in $(CONFIG_GUESS)/" && \
cd $(CONFIG_GUESS) && ./specific.sh ) cd $(CONFIG_GUESS) && ./specific.sh )
@echo "----> Cleaning .svn metadata directories"
@find $(DISTDIR) -type d -name ".svn" | xargs rm -fr
pkg: install pkg: install
@echo "----> Create distribution file $(BLENDNAME)$(EXT1)" @echo "----> Create distribution file $(BLENDNAME)$(EXT1)"

@ -68,11 +68,7 @@ def add_mesh_simple(name, verts, edges, faces):
else: else:
# Mesh with no data, unlikely # Mesh with no data, unlikely
me.edges.extend(edges) me.edges.extend(edges)
me.faces.extend(faces) me.faces.extend(faces)
if is_editmode or Blender.Get('add_editmode'):
EditMode(1)
else: else:
# Object mode add new # Object mode add new
@ -95,9 +91,14 @@ def add_mesh_simple(name, verts, edges, faces):
ob_act.setMatrix(mat) ob_act.setMatrix(mat)
ob_act.loc = cursor ob_act.loc = cursor
if is_editmode or Blender.Get('add_editmode'): me.calcNormals()
EditMode(1)
if is_editmode or Blender.Get('add_editmode'):
EditMode(1)
def write_mesh_script(filepath, me): def write_mesh_script(filepath, me):
@ -112,7 +113,7 @@ def write_mesh_script(filepath, me):
file.write('#!BPY\n') file.write('#!BPY\n')
file.write('"""\n') file.write('"""\n')
file.write('Name: \'%s\'\n' % name) file.write('Name: \'%s\'\n' % name)
file.write('Blender: 243\n') file.write('Blender: 245\n')
file.write('Group: \'AddMesh\'\n') file.write('Group: \'AddMesh\'\n')
file.write('"""\n\n') file.write('"""\n\n')
file.write('import BPyAddMesh\n') file.write('import BPyAddMesh\n')

@ -0,0 +1,479 @@
#!BPY
"""
Name: 'MilkShape3D ASCII (.txt)...'
Blender: 245
Group: 'Import'
Tooltip: 'Import from a MilkShape3D ASCII file format (.txt)'
"""
#
# Author: Markus Ilmola
# Email: markus.ilmola@pp.inet.fi
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# import needed stuff
import os.path
import re
import math
from math import *
import Blender
from Blender import Mathutils
from Blender.Mathutils import *
# Converts ms3d euler angles to a rotation matrix
def RM(a):
sy = sin(a[2])
cy = cos(a[2])
sp = sin(a[1])
cp = cos(a[1])
sr = sin(a[0])
cr = cos(a[0])
return Matrix([cp*cy, cp*sy, -sp], [sr*sp*cy+cr*-sy, sr*sp*sy+cr*cy, sr*cp],[cr*sp*cy+-sr*-sy, cr*sp*sy+-sr*cy, cr*cp])
# Converts ms3d euler angles to a quaternion
def RQ(a):
angle = a[2] * 0.5;
sy = sin(angle);
cy = cos(angle);
angle = a[1] * 0.5;
sp = sin(angle);
cp = cos(angle);
angle = a[0] * 0.5;
sr = sin(angle);
cr = cos(angle);
return Quaternion(cr*cp*cy+sr*sp*sy, sr*cp*cy-cr*sp*sy, cr*sp*cy+sr*cp*sy, cr*cp*sy-sr*sp*cy)
# takes a texture filename and tries to load it
def loadImage(path, filename):
image = None
try:
image = Blender.Image.Load(os.path.abspath(filename))
except IOError:
print "Warning: Failed to load image: " + filename + ". Trying short path instead...\n"
try:
image = Blender.Image.Load(os.path.dirname(path) + "/" + os.path.basename(filename))
except IOError:
print "Warning: Failed to load image: " + os.path.basename(filename) + "!\n"
return image
# returns the next non-empty, non-comment line from the file
def getNextLine(file):
ready = False
while ready==False:
line = file.readline()
if len(line)==0:
print "Warning: End of file reached."
return line
ready = True
line = line.strip()
if len(line)==0 or line.isspace():
ready = False
if len(line)>=2 and line[0]=='/' and line[1]=='/':
ready = False
return line
# imports a MilkShape3D ascii file to the current scene
def import_ms3d_ascii(path):
# limits
MAX_NUMMESHES = 1000
MAX_NUMVERTS = 100000
MAX_NUMNORMALS = 100000
MAX_NUMTRIS = 100000
MAX_NUMMATS = 16
MAX_NUMBONES = 100
MAX_NUMPOSKEYS = 1000
MAX_NUMROTKEYS = 1000
# get scene
scn = Blender.Scene.GetCurrent()
if scn==None:
return "No scene to import to!"
# open the file
try:
file = open(path, 'r')
except IOError:
return "Failed to open the file!"
# Read frame info
try:
lines = getNextLine(file).split()
if len(lines) != 2 or lines[0] != "Frames:":
raise ValueError
lines = getNextLine(file).split()
if len(lines) != 2 or lines[0] != "Frame:":
raise ValueError
except ValueError:
return "Frame information is invalid!"
# Create the mesh
meshOb = Blender.Object.New('Mesh', "MilkShape3D Object")
mesh = Blender.Mesh.New("MilkShape3D Mesh")
meshOb.link(mesh)
scn.objects.link(meshOb)
# read the number of meshes
try:
lines = getNextLine(file).split()
if len(lines)!=2 or lines[0]!="Meshes:":
raise ValueError
numMeshes = int(lines[1])
if numMeshes < 0 or numMeshes > MAX_NUMMESHES:
raise ValueError
except ValueError:
return "Number of meshes is invalid!"
# read meshes
vertBase = 0
faceBase = 0
boneIds = []
for i in range(numMeshes):
# read name, flags and material
try:
lines = re.findall(r'\".*\"|[^ ]+', getNextLine(file))
if len(lines)!=3:
raise ValueError
material = int(lines[2])
except ValueError:
return "Name, flags or material in mesh " + str(i+1) + " are invalid!"
# read the number of vertices
try:
numVerts = int(getNextLine(file))
if numVerts < 0 or numVerts > MAX_NUMVERTS:
raise ValueError
except ValueError:
return "Number of vertices in mesh " + str(i+1) + " is invalid!"
# read vertices
coords = []
uvs = []
for j in xrange(numVerts):
try:
lines = getNextLine(file).split()
if len(lines)!=7:
raise ValueError
coords.append([float(lines[1]), float(lines[2]), float(lines[3])])
uvs.append([float(lines[4]), 1-float(lines[5])])
boneIds.append(int(lines[6]))
except ValueError:
return "Vertex " + str(j+1) + " in mesh " + str(i+1) + " is invalid!"
mesh.verts.extend(coords)
# read number of normals
try:
numNormals = int(getNextLine(file))
if numNormals < 0 or numNormals > MAX_NUMNORMALS:
raise ValueError
except ValueError:
return "Number of normals in mesh " + str(i+1) + " is invalid!"
# read normals
normals = []
for j in xrange(numNormals):
try:
lines = getNextLine(file).split()
if len(lines)!=3:
raise ValueError
normals.append([float(lines[0]), float(lines[1]), float(lines[2])])
except ValueError:
return "Normal " + str(j+1) + " in mesh " + str(i+1) + " is invalid!"
# read the number of triangles
try:
numTris = int(getNextLine(file))
if numTris < 0 or numTris > MAX_NUMTRIS:
raise ValueError
except ValueError:
return "Number of triangles in mesh " + str(i+1) + " is invalid!"
# read triangles
faces = []
for j in xrange(numTris):
# read the triangle
try:
lines = getNextLine(file).split()
if len(lines)!=8:
raise ValueError
v1 = int(lines[1])
v2 = int(lines[2])
v3 = int(lines[3])
faces.append([v1+vertBase, v2+vertBase, v3+vertBase])
except ValueError:
return "Triangle " + str(j+1) + " in mesh " + str(i+1) + " is invalid!"
mesh.faces.extend(faces)
# set texture coordinates and material
for j in xrange(faceBase, len(mesh.faces)):
face = mesh.faces[j]
face.uv = [Vector(uvs[face.verts[0].index-vertBase]), Vector(uvs[face.verts[1].index-vertBase]), Vector(uvs[face.verts[2].index-vertBase])]
if material>=0:
face.mat = material
# increase vertex and face base
vertBase = len(mesh.verts)
faceBase = len(mesh.faces)
# read the number of materials
try:
lines = getNextLine(file).split()
if len(lines)!=2 or lines[0]!="Materials:":
raise ValueError
numMats = int(lines[1])
if numMats < 0 or numMats > MAX_NUMMATS:
raise ValueError
except ValueError:
return "Number of materials is invalid!"
# read the materials
for i in range(numMats):
# read name
name = getNextLine(file)[1:-1]
# create the material
mat = Blender.Material.New(name)
mesh.materials += [mat]
# read ambient color
try:
lines = getNextLine(file).split()
if len(lines)!=4:
raise ValueError
amb = (float(lines[0])+float(lines[1])+float(lines[2]))/3
mat.setAmb(amb)
except ValueError:
return "Ambient color in material " + str(i+1) + " is invalid!"
# read diffuse color
try:
lines = getNextLine(file).split()
if len(lines)!=4:
raise ValueError
mat.setRGBCol([float(lines[0]), float(lines[1]), float(lines[2])])
except ValueError:
return "Diffuse color in material " + str(i+1) + " is invalid!"
# read specular color
try:
lines = getNextLine(file).split()
if len(lines)!=4:
raise ValueError
mat.setSpecCol([float(lines[0]), float(lines[1]), float(lines[2])])
except ValueError:
return "Specular color in material " + str(i+1) + " is invalid!"
# read emissive color
try:
lines = getNextLine(file).split()
if len(lines)!=4:
raise ValueError
emit = (float(lines[0])+float(lines[1])+float(lines[2]))/3
mat.setEmit(emit)
except ValueError:
return "Emissive color in material " + str(i+1) + " is invalid!"
# read shininess
try:
shi = float(getNextLine(file))
#mat.setHardness(int(shi))
except ValueError:
return "Shininess in material " + str(i+1) + " is invalid!"
# read transparency
try:
alpha = float(getNextLine(file))
mat.setAlpha(alpha)
if alpha < 1:
mat.mode |= Blender.Material.Modes.ZTRANSP
except ValueError:
return "Transparency in material " + str(i+1) + " is invalid!"
# read texturemap
texturemap = getNextLine(file)[1:-1]
if len(texturemap)>0:
colorTexture = Blender.Texture.New(name + "_texture")
colorTexture.setType('Image')
colorTexture.setImage(loadImage(path, texturemap))
mat.setTexture(0, colorTexture, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL)
# read alphamap
alphamap = getNextLine(file)[1:-1]
if len(alphamap)>0:
alphaTexture = Blender.Texture.New(name + "_alpha")
alphaTexture.setType('Image')
alphaTexture.setImage(loadImage(path, alphamap))
mat.setTexture(1, alphaTexture, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.ALPHA)
# read the number of bones
try:
lines = getNextLine(file).split()
if len(lines)!=2 or lines[0]!="Bones:":
raise ValueError
numBones = int(lines[1])
if numBones < 0 or numBones > MAX_NUMBONES:
raise ValueError
except:
return "Number of bones is invalid!"
# create the armature
armature = None
armOb = None
if numBones > 0:
armOb = Blender.Object.New('Armature', "MilkShape3D Skeleton")
armature = Blender.Armature.New("MilkShape3D Skeleton")
armature.drawType = Blender.Armature.STICK
armOb.link(armature)
scn.objects.link(armOb)
armOb.makeParentDeform([meshOb])
armature.makeEditable()
# read bones
posKeys = {}
rotKeys = {}
for i in range(numBones):
# read name
name = getNextLine(file)[1:-1]
# create the bone
bone = Blender.Armature.Editbone()
armature.bones[name] = bone
# read parent
parent = getNextLine(file)[1:-1]
if len(parent)>0:
bone.parent = armature.bones[parent]
# read position and rotation
try:
lines = getNextLine(file).split()
if len(lines) != 7:
raise ValueError
pos = [float(lines[1]), float(lines[2]), float(lines[3])]
rot = [float(lines[4]), float(lines[5]), float(lines[6])]
except ValueError:
return "Invalid position or orientation in a bone!"
# set position and orientation
if bone.hasParent():
bone.head = Vector(pos) * bone.parent.matrix + bone.parent.head
bone.tail = bone.head + Vector([1,0,0])
tempM = RM(rot) * bone.parent.matrix
tempM.transpose;
bone.matrix = tempM
else:
bone.head = Vector(pos)
bone.tail = bone.head + Vector([1,0,0])
bone.matrix = RM(rot)
# Create vertex group for this bone
mesh.addVertGroup(name)
vgroup = []
for index, v in enumerate(boneIds):
if v==i:
vgroup.append(index)
mesh.assignVertsToGroup(name, vgroup, 1.0, 1)
# read the number of position key frames
try:
numPosKeys = int(getNextLine(file))
if numPosKeys < 0 or numPosKeys > MAX_NUMPOSKEYS:
raise ValueError
except ValueError:
return "Invalid number of position key frames!"
# read position key frames
posKeys[name] = []
for j in range(numPosKeys):
# read time and position
try:
lines = getNextLine(file).split()
if len(lines) != 4:
raise ValueError
time = float(lines[0])
pos = [float(lines[1]), float(lines[2]), float(lines[3])]
posKeys[name].append([time, pos])
except ValueError:
return "Invalid position key frame!"
# read the number of rotation key frames
try:
numRotKeys = int(getNextLine(file))
if numRotKeys < 0 or numRotKeys > MAX_NUMROTKEYS:
raise ValueError
except ValueError:
return "Invalid number of rotation key frames!"
# read rotation key frames
rotKeys[name] = []
for j in range(numRotKeys):
# read time and rotation
try:
lines = getNextLine(file).split()
if len(lines) != 4:
raise ValueError
time = float(lines[0])
rot = [float(lines[1]), float(lines[2]), float(lines[3])]
rotKeys[name].append([time, rot])
except ValueError:
return "Invalid rotation key frame!"
# create action and pose
action = None
pose = None
if armature != None:
armature.update()
pose = armOb.getPose()
action = armOb.getAction()
if not action:
action = Blender.Armature.NLA.NewAction()
action.setActive(armOb)
# create animation key frames
for name, pbone in pose.bones.items():
# create position keys
for key in posKeys[name]:
pbone.loc = Vector(key[1])
pbone.insertKey(armOb, int(key[0]+0.5), Blender.Object.Pose.LOC, True)
# create rotation keys
for key in rotKeys[name]:
pbone.quat = RQ(key[1])
pbone.insertKey(armOb, int(key[0]+0.5), Blender.Object.Pose.ROT, True)
# set the imported object to be the selected one
scn.objects.selected = []
meshOb.sel= 1
Blender.Redraw()
# The import was a succes!
return ""
# load the model
def fileCallback(filename):
error = import_ms3d_ascii(filename)
if error!="":
Blender.Draw.PupMenu("An error occured during import: " + error + "|Not all data might have been imported succesfully.", 2)
Blender.Window.FileSelector(fileCallback, 'Import')

@ -0,0 +1,93 @@
#!BPY
"""
Name: 'GameLogic Example'
Blender: 245
Group: 'ScriptTemplate'
Tooltip: 'Script template with examples of how to use game logic'
"""
from Blender import Window
import bpy
script_data = \
'''
# GameLogic has been added to the global namespace no need to import
# for keyboard event comparison
# import GameKeys
# support for Vector(), Matrix() types and advanced functions like AngleBetweenVecs(v1,v2) and RotationMatrix(...)
# import Mathutils
# for functions like getWindowWidth(), getWindowHeight()
# import Rasterizer
def main():
cont = GameLogic.getCurrentController()
# The KX_GameObject that owns this controller.
own = cont.getOwner()
# for scripts that deal with spacial logic
own_pos = own.getPosition()
# Some example functions, remove to write your own script.
# check for a positive sensor, will run on any object without errors.
print 'Logic info for KX_GameObject', own.getName()
input = False
for sens in cont.getSensors():
# The sensor can be on another object, we may want to use it
own_sens = sens.getOwner()
print ' sensor:', sens.getName(),
if sens.isPositive():
print '(true)'
input = True
else:
print '(false)'
for actu in cont.getActuators():
# The actuator can be on another object, we may want to use it
own_actu = actu.getOwner()
print ' actuator:', sens.getName()
# This runs the actuator or turns it off
# note that actuators will continue to run unless explicitly turned off.
if input:
GameLogic.addActiveActuator(actu, True)
else:
GameLogic.addActiveActuator(actu, False)
# Its also good practice to get sensors and actuators by names
# so any changes to their order wont break the script.
# sens_key = cont.getSensor('key_sensor')
# actu_motion = cont.getActuator('motion')
# Loop through all other objects in the scene
sce = GameLogic.getCurrentScene()
print 'Scene Objects:', sce.getName()
for ob in sce.getObjectList():
print ' ', ob.getName(), ob.getPosition()
# Example where collision objects are checked for their properties
# adding to our objects "life" property
"""
actu_collide = cont.getSensor('collision_sens')
for ob in actu_collide.getHitObjectList():
# Check to see the object has this property
if hasattr(ob, 'life'):
own.life += ob.life
ob.life = 0
print own.life
"""
main()
'''
new_text = bpy.data.texts.new('gamelogic_example.py')
new_text.write(script_data)
bpy.data.texts.active = new_text
Window.RedrawAll()

@ -0,0 +1,33 @@
#!BPY
"""
Name: 'GameLogic Template'
Blender: 245
Group: 'ScriptTemplate'
Tooltip: 'Basic template for new game logic scripts'
"""
from Blender import Window
import bpy
script_data = \
'''
def main():
cont = GameLogic.getCurrentController()
own = cont.getOwner()
sens = cont.getSensor('mySensor')
actu = cont.getActuator('myActuator')
if sens.isPositive():
GameLogic.addActiveActuator(actu, True)
else:
GameLogic.addActiveActuator(actu, False)
main()
'''
new_text = bpy.data.texts.new('gamelogic_example.py')
new_text.write(script_data)
bpy.data.texts.active = new_text
Window.RedrawAll()

@ -0,0 +1,92 @@
#!BPY
"""
Name: 'IPO Example'
Blender: 245
Group: 'ScriptTemplate'
Tooltip: 'Script template for setting the IPO'
"""
from Blender import Window
import bpy
script_data = \
'''#!BPY
"""
Name: 'My Ipo Script'
Blender: 245
Group: 'Animation'
Tooltip: 'Put some useful info here'
"""
# Add a licence here if you wish to re-distribute, we recommend the GPL
from Blender import Ipo, Mathutils, Window
import bpy, BPyMessages
def makeRandomIpo(object, firstFrame, numberOfFrames, frameStep):
# Create an new Ipo Curve of name myIpo and type Object
myIpo = bpy.data.ipos.new('myIpo', 'Object')
# Create LocX, LocY, and LocZ Ipo curves in our new Curve Object
# and store them so we can access them later
myIpo_x = myIpo.addCurve('LocX')
myIpo_y = myIpo.addCurve('LocY')
myIpo_z = myIpo.addCurve('LocZ')
# What value we want to scale our random value by
ipoScale = 4
# This Calculates the End Frame for use in an xrange() expression
endFrame = firstFrame + (numberOfFrames * frameStep) + frameStep
for frame in xrange(firstFrame, endFrame, frameStep):
# Use the Mathutils Rand() function to get random numbers
ipoValue_x = Mathutils.Rand(-1, 1) * ipoScale
ipoValue_y = Mathutils.Rand(-1, 1) * ipoScale
ipoValue_z = Mathutils.Rand(-1, 1) * ipoScale
# Append to the Ipo curve at location frame, with the value ipoValue_x
# Note that we should pass the append function a tuple or a BezTriple
myIpo_x.append((frame, ipoValue_x))
# Similar to above
myIpo_y.append((frame, ipoValue_y))
myIpo_z.append((frame, ipoValue_z))
# Link our new Ipo Curve to the passed object
object.setIpo(myIpo)
print object
def main():
# Get the active scene, since there can be multiple ones
sce = bpy.data.scenes.active
# Get the active object
object = sce.objects.active
# If there is no active object, pop up an error message
if not object:
BPyMessages.Error_NoActive()
Window.WaitCursor(1)
# Call our makeRandomIpo function
# Pass it our object, Tell it to keys from the start frame until the end frame, at a step of 10 frames
# between them
makeRandomIpo(object, sce.render.sFrame, sce.render.eFrame, 10)
Window.WaitCursor(0)
if __name__ == '__main__':
main()
'''
new_text = bpy.data.texts.new('ipo_template.py')
new_text.write(script_data)
bpy.data.texts.active = new_text
Window.RedrawAll()

@ -0,0 +1,43 @@
/**
*
* $Id: BKE_bullet.h 16773 2008-09-27 22:01:26Z ben2610 $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BKE_BULLET_H
#define BKE_BULLET_H
struct BulletSoftBody;
/* allocates and initializes general main data */
extern struct BulletSoftBody *bsbNew(void);
/* frees internal data and softbody itself */
extern void bsbFree(struct BulletSoftBody *sb);
#endif

@ -0,0 +1,55 @@
/**
* BKE_fluidsim.h
*
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) Blender Foundation
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "DNA_modifier_types.h"
#include "DNA_object_fluidsim.h" // N_T
#include "DNA_object_types.h"
#include "BKE_DerivedMesh.h"
/* old interface */
FluidsimSettings *fluidsimSettingsNew(Object *srcob);
void initElbeemMesh(Object *ob, int *numVertices, float **vertices, int *numTriangles, int **triangles, int useGlobalCoords, int modifierIndex);
/* new fluid-modifier interface */
void fluidsim_init(FluidsimModifierData *fluidmd);
void fluidsim_free(FluidsimModifierData *fluidmd);
DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams);
DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc);
// get bounding box of mesh
void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4],
/*RET*/ float start[3], /*RET*/ float size[3] );

@ -0,0 +1,39 @@
/**
* BKE_shrinkwrap.h
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BKE_SIMPLE_DEFORM_H
#define BKE_SIMPLE_DEFORM_H
struct Object;
struct DerivedMesh;
struct SimpleDeformModifierData;
void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts);
#endif

@ -0,0 +1,95 @@
/*
*
* $Id: bullet.c 16776 2008-09-28 03:07:13Z erwin $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) Blender Foundation
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "MEM_guardedalloc.h"
/* types */
#include "DNA_object_force.h" /* here is the softbody struct */
#include "BKE_bullet.h"
/* ************ Object level, exported functions *************** */
/* allocates and initializes general main data */
BulletSoftBody *bsbNew(void)
{
BulletSoftBody *bsb;
bsb= MEM_callocN(sizeof(BulletSoftBody), "bulletsoftbody");
bsb->flag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT;
bsb->linStiff = 0.5f;
bsb->angStiff = 1.0f;
bsb->volume = 1.0f;
bsb->viterations = 0;
bsb->piterations = 2;
bsb->diterations = 0;
bsb->citerations = 4;
bsb->kSRHR_CL = 0.1f;
bsb->kSKHR_CL = 1.f;
bsb->kSSHR_CL = 0.5f;
bsb->kSR_SPLT_CL = 0.5f;
bsb->kSK_SPLT_CL = 0.5f;
bsb->kSS_SPLT_CL = 0.5f;
bsb->kVCF = 1;
bsb->kDP = 0;
bsb->kDG = 0;
bsb->kLF = 0;
bsb->kPR = 0;
bsb->kVC = 0;
bsb->kDF = 0.2f;
bsb->kMT = 0.05;
bsb->kCHR = 1.0f;
bsb->kKHR = 0.1f;
bsb->kSHR = 1.0f;
bsb->kAHR = 0.7f;
bsb->collisionflags = 0;
//bsb->collisionflags = OB_BSB_COL_CL_RS + OB_BSB_COL_CL_SS;
bsb->numclusteriterations = 64;
return bsb;
}
/* frees all */
void bsbFree(BulletSoftBody *bsb)
{
/* no internal data yet */
MEM_freeN(bsb);
}

@ -0,0 +1,642 @@
/**
* fluidsim.c
*
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) Blender Foundation
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_force.h" // for pointcache
#include "DNA_particle_types.h"
#include "DNA_scene_types.h" // N_T
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
#include "BKE_fluidsim.h"
#include "BKE_global.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
#include "BKE_pointcache.h"
#include "BKE_utildefines.h"
// headers for fluidsim bobj meshes
#include <stdlib.h>
#include "LBM_fluidsim.h"
#include "elbeem.h"
#include <zlib.h>
#include <string.h>
#include <stdio.h>
/* ************************* fluidsim bobj file handling **************************** */
// -----------------------------------------
// forward decleration
// -----------------------------------------
// -----------------------------------------
void fluidsim_init(FluidsimModifierData *fluidmd)
{
#ifndef DISABLE_ELBEEM
if(fluidmd)
{
FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings");
fluidmd->fss = fss;
if(!fss)
return;
fss->type = 0;
fss->show_advancedoptions = 0;
fss->resolutionxyz = 50;
fss->previewresxyz = 25;
fss->realsize = 0.03;
fss->guiDisplayMode = 2; // preview
fss->renderDisplayMode = 3; // render
fss->viscosityMode = 2; // default to water
fss->viscosityValue = 1.0;
fss->viscosityExponent = 6;
// dg TODO: change this to []
fss->gravx = 0.0;
fss->gravy = 0.0;
fss->gravz = -9.81;
fss->animStart = 0.0;
fss->animEnd = 0.30;
fss->gstar = 0.005; // used as normgstar
fss->maxRefine = -1;
// maxRefine is set according to resolutionxyz during bake
// fluid/inflow settings
// fss->iniVel --> automatically set to 0
/* elubie: changed this to default to the same dir as the render output
to prevent saving to C:\ on Windows */
BLI_strncpy(fss->surfdataPath, btempdir, FILE_MAX);
// first init of bounding box
// no bounding box needed
// todo - reuse default init from elbeem!
fss->typeFlags = 0;
fss->domainNovecgen = 0;
fss->volumeInitType = 1; // volume
fss->partSlipValue = 0.0;
fss->generateTracers = 0;
fss->generateParticles = 0.0;
fss->surfaceSmoothing = 1.0;
fss->surfaceSubdivs = 1.0;
fss->particleInfSize = 0.0;
fss->particleInfAlpha = 0.0;
// init fluid control settings
fss->attractforceStrength = 0.2;
fss->attractforceRadius = 0.75;
fss->velocityforceStrength = 0.2;
fss->velocityforceRadius = 0.75;
fss->cpsTimeStart = fss->animStart;
fss->cpsTimeEnd = fss->animEnd;
fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width
/*
BAD TODO: this is done in buttons_object.c in the moment
Mesh *mesh = ob->data;
// calculate bounding box
fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
*/
fss->lastgoodframe = -1;
fss->flag = 0;
}
#endif
return;
}
void fluidsim_free(FluidsimModifierData *fluidmd)
{
#ifndef DISABLE_ELBEEM
if(fluidmd)
{
MEM_freeN(fluidmd->fss);
}
#endif
return;
}
DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc)
{
#ifndef DISABLE_ELBEEM
DerivedMesh *result = NULL;
int framenr;
FluidsimSettings *fss = NULL;
framenr= (int)G.scene->r.cfra;
// only handle fluidsim domains
if(fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN))
return dm;
// sanity check
if(!fluidmd || (fluidmd && !fluidmd->fss))
return dm;
fss = fluidmd->fss;
// timescale not supported yet
// clmd->sim_parms->timescale= timescale;
// support reversing of baked fluid frames here
if((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0))
{
framenr = fss->lastgoodframe - framenr + 1;
CLAMP(framenr, 1, fss->lastgoodframe);
}
/* try to read from cache */
if(((fss->lastgoodframe >= framenr) || (fss->lastgoodframe < 0)) && (result = fluidsim_read_cache(ob, dm, fluidmd, framenr, useRenderParams)))
{
// fss->lastgoodframe = framenr; // set also in src/fluidsim.c
return result;
}
else
{
// display last known good frame
if(fss->lastgoodframe >= 0)
{
if((result = fluidsim_read_cache(ob, dm, fluidmd, fss->lastgoodframe, useRenderParams)))
{
return result;
}
// it was supposed to be a valid frame but it isn't!
fss->lastgoodframe = framenr - 1;
// this could be likely the case when you load an old fluidsim
if((result = fluidsim_read_cache(ob, dm, fluidmd, fss->lastgoodframe, useRenderParams)))
{
return result;
}
}
result = CDDM_copy(dm);
if(result)
{
return result;
}
}
return dm;
#else
return NULL;
#endif
}
#ifndef DISABLE_ELBEEM
/* read .bobj.gz file into a fluidsimDerivedMesh struct */
static DerivedMesh *fluidsim_read_obj(char *filename)
{
int wri,i,j;
float wrf;
int gotBytes;
gzFile gzf;
int numverts = 0, numfaces = 0;
DerivedMesh *dm = NULL;
MFace *mface;
MVert *mvert;
short *normals;
// ------------------------------------------------
// get numverts + numfaces first
// ------------------------------------------------
gzf = gzopen(filename, "rb");
if (!gzf)
{
return NULL;
}
// read numverts
gotBytes = gzread(gzf, &wri, sizeof(wri));
numverts = wri;
// skip verts
for(i=0; i<numverts*3; i++)
{
gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
}
// read number of normals
gotBytes = gzread(gzf, &wri, sizeof(wri));
// skip normals
for(i=0; i<numverts*3; i++)
{
gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
}
/* get no. of triangles */
gotBytes = gzread(gzf, &wri, sizeof(wri));
numfaces = wri;
gzclose( gzf );
// ------------------------------------------------
if(!numfaces || !numverts)
return NULL;
gzf = gzopen(filename, "rb");
if (!gzf)
{
return NULL;
}
dm = CDDM_new(numverts, 0, numfaces);
if(!dm)
{
gzclose( gzf );
return NULL;
}
// read numverts
gotBytes = gzread(gzf, &wri, sizeof(wri));
// read vertex position from file
mvert = CDDM_get_verts(dm);
for(i=0; i<numverts; i++)
{
MVert *mv = &mvert[i];
for(j=0; j<3; j++)
{
gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
mv->co[j] = wrf;
}
}
// should be the same as numverts
gotBytes = gzread(gzf, &wri, sizeof(wri));
if(wri != numverts)
{
if(dm)
dm->release(dm);
gzclose( gzf );
return NULL;
}
normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" );
if(!normals)
{
if(dm)
dm->release(dm);
gzclose( gzf );
return NULL;
}
// read normals from file (but don't save them yet)
for(i=0; i<numverts*3; i++)
{
gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
normals[i] = (short)(wrf*32767.0f);
}
/* read no. of triangles */
gotBytes = gzread(gzf, &wri, sizeof(wri));
if(wri!=numfaces)
printf("Fluidsim: error in reading data from file.\n");
// read triangles from file
mface = CDDM_get_faces(dm);
for(i=0; i<numfaces; i++)
{
int face[4];
MFace *mf = &mface[i];
gotBytes = gzread(gzf, &(face[0]), sizeof( face[0] ));
gotBytes = gzread(gzf, &(face[1]), sizeof( face[1] ));
gotBytes = gzread(gzf, &(face[2]), sizeof( face[2] ));
face[3] = 0;
// check if 3rd vertex has index 0 (not allowed in blender)
if(face[2])
{
mf->v1 = face[0];
mf->v2 = face[1];
mf->v3 = face[2];
}
else
{
mf->v1 = face[1];
mf->v2 = face[2];
mf->v3 = face[0];
}
mf->v4 = face[3];
test_index_face(mf, NULL, 0, 3);
}
gzclose( gzf );
CDDM_calc_edges(dm);
CDDM_apply_vert_normals(dm, (short (*)[3])normals);
MEM_freeN(normals);
// CDDM_calc_normals(result);
return dm;
}
DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
{
int displaymode = 0;
int curFrame = framenr - 1 /*G.scene->r.sfra*/; /* start with 0 at start frame */
char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR];
FluidsimSettings *fss = fluidmd->fss;
DerivedMesh *dm = NULL;
MFace *mface;
int numfaces;
int mat_nr, flag, i;
if(!useRenderParams) {
displaymode = fss->guiDisplayMode;
} else {
displaymode = fss->renderDisplayMode;
}
strncpy(targetDir, fss->surfdataPath, FILE_MAXDIR);
// use preview or final mesh?
if(displaymode==1)
{
// just display original object
return NULL;
}
else if(displaymode==2)
{
strcat(targetDir,"fluidsurface_preview_####");
}
else
{ // 3
strcat(targetDir,"fluidsurface_final_####");
}
BLI_convertstringcode(targetDir, G.sce);
BLI_convertstringframe(targetDir, curFrame); // fixed #frame-no
strcpy(targetFile,targetDir);
strcat(targetFile, ".bobj.gz");
dm = fluidsim_read_obj(targetFile);
if(!dm)
{
// switch, abort background rendering when fluidsim mesh is missing
const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
if(G.background==1) {
if(getenv(strEnvName2)) {
int elevel = atoi(getenv(strEnvName2));
if(elevel>0) {
printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile);
exit(1);
}
}
}
// display org. object upon failure which is in dm
return NULL;
}
// assign material + flags to new dm
mface = orgdm->getFaceArray(orgdm);
mat_nr = mface[0].mat_nr;
flag = mface[0].flag;
mface = dm->getFaceArray(dm);
numfaces = dm->getNumFaces(dm);
for(i=0; i<numfaces; i++)
{
mface[i].mat_nr = mat_nr;
mface[i].flag = flag;
}
// load vertex velocities, if they exist...
// TODO? use generate flag as loading flag as well?
// warning, needs original .bobj.gz mesh loading filename
/*
if(displaymode==3)
{
readVelgz(targetFile, srcob);
}
else
{
// no data for preview, only clear...
int i,j;
for(i=0; i<mesh->totvert;i++) { for(j=0; j<3; j++) { srcob->fluidsimSettings->meshSurfNormals[i].co[j] = 0.; }}
}*/
return dm;
}
void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4],
/*RET*/ float start[3], /*RET*/ float size[3] )
{
float bbsx=0.0, bbsy=0.0, bbsz=0.0;
float bbex=1.0, bbey=1.0, bbez=1.0;
int i;
float vec[3];
VECCOPY(vec, mvert[0].co);
Mat4MulVecfl(obmat, vec);
bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
for(i = 1; i < totvert; i++) {
VECCOPY(vec, mvert[i].co);
Mat4MulVecfl(obmat, vec);
if(vec[0] < bbsx){ bbsx= vec[0]; }
if(vec[1] < bbsy){ bbsy= vec[1]; }
if(vec[2] < bbsz){ bbsz= vec[2]; }
if(vec[0] > bbex){ bbex= vec[0]; }
if(vec[1] > bbey){ bbey= vec[1]; }
if(vec[2] > bbez){ bbez= vec[2]; }
}
// return values...
if(start) {
start[0] = bbsx;
start[1] = bbsy;
start[2] = bbsz;
}
if(size) {
size[0] = bbex-bbsx;
size[1] = bbey-bbsy;
size[2] = bbez-bbsz;
}
}
//-------------------------------------------------------------------------------
// old interface
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
// file handling
//-------------------------------------------------------------------------------
void initElbeemMesh(struct Object *ob,
int *numVertices, float **vertices,
int *numTriangles, int **triangles,
int useGlobalCoords, int modifierIndex)
{
DerivedMesh *dm = NULL;
MVert *mvert;
MFace *mface;
int countTris=0, i, totvert, totface;
float *verts;
int *tris;
dm = mesh_create_derived_index_render(ob, CD_MASK_BAREMESH, modifierIndex);
//dm = mesh_create_derived_no_deform(ob,NULL);
mvert = dm->getVertArray(dm);
mface = dm->getFaceArray(dm);
totvert = dm->getNumVerts(dm);
totface = dm->getNumFaces(dm);
*numVertices = totvert;
verts = MEM_callocN( totvert*3*sizeof(float), "elbeemmesh_vertices");
for(i=0; i<totvert; i++) {
VECCOPY( &verts[i*3], mvert[i].co);
if(useGlobalCoords) { Mat4MulVecfl(ob->obmat, &verts[i*3]); }
}
*vertices = verts;
for(i=0; i<totface; i++) {
countTris++;
if(mface[i].v4) { countTris++; }
}
*numTriangles = countTris;
tris = MEM_callocN( countTris*3*sizeof(int), "elbeemmesh_triangles");
countTris = 0;
for(i=0; i<totface; i++) {
int face[4];
face[0] = mface[i].v1;
face[1] = mface[i].v2;
face[2] = mface[i].v3;
face[3] = mface[i].v4;
tris[countTris*3+0] = face[0];
tris[countTris*3+1] = face[1];
tris[countTris*3+2] = face[2];
countTris++;
if(face[3]) {
tris[countTris*3+0] = face[0];
tris[countTris*3+1] = face[2];
tris[countTris*3+2] = face[3];
countTris++;
}
}
*triangles = tris;
dm->release(dm);
}
/* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
void readVelgz(char *filename, Object *srcob)
{
int wri, i, j;
float wrf;
gzFile gzf;
MVert *vverts = srcob->fluidsimSettings->meshSurfNormals;
int len = strlen(filename);
Mesh *mesh = srcob->data;
// mesh and vverts have to be valid from loading...
// clean up in any case
for(i=0; i<mesh->totvert;i++)
{
for(j=0; j<3; j++)
{
vverts[i].co[j] = 0.;
}
}
if(srcob->fluidsimSettings->domainNovecgen>0) return;
if(len<7)
{
return;
}
// .bobj.gz , correct filename
// 87654321
filename[len-6] = 'v';
filename[len-5] = 'e';
filename[len-4] = 'l';
gzf = gzopen(filename, "rb");
if (!gzf)
return;
gzread(gzf, &wri, sizeof( wri ));
if(wri != mesh->totvert)
{
return;
}
for(i=0; i<mesh->totvert;i++)
{
for(j=0; j<3; j++)
{
gzread(gzf, &wrf, sizeof( wrf ));
vverts[i].co[j] = wrf;
}
}
gzclose(gzf);
}
#endif // DISABLE_ELBEEM

@ -0,0 +1,248 @@
/**
* deform_simple.c
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): André Pinto
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "DNA_object_types.h"
#include "DNA_modifier_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_simple_deform.h"
#include "BKE_DerivedMesh.h"
#include "BKE_deform.h"
#include "BKE_utildefines.h"
#include "BLI_arithb.h"
#include "BKE_shrinkwrap.h"
#include <string.h>
#include <math.h>
//Clamps/Limits the given coordinate to: limits[0] <= co[axis] <= limits[1]
//The ammount of clamp is saved on dcut
static void axis_limit(int axis, const float limits[2], float co[3], float dcut[3])
{
float val = co[axis];
if(limits[0] > val) val = limits[0];
if(limits[1] < val) val = limits[1];
dcut[axis] = co[axis] - val;
co[axis] = val;
}
static void simpleDeform_taper(const float factor, const float dcut[3], float *co)
{
float x = co[0], y = co[1], z = co[2];
float scale = z*factor;
co[0] = x + x*scale;
co[1] = y + y*scale;
co[2] = z;
if(dcut)
{
co[0] += dcut[0];
co[1] += dcut[1];
co[2] += dcut[2];
}
}
static void simpleDeform_stretch(const float factor, const float dcut[3], float *co)
{
float x = co[0], y = co[1], z = co[2];
float scale;
scale = (z*z*factor-factor + 1.0);
co[0] = x*scale;
co[1] = y*scale;
co[2] = z*(1.0+factor);
if(dcut)
{
co[0] += dcut[0];
co[1] += dcut[1];
co[2] += dcut[2];
}
}
static void simpleDeform_twist(const float factor, const float *dcut, float *co)
{
float x = co[0], y = co[1], z = co[2];
float theta, sint, cost;
theta = z*factor;
sint = sin(theta);
cost = cos(theta);
co[0] = x*cost - y*sint;
co[1] = x*sint + y*cost;
co[2] = z;
if(dcut)
{
co[0] += dcut[0];
co[1] += dcut[1];
co[2] += dcut[2];
}
}
static void simpleDeform_bend(const float factor, const float dcut[3], float *co)
{
float x = co[0], y = co[1], z = co[2];
float theta, sint, cost;
theta = x*factor;
sint = sin(theta);
cost = cos(theta);
if(fabs(factor) > 1e-7f)
{
co[0] = -(y-1.0f/factor)*sint;
co[1] = (y-1.0f/factor)*cost + 1.0f/factor;
co[2] = z;
}
if(dcut)
{
co[0] += cost*dcut[0];
co[1] += sint*dcut[0];
co[2] += dcut[2];
}
}
/* simple deform modifier */
void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
static const float lock_axis[2] = {0.0f, 0.0f};
int i;
int limit_axis = 0;
float smd_limit[2], smd_factor;
SpaceTransform *transf = NULL, tmp_transf;
void (*simpleDeform_callback)(const float factor, const float dcut[3], float *co) = NULL; //Mode callback
int vgroup = get_named_vertexgroup_num(ob, smd->vgroup_name);
MDeformVert *dvert = NULL;
//Safe-check
if(smd->origin == ob) smd->origin = NULL; //No self references
if(smd->limit[0] < 0.0) smd->limit[0] = 0.0f;
if(smd->limit[0] > 1.0) smd->limit[0] = 1.0f;
smd->limit[0] = MIN2(smd->limit[0], smd->limit[1]); //Upper limit >= than lower limit
//Calculate matrixs do convert between coordinate spaces
if(smd->origin)
{
transf = &tmp_transf;
if(smd->originOpts & MOD_SIMPLEDEFORM_ORIGIN_LOCAL)
{
space_transform_from_matrixs(transf, ob->obmat, smd->origin->obmat);
}
else
{
Mat4CpyMat4(transf->local2target, smd->origin->obmat);
Mat4Invert(transf->target2local, transf->local2target);
}
}
//Setup vars
limit_axis = (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) ? 0 : 2; //Bend limits on X.. all other modes limit on Z
//Update limits if needed
{
float lower = FLT_MAX;
float upper = -FLT_MAX;
for(i=0; i<numVerts; i++)
{
float tmp[3];
VECCOPY(tmp, vertexCos[i]);
if(transf) space_transform_apply(transf, tmp);
lower = MIN2(lower, tmp[limit_axis]);
upper = MAX2(upper, tmp[limit_axis]);
}
//SMD values are normalized to the BV, calculate the absolut values
smd_limit[1] = lower + (upper-lower)*smd->limit[1];
smd_limit[0] = lower + (upper-lower)*smd->limit[0];
smd_factor = smd->factor / MAX2(FLT_EPSILON, smd_limit[1]-smd_limit[0]);
}
if(dm)
dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
switch(smd->mode)
{
case MOD_SIMPLEDEFORM_MODE_TWIST: simpleDeform_callback = simpleDeform_twist; break;
case MOD_SIMPLEDEFORM_MODE_BEND: simpleDeform_callback = simpleDeform_bend; break;
case MOD_SIMPLEDEFORM_MODE_TAPER: simpleDeform_callback = simpleDeform_taper; break;
case MOD_SIMPLEDEFORM_MODE_STRETCH: simpleDeform_callback = simpleDeform_stretch; break;
default:
return; //No simpledeform mode?
}
for(i=0; i<numVerts; i++)
{
float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup);
if(weight != 0.0f)
{
float co[3], dcut[3] = {0.0f, 0.0f, 0.0f};
if(transf) space_transform_apply(transf, vertexCos[i]);
VECCOPY(co, vertexCos[i]);
//Apply axis limits
if(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) //Bend mode shoulnt have any lock axis
{
if(smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) axis_limit(0, lock_axis, co, dcut);
if(smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) axis_limit(1, lock_axis, co, dcut);
}
axis_limit(limit_axis, smd_limit, co, dcut);
simpleDeform_callback(smd_factor, dcut, co); //Apply deform
VecLerpf(vertexCos[i], vertexCos[i], co, weight); //Use vertex weight has coef of linear interpolation
if(transf) space_transform_invert(transf, vertexCos[i]);
}
}
}

@ -0,0 +1,9 @@
#include "GLBlendEquation.h"
void FRS_glBlendEquation(GLenum mode) {
if( glBlendEquation ) {
glBlendEquation(mode);
} else if ( glBlendEquationEXT ) {
glBlendEquationEXT(mode);
}
}

@ -0,0 +1,16 @@
#ifndef GLBLENDEQUATION_H
#define GLBLENDEQUATION_H
#include <GL/glew.h>
#ifdef WIN32
# include <windows.h>
#endif
#ifdef __MACH__
# include <OpenGL/gl.h>
#else
# include <GL/gl.h>
#endif
void FRS_glBlendEquation(GLenum mode);
#endif // GLBLENDEQUATION_H

@ -0,0 +1,117 @@
/**
* $Id: BIF_keyframing.h 14444 2008-04-16 22:40:48Z aligorith $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place * Suite 330, Boston, MA 02111*1307, USA.
*
* The Original Code is Copyright (C) 2008, Blender Foundation
* This is a new part of Blender (with some old code)
*
* Contributor(s): Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BIF_KEYFRAMING_H
#define BIF_KEYFRAMING_H
struct ListBase;
struct ID;
struct IpoCurve;
struct BezTriple;
/* ************ Keyframing Management **************** */
/* Lesser Keyframing API call:
* Use this when validation of necessary animation data isn't necessary as it already
* exists, and there is a beztriple that can be directly copied into the array.
*/
int insert_bezt_icu(struct IpoCurve *icu, struct BezTriple *bezt);
/* Main Keyframing API call:
* Use this when validation of necessary animation data isn't necessary as it
* already exists. It will insert a keyframe using the current value being keyframed.
*/
void insert_vert_icu(struct IpoCurve *icu, float x, float y, short flag);
/* flags for use in insert_key(), and insert_vert_icu() */
enum {
INSERTKEY_NEEDED = (1<<0), /* only insert keyframes where they're needed */
INSERTKEY_MATRIX = (1<<1), /* insert 'visual' keyframes where possible/needed */
INSERTKEY_FAST = (1<<2), /* don't recalculate handles,etc. after adding key */
INSERTKEY_FASTR = (1<<3), /* don't realloc mem (or increase count, as array has already been set out) */
INSERTKEY_REPLACE = (1<<4), /* only replace an existing keyframe (this overrides INSERTKEY_NEEDED) */
} eInsertKeyFlags;
/* -------- */
/* Main Keyframing API calls:
* Use this to create any necessary animation data,, and then insert a keyframe
* using the current value being keyframed, in the relevant place. Returns success.
*/
// TODO: adapt this for new data-api -> this blocktype, etc. stuff is evil!
short insertkey(struct ID *id, int blocktype, char *actname, char *constname, int adrcode, short flag);
/* Main Keyframing API call:
* Use this to delete keyframe on current frame for relevant channel. Will perform checks just in case.
*/
short deletekey(struct ID *id, int blocktype, char *actname, char *constname, int adrcode, short flag);
/* Main Keyframe Management calls:
* These handle keyframes management from various spaces. They will handle the menus
* required for each space.
*/
void common_insertkey(void);
void common_deletekey(void);
/* ************ Auto-Keyframing ********************** */
/* Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)
* are defined in DNA_userdef_types.h
* - Scene settings take presidence over those for userprefs, with old files
* inheriting userpref settings for the scene settings
* - "On/Off + Mode" are stored per Scene, but "settings" are currently stored
* as userprefs
*/
/* Auto-Keying macros for use by various tools */
/* check if auto-keyframing is enabled (per scene takes presidence) */
#define IS_AUTOKEY_ON ((G.scene) ? (G.scene->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
/* check the mode for auto-keyframing (per scene takes presidence) */
#define IS_AUTOKEY_MODE(mode) ((G.scene) ? (G.scene->autokey_mode == AUTOKEY_MODE_##mode) : (U.autokey_mode == AUTOKEY_MODE_##mode))
/* check if a flag is set for auto-keyframing (as userprefs only!) */
#define IS_AUTOKEY_FLAG(flag) (U.autokey_flag & AUTOKEY_FLAG_##flag)
/* ************ Keyframe Checking ******************** */
/* Checks whether a keyframe exists for the given ID-block one the given frame */
short id_cfra_has_keyframe(struct ID *id, short filter);
/* filter flags fr id_cfra_has_keyframe */
enum {
/* general */
ANIMFILTER_ALL = 0, /* include all available animation data */
ANIMFILTER_LOCAL = (1<<0), /* only include locally available anim data */
/* object specific */
ANIMFILTER_MAT = (1<<1), /* include material keyframes too */
ANIMFILTER_SKEY = (1<<2), /* shape keys (for geometry) */
} eAnimFilterFlags;
#endif /* BIF_KEYFRAMING_H */

File diff suppressed because it is too large Load Diff