aesop-physics.cpp

Go to the documentation of this file.
00001 /*
00002  * aesop-physics.cpp
00003  *
00004  * Copyright (C) 2008,2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Implementation of aesop physics engine.
00032  * For now, this is just a thin wrapper on top of the Bullet engine.
00033  */
00034 
00035 // includes --------------------------------------------------------------------
00036 #include "aesop-physics.h"              // always include our own header first!
00037 
00038 #include "bullet/bullet.h"      // bullet physics library
00039 
00040 #include "common/wave_ex.h"
00041 #include "datahash/datahash_util.h"
00042 #include "hfield/heightfield.h"
00043 #include "perf/perf.h"
00044 #include "threadsafe/threadsafe_queue.h"
00045 #include "trimesh/trimesh.h"
00046 
00047 
00048 namespace aesop {
00049 
00050 
00051 // TODO: make this settable by clients!
00052 static const float s_stepHeight                 = 0.35;         // 35cm
00053 static const int s_ghostCollisionFlags          =
00054                         btCollisionObject::CF_KINEMATIC_OBJECT;
00055 
00056 // interface destructor implementation
00057 PhysicsObject::~PhysicsObject(void) throw() { }
00058 PhysicsShape::~PhysicsShape(void) throw() { }
00059 PhysicsWorld::~PhysicsWorld(void) throw() { }
00060 
00061 
00062 typedef btTransform Transform3D;
00063 
00064 
00066 //
00067 //      static physics object ID map
00068 //
00070 
00071 typedef std::map<dword_t, smart_ptr<PhysicsObject> > id_object_map_t;
00072 static id_object_map_t s_idMap;
00073 static smart_mutex s_idMapMutex;
00074 
00075 
00076 template <class T>
00077 long
00078 getNewIdForObject
00079 (
00080 IN smart_ptr<T>& in_obj
00081 )
00082 {
00083         // attempt to cast
00084         smart_ptr<PhysicsObject> obj = in_obj;
00085         ASSERT(obj, "failed to downcast?");
00086 
00087         // lock!
00088         mlock l(s_idMapMutex);
00089 
00090         // generate a random ID
00091         for (;;) {
00092                 long id = rand() + 1;
00093                 ASSERT(id > 0, "bad id: %ld", id);
00094                 if (s_idMap.end() == s_idMap.find(id)) {
00095                         // found an unused ID!
00096                         s_idMap[id] = obj;
00097                         return id;
00098                 }
00099         }
00100 }
00101 
00102 
00103 
00104 smart_ptr<PhysicsObject>
00105 getPhysicsObjectById
00106 (
00107 IN dword_t id
00108 )
00109 {
00110         ASSERT(id > 0, "Bad id: %ld", (long) id);
00111 
00112         // lock!
00113         mlock l(s_idMapMutex);
00114 
00115         id_object_map_t::iterator i = s_idMap.find(id);
00116         if (s_idMap.end() == i) {
00117                 DPRINTF("Object with id %ld not found!", (long) id);
00118                 return NULL;
00119         }
00120 
00121         return i->second;
00122 }
00123 
00124 
00125 
00126 static void
00127 removeObjectFromIdMap
00128 (
00129 IN long id
00130 )
00131 {
00132         ASSERT(id > 0, "Bad id: %ld", id);
00133 
00134         // lock!
00135         mlock l(s_idMapMutex);
00136 
00137         id_object_map_t::iterator i = s_idMap.find(id);
00138         if (s_idMap.end() != i) {
00139                 s_idMap.erase(i);
00140         }
00141 }
00142 
00143 
00144 
00146 //
00147 //      static helper methods
00148 //
00150 
00151 static inline btVector3
00152 getBulletVectorFromPoint3d
00153 (
00154 IN const point3d_t& pos
00155 )
00156 throw()
00157 {
00158         return btVector3(pos.x, pos.y, pos.z);
00159 }
00160 
00161 
00162 
00163 template <class T>
00164 static inline point3d_t
00165 getPoint3dFromBulletType
00166 (
00167 IN const T& v
00168 )
00169 throw()
00170 {
00171         return point3d_t(v.x(), v.y(), v.z());
00172 }
00173 
00174 
00175 
00176 static inline point3d_t
00177 getNullPoint
00178 (
00179 void
00180 )
00181 throw()
00182 {
00183         point3d_t p;
00184         p.clear();
00185         return p;
00186 }
00187 
00188 
00189 
00190 static point3d_t
00191 getCollisionObjectPosition
00192 (
00193 IN const btCollisionObject * obj
00194 )
00195 {
00196         ASSERT(obj, "null");
00197 
00198         const btTransform& T = obj->getWorldTransform();
00199         btVector3 localOrigin(0, 0, 0);
00200         btVector3 position = T(localOrigin);
00201 
00202         return point3d_t(position.x(), position.y(), position.z());
00203 }
00204 
00205 
00206 
00207 static void
00208 dumpVector
00209 (
00210 IN const char * title,
00211 IN const btVector3& v
00212 )
00213 throw()
00214 {
00215         ASSERT(title, "null");
00216 
00217         DPRINTF("%s: [ %5.1f, %5.1f, %5.1f ]", title,
00218             v[0], v[1], v[2]);
00219 }
00220 
00221 
00222 
00223 static void
00224 dumpAabb
00225 (
00226 IN const char * title,
00227 IN const btVector3& aabbMin,
00228 IN const btVector3& aabbMax
00229 )
00230 throw()
00231 {
00232         ASSERT(title, "null");
00233 
00234         DPRINTF("%s: ( %5.1f, %5.1f, %5.1f ) - ( %5.1f, %5.1f, %5.1f )",
00235             title, aabbMin[0], aabbMin[1], aabbMin[2],
00236             aabbMax[0], aabbMax[1], aabbMax[2]);
00237 }
00238 
00239 
00240 
00241 static void
00242 dumpCollisionObject
00243 (
00244 IN const char * title,
00245 IN const btCollisionObject * obj
00246 )
00247 throw()
00248 {
00249         ASSERT(obj, "null");
00250         ASSERT(sizeof(btScalar) == sizeof(float), "mismatch!");
00251 
00252         // what is it?
00253         const btCollisionShape * shape = obj->getCollisionShape();
00254         ASSERT(shape, "null shape for rigid body");
00255 
00256         const char * shape_name = shape->getName();
00257         if (!title) {
00258                 title = shape_name;
00259         }
00260 
00261         DPRINTF("  %s", title);
00262         DPRINTF("    shape name = '%s'", shape->getName());
00263         DPRINTF("    shape type = %d", shape->getShapeType());
00264         DPRINTF("    Object flags: %s %s %s %s",
00265             shape->isPolyhedral() ? "polyhedral" : "",
00266             shape->isConvex() ? "convex" : "",
00267             shape->isConcave() ? "concave" : "",
00268             shape->isCompound() ? "compound" : "");
00269 
00270         // where is it?
00271         point3d_t pos = getCollisionObjectPosition(obj);
00272         DPRINTF("    position: (%f, %f, %f)", pos.x, pos.y, pos.z);
00273 
00274         // bounding box
00275         btTransform T = obj->getWorldTransform();
00276         btVector3 aabbMin, aabbMax;
00277         shape->getAabb(T, aabbMin, aabbMax);
00278         dumpAabb("    aabb from shape", aabbMin, aabbMax);
00279 
00280         T.setIdentity();
00281         shape->getAabb(T, aabbMin, aabbMax);
00282         dumpAabb("    aabb (relative)", aabbMin, aabbMax);
00283 
00284         // broadphase proxy (world's additional state)
00285         const btBroadphaseProxy * proxy = obj->getBroadphaseHandle();
00286         if (proxy) {
00287                 DPRINTF("    unique ID = %d", proxy->getUid());
00288         } else {
00289                 DPRINTF("    NULL proxy -- not in world?");
00290         }
00291 
00292         // rigid body particulars
00293         const btRigidBody * prb = dynamic_cast<const btRigidBody *>(obj);
00294         if (prb) {
00295                 DPRINTF("    inverse mass = %f", prb->getInvMass());
00296 
00297                 btVector3 linVel = prb->getLinearVelocity();
00298                 dumpVector("    linear velocity", linVel);
00299 
00300                 prb->getAabb(aabbMin, aabbMax);
00301                 dumpAabb("    aabb from rigid body ", aabbMin, aabbMax);
00302         }
00303 }
00304 
00305 
00306 
00308 //
00309 //      ObjectImpl -- class that implements the PhysicsObject interface
00310 //
00312 
00313 class ObjectImpl : public PhysicsObject {
00314 public:
00315         ObjectImpl(void) throw();
00316         ~ObjectImpl(void) throw() { }
00317 
00318         // aesop::PhysicsObject class interface methods ------------------------
00319         dword_t getId(void) const throw() { return m_id; }
00320         int getFlags(void) const throw() { return m_flags; }
00321         void dump(IN const char * txt) const throw() {
00322                         DPRINTF("Physics object: %s", txt);
00323                         DPRINTF("  id: %ld", (long) m_id);
00324                         dumpCollisionObject(txt, m_obj);
00325                 }
00326         point3d_t getPosition(void) const throw()
00327                                 { return getCollisionObjectPosition(m_obj); }
00328         rect3d_t getBoundingBox(void) const throw();
00329         quaternion_t getOrientation(void) const throw();
00330         point3d_t getLinearVelocity(void) const throw();
00331         point3d_t getAngularVelocity(void) const throw();
00332         void setOrientation(IN const quaternion_t& orient);
00333         void setLinearVelocity(IN const point3d_t& linear);
00334         void setAngularVelocity(IN const point3d_t& angular);
00335         
00336         void requestMove(IN const point3d_t& delta, IN float dt);
00337         void setPosition(IN const point3d_t& pos);
00338         float getMass(void) const throw() { return m_mass; }
00339         void iterateOverlappingObjects(IN object_iteration_fn fn,
00340                                 IN void * context);
00341         void setUserPointer(IN void * up) throw() { m_up = up; }
00342         void * getUserPointer(void) const throw() { return m_up; }
00343 
00344         // public class methods ------------------------------------------------
00345         void setId(IN dword_t id) throw() { m_id = id; }
00346         bool isMoveable(void) const throw() { return !!m_ghost; }
00347         btCollisionObject * getCollisionObject(void) throw() {
00348                                         ASSERT(m_obj, "null");
00349                                         return m_obj;
00350                                 }
00351         btKinematicCharacterController * getCharacter(void)
00352                                 { return m_character; }
00353         bool wantCollisionEvents(void) const throw()
00354                                 { return eFlag_Events & m_flags; }
00355 
00356         // static factory methods ----------------------------------------------
00357         static smart_ptr<ObjectImpl> create(IN smart_ptr<btCollisionObject>& o,
00358                                 IN const physics_meta_t& meta);
00359         static smart_ptr<ObjectImpl> create(
00360                                 IN smart_ptr<btKinematicCharacterController>& c,
00361                                 IN smart_ptr<btPairCachingGhostObject>& ghost,
00362                                 IN const physics_meta_t& meta);
00363 
00364 private:
00365         // private helper methods ----------------------------------------------
00366         void addContext(IN const physics_meta_t& meta);
00367 
00368         // private member data -------------------------------------------------
00369         int                                     m_flags;
00370         dword_t                                 m_id;
00371         float                                   m_mass;
00372         void *                                  m_up;
00373         point3d_t                               m_linVel; // only for moveable
00374         btRigidBody *                           m_rigidBody; // weak ref!
00375         smart_ptr<btCollisionObject>            m_obj;
00376         smart_ptr<btKinematicCharacterController> m_character;
00377         smart_ptr<btPairCachingGhostObject>     m_ghost;
00378 };
00379 
00380 typedef std::vector<ObjectImpl *> vec_objimpl_t;
00381 
00382 
00383 
00384 ObjectImpl::ObjectImpl(void)
00385 throw()
00386 {
00387         m_id = 0;
00388         m_flags = 0;
00389         m_mass = 0.0;
00390         m_up = 0;
00391         m_linVel.clear();
00392 }
00393 
00394 
00395 
00396 static ObjectImpl *
00397 getObject
00398 (
00399 IN PhysicsObject * obj
00400 )
00401 {
00402         ASSERT(obj, "null");
00403         ObjectImpl * o = dynamic_cast<ObjectImpl *>(obj);
00404         ASSERT(o, "PhysicsObject not implemented by ObjectImpl?");
00405         return o;
00406 }
00407 
00408 
00409 
00410 // Funky!  Bullet sometimes provides btCollisionObjects as void *
00411 // I think this is some sort of polymorphism.
00412 // Anyway, for these use cases we can map (using the userPointer)
00413 //  back to ObjectImpl *
00414 static ObjectImpl *
00415 getPhysicsObject
00416 (
00417 IN void * pv
00418 )
00419 {
00420         ASSERT(pv, "null");
00421         btCollisionObject * obj = (btCollisionObject *) pv;
00422         ObjectImpl * poi = (ObjectImpl *) obj->getUserPointer();
00423         ASSERT(poi, "user pointer was never set?");
00424         return poi;
00425 }
00426 
00427 
00428 
00429 rect3d_t
00430 ObjectImpl::getBoundingBox
00431 (
00432 void
00433 )
00434 const
00435 throw()
00436 {
00437         ASSERT(m_obj, "null collision object");
00438         const btCollisionShape * shape = m_obj->getCollisionShape();
00439 
00440         btTransform T = m_obj->getWorldTransform();
00441         btVector3 aabbMin, aabbMax;
00442         shape->getAabb(T, aabbMin, aabbMax);
00443 
00444         rect3d_t r;
00445         r.x0 = aabbMin.x();
00446         r.y0 = aabbMin.y();
00447         r.z0 = aabbMin.z();
00448         r.x1 = aabbMax.x();
00449         r.y1 = aabbMax.y();
00450         r.z1 = aabbMax.z();
00451         return r;
00452 }
00453 
00454 
00455 
00456 quaternion_t
00457 ObjectImpl::getOrientation
00458 (
00459 void
00460 )
00461 const
00462 throw()
00463 {
00464         ASSERT(m_obj, "null collision object?");
00465 
00466         const btTransform& T = m_obj->getWorldTransform();
00467         btQuaternion q = T.getRotation();
00468         quaternion_t retval;
00469         retval.x = q.x();
00470         retval.y = q.y();
00471         retval.z = q.z();
00472         retval.w = q.w();
00473         return retval;
00474 }
00475 
00476 
00477 
00478 point3d_t
00479 ObjectImpl::getLinearVelocity
00480 (
00481 void
00482 )
00483 const
00484 throw()
00485 {
00486         ASSERT(m_obj, "null collision object?");
00487 
00488         // are we moveable?
00489         if (this->isMoveable()) {
00490                 //DPRINTF("Moveable object has linear velocity!");
00491                 //m_linVel.dump("  here it is");
00492                 return m_linVel;
00493         }
00494 
00495         // not moveable: see what bullet says
00496         if (m_rigidBody) {
00497                 return getPoint3dFromBulletType(
00498                     m_rigidBody->getLinearVelocity());
00499         }
00500 
00501         // no idea!  Say zero
00502         //DPRINTF("Unknown velocity!");
00503         return getNullPoint();
00504 }
00505 
00506 
00507 
00508 point3d_t
00509 ObjectImpl::getAngularVelocity
00510 (
00511 void
00512 )
00513 const
00514 throw()
00515 {
00516         ASSERT(m_obj, "null collision object?");
00517 
00518         if (m_rigidBody) {
00519                 return getPoint3dFromBulletType(
00520                     m_rigidBody->getAngularVelocity());
00521         }
00522         return getNullPoint();
00523 }
00524 
00525 
00526 
00527 void
00528 ObjectImpl::setOrientation
00529 (
00530 IN const quaternion_t& orient
00531 )
00532 {
00533         ASSERT(m_obj, "requires object");
00534 
00535 //      orient.dump("Setting orientation");
00536 
00537         // TODO: is there a cleaner way to set orientation?
00538         // this is what I do:
00539         //  - get the position
00540         //  - create a new transform for position and orientation
00541 
00542         point3d_t pos = this->getPosition();
00543         btTransform T;
00544         T.setOrigin(getBulletVectorFromPoint3d(pos));
00545         btQuaternion q(orient.x, orient.y, orient.z, orient.w);
00546         T.setRotation(q);
00547 
00548         m_obj->setWorldTransform(T);
00549 }
00550 
00551 
00552 
00553 void
00554 ObjectImpl::setLinearVelocity
00555 (
00556 IN const point3d_t& linear
00557 )
00558 {
00559         ASSERT(m_obj, "requires object");
00560 
00561         // moveable object?
00562         if (this->isMoveable()) {
00563                 this->requestMove(linear, 1.0);
00564                 return;
00565         }
00566 
00567         if (!m_rigidBody) {
00568                 return;
00569         }
00570 
00571         m_rigidBody->setLinearVelocity(getBulletVectorFromPoint3d(linear));
00572 }
00573 
00574 
00575 
00576 void
00577 ObjectImpl::setAngularVelocity
00578 (
00579 IN const point3d_t& angular
00580 )
00581 {
00582         ASSERT(m_obj, "requires object");
00583         if (!m_rigidBody) {
00584                 return;
00585         }
00586 
00587         m_rigidBody->setAngularVelocity(getBulletVectorFromPoint3d(angular));
00588 }
00589 
00590 
00591 
00592 void
00593 ObjectImpl::requestMove
00594 (
00595 IN const point3d_t& delta,
00596 IN float dt
00597 )
00598 {
00599         ASSERT(dt > 0.0, "bad time delta: %f", dt);
00600         if (!this->isMoveable()) {
00601                 DPRINTF("Asking a non-moveable object to move?");
00602                 return;
00603         }
00604         ASSERT(m_character, "null");
00605 
00606         // TODO: we are hoping that another requestMove() update comes in
00607         //      before this one expires!  We (outside of the character)
00608         //      have no idea when the time dt expires.
00609         // We probably need a bullet fix for this: moving character objects
00610         //      should advertise their linear velocity.
00611         m_linVel = (1.0 / dt) * delta;
00612 //      m_linVel.dump("Velocity");
00613         m_character->setVelocityForTimeInterval(
00614                 getBulletVectorFromPoint3d(m_linVel), dt);
00615 }
00616 
00617 
00618 
00619 void
00620 ObjectImpl::setPosition
00621 (
00622 IN const point3d_t& pos
00623 )
00624 {
00625         // create a new world transform
00626         btTransform T;
00627         T.setIdentity();
00628         T.setOrigin(getBulletVectorFromPoint3d(pos));
00629 
00630         // move
00631         m_obj->setWorldTransform(T);
00632 }
00633 
00634 
00635 
00636 void
00637 ObjectImpl::iterateOverlappingObjects
00638 (
00639 IN object_iteration_fn fn,
00640 IN void * context
00641 )
00642 {
00643         ASSERT(fn, "null");
00644         // ASSERT(context) -- we don't care!
00645 
00646         btGhostObject * ghost =
00647             dynamic_cast<btGhostObject *>((btCollisionObject *) m_obj);
00648         if (!ghost) {
00649                 DPRINTF("WARNING: can only iterate overlapping pairs for "
00650                     "ghost objects!");
00651                 return;         // do nothing
00652         }
00653 
00654         int numObjects = ghost->getNumOverlappingObjects();
00655         for (int i = 0; i < numObjects; ++i) {
00656                 btCollisionObject * cobj = ghost->getOverlappingObject(i);
00657                 ASSERT(cobj, "null");
00658 
00659                 ObjectImpl * other = getPhysicsObject(cobj);
00660                 ASSERT(other, "null");
00661 
00662                 // get ref-counted object
00663                 // TODO: check performance impact of this additional lookup!
00664                 long id = other->getId();
00665                 smart_ptr<PhysicsObject> obj = getPhysicsObjectById(id);
00666                 ASSERT(obj, "null");
00667 
00668                 // call the provided callback function
00669                 fn(obj, context);
00670         }
00671 }
00672 
00673 
00674 
00675 void
00676 ObjectImpl::addContext
00677 (
00678 IN const physics_meta_t& meta
00679 )
00680 {
00681         // directly copy some meta information to instance
00682         m_flags = meta.objectFlags;
00683 
00684         // copy mass
00685         m_mass = meta.mass;
00686 
00687         // attempt an upcast
00688         m_rigidBody = dynamic_cast<btRigidBody *>((btCollisionObject *) m_obj);
00689 
00690         // store backpointer in bullet collision object
00691         m_obj->setUserPointer((void *) this);
00692 }
00693 
00694 
00695 
00696 smart_ptr<ObjectImpl>
00697 ObjectImpl::create
00698 (
00699 IN smart_ptr<btCollisionObject>& o,
00700 IN const physics_meta_t& meta
00701 )
00702 {
00703         ASSERT(o, "null");
00704 
00705         smart_ptr<ObjectImpl> local = new ObjectImpl;
00706         ASSERT(local, "out of memory");
00707         local->m_obj = o;
00708 
00709         local->addContext(meta);
00710 
00711         return local;
00712 }
00713 
00714 
00715 
00716 smart_ptr<ObjectImpl>
00717 ObjectImpl::create
00718 (
00719 IN smart_ptr<btKinematicCharacterController>& character,
00720 IN smart_ptr<btPairCachingGhostObject>& ghost,
00721 IN const physics_meta_t& meta
00722 )
00723 {
00724         ASSERT(character, "null");
00725         ASSERT(ghost, "null");
00726 
00727         smart_ptr<ObjectImpl> local = new ObjectImpl;
00728         ASSERT(local, "out of memory");
00729 
00730         local->m_character = character;
00731         local->m_ghost = ghost;
00732         local->m_obj = ghost;
00733 
00734         local->addContext(meta);
00735 
00736         return local;
00737 }
00738 
00739 
00740 
00742 //
00743 //      ShapeImpl -- class that implements the PhysicsShape interface
00744 //
00746 
00747 class ShapeImpl : public PhysicsShape {
00748 public:
00749         ~ShapeImpl(void) throw() { }
00750 
00751         // sigh... need yet another place to store bullet state! ---------------
00752         struct private_context_t {
00753                 smart_ptr<btTriangleIndexVertexArray>           tiva;
00754         };
00755 
00756         // aesop::PhysicsShape class interface methods ------------------------
00757         void setContext(IN void * ctx) throw() {
00758                         ASSERT(m_shape, "null");
00759                         m_shape->setUserPointer((void *) ctx);
00760                 }
00761 
00762         void * getContext(void) throw() {
00763                         ASSERT(m_shape, "null");
00764                         return m_shape->getUserPointer();
00765                 }
00766 
00767         // public class methods ------------------------------------------------
00768         btCollisionShape * getShape(void) throw() {
00769                         ASSERT(m_shape, "null");
00770                         return m_shape;
00771                 }
00772 
00773         // static factory methods ----------------------------------------------
00774         static smart_ptr<ShapeImpl> create(IN smart_ptr<btCollisionShape>& shape,
00775                                 IN private_context_t * ctx = NULL)
00776                 {
00777                         ASSERT(shape, "null");
00778                         smart_ptr<ShapeImpl> local = new ShapeImpl;
00779                         ASSERT(local, "out of memory");
00780                         local->m_shape = shape;
00781                         if (ctx) {
00782                                 local->m_ctx = *ctx;
00783                         }
00784                         return local;
00785                 }
00786 
00787 private:
00788         // private data members ------------------------------------------------
00789         smart_ptr<btCollisionShape>     m_shape;
00790         private_context_t               m_ctx;
00791 };
00792 
00793 
00794 
00795 static ShapeImpl *
00796 getShape
00797 (
00798 IN const PhysicsShape * s
00799 )
00800 {
00801         ASSERT(s, "null");
00802 
00803         const ShapeImpl * csi = dynamic_cast<const ShapeImpl *>(s);
00804         ASSERT(csi, "PhysicsShape not implemented with ShapeImpl?");
00805 
00806         // have to cast away const-ness
00807         return (ShapeImpl *) csi;
00808 }
00809 
00810 
00811 
00813 //
00814 //      World -- class that implements the aesop::PhysicsWorld interface
00815 //
00817 
00818 class World : public PhysicsWorld {
00819 public:
00820         World(void) throw();
00821         ~World(void) throw() { this->removeAll(); }
00822 
00823         // public class methods ------------------------------------------------
00824         void initialize(IN const Datahash * params);
00825 
00826         // aesop::PhysicsWorld class interface methods --------------------------
00827         void addObject(IN smart_ptr<PhysicsObject>&obj);
00828         void removeObject(IN PhysicsObject * obj);
00829         long getObjectCount(void) throw();
00830         void tick(IN float seconds);
00831 
00832         void getObjectIterator(OUT object_iterator_t& i);
00833         bool getNextObject(IO object_iterator_t& i,
00834                                 OUT smart_ptr<PhysicsObject>& obj);
00835 
00836         void getCollisionIterator(OUT collision_iterator_t& i);
00837         bool getNextCollision(IO collision_iterator_t& i,
00838                                 OUT collision_record_t& cr);
00839 
00840         smart_ptr<PhysicsObject> rayTest(IN const point3d_t& from,
00841                                 IN const point3d_t& to);
00842 
00843 private:
00844         // private typedefs ----------------------------------------------------
00845         struct real_obj_iter_t {
00846                 dword_t                         magic;
00847                 dword_t                         rvn;
00848                 id_object_map_t::iterator       iter;
00849         };
00850 
00851         struct real_collision_iter_t {
00852                 dword_t                         magic;
00853                 dword_t                         rvn;
00854                 int                             iManifold;
00855         };
00856 
00857         // private helper methods ----------------------------------------------
00858         static real_obj_iter_t * getRealObjectIterator(
00859                                 IN object_iterator_t& i) throw()
00860                 { return (real_obj_iter_t *) &i; }
00861 
00862         static real_collision_iter_t * getRealCollisionIterator(
00863                                 IN collision_iterator_t& i) throw()
00864                 { return (real_collision_iter_t *) &i; }
00865 
00866         void removeObjectInternal(IN ObjectImpl * o);
00867         void removeAll(void);
00868 
00869         // private member data -------------------------------------------------
00870         id_object_map_t                                 m_objects;
00871         int                                             m_maxTimeSteps;
00872         float                                           m_engineTimeStep;
00873         smart_ptr<btDefaultCollisionConfiguration>      m_colcfg;
00874         smart_ptr<btCollisionDispatcher>                m_dispatch;
00875         smart_ptr<btAxisSweep3>                         m_as3;
00876         smart_ptr<btSequentialImpulseConstraintSolver>  m_solver;
00877         smart_ptr<btDiscreteDynamicsWorld>              m_world;
00878         smart_mutex                                     m_mutex;
00879         dword_t                                         m_rvn; // record version
00880 };
00881 
00882 static const dword_t s_dwMagicObject            = 0x34892199;
00883 static const dword_t s_dwMagicCollision         = 0x55784923;
00884 
00885 
00886 
00887 World::World
00888 (
00889 void
00890 )
00891 throw()
00892 {
00893         m_rvn = 777;            // random
00894 }
00895 
00896 
00897 
00898 void
00899 World::initialize
00900 (
00901 IN const Datahash * params
00902 )
00903 {
00904         ASSERT(params, "null");
00905 
00906         // first: sanity checks on iterator sizes
00907         ASSERT2(sizeof(object_iterator_t) >= sizeof(real_obj_iter_t),
00908             "Public iterator is too small!  " << sizeof(object_iterator_t)
00909             << " bytes vs. " << sizeof(real_obj_iter_t) << " bytes.");
00910         ASSERT2(sizeof(collision_iterator_t) >= sizeof(real_collision_iter_t),
00911             "Public iterator is too small!  " << sizeof(collision_iterator_t)
00912             << " bytes vs. " << sizeof(real_collision_iter_t) << " bytes.");
00913 
00914         smart_ptr<Datahash> phys = getSubhash(params, "physics");
00915         ASSERT(phys, "null physics subhash?");
00916 
00917         // look up any parameters from physics section?
00918         float minCoord = getFloat(phys, "minCoord");
00919         float maxCoord = getFloat(phys, "maxCoord");
00920         ASSERT(maxCoord > minCoord, "Bad min/max = %f / %f",
00921             minCoord, maxCoord);
00922 
00923         m_maxTimeSteps = getInt(phys, "maxTimeSteps");
00924         ASSERT(m_maxTimeSteps > 0, "Bad maxTimeSteps: %d",
00925             m_maxTimeSteps);
00926         m_engineTimeStep = getFloat(phys, "engineTimeStep");
00927         ASSERT(m_engineTimeStep > 0.0, "Bad engineTimeStep: %f",
00928             m_engineTimeStep);
00929 
00930         int gravAxis = getInt(phys, "gravityAxis");
00931         ASSERT(gravAxis > -2 && gravAxis < 3, "Bad gravity axis: %d",
00932             gravAxis);
00933         float gravity = getFloat(phys, "gravity");
00934 
00935         // initialize bullet objects
00936         // TODO: understand these better!  See test_bullet code...
00937         DPRINTF("Initializing Bullet physics engine...");
00938         DPRINTF("  physics engine time step = %f seconds",
00939             m_engineTimeStep);
00940 
00941         // collision configuration
00942         m_colcfg = new btDefaultCollisionConfiguration();
00943         ASSERT(m_colcfg, "failed to create collision config");
00944 
00945         // collision dispatcher
00946         m_dispatch = new btCollisionDispatcher(m_colcfg);
00947         ASSERT(m_dispatch, "failed to create collision dispatcher");
00948 
00949         // create axis-aligned bounding box (AABB)
00950         btVector3 min(minCoord, minCoord, minCoord);
00951         btVector3 max(maxCoord, maxCoord, maxCoord);
00952 
00953         m_as3 = new btAxisSweep3(min, max);
00954         ASSERT(m_as3, "Failed to create axis sweep object");
00955 
00956         // constraint solver
00957         m_solver = new btSequentialImpulseConstraintSolver;
00958         ASSERT(m_solver, "failed to create constraint solver");
00959 
00960         // okay, finally create the physics simulation world
00961         m_world = new btDiscreteDynamicsWorld(m_dispatch, m_as3, m_solver,
00962             m_colcfg);
00963         ASSERT(m_world, "failed to create bullet physics world");
00964 
00965         // set up for ghost collisions
00966         m_as3->getOverlappingPairCache()->setInternalGhostPairCallback(
00967             new btGhostPairCallback);
00968 
00969         // set gravity
00970         if (gravAxis >= 0) {
00971                 btVector3 grav(0, 0, 0);
00972                 grav[gravAxis] = gravity;
00973                 dumpVector("  world gravity", grav);
00974                 m_world->setGravity(grav);
00975         }
00976 
00977         // all done!
00978         DPRINTF("Finished initializing physics engine...");
00979 }
00980 
00981 
00982 
00984 //
00985 //      World -- PhysicsWorld class interface methods
00986 //
00988 
00989 void
00990 World::addObject
00991 (
00992 IN smart_ptr<PhysicsObject>& obj
00993 )
00994 {
00995         ASSERT(obj, "null");
00996 
00997 //      obj->dump("Adding object!");
00998 
00999         ObjectImpl * o = getObject(obj);
01000         ASSERT(o, "null");
01001 
01002         // lock!
01003         mlock l(m_mutex);
01004         ++m_rvn;        // modifying data structures...
01005 
01006         // get an id
01007         long id = getNewIdForObject(obj);
01008         o->setId(id);
01009 
01010         btCollisionObject * co = o->getCollisionObject();
01011         btRigidBody * rb = dynamic_cast<btRigidBody *>(co);
01012         if (rb) {
01013 //              DPRINTF("  Adding as rigid body...");
01014                 m_world->addRigidBody(rb);
01015         } else {
01016 //              DPRINTF("  Adding as collision object...");
01017 
01018                 int filterGroup = btBroadphaseProxy::DefaultFilter;
01019                 int filterMask = btBroadphaseProxy::AllFilter;
01020                 m_world->addCollisionObject(co, filterGroup, filterMask);
01021         }
01022 
01023         if (o->isMoveable()) {
01024                 DPRINTF("  Adding character...");
01025                 m_world->addCharacter(o->getCharacter());
01026         }
01027 
01028         // add to our map
01029         m_objects[id] = obj;
01030 }
01031 
01032 
01033 
01034 void
01035 World::removeObject
01036 (
01037 IN PhysicsObject * obj
01038 )
01039 {
01040         ASSERT(obj, "null");
01041         ObjectImpl * o = getObject(obj);
01042         ASSERT(o, "null");
01043 
01044         // lock!
01045         mlock l(m_mutex);
01046         ++m_rvn;        // updating map
01047         this->removeObjectInternal(o);
01048 }
01049 
01050 
01051 
01052 long
01053 World::getObjectCount
01054 (
01055 void
01056 )
01057 throw()
01058 {
01059         // lock!
01060         mlock l(m_mutex);
01061 
01062         int n0 = m_world->getNumCollisionObjects();
01063         int n1 = m_objects.size();
01064         ASSERT(n0 == n1, "World has %d objects, we have %d", n0, n1);
01065         return n1;
01066 }
01067 
01068 
01069 
01070 void
01071 World::tick
01072 (
01073 IN float seconds
01074 )
01075 {
01076         ASSERT(seconds > 0.0, "Bad tick duration: %f", seconds);
01077 
01078         // lock!
01079         mlock l(m_mutex);
01080         ++m_rvn;        // simulation changes state
01081 
01082         // wrap simulation calls with a timer
01083         perf::Timer timer("PhysicsWorld::tick");
01084         long nSteps = (long) (seconds / m_engineTimeStep);
01085         if (nSteps > m_maxTimeSteps) {
01086                 DPRINTF("WARNING: losing time");
01087         }
01088         m_world->stepSimulation(seconds, m_maxTimeSteps,
01089             m_engineTimeStep);
01090 }
01091 
01092 
01093 
01094 void
01095 World::getObjectIterator
01096 (
01097 OUT object_iterator_t& i
01098 )
01099 {
01100         real_obj_iter_t * ri = getRealObjectIterator(i);
01101         ri->magic = s_dwMagicObject;
01102 
01103         // lock!
01104         mlock l(m_mutex);
01105         ri->rvn = m_rvn;
01106         ri->iter = m_objects.begin();
01107 }
01108 
01109 
01110 
01111 bool
01112 World::getNextObject
01113 (
01114 IO object_iterator_t& i,
01115 OUT smart_ptr<PhysicsObject>& obj
01116 )
01117 {
01118         obj = NULL;
01119         real_obj_iter_t * ri = getRealObjectIterator(i);
01120         if (s_dwMagicObject != ri->magic) {
01121                 WAVE_EX(wex);
01122                 wex << "Invalid iterator passed to getNextObject()";
01123         }
01124 
01125         // lock!
01126         mlock l(m_mutex);
01127         if (ri->rvn != m_rvn)
01128                 return false;           // something changed!
01129 
01130         if (m_objects.end() == ri->iter)
01131                 return false;           // end of iteration
01132 
01133         // have a valid iterator
01134         obj = ri->iter->second;
01135         ASSERT(obj, "null object in our map");
01136         ++ri->iter;
01137         return true;
01138 }
01139 
01140 
01141 
01142 void
01143 World::getCollisionIterator
01144 (
01145 OUT collision_iterator_t& i
01146 )
01147 {
01148         real_collision_iter_t * ri = getRealCollisionIterator(i);
01149         ri->magic = s_dwMagicCollision;
01150 
01151         // lock!
01152         mlock l(m_mutex);
01153         ri->rvn = m_rvn;
01154         ri->iManifold = 0;
01155 }
01156 
01157 
01158 
01159 bool
01160 World::getNextCollision
01161 (
01162 IO collision_iterator_t& i,
01163 OUT collision_record_t& cr
01164 )
01165 {
01166         cr.clear();
01167         real_collision_iter_t * ri = getRealCollisionIterator(i);
01168         if (s_dwMagicCollision != ri->magic) {
01169                 WAVE_EX(wex);
01170                 wex << "Invalid collision iterator in getNextCollision()";
01171         }
01172 
01173         // lock!
01174         mlock l(m_mutex);
01175 
01176         // does the record version number (rvn) match?
01177         if (m_rvn != ri->rvn)
01178                 return false;   // something has changed
01179 
01180         int N = m_dispatch->getNumManifolds();
01181         if (ri->iManifold >= N)
01182                 return false;   // end of iteration
01183 
01184         // loop through remaining manifolds
01185         for (; ri->iManifold < N; ++ri->iManifold) {
01186                 btPersistentManifold * m =
01187                     m_dispatch->getManifoldByIndexInternal(ri->iManifold);
01188                 if (!m || !m->getNumContacts())
01189                         continue;       // skip boring manifolds
01190 
01191                 ObjectImpl * o0 = getPhysicsObject(m->getBody0());
01192                 ObjectImpl * o1 = getPhysicsObject(m->getBody1());
01193 
01194                 if (o0->wantCollisionEvents() &&
01195                     o1->wantCollisionEvents()) {
01196                         // got a collision!
01197                         cr.obj1 = getPhysicsObjectById(o0->getId());
01198                         cr.obj2 = getPhysicsObjectById(o1->getId());
01199                         ASSERT(cr.obj1 && cr.obj2,
01200                             "objects in collision not in global id map");
01201                         return true;
01202                 }
01203         }
01204 
01205         // got here?  end of iteration
01206         return false;
01207 }
01208 
01209 
01210 
01211 smart_ptr<PhysicsObject>
01212 World::rayTest
01213 (
01214 IN const point3d_t& from,
01215 IN const point3d_t& to
01216 )
01217 {
01218         perf::Timer timer("PhysicsWorld::rayTest");
01219         ASSERT(m_world, "null");
01220 
01221         // xform to btVector3 objects
01222         btVector3 btFrom = getBulletVectorFromPoint3d(from);
01223         btVector3 btTo = getBulletVectorFromPoint3d(to);
01224 
01225         // construct raycast callback object
01226         btCollisionWorld::ClosestRayResultCallback rayCallback(btFrom, btTo);
01227 
01228         // lock
01229         mlock m(m_mutex);
01230 
01231         // raycast in world
01232         m_world->rayTest(btFrom, btTo, rayCallback);
01233 
01234         // hit anything?
01235         if (!rayCallback.hasHit())
01236                 return NULL;            // nope
01237 
01238         // hit something--figure out what it was!
01239         ASSERT(rayCallback.m_collisionObject, "null");
01240         ObjectImpl * poi = getPhysicsObject(rayCallback.m_collisionObject);
01241         ASSERT(poi, "null");
01242 
01243         // a bit weird--we need to do another lookup to verify we hand back
01244         //   a safely ref-counted pointer.  If this becomes a performance
01245         //   issue, we may need another level of indirection in the
01246         //   bullet user pointer.
01247         long id = poi->getId();
01248         ASSERT(id, "bad object ID");
01249         return getPhysicsObjectById(id);
01250 }
01251 
01252 
01253 
01255 //
01256 //      World -- private helper methods
01257 //
01259 
01260 void
01261 World::removeObjectInternal
01262 (
01263 IN ObjectImpl * o
01264 )
01265 {
01266         // NOTE: assumes the caller has taken the mutex!
01267         // also, caller should update rvn if appropriate
01268         ASSERT(o, "null");
01269 
01270         // take out of global ID map
01271         long id = o->getId();
01272         removeObjectFromIdMap(id);
01273         o->setId(0);            // no longer ID'd
01274 
01275         // remove from world
01276         btCollisionObject * bto = o->getCollisionObject();
01277         btRigidBody * btr = dynamic_cast<btRigidBody *>(bto);
01278         if (btr) {
01279                 m_world->removeRigidBody(btr);
01280         } else {
01281                 m_world->removeCollisionObject(bto);
01282         }
01283 
01284         btKinematicCharacterController * btc = o->getCharacter();
01285         if (btc) {
01286                 m_world->removeCharacter(btc);
01287         }
01288 
01289         // remove from our collection
01290         id_object_map_t::iterator i = m_objects.find(id);
01291         if (m_objects.end() != i) {
01292                 m_objects.erase(i);
01293         }
01294 }
01295 
01296 
01297 
01298 void
01299 World::removeAll
01300 (
01301 void
01302 )
01303 {
01304         // NOTE: assumes caller has taken mutex!
01305         // caller should also increment rvn if appropriate
01306         while (m_objects.size() > 0) {
01307                 id_object_map_t::iterator i = m_objects.begin();
01308                 smart_ptr<PhysicsObject> obj = i->second;
01309                 ASSERT(obj, "null object in our id map");
01310 
01311                 ObjectImpl * o = getObject(obj);
01312                 ASSERT(o, "null");
01313 
01314                 this->removeObjectInternal(o);
01315         }
01316 }
01317 
01318 
01319 
01321 //
01322 //      public API
01323 //
01325 
01326 void
01327 getVectorFromEulerAngles
01328 (
01329 IN const point3d_t& euler,
01330 OUT point3d_t& vector
01331 )
01332 throw()
01333 {
01334         btQuaternion q;
01335         q.setEulerZYX(euler.z, euler.y, euler.x);
01336 
01337         btTransform T(q);
01338 
01339         btVector3 out = T * btVector3(0, 0, 1);
01340         vector.x = out.x();
01341         vector.y = out.y();
01342         vector.z = out.z();
01343 }
01344 
01345 
01346 
01347 void
01348 getVectorFromQuaternion
01349 (
01350 IN const quaternion_t& q,
01351 OUT point3d_t& vector
01352 )
01353 throw()
01354 {
01355         btQuaternion Q(q.x, q.y, q.z, q.w);
01356         btTransform T(Q);
01357 
01358         btVector3 out = T * btVector3(0, 0, 1);
01359         vector.x = out.x();
01360         vector.y = out.y();
01361         vector.z = out.z();
01362 }
01363 
01364 
01365 
01366 void
01367 dumpWorld
01368 (
01369 IN PhysicsWorld * world
01370 )
01371 throw()
01372 {
01373         ASSERT(world, "null");
01374 
01375         DPRINTF("Debug information for physics world:");
01376 
01377         PhysicsWorld::object_iterator_t i;
01378         world->getObjectIterator(i);
01379         smart_ptr<PhysicsObject> obj;
01380         while (world->getNextObject(i, obj)) {
01381                 ASSERT(obj, "null");
01382                 obj->dump("");
01383         }
01384 }
01385 
01386 
01387 
01388 
01389 void
01390 getTransformFromPlacement
01391 (
01392 IN const placement_t& placement,
01393 OUT Transform3D& T
01394 )
01395 {
01396         T.setIdentity();
01397         T.setOrigin(getBulletVectorFromPoint3d(placement.position));
01398         btQuaternion q(placement.rotation.x, placement.rotation.y,
01399                         placement.rotation.z, placement.rotation.w);
01400         T.setRotation(q);
01401 }
01402 
01403 
01404 
01405 smart_ptr<PhysicsShape>
01406 createBoxShape
01407 (
01408 IN const point3d_t& dimensions
01409 )
01410 {
01411         ASSERT(dimensions.x >= 0.0, "Bad box x-dimension: %f", dimensions.x);
01412         ASSERT(dimensions.y >= 0.0, "Bad box y-dimension: %f", dimensions.y);
01413         ASSERT(dimensions.z >= 0.0, "Bad box z-dimension: %f", dimensions.z);
01414 
01415         btVector3 halfExtent(0.5 * dimensions.x, 0.5 * dimensions.y,
01416             0.5 * dimensions.z);
01417         smart_ptr<btCollisionShape> shape = new btBoxShape(halfExtent);
01418         ASSERT(shape, "out of memory");
01419 
01420         return ShapeImpl::create(shape);
01421 }
01422 
01423 
01424 
01425 smart_ptr<PhysicsShape>
01426 createCubeShape
01427 (
01428 IN float edge_length
01429 )
01430 {
01431         ASSERT(edge_length > 0.0, "Bad cube edge length: %f", edge_length);
01432 
01433         return createBoxShape(point3d_t(edge_length, edge_length, edge_length));
01434 }
01435 
01436 
01437 
01438 smart_ptr<PhysicsShape>
01439 createTrimeshShape
01440 (
01441 IN const trimesh::Trimesh * trimesh
01442 )
01443 {
01444         ASSERT(trimesh, "null");
01445 
01446         const int triangleStride = 3 * sizeof(int);
01447         const int vertexStride = sizeof(point3d_t);
01448 
01449         // create object that lets bullet access vertex/triangle arrays
01450         // we put this in shape private context so the shape can own it
01451         ShapeImpl::private_context_t pctx;
01452         pctx.tiva = new btTriangleIndexVertexArray(
01453             trimesh->getTriangleCount(), (int *) trimesh->getTriangleArray(), triangleStride,
01454             trimesh->getVertexCount(), (btScalar *) trimesh->getVertexArray(), vertexStride);
01455         ASSERT(pctx.tiva, "out of memory");
01456 
01457         // create actual bullet triangle mesh
01458         btBvhTriangleMeshShape * btmShape =
01459             new btBvhTriangleMeshShape(pctx.tiva, true);
01460         ASSERT(btmShape, "null");
01461 
01462         // wrap and return
01463         smart_ptr<btCollisionShape> shape = btmShape;
01464         return ShapeImpl::create(shape, &pctx);
01465 }
01466 
01467 
01468 
01469 smart_ptr<PhysicsShape>
01470 createHeightfieldShape
01471 (
01472 IN const hfield::Heightfield * field
01473 )
01474 {
01475         ASSERT(field, "null");
01476 
01477         DPRINTF("Constructing heightfield shape");
01478 
01479         // construct btHeightfieldTerrainShape
01480         long width = field->getWidth();
01481         long length = field->getLength();
01482         DPRINTF("  width = %ld", width);
01483         DPRINTF("  length= %ld", length);
01484         ASSERT(width > 1 && length > 1, "Bad width/length?");
01485 
01486         long nSize = width * length;
01487         DPRINTF("  size  = %ld", nSize);
01488 
01489         float yScale = field->getYScale();
01490         DPRINTF("  yScale = %f", yScale);
01491         ASSERT(yScale > 0.0, "Bad y-scale: %f", yScale);
01492 
01493         const short * raw = field->getHeightArray();
01494         ASSERT(raw, "null height array?");
01495 
01496         // min/max height
01497         float minHeight = field->getMinHeight() * yScale;
01498         float maxHeight = field->getMaxHeight() * yScale;
01499         DPRINTF("  min = %f", minHeight);
01500         DPRINTF("  max = %f", maxHeight);
01501 
01502         int upAxis = 1;         // y-axis is "up"
01503 
01504         btHeightfieldTerrainShape * terrain =
01505             new btHeightfieldTerrainShape(width, length, (void *) raw, yScale,
01506                                           minHeight, maxHeight, upAxis,
01507                                           PHY_SHORT, false);
01508         ASSERT(terrain, "out of memory");
01509         DPRINTF("Successfully created a btHeightfieldTerrainShape!");
01510 
01511         // apply local scaling (grid spacing)
01512         float xzScale = field->getXZScale();
01513         ASSERT(xzScale > 0.0, "Bad xz scale: %f", xzScale);
01514         btVector3 localScaling(xzScale, 1.0, xzScale);
01515         terrain->setLocalScaling(localScaling);
01516 
01517         // wrap and return
01518         smart_ptr<btCollisionShape> shape = terrain;
01519         return ShapeImpl::create(shape);
01520 }
01521 
01522 
01523 
01524 smart_ptr<PhysicsShape>
01525 createCapsuleShape
01526 (
01527 IN float height,
01528 IN float radius
01529 )
01530 {
01531         ASSERT(height > 0, "Bad capsule height: %f", height);
01532         ASSERT(radius > 0, "Bad capsule radius: %f", radius);
01533 
01534         smart_ptr<btCapsuleShape> capsule = new btCapsuleShape(radius, height);
01535         ASSERT(capsule, "out of memory");
01536 
01537         smart_ptr<btCollisionShape> shape = capsule;
01538         return ShapeImpl::create(shape);
01539 }
01540 
01541 
01542 
01543 smart_ptr<PhysicsObject>
01544 createMoveableObject
01545 (
01546 IN const physics_meta_t& meta,
01547 IN const placement_t& placement
01548 )
01549 {
01550         ASSERT(meta.shape, "null");
01551         ASSERT(meta.mass >= 0.0, "Bad mass: %f", meta.mass);
01552 
01553         // create transform from instance
01554         Transform3D T;
01555         getTransformFromPlacement(placement, T);
01556 
01557         // get actual bullet shape
01558         ShapeImpl * si = getShape(meta.shape);
01559         ASSERT(si, "null");
01560         btCollisionShape * shape1 = si->getShape();
01561         ASSERT(shape1, "null");
01562         btConvexShape * shape = dynamic_cast<btConvexShape *>(shape1);
01563         ASSERT(shape, "moveable objects must use convex shapes!");
01564 
01565         // okay, create ghost
01566         smart_ptr<btPairCachingGhostObject> ghost =
01567             new btPairCachingGhostObject;
01568         ASSERT(ghost, "out of memory");
01569         ghost->setWorldTransform(T);
01570         ghost->setCollisionShape(shape);
01571         ghost->setCollisionFlags(s_ghostCollisionFlags);
01572 
01573         // create character
01574         smart_ptr<btKinematicCharacterController> character =
01575             new btKinematicCharacterController(ghost, shape, s_stepHeight);
01576         ASSERT(character, "out of memory");
01577 
01578         // create this object
01579         return ObjectImpl::create(character, ghost, meta);
01580 }
01581 
01582 
01583 
01584 smart_ptr<PhysicsObject>
01585 createObject
01586 (
01587 IN const physics_meta_t& meta,
01588 IN const placement_t& placement
01589 )
01590 {
01591         ASSERT(meta.shape, "null");
01592         ASSERT(meta.mass >= 0.0, "Bad mass: %f", meta.mass);
01593 
01594         // quick shortcut--moveable is handled differently for now...
01595         if (PhysicsObject::eFlag_Moveable & meta.objectFlags) {
01596                 return createMoveableObject(meta, placement);
01597         }
01598 
01599         // create transform from instance
01600         Transform3D T;
01601         getTransformFromPlacement(placement, T);
01602 
01603         bool isDynamic = (meta.mass > 0.0);
01604 
01605         // get actual bullet shape
01606         ShapeImpl * si = getShape(meta.shape);
01607         ASSERT(si, "null");
01608         btCollisionShape * shape = si->getShape();
01609         ASSERT(shape, "null");
01610 
01611         smart_ptr<btCollisionObject> obj;
01612         if (PhysicsObject::eFlag_Ghost & meta.objectFlags) {
01613                 if (meta.mass > 0.0) {
01614                         WAVE_EX(wex);
01615                         wex << "Only immobile ghost objects allowed for now.";
01616                 }
01617 
01618                 // okay, create ghost
01619                 smart_ptr<btPairCachingGhostObject> ghost =
01620                     new btPairCachingGhostObject;
01621                 ASSERT(ghost, "out of memory");
01622                 ghost->setWorldTransform(T);
01623                 ghost->setCollisionShape(shape);
01624 
01625                 int flags = s_ghostCollisionFlags;
01626                 if (PhysicsObject::eFlag_NoCollisions & meta.objectFlags) {
01627                         // override default ghost behavior
01628                         DPRINTF("Updating flags!");
01629                         flags = btCollisionObject::CF_NO_CONTACT_RESPONSE;
01630                 }
01631                 ghost->setCollisionFlags(flags);
01632                 obj = ghost;
01633         } else {
01634                 // not a ghost!  add real object
01635 
01636                 // determine inertia
01637                 btVector3 localInertia(0, 0, 0);
01638                 if (isDynamic) {
01639                         shape->calculateLocalInertia(meta.mass, localInertia);
01640                 }
01641 
01642                 // leak!
01643                 btDefaultMotionState * motionState = new btDefaultMotionState(T);
01644                 ASSERT(motionState, "null");
01645                 motionState->setWorldTransform(T);
01646 
01647                 // create rigid body
01648                 btRigidBody::btRigidBodyConstructionInfo
01649                     info(meta.mass, motionState, shape, localInertia);
01650                 smart_ptr<btRigidBody> body = new btRigidBody(info);
01651                 ASSERT(body, "out of memory");
01652                 obj = body;
01653         }
01654 
01655         // wrap
01656         ASSERT(obj, "should have collision object now");
01657         return ObjectImpl::create(obj, meta);
01658 }
01659 
01660 
01661 
01662 smart_ptr<PhysicsWorld>
01663 PhysicsWorld::create
01664 (
01665 IN const Datahash * params
01666 )
01667 {
01668         ASSERT(params, "null");
01669 
01670         smart_ptr<World> local = new World;
01671         ASSERT(local, "out of memory");
01672 
01673         local->initialize(params);
01674 
01675         return local;
01676 }
01677 
01678 
01679 
01680 smart_ptr<PhysicsObject>
01681 getObjectHitFromPlacement
01682 (
01683 IN PhysicsWorld * world,
01684 IN const placement_t& placement,
01685 IN float half_extent
01686 )
01687 {
01688         ASSERT(world, "null");
01689         ASSERT(half_extent > 0, "Bad half extent: %f", half_extent);
01690 
01691         const float max_range = 256.0;
01692 
01693         // get the orientation (what direction the object is pointed)
01694         point3d_t dir;
01695         getVectorFromQuaternion(placement.rotation, dir);
01696 
01697         point3d_t from = placement.position + half_extent * dir;
01698         point3d_t to = from + max_range * dir;
01699 
01700         return world->rayTest(from, to);
01701 }
01702 
01703 
01704 
01705 };              // aesop namespace
01706