Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/questsystem5/src/orxonox/objects/Scene.cc @ 2988

Last change on this file since 2988 was 2908, checked in by dafrick, 16 years ago

Reverted to revision 2906 (because I'm too stupid to merge correctly, 2nd try will follow shortly. ;))

  • Property svn:eol-style set to native
File size: 13.6 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *      Reto Grieder (physics)
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30#include "OrxonoxStableHeaders.h"
31#include "Scene.h"
32
33#include <OgreRoot.h>
34#include <OgreSceneManagerEnumerator.h>
35#include <OgreSceneNode.h>
36
37#include "BulletCollision/BroadphaseCollision/btAxisSweep3.h"
38#include "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h"
39#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h"
40#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h"
41
42#include "core/CoreIncludes.h"
43#include "core/Core.h"
44#include "core/XMLPort.h"
45#include "tools/BulletConversions.h"
46#include "objects/worldentities/WorldEntity.h"
47
48namespace orxonox
49{
50    CreateFactory(Scene);
51
52    Scene::Scene(BaseObject* creator) : BaseObject(creator), Synchronisable(creator)
53    {
54        RegisterObject(Scene);
55
56        this->setScene(this);
57        this->bShadows_ = true;
58
59        if (Core::showsGraphics())
60        {
61            if (Ogre::Root::getSingletonPtr())
62            {
63                this->sceneManager_ = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
64                this->rootSceneNode_ = this->sceneManager_->getRootSceneNode();
65            }
66            else
67            {
68                this->sceneManager_ = 0;
69                this->rootSceneNode_ = 0;
70            }
71        }
72        else
73        {
74            // create a dummy SceneManager of our own since we don't have Ogre::Root.
75            this->sceneManager_ = new Ogre::DefaultSceneManager("");
76            this->rootSceneNode_ = this->sceneManager_->getRootSceneNode();
77        }
78
79        // No physics yet, XMLPort will do that.
80        const int defaultMaxWorldSize = 100000;
81        this->negativeWorldRange_ = Vector3::UNIT_SCALE * -defaultMaxWorldSize;
82        this->positiveWorldRange_ = Vector3::UNIT_SCALE *  defaultMaxWorldSize;
83        this->gravity_ = Vector3::ZERO;
84        this->physicalWorld_   = 0;
85        this->solver_          = 0;
86        this->dispatcher_      = 0;
87        this->collisionConfig_ = 0;
88        this->broadphase_      = 0;
89
90        this->registerVariables();
91    }
92
93    Scene::~Scene()
94    {
95        if (this->isInitialized())
96        {
97            if (Ogre::Root::getSingletonPtr())
98            {
99                Ogre::Root::getSingleton().destroySceneManager(this->sceneManager_);
100            }
101            else if (!Core::showsGraphics())
102            {
103                delete this->sceneManager_;
104            }
105
106            this->setPhysicalWorld(false);
107        }
108    }
109
110    void Scene::XMLPort(Element& xmlelement, XMLPort::Mode mode)
111    {
112        SUPER(Scene, XMLPort, xmlelement, mode);
113
114        XMLPortParam(Scene, "skybox", setSkybox, getSkybox, xmlelement, mode);
115        XMLPortParam(Scene, "ambientlight", setAmbientLight, getAmbientLight, xmlelement, mode).defaultValues(ColourValue(0.2, 0.2, 0.2, 1));
116        XMLPortParam(Scene, "shadow", setShadow, getShadow, xmlelement, mode).defaultValues(true);
117
118        XMLPortParam(Scene, "gravity", setGravity, getGravity, xmlelement, mode);
119        XMLPortParam(Scene, "negativeWorldRange", setNegativeWorldRange, getNegativeWorldRange, xmlelement, mode);
120        XMLPortParam(Scene, "positiveWorldRange", setPositiveWorldRange, getPositiveWorldRange, xmlelement, mode);
121        XMLPortParam(Scene, "hasPhysics", setPhysicalWorld, hasPhysics, xmlelement, mode).defaultValues(true);
122
123        XMLPortObjectExtended(Scene, BaseObject, "", addObject, getObject, xmlelement, mode, true, false);
124    }
125
126    void Scene::registerVariables()
127    {
128        registerVariable(this->skybox_,             variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applySkybox));
129        registerVariable(this->ambientLight_,       variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applyAmbientLight));
130        registerVariable(this->negativeWorldRange_, variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_negativeWorldRange));
131        registerVariable(this->positiveWorldRange_, variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_positiveWorldRange));
132        registerVariable(this->gravity_,            variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_gravity));
133        registerVariable(this->bHasPhysics_,        variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_hasPhysics));
134        registerVariable(this->bShadows_,           variableDirection::toclient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applyShadows));
135    }
136
137    void Scene::setNegativeWorldRange(const Vector3& range)
138    {
139        if (range.length() < 10.0f)
140        {
141            CCOUT(2) << "Warning: Setting the negative world range to a very small value: "
142                     << omni_cast<std::string>(range) << std::endl;
143        }
144        if (this->hasPhysics())
145        {
146            CCOUT(2) << "Warning: Attempting to set the physical world range at run time. "
147                     << "This causes a complete physical reload which might take some time." << std::endl;
148            this->setPhysicalWorld(false);
149            this->negativeWorldRange_ = range;
150            this->setPhysicalWorld(true);
151        }
152        else
153            this->negativeWorldRange_ = range;
154    }
155
156    void Scene::setPositiveWorldRange(const Vector3& range)
157    {
158        if (range.length() < 10.0f)
159        {
160            CCOUT(2) << "Warning: Setting the positive world range to a very small value: "
161                     << omni_cast<std::string>(range) << std::endl;
162        }
163        if (this->hasPhysics())
164        {
165            CCOUT(2) << "Warning: Attempting to set the physical world range at run time. "
166                     << "This causes a complete physical reload which might take some time." << std::endl;
167            this->setPhysicalWorld(false);
168            this->positiveWorldRange_ = range;
169            this->setPhysicalWorld(true);
170        }
171        else
172            this->positiveWorldRange_ = range;
173    }
174
175    void Scene::setGravity(const Vector3& gravity)
176    {
177        this->gravity_ = gravity;
178        if (this->hasPhysics())
179            this->physicalWorld_->setGravity(omni_cast<btVector3>(this->gravity_));
180    }
181
182    void Scene::setPhysicalWorld(bool wantPhysics)
183    {
184        this->bHasPhysics_ = wantPhysics;
185        if (wantPhysics && !hasPhysics())
186        {
187            // Note: These are all little known default classes and values.
188            //       It would require further investigation to properly dertermine the right choices.
189            this->broadphase_      = new bt32BitAxisSweep3(
190                omni_cast<btVector3>(this->negativeWorldRange_), omni_cast<btVector3>(this->positiveWorldRange_));
191            this->collisionConfig_ = new btDefaultCollisionConfiguration();
192            this->dispatcher_      = new btCollisionDispatcher(this->collisionConfig_);
193            this->solver_          = new btSequentialImpulseConstraintSolver();
194
195            this->physicalWorld_   = new btDiscreteDynamicsWorld(this->dispatcher_, this->broadphase_, this->solver_, this->collisionConfig_);
196            this->physicalWorld_->setGravity(omni_cast<btVector3>(this->gravity_));
197
198            // also set the collision callback variable.
199            // Note: This is a global variable which we assign a static function.
200            // TODO: Check whether this (or anything about Bullet) works with multiple physics engine instances.
201            gContactAddedCallback = &Scene::collisionCallback;
202        }
203        else if (!wantPhysics && hasPhysics())
204        {
205            // Remove all WorldEntities and shove them to the queue since they would still like to be in a physical world.
206            for (std::set<WorldEntity*>::const_iterator it = this->physicalObjects_.begin();
207                it != this->physicalObjects_.end(); ++it)
208            {
209                this->physicalWorld_->removeRigidBody((*it)->physicalBody_);
210                this->physicalObjectQueue_.insert(*it);
211            }
212            this->physicalObjects_.clear();
213
214            delete this->physicalWorld_;
215            delete this->solver_;
216            delete this->dispatcher_;
217            delete this->collisionConfig_;
218            delete this->broadphase_;
219            this->physicalWorld_   = 0;
220            this->solver_          = 0;
221            this->dispatcher_      = 0;
222            this->collisionConfig_ = 0;
223            this->broadphase_      = 0;
224        }
225    }
226
227    void Scene::tick(float dt)
228    {
229        if (!Core::showsGraphics())
230        {
231            // We need to update the scene nodes if we don't render
232            this->rootSceneNode_->_update(true, false);
233        }
234        if (this->hasPhysics())
235        {
236            // TODO: This here is bad practice! It will slow down the first tick() by ages.
237            //       Rather have an initialise() method as well, called by the Level after everything has been loaded.
238            if (this->physicalObjectQueue_.size() > 0)
239            {
240                // Add all scheduled WorldEntities
241                for (std::set<WorldEntity*>::const_iterator it = this->physicalObjectQueue_.begin();
242                    it != this->physicalObjectQueue_.end(); ++it)
243                {
244                    this->physicalWorld_->addRigidBody((*it)->physicalBody_);
245                    this->physicalObjects_.insert(*it);
246                }
247                this->physicalObjectQueue_.clear();
248            }
249
250            // Note: 60 means that Bullet will do physics correctly down to 1 frames per seconds.
251            //       Under that mark, the simulation will "loose time" and get unusable.
252            physicalWorld_->stepSimulation(dt, 60);
253        }
254    }
255
256    void Scene::setSkybox(const std::string& skybox)
257    {
258        if (Core::showsGraphics() && this->sceneManager_)
259            this->sceneManager_->setSkyBox(true, skybox);
260
261        this->skybox_ = skybox;
262    }
263
264    void Scene::setAmbientLight(const ColourValue& colour)
265    {
266        if (Core::showsGraphics() && this->sceneManager_)
267            this->sceneManager_->setAmbientLight(colour);
268
269        this->ambientLight_ = colour;
270    }
271
272    void Scene::setShadow(bool bShadow)
273    {
274        if (Core::showsGraphics() && this->sceneManager_)
275        {
276            if (bShadow)
277                this->sceneManager_->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
278            else
279                this->sceneManager_->setShadowTechnique(Ogre::SHADOWTYPE_NONE);
280        }
281
282        this->bShadows_ = bShadow;
283    }
284
285    void Scene::addObject(BaseObject* object)
286    {
287        this->objects_.push_back(object);
288        object->setScene(this);
289    }
290
291    BaseObject* Scene::getObject(unsigned int index) const
292    {
293        unsigned int i = 0;
294        for (std::list<BaseObject*>::const_iterator it = this->objects_.begin(); it != this->objects_.end(); ++it)
295        {
296            if (i == index)
297                return (*it);
298            ++i;
299        }
300        return 0;
301    }
302
303    void Scene::addPhysicalObject(WorldEntity* object)
304    {
305        if (object)
306        {
307            std::set<WorldEntity*>::iterator it = this->physicalObjects_.find(object);
308            if (it != this->physicalObjects_.end())
309                return;
310
311            this->physicalObjectQueue_.insert(object);
312        }
313    }
314
315    void Scene::removePhysicalObject(WorldEntity* object)
316    {
317        // check queue first
318        std::set<WorldEntity*>::iterator it = this->physicalObjectQueue_.find(object);
319        if (it != this->physicalObjectQueue_.end())
320        {
321            this->physicalObjectQueue_.erase(it);
322            return;
323        }
324
325        it = this->physicalObjects_.find(object);
326        if (it == this->physicalObjects_.end())
327            return;
328        this->physicalObjects_.erase(it);
329
330        if (this->hasPhysics())
331            this->physicalWorld_->removeRigidBody(object->physicalBody_);
332    }
333
334    /*static*/ bool Scene::collisionCallback(btManifoldPoint& cp, const btCollisionObject* colObj0, int partId0,
335                                             int index0, const btCollisionObject* colObj1, int partId1, int index1)
336    {
337        // get the WorldEntity pointers
338        WorldEntity* object0 = (WorldEntity*)colObj0->getUserPointer();
339        assert(dynamic_cast<WorldEntity*>(object0));
340        WorldEntity* object1 = (WorldEntity*)colObj1->getUserPointer();
341        assert(dynamic_cast<WorldEntity*>(object1));
342
343        // false means that bullet will assume we didn't modify the contact
344        bool modified = false;
345        if (object0->isCollisionCallbackActive())
346        {
347            modified |= object0->collidesAgainst(object1, cp);
348            if (object1->isCollisionCallbackActive())
349                modified |= object1->collidesAgainst(object0, cp);
350        }
351        else
352            modified |= object1->collidesAgainst(object0, cp);
353
354        return modified;
355    }
356}
Note: See TracBrowser for help on using the repository browser.