Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/external/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp @ 8353

Last change on this file since 8353 was 8351, checked in by rgrieder, 14 years ago

Merged kicklib2 branch back to trunk (includes former branches ois_update, mac_osx and kicklib).

Notes for updating

Linux:
You don't need an extra package for CEGUILua and Tolua, it's already shipped with CEGUI.
However you do need to make sure that the OgreRenderer is installed too with CEGUI 0.7 (may be a separate package).
Also, Orxonox now recognises if you install the CgProgramManager (a separate package available on newer Ubuntu on Debian systems).

Windows:
Download the new dependency packages versioned 6.0 and use these. If you have problems with that or if you don't like the in game console problem mentioned below, you can download the new 4.3 version of the packages (only available for Visual Studio 2005/2008).

Key new features:

  • *Support for Mac OS X*
  • Visual Studio 2010 support
  • Bullet library update to 2.77
  • OIS library update to 1.3
  • Support for CEGUI 0.7 —> Support for Arch Linux and even SuSE
  • Improved install target
  • Compiles now with GCC 4.6
  • Ogre Cg Shader plugin activated for Linux if available
  • And of course lots of bug fixes

There are also some regressions:

  • No support for CEGUI 0.5, Ogre 1.4 and boost 1.35 - 1.39 any more
  • In game console is not working in main menu for CEGUI 0.7
  • Tolua (just the C lib, not the application) and CEGUILua libraries are no longer in our repository. —> You will need to get these as well when compiling Orxonox
  • And of course lots of new bugs we don't yet know about
  • Property svn:eol-style set to native
