21 #include "phyobject.h"
23 #include "private/phyobjectprivate.h"
24 #include "private/worldprivate.h"
25 #include "motorcontrollers.h"
27 #include <QMutexLocker>
34 MaterialDB::MaterialDB( World* w ) : mats(), pmap() {
36 createMaterial(
"nonCollidable" );
37 createMaterial(
"default" );
41 if ( mats.contains( name ) ) {
44 #ifdef WORLDSIM_USE_NEWTON
45 NewtonWorld* ngdWorld = worldv->priv->world;
47 if ( name ==
"default" ) {
48 newm = NewtonMaterialGetDefaultGroupID( ngdWorld );
50 newm = NewtonMaterialCreateGroupID( ngdWorld );
52 worldv->priv->matIDs[name] = newm;
53 NewtonMaterialSetCollisionCallback( ngdWorld, newm, newm, (
void*)worldv, NULL, (WorldPrivate::processCollisionHandler) );
55 foreach( QString k, mats.values() ) {
56 int kid = worldv->priv->matIDs[k];
57 NewtonMaterialSetCollisionCallback( ngdWorld, newm, kid, (
void*)worldv, NULL, (WorldPrivate::processCollisionHandler) );
60 NewtonMaterialSetDefaultCollidable( ngdWorld, worldv->priv->matIDs[
"nonCollidable"], newm, 0 );
67 if ( !mats.contains( mat1 ) )
return;
68 if ( !mats.contains( mat2 ) )
return;
69 QString pkey = createKey( mat1, mat2 );
70 pmap[pkey].staticFriction = st;
71 pmap[pkey].dynamicFriction = kn;
72 #ifdef WORLDSIM_USE_NEWTON
73 int id1 = worldv->priv->matIDs[mat1];
74 int id2 = worldv->priv->matIDs[mat2];
75 NewtonMaterialSetDefaultFriction( worldv->priv->world, id1, id2, st, kn );
81 if ( !mats.contains( mat1 ) )
return;
82 if ( !mats.contains( mat2 ) )
return;
83 QString pkey = createKey( mat1, mat2 );
84 pmap[pkey].elasticity = el;
85 #ifdef WORLDSIM_USE_NEWTON
86 int id1 = worldv->priv->matIDs[mat1];
87 int id2 = worldv->priv->matIDs[mat2];
88 NewtonMaterialSetDefaultElasticity( worldv->priv->world, id1, id2, el );
94 if ( !mats.contains( mat1 ) )
return;
95 if ( !mats.contains( mat2 ) )
return;
96 QString pkey = createKey( mat1, mat2 );
97 pmap[pkey].softness = sf;
98 #ifdef WORLDSIM_USE_NEWTON
99 int id1 = worldv->priv->matIDs[mat1];
100 int id2 = worldv->priv->matIDs[mat2];
101 NewtonMaterialSetDefaultSoftness( worldv->priv->world, id1, id2, sf );
107 gravities[mat] = force;
111 if ( gravities.contains( mat ) ) {
112 return gravities[mat];
120 if ( !mats.contains( mat1 ) )
return;
121 if ( !mats.contains( mat2 ) )
return;
122 QString pkey = createKey( mat1, mat2 );
123 pmap[pkey].collisions = enable;
124 #ifdef WORLDSIM_USE_NEWTON
125 int id1 = worldv->priv->matIDs[mat1];
126 int id2 = worldv->priv->matIDs[mat2];
127 NewtonMaterialSetDefaultCollidable( worldv->priv->world, id1, id2, enable );
138 QString MaterialDB::createKey( QString mat1, QString mat2 ) {
140 return mat1 +
":" + mat2;
142 return mat2 +
":" + mat1;
147 : QObject(), minP(-100,-100,-100), maxP(100,100,100), objs(), jointsv(), mapObjJoints(),
158 priv =
new WorldPrivate();
160 #ifdef WORLDSIM_USE_NEWTON
161 priv->world = NewtonCreate();
162 NewtonInvalidateCache( priv->world );
163 NewtonSetWorldSize( priv->world, &
minP[0], &maxP[0] );
165 NewtonSetMinimumFrameRate( priv->world, 100 );
167 NewtonSetSolverModel( priv->world, 0 );
168 NewtonSetFrictionModel( priv->world, 0 );
186 if ( js->
owner() == NULL ) {
190 while ( !
objs.isEmpty() ) {
192 if ( obj->
owner() == NULL ) {
196 #ifdef WORLDSIM_USE_NEWTON
197 NewtonDestroy( priv->world );
207 if ( isInit )
return;
223 while( isrealtimev && timer.
tac()/1000000.0 <
timestepv ) { };
227 for( QLinkedList<WObject*>::iterator it =
objs.begin(); it !=
objs.end(); it++ ) {
231 for( QLinkedList<PhyJoint*>::iterator it =
jointsv.begin(); it !=
jointsv.end(); it++ ) {
237 #ifdef WORLDSIM_USE_NEWTON
241 for( QLinkedList<WObject*>::iterator it =
objs.begin(); it !=
objs.end(); it++ ) {
245 for( QLinkedList<PhyJoint*>::iterator it =
jointsv.begin(); it !=
jointsv.end(); it++ ) {
254 if ( isFinish )
return;
262 if ( state == playingS )
return timerId;
263 if ( timerId != 0 )
return timerId;
265 timerId = startTimer( 0 );
271 if ( timerId != 0 ) killTimer( timerId );
280 if ( timerId != 0 ) killTimer( timerId );
292 switch( e->type() ) {
337 #ifdef WORLDSIM_USE_NEWTON
338 NewtonSetMinimumFrameRate( priv->world, frames );
355 blockSignals(
true );
356 bool b = isrealtimev;
362 blockSignals(
false );
372 if ( obj->
name() ==
name )
return obj;
386 nobjs.insert( qMakePair( obj1, obj2 ) );
387 nobjs.insert( qMakePair( obj2, obj1 ) );
391 nobjs.remove( qMakePair( obj1, obj2 ) );
392 nobjs.remove( qMakePair( obj2, obj1 ) );
396 #ifdef WORLDSIM_USE_NEWTON
397 if ( model ==
"exact" ) {
398 NewtonSetSolverModel( priv->world, 0 );
399 }
else if ( model ==
"linear" ) {
400 NewtonSetSolverModel( priv->world, 1 );
406 #ifdef WORLDSIM_USE_NEWTON
407 if ( model ==
"exact" ) {
408 NewtonSetFrictionModel( priv->world, 0 );
409 }
else if ( model ==
"linear" ) {
410 NewtonSetFrictionModel( priv->world, 1 );
416 #ifdef WORLDSIM_USE_NEWTON
417 numThreads =
max( 1, numThreads );
418 NewtonSetThreadsCount( priv->world, numThreads );
425 #ifdef WORLDSIM_USE_NEWTON
426 NewtonSetWorldSize( priv->world, &
minP[0], &maxP[0] );
436 void World::pushObject(
WObject* phy ) {
437 objs.push_back( phy );
441 void World::popObject( WObject* phy ) {
442 const int numRemoved =
objs.removeAll( phy );
443 if ( numRemoved == 1 ) {
446 PhyObject*
const phyObject =
dynamic_cast<PhyObject*
>(phy);
447 if ( ( phyObject != NULL ) && ( cmap.contains( phyObject ) ) ) {
448 const contactVec &cvec = cmap[ phyObject ];
449 foreach ( Contact c, cvec ) {
450 contactVec &otherCVec = cmap[ c.collide ];
451 contactVec::iterator it = otherCVec.begin();
452 while ( it != otherCVec.end() ) {
453 if ( it->collide == phyObject ) {
454 it = otherCVec.erase( it );
459 if ( otherCVec.isEmpty() ) {
461 cmap.remove( c.collide );
464 cmap.remove( phyObject );
469 else if (numRemoved > 1) {
470 qDebug(
"INTERNAL ERROR: more than one object with the same address found in the World::objs list" );
475 void World::pushJoint( PhyJoint* phy ) {
478 if ( phy->parent() ) {
484 void World::popJoint( PhyJoint* phy ) {
485 const int numRemoved =
jointsv.removeAll( phy );
486 if ( numRemoved == 1 ) {
489 if ( phy->parent() ) {
496 else if (numRemoved > 1) {
497 qDebug(
"INTERNAL ERROR: more than one joint with the same address found in the World::jointsv list" );
503 #ifdef WORLDSIM_USE_NEWTON
505 NewtonInvalidateCache( priv->world );
527 #ifdef WORLDSIM_USE_NEWTON
529 real *
const tmp_data =
new real[2 * 3 * maxContacts + maxContacts];
530 real *
const tmp_contacts = &tmp_data[0 * 3 * maxContacts];
531 real *
const tmp_normals = &tmp_data[1 * 3 * maxContacts];
532 real *
const tmp_penetra = &tmp_data[2 * 3 * maxContacts];
537 const int numContacts = NewtonCollisionCollide( priv->world, maxContacts, obj1->
priv->collision, &t1[0][0], obj2->
priv->collision, &t2[0][0], tmp_contacts, tmp_normals, tmp_penetra, 0 );
540 if (contacts != NULL) {
541 contacts->resize(numContacts);
542 for (
int i = 0; i < numContacts; i++) {
543 (*contacts)[i].x = tmp_contacts[0 + i * 3];
544 (*contacts)[i].y = tmp_contacts[1 + i * 3];
545 (*contacts)[i].z = tmp_contacts[2 + i * 3];
548 if (normals != NULL) {
549 normals->resize(numContacts);
550 for (
int i = 0; i < numContacts; i++) {
551 (*normals)[i].x = tmp_normals[0 + i * 3];
552 (*normals)[i].y = tmp_normals[1 + i * 3];
553 (*normals)[i].z = tmp_normals[2 + i * 3];
556 if (penetra != NULL) {
557 penetra->resize(numContacts);
558 for (
int i = 0; i < numContacts; i++) {
559 (*penetra)[i] = tmp_penetra[i];
564 return (numContacts != 0);
571 return checkContacts( obj1, obj2, maxContacts, contacts, NULL, NULL);
573 if (!cmap.contains(obj1)) {
578 const contactVec& c = cmap[obj1];
579 bool collision =
false;
580 if (contacts != NULL) {
585 for (
int i = 0; i < c.size(); i++) {
586 if (c[i].collide == obj2) {
588 if ((contacts != NULL) && (contacts->size() < maxContacts)) {
590 contacts->append(c[i].worldPos);
601 #ifdef WORLDSIM_USE_NEWTON
609 const real contact = NewtonCollisionRayCast(obj->
priv->collision, &localStart[0], &localEnd[0], n, &attribute);
611 if (normal != NULL) {
625 #ifdef WORLDSIM_USE_NEWTON
626 WorldPrivate::WorldRayCastCallbackUserData data(start, end, onlyClosest, ignoredObjs);
629 NewtonWorldRayCast(priv->world, &start[0], &end[0], WorldPrivate::worldRayFilterCallback, &data, NULL);
633 return rayCastHitVector();
651 #ifdef WORLDSIM_USE_NEWTON
655 int ret = NewtonCollisionClosestPoint( priv->world,
656 objA->
priv->collision, &t1[0][0],
657 objB->
priv->collision, &t2[0][0],
658 &pointA[0], &pointB[0], &normal[0], 0 );
bool getKinematic() const
Returns true if the object has kinematic behaviour.
void advanceUntil(real time)
Advance the World until the time passed is reached (approx.
void enableCollision(QString mat1, QString mat2, bool enable=true)
Enable/Disable the collision between materials passed.
the MaterialDB class managea the material properties
void size(wVector &minPoint, wVector &maxPoint)
Get the bounding box of the world.
void setGravityForce(QString mat, real force)
configure the force gravity that will be applied to object of material specified
void addedObject(WObject *)
emitted when an WObject has been added
void setFrictionModel(QString model)
See Physic Engine Documentation.
void advance()
Do a step of the World.
void setGravityForce(real g)
Set the gravity force.
void resized()
emitted when the World change its size
rayCastHitVector worldRayCast(wVector start, wVector end, bool onlyClosest, const QSet< PhyObject * > &ignoredObjs=QSet< PhyObject * >())
Returns the bodyes which intersect the ray from start to end.
void setSize(const wVector &minPoint, const wVector &maxPoint)
See Physic Engine Documentation.
void removedObject(WObject *)
emitted when an WObject has been removed
QHash< WObject *, QList< PhyJoint * > > mapObjJoints
Map object -> joints.
real timestepv
The time step.
bool getStatic() const
Returns true if the object is static.
void finished()
When exit from finalize method.
real time
The elapsed simulation-time from last calls of initialize()
void setFrictions(QString mat1, QString mat2, real st, real kn)
configure the default Friction between materials specified
void initialize()
Initialize the World, it doesn't do anything if it's already initialized.
void setIsRealTime(bool b)
Enable/Disable Real-time advance.
real gforce
Gravity Force.
const QHash< WObject *, QList< PhyJoint * > > mapObjectsToJoints()
Map object -> joints.
void cleanUpMemory()
Clean up memory.
wMatrix inverse() const
calculate the inverse of transformation matrix
FARSA_UTIL_TEMPLATE const T max(const T &t1, const U &t2)
QLinkedList< WObject * > objs
Vector of WObject inside the World.
const QLinkedList< WObject * > objects()
Return the vector of objects present in this world.
void pause()
Pause the World.
bool checkContacts(PhyObject *obj1, PhyObject *obj2, int maxContacts=4, QVector< wVector > *contacts=NULL, QVector< wVector > *normals=NULL, QVector< real > *penetra=NULL)
Checks whether two objects collide or not.
PhyObjectPrivate * priv
Engine encapsulation.
void setElasticity(QString mat1, QString mat2, real)
configure the default Elasticity between materials specified the order doesn't matter ...
void addedJoint(PhyJoint *)
emitted when an PhyJoint has been added
wVector minP
Size of the Newton world.
void finalize()
Operation performed at the end of the simulation.
const wMatrix & matrix() const
return a reference to the transformation matrix
void paused()
When the stop method is called.
const QLinkedList< PhyJoint * > joints()
Return the vector of joints present in this world.
void timerEvent(QTimerEvent *e)
Event for handling play/stop in order to stay syncronized with QT main thread.
void setSoftness(QString mat1, QString mat2, real)
configure the default Softness between materials specified the order doesn't matter ...
int play()
run the World calling advance as fast as possibile (return the timerId)
void stop()
Stop the World.
real gravityForce(QString mat)
Return the corresponding gravity force setted If no setted, that World::gravityForce will be returned...
void setTimeStep(real)
Set the time step.
void resetElapsedTime()
Reset the time counter and restart from zero seconds.
real timeStep() const
get the time step setted
void enableCollision(PhyObject *obj1, PhyObject *obj2)
Enable collision.
WObject * getObject(QString name)
Return the WObject with name specified, otherwise return NULL.
void initialized()
When exit from initialize method.
real elapsedTime() const
Get the elapsed time.
bool createMaterial(QString name)
Create a new material It return false if already exists a material with name passed.
const contactMap & contacts()
return the contact map
bool smartCheckContacts(PhyObject *obj1, PhyObject *obj2, int maxContacts=4, QVector< wVector > *contacts=NULL)
Checks whether two objects collide or not.
real collisionRayCast(PhyObject *obj, wVector start, wVector end, wVector *normal=NULL)
Checks whether the ray from start to end intersects obj.
void setMultiThread(int numThreads)
Set the multi-thread functionality.
real gravityForce() const
Return the gravity force.
virtual ~World()
Destructor.
World(QString worldname)
Constructor.
void setProperties(QString mat1, QString mat2, real fs, real fk, real el, real sf, bool en=true)
set Frictions, Elasticity, Softness and Enabled/Disable collision between materials ...
bool closestPoints(PhyObject *objA, PhyObject *objB, wVector &pointA, wVector &pointB)
calculate the two closest points between the two objects;
QString name() const
Return the name of this object.
void stopped()
When the stopped method is called.
void setMinimumFrameRate(unsigned int frames)
Set the minimum frame rate; in other word the number of integration steps per seconds regardless the ...
Ownable * owner() const
Returns the owner of this object.
wVector transformVector(const wVector &v) const
apply both rotation and translation to the vector v
QString name() const
Return the name.
void setSolverModel(QString model)
See Physic Engine Documentation.
void advanced()
When exit from advance method.
bool isRealTime() const
return true is real-time is enabled ; false otherwise
QLinkedList< PhyJoint * > jointsv
Vector of Joints inside the World.
void disableCollision(PhyObject *obj1, PhyObject *obj2)
Disable collision between bodies.
void removedJoint(PhyJoint *)
emitted when an PhyJoint has been removed
void customEvent(QEvent *e)
Custom Events.