Index: code/branches/presentation/src/orxonox/objects/Scene.cc
===================================================================
--- code/branches/presentation/src/orxonox/objects/Scene.cc	(revision 2371)
+++ code/branches/presentation/src/orxonox/objects/Scene.cc	(revision 2459)
@@ -22,4 +22,5 @@
  *   Author:
  *      Fabian 'x3n' Landau
+ *      Reto Grieder (physics)
  *   Co-authors:
  *      ...
@@ -35,7 +36,14 @@
 #include <OgreLight.h>
 
+#include "BulletCollision/BroadphaseCollision/btAxisSweep3.h"
+#include "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h"
+#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h"
+#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h"
+
 #include "core/CoreIncludes.h"
 #include "core/Core.h"
 #include "core/XMLPort.h"
+#include "tools/BulletConversions.h"
+#include "objects/worldentities/WorldEntity.h"
 
 namespace orxonox
@@ -69,4 +77,15 @@
             this->rootSceneNode_ = this->sceneManager_->getRootSceneNode();
         }
+
+        // No physics yet, XMLPort will do that.
+        const int defaultMaxWorldSize = 100000;
+        this->negativeWorldRange_ = Vector3::UNIT_SCALE * -defaultMaxWorldSize;
+        this->positiveWorldRange_ = Vector3::UNIT_SCALE *  defaultMaxWorldSize;
+        this->gravity_ = Vector3::ZERO;
+        this->physicalWorld_   = 0;
+        this->solver_          = 0;
+        this->dispatcher_      = 0;
+        this->collisionConfig_ = 0;
+        this->broadphase_      = 0;
 
         // test test test
@@ -91,5 +110,4 @@
             if (Ogre::Root::getSingletonPtr())
             {
-//                this->sceneManager_->destroySceneNode(this->rootSceneNode_->getName()); // TODO: remove getName() for newer versions of Ogre
                 Ogre::Root::getSingleton().destroySceneManager(this->sceneManager_);
             }
@@ -98,4 +116,6 @@
                 delete this->sceneManager_;
             }
+
+            this->setPhysicalWorld(false);
         }
     }
@@ -109,4 +129,8 @@
         XMLPortParam(Scene, "shadow", setShadow, getShadow, xmlelement, mode).defaultValues(true);
 
+        XMLPortParam(Scene, "negativeWorldRange", setNegativeWorldRange, getNegativeWorldRange, xmlelement, mode);
+        XMLPortParam(Scene, "positiveWorldRange", setPositiveWorldRange, getPositiveWorldRange, xmlelement, mode);
+        XMLPortParam(Scene, "hasPhysics", setPhysicalWorld, hasPhysics, xmlelement, mode).defaultValues(true);
+
         XMLPortObjectExtended(Scene, BaseObject, "", addObject, getObject, xmlelement, mode, true, false);
     }