File size: 33.5 KB
RevLine 
[1963]1/*
2Bullet Continuous Collision Detection and Physics Library
[8351]3Copyright (c) 2003-2009 Erwin Coumans  http://bulletphysics.org
[1963]4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15
16
17#include "btDiscreteDynamicsWorld.h"
18
19//collision detection
20#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
21#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h"
[8351]22#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
[1963]23#include "BulletCollision/CollisionShapes/btCollisionShape.h"
24#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h"
25#include "LinearMath/btTransformUtil.h"
26#include "LinearMath/btQuickprof.h"
27
28//rigidbody & constraints
29#include "BulletDynamics/Dynamics/btRigidBody.h"
30#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h"
31#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h"
32#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
[2882]33#include "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h"
34#include "BulletDynamics/ConstraintSolver/btHingeConstraint.h"
35#include "BulletDynamics/ConstraintSolver/btConeTwistConstraint.h"
36#include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h"
37#include "BulletDynamics/ConstraintSolver/btSliderConstraint.h"
[1963]38
[8351]39#include "LinearMath/btIDebugDraw.h"
[1963]40#include "BulletCollision/CollisionShapes/btSphereShape.h"
41
42
[2882]43#include "BulletDynamics/Dynamics/btActionInterface.h"
[1963]44#include "LinearMath/btQuickprof.h"
45#include "LinearMath/btMotionState.h"
46
[8351]47#include "LinearMath/btSerializer.h"
[1963]48
49
50
51btDiscreteDynamicsWorld::btDiscreteDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver, btCollisionConfiguration* collisionConfiguration)
52:btDynamicsWorld(dispatcher,pairCache,collisionConfiguration),
53m_constraintSolver(constraintSolver),
54m_gravity(0,-10,0),
[8351]55m_localTime(0),
56m_synchronizeAllMotionStates(false),
[1963]57m_profileTimings(0)
58{
59        if (!m_constraintSolver)
60        {
61                void* mem = btAlignedAlloc(sizeof(btSequentialImpulseConstraintSolver),16);
62                m_constraintSolver = new (mem) btSequentialImpulseConstraintSolver;
63                m_ownsConstraintSolver = true;
64        } else
65        {
66                m_ownsConstraintSolver = false;
67        }
68
69        {
70                void* mem = btAlignedAlloc(sizeof(btSimulationIslandManager),16);
71                m_islandManager = new (mem) btSimulationIslandManager();
72        }
73
74        m_ownsIslandManager = true;
75}
76
77
78btDiscreteDynamicsWorld::~btDiscreteDynamicsWorld()
79{
80        //only delete it when we created it
81        if (m_ownsIslandManager)
82        {
83                m_islandManager->~btSimulationIslandManager();
84                btAlignedFree( m_islandManager);
85        }
86        if (m_ownsConstraintSolver)
87        {
88
89                m_constraintSolver->~btConstraintSolver();
90                btAlignedFree(m_constraintSolver);
91        }
92}
93
94void    btDiscreteDynamicsWorld::saveKinematicState(btScalar timeStep)
95{
[8351]96///would like to iterate over m_nonStaticRigidBodies, but unfortunately old API allows
97///to switch status _after_ adding kinematic objects to the world
98///fix it for Bullet 3.x release
[1963]99        for (int i=0;i<m_collisionObjects.size();i++)
100        {
101                btCollisionObject* colObj = m_collisionObjects[i];
102                btRigidBody* body = btRigidBody::upcast(colObj);
[8351]103                if (body && body->getActivationState() != ISLAND_SLEEPING)
[1963]104                {
[8351]105                        if (body->isKinematicObject())
106                        {
107                                //to calculate velocities next frame
108                                body->saveKinematicState(timeStep);
109                        }
[1963]110                }
111        }
[8351]112
[1963]113}
114
115void    btDiscreteDynamicsWorld::debugDrawWorld()
116{
[2430]117        BT_PROFILE("debugDrawWorld");
[1963]118
[8351]119        btCollisionWorld::debugDrawWorld();
[1963]120
[2882]121        bool drawConstraints = false;
122        if (getDebugDrawer())
123        {
124                int mode = getDebugDrawer()->getDebugMode();
125                if(mode  & (btIDebugDraw::DBG_DrawConstraints | btIDebugDraw::DBG_DrawConstraintLimits))
126                {
127                        drawConstraints = true;
128                }
129        }
130        if(drawConstraints)
131        {
132                for(int i = getNumConstraints()-1; i>=0 ;i--)
133                {
134                        btTypedConstraint* constraint = getConstraint(i);
135                        debugDrawConstraint(constraint);
136                }
137        }
[1963]138
139
[2882]140
[1963]141        if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb))
142        {
143                int i;
144
[2882]145                if (getDebugDrawer() && getDebugDrawer()->getDebugMode())
[1963]146                {
[2882]147                        for (i=0;i<m_actions.size();i++)
[1963]148                        {
[2882]149                                m_actions[i]->debugDraw(m_debugDrawer);
[1963]150                        }
151                }
152        }
153}
154
155void    btDiscreteDynamicsWorld::clearForces()
156{
[2430]157        ///@todo: iterate over awake simulation islands!
[8351]158        for ( int i=0;i<m_nonStaticRigidBodies.size();i++)
[1963]159        {
[8351]160                btRigidBody* body = m_nonStaticRigidBodies[i];
161                //need to check if next line is ok
162                //it might break backward compatibility (people applying forces on sleeping objects get never cleared and accumulate on wake-up
163                body->clearForces();
[1963]164        }
165}       
166
167///apply gravity, call this once per timestep
168void    btDiscreteDynamicsWorld::applyGravity()
169{
[2430]170        ///@todo: iterate over awake simulation islands!
[8351]171        for ( int i=0;i<m_nonStaticRigidBodies.size();i++)
[1963]172        {
[8351]173                btRigidBody* body = m_nonStaticRigidBodies[i];
174                if (body->isActive())
[1963]175                {
176                        body->applyGravity();
177                }
178        }
179}
180
181
[2430]182void    btDiscreteDynamicsWorld::synchronizeSingleMotionState(btRigidBody* body)
183{
184        btAssert(body);
[1963]185
[2430]186        if (body->getMotionState() && !body->isStaticOrKinematicObject())
187        {
188                //we need to call the update at least once, even for sleeping objects
189                //otherwise the 'graphics' transform never updates properly
190                ///@todo: add 'dirty' flag
191                //if (body->getActivationState() != ISLAND_SLEEPING)
192                {
193                        btTransform interpolatedTransform;
194                        btTransformUtil::integrateTransform(body->getInterpolationWorldTransform(),
195                                body->getInterpolationLinearVelocity(),body->getInterpolationAngularVelocity(),m_localTime*body->getHitFraction(),interpolatedTransform);
196                        body->getMotionState()->setWorldTransform(interpolatedTransform);
197                }
198        }
199}
200
201
[1963]202void    btDiscreteDynamicsWorld::synchronizeMotionStates()
203{
[2430]204        BT_PROFILE("synchronizeMotionStates");
[8351]205        if (m_synchronizeAllMotionStates)
[1963]206        {
[8351]207                //iterate  over all collision objects
[1963]208                for ( int i=0;i<m_collisionObjects.size();i++)
209                {
210                        btCollisionObject* colObj = m_collisionObjects[i];
211                        btRigidBody* body = btRigidBody::upcast(colObj);
[2430]212                        if (body)
213                                synchronizeSingleMotionState(body);
[1963]214                }
[8351]215        } else
[1963]216        {
[8351]217                //iterate over all active rigid bodies
218                for ( int i=0;i<m_nonStaticRigidBodies.size();i++)
[1963]219                {
[8351]220                        btRigidBody* body = m_nonStaticRigidBodies[i];
221                        if (body->isActive())
222                                synchronizeSingleMotionState(body);
[1963]223                }
224        }
225}
226
227
228int     btDiscreteDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps, btScalar fixedTimeStep)
229{
230        startProfiling(timeStep);
231
232        BT_PROFILE("stepSimulation");
233
234        int numSimulationSubSteps = 0;
235
236        if (maxSubSteps)
237        {
238                //fixed timestep with interpolation
239                m_localTime += timeStep;
240                if (m_localTime >= fixedTimeStep)
241                {
242                        numSimulationSubSteps = int( m_localTime / fixedTimeStep);
243                        m_localTime -= numSimulationSubSteps * fixedTimeStep;
244                }
245        } else
246        {
247                //variable timestep
248                fixedTimeStep = timeStep;
249                m_localTime = timeStep;
250                if (btFuzzyZero(timeStep))
251                {
252                        numSimulationSubSteps = 0;
253                        maxSubSteps = 0;
254                } else
255                {
256                        numSimulationSubSteps = 1;
257                        maxSubSteps = 1;
258                }
259        }
260
261        //process some debugging flags
262        if (getDebugDrawer())
263        {
[2882]264                btIDebugDraw* debugDrawer = getDebugDrawer ();
265                gDisableDeactivation = (debugDrawer->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0;
[1963]266        }
267        if (numSimulationSubSteps)
268        {
269
[8351]270                //clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
271                int clampedSimulationSteps = (numSimulationSubSteps > maxSubSteps)? maxSubSteps : numSimulationSubSteps;
[1963]272
[8351]273                saveKinematicState(fixedTimeStep*clampedSimulationSteps);
274
[1963]275                applyGravity();
276
[8351]277               
[1963]278
279                for (int i=0;i<clampedSimulationSteps;i++)
280                {
281                        internalSingleStepSimulation(fixedTimeStep);
282                        synchronizeMotionStates();
283                }
284
[8351]285        } else
286        {
287                synchronizeMotionStates();
288        }
[1963]289
290        clearForces();
291
292#ifndef BT_NO_PROFILE
293        CProfileManager::Increment_Frame_Counter();
294#endif //BT_NO_PROFILE
295       
296        return numSimulationSubSteps;
297}
298
299void    btDiscreteDynamicsWorld::internalSingleStepSimulation(btScalar timeStep)
300{
301       
302        BT_PROFILE("internalSingleStepSimulation");
303
[8351]304        if(0 != m_internalPreTickCallback) {
305                (*m_internalPreTickCallback)(this, timeStep);
306        }       
307
[1963]308        ///apply gravity, predict motion
309        predictUnconstraintMotion(timeStep);
310
311        btDispatcherInfo& dispatchInfo = getDispatchInfo();
312
313        dispatchInfo.m_timeStep = timeStep;
314        dispatchInfo.m_stepCount = 0;
315        dispatchInfo.m_debugDraw = getDebugDrawer();
316
317        ///perform collision detection
318        performDiscreteCollisionDetection();
319
320        calculateSimulationIslands();
321
322       
323        getSolverInfo().m_timeStep = timeStep;
324       
325
326
327        ///solve contact and other joint constraints
328        solveConstraints(getSolverInfo());
329       
330        ///CallbackTriggers();
331
332        ///integrate transforms
333        integrateTransforms(timeStep);
334
335        ///update vehicle simulation
[2882]336        updateActions(timeStep);
[2430]337       
[1963]338        updateActivationState( timeStep );
339
340        if(0 != m_internalTickCallback) {
341                (*m_internalTickCallback)(this, timeStep);
342        }       
343}
344
345void    btDiscreteDynamicsWorld::setGravity(const btVector3& gravity)
346{
347        m_gravity = gravity;
[8351]348        for ( int i=0;i<m_nonStaticRigidBodies.size();i++)
[1963]349        {
[8351]350                btRigidBody* body = m_nonStaticRigidBodies[i];
351                if (body->isActive() && !(body->getFlags() &BT_DISABLE_WORLD_GRAVITY))
[1963]352                {
353                        body->setGravity(gravity);
354                }
355        }
356}
357
358btVector3 btDiscreteDynamicsWorld::getGravity () const
359{
360        return m_gravity;
361}
362
[8351]363void    btDiscreteDynamicsWorld::addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup,short int collisionFilterMask)
364{
365        btCollisionWorld::addCollisionObject(collisionObject,collisionFilterGroup,collisionFilterMask);
366}
[1963]367
[8351]368void    btDiscreteDynamicsWorld::removeCollisionObject(btCollisionObject* collisionObject)
369{
370        btRigidBody* body = btRigidBody::upcast(collisionObject);
371        if (body)
372                removeRigidBody(body);
373        else
374                btCollisionWorld::removeCollisionObject(collisionObject);
375}
376
[1963]377void    btDiscreteDynamicsWorld::removeRigidBody(btRigidBody* body)
378{
[8351]379        m_nonStaticRigidBodies.remove(body);
380        btCollisionWorld::removeCollisionObject(body);
[1963]381}
382
[8351]383
[1963]384void    btDiscreteDynamicsWorld::addRigidBody(btRigidBody* body)
385{
[8351]386        if (!body->isStaticOrKinematicObject() && !(body->getFlags() &BT_DISABLE_WORLD_GRAVITY))
[1963]387        {
388                body->setGravity(m_gravity);
389        }
390
391        if (body->getCollisionShape())
392        {
[8351]393                if (!body->isStaticObject())
394                {
395                        m_nonStaticRigidBodies.push_back(body);
396                } else
397                {
398                        body->setActivationState(ISLAND_SLEEPING);
399                }
400
[1963]401                bool isDynamic = !(body->isStaticObject() || body->isKinematicObject());
402                short collisionFilterGroup = isDynamic? short(btBroadphaseProxy::DefaultFilter) : short(btBroadphaseProxy::StaticFilter);
403                short collisionFilterMask = isDynamic?  short(btBroadphaseProxy::AllFilter) :   short(btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter);
404
405                addCollisionObject(body,collisionFilterGroup,collisionFilterMask);
406        }
407}
408
409void    btDiscreteDynamicsWorld::addRigidBody(btRigidBody* body, short group, short mask)
410{
[8351]411        if (!body->isStaticOrKinematicObject() && !(body->getFlags() &BT_DISABLE_WORLD_GRAVITY))
[1963]412        {
413                body->setGravity(m_gravity);
414        }
415
416        if (body->getCollisionShape())
417        {
[8351]418                if (!body->isStaticObject())
419                {
420                        m_nonStaticRigidBodies.push_back(body);
421                }
422                 else
423                {
424                        body->setActivationState(ISLAND_SLEEPING);
425                }
[1963]426                addCollisionObject(body,group,mask);
427        }
428}
429
430
[2882]431void    btDiscreteDynamicsWorld::updateActions(btScalar timeStep)
[1963]432{
[2882]433        BT_PROFILE("updateActions");
[1963]434       
[2882]435        for ( int i=0;i<m_actions.size();i++)
[1963]436        {
[2882]437                m_actions[i]->updateAction( this, timeStep);
[1963]438        }
439}
[2430]440       
441       
[1963]442void    btDiscreteDynamicsWorld::updateActivationState(btScalar timeStep)
443{
444        BT_PROFILE("updateActivationState");
445
[8351]446        for ( int i=0;i<m_nonStaticRigidBodies.size();i++)
[1963]447        {
[8351]448                btRigidBody* body = m_nonStaticRigidBodies[i];
[1963]449                if (body)
450                {
451                        body->updateDeactivation(timeStep);
452
453                        if (body->wantsSleeping())
454                        {
455                                if (body->isStaticOrKinematicObject())
456                                {
457                                        body->setActivationState(ISLAND_SLEEPING);
458                                } else
459                                {
460                                        if (body->getActivationState() == ACTIVE_TAG)
461                                                body->setActivationState( WANTS_DEACTIVATION );
462                                        if (body->getActivationState() == ISLAND_SLEEPING) 
463                                        {
464                                                body->setAngularVelocity(btVector3(0,0,0));
465                                                body->setLinearVelocity(btVector3(0,0,0));
466                                        }
467
468                                }
469                        } else
470                        {
471                                if (body->getActivationState() != DISABLE_DEACTIVATION)
472                                        body->setActivationState( ACTIVE_TAG );
473                        }
474                }
475        }
476}
477
478void    btDiscreteDynamicsWorld::addConstraint(btTypedConstraint* constraint,bool disableCollisionsBetweenLinkedBodies)
479{
480        m_constraints.push_back(constraint);
481        if (disableCollisionsBetweenLinkedBodies)
482        {
483                constraint->getRigidBodyA().addConstraintRef(constraint);
484                constraint->getRigidBodyB().addConstraintRef(constraint);
485        }
486}
487
488void    btDiscreteDynamicsWorld::removeConstraint(btTypedConstraint* constraint)
489{
490        m_constraints.remove(constraint);
491        constraint->getRigidBodyA().removeConstraintRef(constraint);
492        constraint->getRigidBodyB().removeConstraintRef(constraint);
493}
494
[2882]495void    btDiscreteDynamicsWorld::addAction(btActionInterface* action)
[1963]496{
[2882]497        m_actions.push_back(action);
[1963]498}
499
[2882]500void    btDiscreteDynamicsWorld::removeAction(btActionInterface* action)
[1963]501{
[2882]502        m_actions.remove(action);
[1963]503}
504
[2882]505
506void    btDiscreteDynamicsWorld::addVehicle(btActionInterface* vehicle)
[2430]507{
[2882]508        addAction(vehicle);
[2430]509}
510
[2882]511void    btDiscreteDynamicsWorld::removeVehicle(btActionInterface* vehicle)
[2430]512{
[2882]513        removeAction(vehicle);
[2430]514}
515
[2882]516void    btDiscreteDynamicsWorld::addCharacter(btActionInterface* character)
517{
518        addAction(character);
519}
[2430]520
[2882]521void    btDiscreteDynamicsWorld::removeCharacter(btActionInterface* character)
522{
523        removeAction(character);
524}
525
526
[1963]527SIMD_FORCE_INLINE       int     btGetConstraintIslandId(const btTypedConstraint* lhs)
528{
529        int islandId;
530       
531        const btCollisionObject& rcolObj0 = lhs->getRigidBodyA();
532        const btCollisionObject& rcolObj1 = lhs->getRigidBodyB();
533        islandId= rcolObj0.getIslandTag()>=0?rcolObj0.getIslandTag():rcolObj1.getIslandTag();
534        return islandId;
535
536}
537
538
539class btSortConstraintOnIslandPredicate
540{
541        public:
542
543                bool operator() ( const btTypedConstraint* lhs, const btTypedConstraint* rhs )
544                {
545                        int rIslandId0,lIslandId0;
546                        rIslandId0 = btGetConstraintIslandId(rhs);
547                        lIslandId0 = btGetConstraintIslandId(lhs);
548                        return lIslandId0 < rIslandId0;
549                }
550};
551
552
553
554void    btDiscreteDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo)
555{
556        BT_PROFILE("solveConstraints");
557       
558        struct InplaceSolverIslandCallback : public btSimulationIslandManager::IslandCallback
559        {
560
561                btContactSolverInfo&    m_solverInfo;
562                btConstraintSolver*             m_solver;
563                btTypedConstraint**             m_sortedConstraints;
564                int                                             m_numConstraints;
565                btIDebugDraw*                   m_debugDrawer;
566                btStackAlloc*                   m_stackAlloc;
567                btDispatcher*                   m_dispatcher;
[8351]568               
569                btAlignedObjectArray<btCollisionObject*> m_bodies;
570                btAlignedObjectArray<btPersistentManifold*> m_manifolds;
571                btAlignedObjectArray<btTypedConstraint*> m_constraints;
[1963]572
[8351]573
[1963]574                InplaceSolverIslandCallback(
575                        btContactSolverInfo& solverInfo,
576                        btConstraintSolver*     solver,
577                        btTypedConstraint** sortedConstraints,
578                        int     numConstraints,
579                        btIDebugDraw*   debugDrawer,
580                        btStackAlloc*                   stackAlloc,
581                        btDispatcher* dispatcher)
582                        :m_solverInfo(solverInfo),
583                        m_solver(solver),
584                        m_sortedConstraints(sortedConstraints),
585                        m_numConstraints(numConstraints),
586                        m_debugDrawer(debugDrawer),
587                        m_stackAlloc(stackAlloc),
588                        m_dispatcher(dispatcher)
589                {
590
591                }
592
[8351]593
[1963]594                InplaceSolverIslandCallback& operator=(InplaceSolverIslandCallback& other)
595                {
596                        btAssert(0);
597                        (void)other;
598                        return *this;
599                }
600                virtual void    ProcessIsland(btCollisionObject** bodies,int numBodies,btPersistentManifold**   manifolds,int numManifolds, int islandId)
601                {
602                        if (islandId<0)
603                        {
[2882]604                                if (numManifolds + m_numConstraints)
605                                {
606                                        ///we don't split islands, so all constraints/contact manifolds/bodies are passed into the solver regardless the island id
607                                        m_solver->solveGroup( bodies,numBodies,manifolds, numManifolds,&m_sortedConstraints[0],m_numConstraints,m_solverInfo,m_debugDrawer,m_stackAlloc,m_dispatcher);
608                                }
[1963]609                        } else
610                        {
611                                        //also add all non-contact constraints/joints for this island
612                                btTypedConstraint** startConstraint = 0;
613                                int numCurConstraints = 0;
614                                int i;
615                               
616                                //find the first constraint for this island
617                                for (i=0;i<m_numConstraints;i++)
618                                {
619                                        if (btGetConstraintIslandId(m_sortedConstraints[i]) == islandId)
620                                        {
621                                                startConstraint = &m_sortedConstraints[i];
622                                                break;
623                                        }
624                                }
625                                //count the number of constraints in this island
626                                for (;i<m_numConstraints;i++)
627                                {
628                                        if (btGetConstraintIslandId(m_sortedConstraints[i]) == islandId)
629                                        {
630                                                numCurConstraints++;
631                                        }
632                                }
633
[8351]634                                if (m_solverInfo.m_minimumSolverBatchSize<=1)
[1963]635                                {
[8351]636                                        ///only call solveGroup if there is some work: avoid virtual function call, its overhead can be excessive
637                                        if (numManifolds + numCurConstraints)
638                                        {
639                                                m_solver->solveGroup( bodies,numBodies,manifolds, numManifolds,startConstraint,numCurConstraints,m_solverInfo,m_debugDrawer,m_stackAlloc,m_dispatcher);
640                                        }
641                                } else
642                                {
643                                       
644                                        for (i=0;i<numBodies;i++)
645                                                m_bodies.push_back(bodies[i]);
646                                        for (i=0;i<numManifolds;i++)
647                                                m_manifolds.push_back(manifolds[i]);
648                                        for (i=0;i<numCurConstraints;i++)
649                                                m_constraints.push_back(startConstraint[i]);
650                                        if ((m_constraints.size()+m_manifolds.size())>m_solverInfo.m_minimumSolverBatchSize)
651                                        {
652                                                processConstraints();
653                                        } else
654                                        {
655                                                //printf("deferred\n");
656                                        }
[1963]657                                }
658                        }
659                }
[8351]660                void    processConstraints()
661                {
662                        if (m_manifolds.size() + m_constraints.size()>0)
663                        {
664                                m_solver->solveGroup( &m_bodies[0],m_bodies.size(), &m_manifolds[0], m_manifolds.size(), &m_constraints[0], m_constraints.size() ,m_solverInfo,m_debugDrawer,m_stackAlloc,m_dispatcher);
665                        }
666                        m_bodies.resize(0);
667                        m_manifolds.resize(0);
668                        m_constraints.resize(0);
[1963]669
[8351]670                }
671
[1963]672        };
673
[8351]674       
675
[1963]676        //sorted version of all btTypedConstraint, based on islandId
677        btAlignedObjectArray<btTypedConstraint*>        sortedConstraints;
678        sortedConstraints.resize( m_constraints.size());
679        int i; 
680        for (i=0;i<getNumConstraints();i++)
681        {
682                sortedConstraints[i] = m_constraints[i];
683        }
684
[2882]685//      btAssert(0);
[1963]686               
687       
688
689        sortedConstraints.quickSort(btSortConstraintOnIslandPredicate());
690       
691        btTypedConstraint** constraintsPtr = getNumConstraints() ? &sortedConstraints[0] : 0;
692       
693        InplaceSolverIslandCallback     solverCallback( solverInfo,     m_constraintSolver, constraintsPtr,sortedConstraints.size(),    m_debugDrawer,m_stackAlloc,m_dispatcher1);
694       
695        m_constraintSolver->prepareSolve(getCollisionWorld()->getNumCollisionObjects(), getCollisionWorld()->getDispatcher()->getNumManifolds());
696       
697        /// solve all the constraints for this island
[2430]698        m_islandManager->buildAndProcessIslands(getCollisionWorld()->getDispatcher(),getCollisionWorld(),&solverCallback);
[1963]699
[8351]700        solverCallback.processConstraints();
701
[1963]702        m_constraintSolver->allSolved(solverInfo, m_debugDrawer, m_stackAlloc);
703}
704
705
706
707
708void    btDiscreteDynamicsWorld::calculateSimulationIslands()
709{
710        BT_PROFILE("calculateSimulationIslands");
711
712        getSimulationIslandManager()->updateActivationState(getCollisionWorld(),getCollisionWorld()->getDispatcher());
713
714        {
715                int i;
716                int numConstraints = int(m_constraints.size());
717                for (i=0;i< numConstraints ; i++ )
718                {
719                        btTypedConstraint* constraint = m_constraints[i];
720
721                        const btRigidBody* colObj0 = &constraint->getRigidBodyA();
722                        const btRigidBody* colObj1 = &constraint->getRigidBodyB();
723
724                        if (((colObj0) && (!(colObj0)->isStaticOrKinematicObject())) &&
725                                ((colObj1) && (!(colObj1)->isStaticOrKinematicObject())))
726                        {
727                                if (colObj0->isActive() || colObj1->isActive())
728                                {
729
730                                        getSimulationIslandManager()->getUnionFind().unite((colObj0)->getIslandTag(),
731                                                (colObj1)->getIslandTag());
732                                }
733                        }
734                }
735        }
736
737        //Store the island id in each body
738        getSimulationIslandManager()->storeIslandActivationState(getCollisionWorld());
739
740       
741}
742
743
744
[8351]745
[1963]746class btClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
747{
748        btCollisionObject* m_me;
749        btScalar m_allowedPenetration;
750        btOverlappingPairCache* m_pairCache;
[2882]751        btDispatcher* m_dispatcher;
[1963]752
753
754public:
[2882]755        btClosestNotMeConvexResultCallback (btCollisionObject* me,const btVector3& fromA,const btVector3& toA,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) : 
[1963]756          btCollisionWorld::ClosestConvexResultCallback(fromA,toA),
[8351]757                m_me(me),
[1963]758                m_allowedPenetration(0.0f),
[2882]759                m_pairCache(pairCache),
760                m_dispatcher(dispatcher)
[1963]761        {
762        }
763
764        virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
765        {
766                if (convexResult.m_hitCollisionObject == m_me)
[2430]767                        return 1.0f;
[1963]768
[2430]769                //ignore result if there is no contact response
770                if(!convexResult.m_hitCollisionObject->hasContactResponse())
771                        return 1.0f;
772
[1963]773                btVector3 linVelA,linVelB;
774                linVelA = m_convexToWorld-m_convexFromWorld;
775                linVelB = btVector3(0,0,0);//toB.getOrigin()-fromB.getOrigin();
776
777                btVector3 relativeVelocity = (linVelA-linVelB);
778                //don't report time of impact for motion away from the contact normal (or causes minor penetration)
779                if (convexResult.m_hitNormalLocal.dot(relativeVelocity)>=-m_allowedPenetration)
780                        return 1.f;
781
782                return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
783        }
784
785        virtual bool needsCollision(btBroadphaseProxy* proxy0) const
786        {
787                //don't collide with itself
788                if (proxy0->m_clientObject == m_me)
789                        return false;
790
791                ///don't do CCD when the collision filters are not matching
[2430]792                if (!ClosestConvexResultCallback::needsCollision(proxy0))
[1963]793                        return false;
794
[2882]795                btCollisionObject* otherObj = (btCollisionObject*) proxy0->m_clientObject;
796
797                //call needsResponse, see http://code.google.com/p/bullet/issues/detail?id=179
798                if (m_dispatcher->needsResponse(m_me,otherObj))
[1963]799                {
[2882]800                        ///don't do CCD when there are already contact points (touching contact/penetration)
801                        btAlignedObjectArray<btPersistentManifold*> manifoldArray;
802                        btBroadphasePair* collisionPair = m_pairCache->findPair(m_me->getBroadphaseHandle(),proxy0);
803                        if (collisionPair)
[1963]804                        {
[2882]805                                if (collisionPair->m_algorithm)
[1963]806                                {
[2882]807                                        manifoldArray.resize(0);
808                                        collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
809                                        for (int j=0;j<manifoldArray.size();j++)
810                                        {
811                                                btPersistentManifold* manifold = manifoldArray[j];
812                                                if (manifold->getNumContacts()>0)
813                                                        return false;
814                                        }
[1963]815                                }
816                        }
817                }
818                return true;
819        }
820
821
822};
823
824///internal debugging variable. this value shouldn't be too high
825int gNumClampedCcdMotions=0;
826
827//#include "stdio.h"
828void    btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
829{
830        BT_PROFILE("integrateTransforms");
831        btTransform predictedTrans;
[8351]832        for ( int i=0;i<m_nonStaticRigidBodies.size();i++)
[1963]833        {
[8351]834                btRigidBody* body = m_nonStaticRigidBodies[i];
835                body->setHitFraction(1.f);
836
837                if (body->isActive() && (!body->isStaticOrKinematicObject()))
[1963]838                {
[8351]839                        body->predictIntegratedTransform(timeStep, predictedTrans);
840                        btScalar squareMotion = (predictedTrans.getOrigin()-body->getWorldTransform().getOrigin()).length2();
[1963]841
[8351]842                        if (body->getCcdSquareMotionThreshold() && body->getCcdSquareMotionThreshold() < squareMotion)
[1963]843                        {
[8351]844                                BT_PROFILE("CCD motion clamping");
845                                if (body->getCollisionShape()->isConvex())
[1963]846                                {
[8351]847                                        gNumClampedCcdMotions++;
848                                       
849                                        btClosestNotMeConvexResultCallback sweepResults(body,body->getWorldTransform().getOrigin(),predictedTrans.getOrigin(),getBroadphase()->getOverlappingPairCache(),getDispatcher());
850                                        //btConvexShape* convexShape = static_cast<btConvexShape*>(body->getCollisionShape());
851                                        btSphereShape tmpSphere(body->getCcdSweptSphereRadius());//btConvexShape* convexShape = static_cast<btConvexShape*>(body->getCollisionShape());
[2430]852
[8351]853                                        sweepResults.m_collisionFilterGroup = body->getBroadphaseProxy()->m_collisionFilterGroup;
854                                        sweepResults.m_collisionFilterMask  = body->getBroadphaseProxy()->m_collisionFilterMask;
[2430]855
[8351]856                                        convexSweepTest(&tmpSphere,body->getWorldTransform(),predictedTrans,sweepResults);
857                                        if (sweepResults.hasHit() && (sweepResults.m_closestHitFraction < 1.f))
858                                        {
859                                                body->setHitFraction(sweepResults.m_closestHitFraction);
860                                                body->predictIntegratedTransform(timeStep*body->getHitFraction(), predictedTrans);
861                                                body->setHitFraction(0.f);
[1963]862//                                                      printf("clamped integration to hit fraction = %f\n",fraction);
863                                        }
864                                }
865                        }
[8351]866                       
867                        body->proceedToTransform( predictedTrans);
[1963]868                }
869        }
870}
871
872
873
[2430]874
875
[1963]876void    btDiscreteDynamicsWorld::predictUnconstraintMotion(btScalar timeStep)
877{
878        BT_PROFILE("predictUnconstraintMotion");
[8351]879        for ( int i=0;i<m_nonStaticRigidBodies.size();i++)
[1963]880        {
[8351]881                btRigidBody* body = m_nonStaticRigidBodies[i];
882                if (!body->isStaticOrKinematicObject())
[1963]883                {
[8351]884                        body->integrateVelocities( timeStep);
885                        //damping
886                        body->applyDamping(timeStep);
[1963]887
[8351]888                        body->predictIntegratedTransform(timeStep,body->getInterpolationWorldTransform());
[1963]889                }
890        }
891}
892
893
894void    btDiscreteDynamicsWorld::startProfiling(btScalar timeStep)
895{
896        (void)timeStep;
897
898#ifndef BT_NO_PROFILE
899        CProfileManager::Reset();
900#endif //BT_NO_PROFILE
901
902}
903
904
905
906
907       
908
[2882]909void btDiscreteDynamicsWorld::debugDrawConstraint(btTypedConstraint* constraint)
910{
911        bool drawFrames = (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawConstraints) != 0;
912        bool drawLimits = (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawConstraintLimits) != 0;
913        btScalar dbgDrawSize = constraint->getDbgDrawSize();
914        if(dbgDrawSize <= btScalar(0.f))
915        {
916                return;
917        }
918
919        switch(constraint->getConstraintType())
920        {
921                case POINT2POINT_CONSTRAINT_TYPE:
922                        {
923                                btPoint2PointConstraint* p2pC = (btPoint2PointConstraint*)constraint;
924                                btTransform tr;
925                                tr.setIdentity();
926                                btVector3 pivot = p2pC->getPivotInA();
927                                pivot = p2pC->getRigidBodyA().getCenterOfMassTransform() * pivot; 
928                                tr.setOrigin(pivot);
929                                getDebugDrawer()->drawTransform(tr, dbgDrawSize);
930                                // that ideally should draw the same frame     
931                                pivot = p2pC->getPivotInB();
932                                pivot = p2pC->getRigidBodyB().getCenterOfMassTransform() * pivot; 
933                                tr.setOrigin(pivot);
934                                if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
935                        }
936                        break;
937                case HINGE_CONSTRAINT_TYPE:
938                        {
939                                btHingeConstraint* pHinge = (btHingeConstraint*)constraint;
940                                btTransform tr = pHinge->getRigidBodyA().getCenterOfMassTransform() * pHinge->getAFrame();
941                                if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
942                                tr = pHinge->getRigidBodyB().getCenterOfMassTransform() * pHinge->getBFrame();
943                                if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
944                                btScalar minAng = pHinge->getLowerLimit();
945                                btScalar maxAng = pHinge->getUpperLimit();
946                                if(minAng == maxAng)
947                                {
948                                        break;
949                                }
950                                bool drawSect = true;
951                                if(minAng > maxAng)
952                                {
953                                        minAng = btScalar(0.f);
954                                        maxAng = SIMD_2_PI;
955                                        drawSect = false;
956                                }
957                                if(drawLimits) 
958                                {
959                                        btVector3& center = tr.getOrigin();
960                                        btVector3 normal = tr.getBasis().getColumn(2);
961                                        btVector3 axis = tr.getBasis().getColumn(0);
962                                        getDebugDrawer()->drawArc(center, normal, axis, dbgDrawSize, dbgDrawSize, minAng, maxAng, btVector3(0,0,0), drawSect);
963                                }
964                        }
965                        break;
966                case CONETWIST_CONSTRAINT_TYPE:
967                        {
968                                btConeTwistConstraint* pCT = (btConeTwistConstraint*)constraint;
969                                btTransform tr = pCT->getRigidBodyA().getCenterOfMassTransform() * pCT->getAFrame();
970                                if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
971                                tr = pCT->getRigidBodyB().getCenterOfMassTransform() * pCT->getBFrame();
972                                if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
973                                if(drawLimits)
974                                {
975                                        //const btScalar length = btScalar(5);
976                                        const btScalar length = dbgDrawSize;
977                                        static int nSegments = 8*4;
978                                        btScalar fAngleInRadians = btScalar(2.*3.1415926) * (btScalar)(nSegments-1)/btScalar(nSegments);
979                                        btVector3 pPrev = pCT->GetPointForAngle(fAngleInRadians, length);
980                                        pPrev = tr * pPrev;
981                                        for (int i=0; i<nSegments; i++)
982                                        {
983                                                fAngleInRadians = btScalar(2.*3.1415926) * (btScalar)i/btScalar(nSegments);
984                                                btVector3 pCur = pCT->GetPointForAngle(fAngleInRadians, length);
985                                                pCur = tr * pCur;
986                                                getDebugDrawer()->drawLine(pPrev, pCur, btVector3(0,0,0));
987
988                                                if (i%(nSegments/8) == 0)
989                                                        getDebugDrawer()->drawLine(tr.getOrigin(), pCur, btVector3(0,0,0));
990
991                                                pPrev = pCur;
992                                        }                                               
993                                        btScalar tws = pCT->getTwistSpan();
994                                        btScalar twa = pCT->getTwistAngle();
995                                        bool useFrameB = (pCT->getRigidBodyB().getInvMass() > btScalar(0.f));
996                                        if(useFrameB)
997                                        {
998                                                tr = pCT->getRigidBodyB().getCenterOfMassTransform() * pCT->getBFrame();
999                                        }
1000                                        else
1001                                        {
1002                                                tr = pCT->getRigidBodyA().getCenterOfMassTransform() * pCT->getAFrame();
1003                                        }
1004                                        btVector3 pivot = tr.getOrigin();
1005                                        btVector3 normal = tr.getBasis().getColumn(0);
1006                                        btVector3 axis1 = tr.getBasis().getColumn(1);
1007                                        getDebugDrawer()->drawArc(pivot, normal, axis1, dbgDrawSize, dbgDrawSize, -twa-tws, -twa+tws, btVector3(0,0,0), true);
1008
1009                                }
1010                        }
1011                        break;
1012                case D6_CONSTRAINT_TYPE:
1013                        {
1014                                btGeneric6DofConstraint* p6DOF = (btGeneric6DofConstraint*)constraint;
1015                                btTransform tr = p6DOF->getCalculatedTransformA();
1016                                if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
1017                                tr = p6DOF->getCalculatedTransformB();
1018                                if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
1019                                if(drawLimits) 
1020                                {
1021                                        tr = p6DOF->getCalculatedTransformA();
1022                                        const btVector3& center = p6DOF->getCalculatedTransformB().getOrigin();
1023                                        btVector3 up = tr.getBasis().getColumn(2);
1024                                        btVector3 axis = tr.getBasis().getColumn(0);
1025                                        btScalar minTh = p6DOF->getRotationalLimitMotor(1)->m_loLimit;
1026                                        btScalar maxTh = p6DOF->getRotationalLimitMotor(1)->m_hiLimit;
1027                                        btScalar minPs = p6DOF->getRotationalLimitMotor(2)->m_loLimit;
1028                                        btScalar maxPs = p6DOF->getRotationalLimitMotor(2)->m_hiLimit;
1029                                        getDebugDrawer()->drawSpherePatch(center, up, axis, dbgDrawSize * btScalar(.9f), minTh, maxTh, minPs, maxPs, btVector3(0,0,0));
1030                                        axis = tr.getBasis().getColumn(1);
1031                                        btScalar ay = p6DOF->getAngle(1);
1032                                        btScalar az = p6DOF->getAngle(2);
1033                                        btScalar cy = btCos(ay);
1034                                        btScalar sy = btSin(ay);
1035                                        btScalar cz = btCos(az);
1036                                        btScalar sz = btSin(az);
1037                                        btVector3 ref;
1038                                        ref[0] = cy*cz*axis[0] + cy*sz*axis[1] - sy*axis[2];
1039                                        ref[1] = -sz*axis[0] + cz*axis[1];
1040                                        ref[2] = cz*sy*axis[0] + sz*sy*axis[1] + cy*axis[2];
1041                                        tr = p6DOF->getCalculatedTransformB();
1042                                        btVector3 normal = -tr.getBasis().getColumn(0);
1043                                        btScalar minFi = p6DOF->getRotationalLimitMotor(0)->m_loLimit;
1044                                        btScalar maxFi = p6DOF->getRotationalLimitMotor(0)->m_hiLimit;
1045                                        if(minFi > maxFi)
1046                                        {
1047                                                getDebugDrawer()->drawArc(center, normal, ref, dbgDrawSize, dbgDrawSize, -SIMD_PI, SIMD_PI, btVector3(0,0,0), false);
1048                                        }
1049                                        else if(minFi < maxFi)
1050                                        {
1051                                                getDebugDrawer()->drawArc(center, normal, ref, dbgDrawSize, dbgDrawSize, minFi, maxFi, btVector3(0,0,0), true);
1052                                        }
1053                                        tr = p6DOF->getCalculatedTransformA();
1054                                        btVector3 bbMin = p6DOF->getTranslationalLimitMotor()->m_lowerLimit;
1055                                        btVector3 bbMax = p6DOF->getTranslationalLimitMotor()->m_upperLimit;
1056                                        getDebugDrawer()->drawBox(bbMin, bbMax, tr, btVector3(0,0,0));
1057                                }
1058                        }
1059                        break;
1060                case SLIDER_CONSTRAINT_TYPE:
1061                        {
1062                                btSliderConstraint* pSlider = (btSliderConstraint*)constraint;
1063                                btTransform tr = pSlider->getCalculatedTransformA();
1064                                if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
1065                                tr = pSlider->getCalculatedTransformB();
1066                                if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
1067                                if(drawLimits)
1068                                {
[8351]1069                                        btTransform tr = pSlider->getUseLinearReferenceFrameA() ? pSlider->getCalculatedTransformA() : pSlider->getCalculatedTransformB();
[2882]1070                                        btVector3 li_min = tr * btVector3(pSlider->getLowerLinLimit(), 0.f, 0.f);
1071                                        btVector3 li_max = tr * btVector3(pSlider->getUpperLinLimit(), 0.f, 0.f);
1072                                        getDebugDrawer()->drawLine(li_min, li_max, btVector3(0, 0, 0));
1073                                        btVector3 normal = tr.getBasis().getColumn(0);
1074                                        btVector3 axis = tr.getBasis().getColumn(1);
1075                                        btScalar a_min = pSlider->getLowerAngLimit();
1076                                        btScalar a_max = pSlider->getUpperAngLimit();
1077                                        const btVector3& center = pSlider->getCalculatedTransformB().getOrigin();
1078                                        getDebugDrawer()->drawArc(center, normal, axis, dbgDrawSize, dbgDrawSize, a_min, a_max, btVector3(0,0,0), true);
1079                                }
1080                        }
1081                        break;
1082                default : 
1083                        break;
1084        }
1085        return;
[8351]1086}
[2882]1087
1088
1089
1090
1091
[1963]1092void    btDiscreteDynamicsWorld::setConstraintSolver(btConstraintSolver* solver)
1093{
1094        if (m_ownsConstraintSolver)
1095        {
1096                btAlignedFree( m_constraintSolver);
1097        }
1098        m_ownsConstraintSolver = false;
1099        m_constraintSolver = solver;
1100}
1101
1102btConstraintSolver* btDiscreteDynamicsWorld::getConstraintSolver()
1103{
1104        return m_constraintSolver;
1105}
1106
1107
1108int             btDiscreteDynamicsWorld::getNumConstraints() const
1109{
1110        return int(m_constraints.size());
1111}
1112btTypedConstraint* btDiscreteDynamicsWorld::getConstraint(int index)
1113{
1114        return m_constraints[index];
1115}
1116const btTypedConstraint* btDiscreteDynamicsWorld::getConstraint(int index) const
1117{
1118        return m_constraints[index];
1119}
[2882]1120
1121
[8351]1122
1123void    btDiscreteDynamicsWorld::serializeRigidBodies(btSerializer* serializer)
1124{
1125        int i;
1126        //serialize all collision objects
1127        for (i=0;i<m_collisionObjects.size();i++)
1128        {
1129                btCollisionObject* colObj = m_collisionObjects[i];
1130                if (colObj->getInternalType() & btCollisionObject::CO_RIGID_BODY)
1131                {
1132                        int len = colObj->calculateSerializeBufferSize();
1133                        btChunk* chunk = serializer->allocate(len,1);
1134                        const char* structType = colObj->serialize(chunk->m_oldPtr, serializer);
1135                        serializer->finalizeChunk(chunk,structType,BT_RIGIDBODY_CODE,colObj);
1136                }
1137        }
1138
1139        for (i=0;i<m_constraints.size();i++)
1140        {
1141                btTypedConstraint* constraint = m_constraints[i];
1142                int size = constraint->calculateSerializeBufferSize();
1143                btChunk* chunk = serializer->allocate(size,1);
1144                const char* structType = constraint->serialize(chunk->m_oldPtr,serializer);
1145                serializer->finalizeChunk(chunk,structType,BT_CONSTRAINT_CODE,constraint);
1146        }
1147}
1148
1149
1150void    btDiscreteDynamicsWorld::serialize(btSerializer* serializer)
1151{
1152
1153        serializer->startSerialization();
1154
1155        serializeRigidBodies(serializer);
1156
1157        serializeCollisionObjects(serializer);
1158
1159        serializer->finishSerialization();
1160}
1161
Note: See TracBrowser for help on using the repository browser.