@@ -114,6 +138,123 @@
     void Scene::registerVariables()
     {
-        registerVariable(this->skybox_,     variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applySkybox));
-        registerVariable(this->ambientLight_, variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applyAmbientLight));
+        registerVariable(this->skybox_,             variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applySkybox));
+        registerVariable(this->ambientLight_,       variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applyAmbientLight));
+        registerVariable(this->negativeWorldRange_, variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_negativeWorldRange));
+        registerVariable(this->positiveWorldRange_, variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_positiveWorldRange));
+        registerVariable(this->gravity_,            variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_gravity));
+        registerVariable(this->bHasPhysics_,        variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_hasPhysics));
+    }
+
+    void Scene::setNegativeWorldRange(const Vector3& range)
+    {
+        if (range.length() < 10.0f)
+        {
+            CCOUT(2) << "Warning: Setting the negative world range to a very small value: "
+                     << omni_cast<std::string>(range) << std::endl;
+        }
+        if (this->hasPhysics())
+        {
+            CCOUT(2) << "Warning: Attempting to set the physical world range at run time. " 
+                     << "This causes a complete physical reload which might take some time." << std::endl;
+            this->setPhysicalWorld(false);
+            this->negativeWorldRange_ = range;
+            this->setPhysicalWorld(true);
+        }
+        else
+            this->negativeWorldRange_ = range;
+    }
+
+    void Scene::setPositiveWorldRange(const Vector3& range)
+    {
+        if (range.length() < 10.0f)
+        {
+            CCOUT(2) << "Warning: Setting the positive world range to a very small value: "
+                     << omni_cast<std::string>(range) << std::endl;
+        }
+        if (this->hasPhysics())
+        {
+            CCOUT(2) << "Warning: Attempting to set the physical world range at run time. " 
+                     << "This causes a complete physical reload which might take some time." << std::endl;
+            this->setPhysicalWorld(false);
+            this->positiveWorldRange_ = range;
+            this->setPhysicalWorld(true);
+        }
+        else
+            this->positiveWorldRange_ = range;
+    }
+
+    void Scene::setGravity(const Vector3& gravity)
+    {
+        this->gravity_ = gravity;
+        if (this->hasPhysics())
+            this->physicalWorld_->setGravity(omni_cast<btVector3>(this->gravity_));
+    }
+
+    void Scene::setPhysicalWorld(bool wantPhysics)
+    {
+        this->bHasPhysics_ = wantPhysics;
+        if (wantPhysics && !hasPhysics())
+        {
+            // Note: These are all little known default classes and values.
+            //       It would require further investigation to properly dertermine the right choices.
+            this->broadphase_      = new bt32BitAxisSweep3(
+                omni_cast<btVector3>(this->negativeWorldRange_), omni_cast<btVector3>(this->positiveWorldRange_));
+            this->collisionConfig_ = new btDefaultCollisionConfiguration();
+            this->dispatcher_      = new btCollisionDispatcher(this->collisionConfig_);
+            this->solver_          = new btSequentialImpulseConstraintSolver;
+
+            this->physicalWorld_   = new btDiscreteDynamicsWorld(this->dispatcher_, this->broadphase_, this->solver_, this->collisionConfig_);
+            this->physicalWorld_->setGravity(omni_cast<btVector3>(this->gravity_));
+        }
+        else if (!wantPhysics && hasPhysics())
+        {
+            // Remove all WorldEntities and shove them to the queue since they would still like to be in a physical world.
+            for (std::set<WorldEntity*>::const_iterator it = this->physicalObjects_.begin();
+                it != this->physicalObjects_.end(); ++it)
+            {
+                this->physicalWorld_->removeRigidBody((*it)->getPhysicalBody());
+                this->physicalObjectQueue_.insert(*it);
+            }
+            this->physicalObjects_.clear();
+
+            delete this->physicalWorld_;
+            delete this->solver_;
+            delete this->dispatcher_;
+            delete this->collisionConfig_;
+            delete this->broadphase_;
+            this->physicalWorld_   = 0;
+            this->solver_          = 0;
+            this->dispatcher_      = 0;
+            this->collisionConfig_ = 0;
+            this->broadphase_      = 0;
+        }
+    }
+
+    void Scene::tick(float dt)
+    {
+        if (!Core::showsGraphics())
+        {
+            // We need to update the scene nodes if we don't render
+            this->rootSceneNode_->_update(true, false);
+        }
+        if (this->hasPhysics())
+        {
+            // TODO: This here is bad practice! It will slow down the first tick() by ages.
+            //       Rather have an initialise() method as well, called by the Level after everything has been loaded.
+            if (this->physicalObjectQueue_.size() > 0)
+            {
+                // Add all scheduled WorldEntities
+                for (std::set<WorldEntity*>::const_iterator it = this->physicalObjectQueue_.begin();
+                    it != this->physicalObjectQueue_.end(); ++it)
+                {
+                    this->physicalWorld_->addRigidBody((*it)->getPhysicalBody());
+                }
+                this->physicalObjectQueue_.clear();
+            }
+
+            // Note: 60 means that Bullet will do physics correctly down to 1 frames per seconds.
+            //       Under that mark, the simulation will "loose time" and get unusable.
+            physicalWorld_->stepSimulation(dt, 60);
+        }
     }
 
@@ -165,11 +306,33 @@
     }
 
-    void Scene::tick(float dt)
-    {
-        if (!Core::showsGraphics())
-        {
-            // We need to update the scene nodes if we don't render
-            this->rootSceneNode_->_update(true, false);
-        }
+    void Scene::addPhysicalObject(WorldEntity* object)
+    {
+        if (object)
+        {
+            std::set<WorldEntity*>::iterator it = this->physicalObjects_.find(object);
+            if (it != this->physicalObjects_.end())
+                return;
+
+            this->physicalObjectQueue_.insert(object);
+        }
+    }
+
+    void Scene::removePhysicalObject(WorldEntity* object)
+    {
+        // check queue first
+        std::set<WorldEntity*>::iterator it = this->physicalObjectQueue_.find(object);
+        if (it != this->physicalObjectQueue_.end())
+        {
+            this->physicalObjectQueue_.erase(it);
+            return;
+        }
+
+        it = this->physicalObjects_.find(object);
+        if (it == this->physicalObjects_.end())
+            return;
+        this->physicalObjects_.erase(it);
+
+        if (this->hasPhysics())
+            this->physicalWorld_->removeRigidBody(object->getPhysicalBody());
     }
 }
