Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core5/src/orxonox/Scene.cc @ 5867

Last change on this file since 5867 was 5839, checked in by scheusso, 15 years ago

Fixed problem with scene and creators
creatorID is now always the objectID of the scene except for the case

  • if the object is the scene (then the creatorID is OBJECTID_UNKNOWN)
  • if the object is "above" the scene (e.g. level), then the cID is also OBJECTID_UNKNOWN
  • 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 "Scene.h"
31
32#include <OgreRoot.h>
33#include <OgreSceneManager.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/GameMode.h"
44#include "core/XMLPort.h"
45#include "tools/BulletConversions.h"
46#include "Radar.h"
47#include "worldentities/WorldEntity.h"
48
49namespace orxonox
50{
51    CreateFactory(Scene);
52
53    Scene::Scene(BaseObject* creator) : BaseObject(creator), Synchronisable(creator)
54    {
55        RegisterObject(Scene);
56
57        this->setScene(SmartPtr<Scene>(this, false), OBJECTID_UNKNOWN);
58        this->bShadows_ = true;
59
60        if (GameMode::showsGraphics())
61        {
62            assert(Ogre::Root::getSingletonPtr());
63            this->sceneManager_ = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
64            this->rootSceneNode_ = this->sceneManager_->getRootSceneNode();
65
66            this->radar_ = new Radar();
67        }
68        else
69        {
70            // create a dummy SceneManager of our own since we don't have Ogre::Root.
71            this->sceneManager_ = new Ogre::DefaultSceneManager("");
72            this->rootSceneNode_ = this->sceneManager_->getRootSceneNode();
73
74            this->radar_ = 0;
75        }
76
77        // No physics yet, XMLPort will do that.
78        const int defaultMaxWorldSize = 100000;
79        this->negativeWorldRange_ = Vector3::UNIT_SCALE * -defaultMaxWorldSize;
80        this->positiveWorldRange_ = Vector3::UNIT_SCALE *  defaultMaxWorldSize;
81        this->gravity_ = Vector3::ZERO;
82        this->physicalWorld_   = 0;
83        this->solver_          = 0;
84        this->dispatcher_      = 0;
85        this->collisionConfig_ = 0;
86        this->broadphase_      = 0;
87
88        this->registerVariables();
89    }
90
91    Scene::~Scene()
92    {
93        if (this->isInitialized())
94        {
95            if (GameMode::showsGraphics())
96                Ogre::Root::getSingleton().destroySceneManager(this->sceneManager_);
97            else
98                delete this->sceneManager_;
99
100            if (this->radar_)
101                this->radar_->destroy();
102
103            this->setPhysicalWorld(false);
104        }
105    }
106
107    void Scene::XMLPort(Element& xmlelement, XMLPort::Mode mode)
108    {
109        SUPER(Scene, XMLPort, xmlelement, mode);
110
111        XMLPortParam(Scene, "skybox", setSkybox, getSkybox, xmlelement, mode);
112        XMLPortParam(Scene, "ambientlight", setAmbientLight, getAmbientLight, xmlelement, mode).defaultValues(ColourValue(0.2f, 0.2f, 0.2f, 1.0f));
113        XMLPortParam(Scene, "shadow", setShadow, getShadow, xmlelement, mode).defaultValues(true);
114
115        XMLPortParam(Scene, "gravity", setGravity, getGravity, xmlelement, mode);
116        XMLPortParam(Scene, "negativeWorldRange", setNegativeWorldRange, getNegativeWorldRange, xmlelement, mode);
117        XMLPortParam(Scene, "positiveWorldRange", setPositiveWorldRange, getPositiveWorldRange, xmlelement, mode);
118        XMLPortParam(Scene, "hasPhysics", setPhysicalWorld, hasPhysics, xmlelement, mode).defaultValues(true);
119
120        XMLPortObjectExtended(Scene, BaseObject, "", addObject, getObject, xmlelement, mode, true, false);
121    }
122
123    void Scene::registerVariables()
124    {
125        registerVariable(this->skybox_,             VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applySkybox));
126        registerVariable(this->ambientLight_,       VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applyAmbientLight));
127        registerVariable(this->negativeWorldRange_, VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_negativeWorldRange));
128        registerVariable(this->positiveWorldRange_, VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_positiveWorldRange));
129        registerVariable(this->gravity_,            VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_gravity));
130        registerVariable(this->bHasPhysics_,        VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_hasPhysics));
131        registerVariable(this->bShadows_,           VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applyShadows));
132    }
133
134    void Scene::setNegativeWorldRange(const Vector3& range)
135    {
136        if (range.length() < 10.0f)
137        {
138            CCOUT(2) << "Warning: Setting the negative world range to a very small value: "
139                     << multi_cast<std::string>(range) << std::endl;
140        }
141        if (this->hasPhysics())
142        {
143            CCOUT(2) << "Warning: Attempting to set the physical world range at run time. "
144                     << "This causes a complete physical reload which might take some time." << std::endl;
145            this->setPhysicalWorld(false);
146            this->negativeWorldRange_ = range;
147            this->setPhysicalWorld(true);
148        }
149        else
150            this->negativeWorldRange_ = range;
151    }
152
153    void Scene::setPositiveWorldRange(const Vector3& range)
154    {
155        if (range.length() < 10.0f)
156        {
157            CCOUT(2) << "Warning: Setting the positive world range to a very small value: "
158                     << multi_cast<std::string>(range) << std::endl;
159        }
160        if (this->hasPhysics())
161        {
162            CCOUT(2) << "Warning: Attempting to set the physical world range at run time. "
163                     << "This causes a complete physical reload which might take some time." << std::endl;
164            this->setPhysicalWorld(false);
165            this->positiveWorldRange_ = range;
166            this->setPhysicalWorld(true);
167        }
168        else
169            this->positiveWorldRange_ = range;
170    }
171
172    void Scene::setGravity(const Vector3& gravity)
173    {
174        this->gravity_ = gravity;
175        if (this->hasPhysics())
176            this->physicalWorld_->setGravity(multi_cast<btVector3>(this->gravity_));
177    }
178
179    void Scene::setPhysicalWorld(bool wantPhysics)
180    {
181        this->bHasPhysics_ = wantPhysics;
182        if (wantPhysics && !hasPhysics())
183        {
184            // Note: These are all little known default classes and values.
185            //       It would require further investigation to properly dertermine the right choices.
186            this->broadphase_      = new bt32BitAxisSweep3(
187                multi_cast<btVector3>(this->negativeWorldRange_), multi_cast<btVector3>(this->positiveWorldRange_));
188            this->collisionConfig_ = new btDefaultCollisionConfiguration();
189            this->dispatcher_      = new btCollisionDispatcher(this->collisionConfig_);
190            this->solver_          = new btSequentialImpulseConstraintSolver();
191
192            this->physicalWorld_   = new btDiscreteDynamicsWorld(this->dispatcher_, this->broadphase_, this->solver_, this->collisionConfig_);
193            this->physicalWorld_->setGravity(multi_cast<btVector3>(this->gravity_));
194
195            // also set the collision callback variable.
196            // Note: This is a global variable which we assign a static function.
197            // TODO: Check whether this (or anything about Bullet) works with multiple physics engine instances.
198            gContactAddedCallback = &Scene::collisionCallback;
199        }
200        else if (!wantPhysics && hasPhysics())
201        {
202            // Remove all WorldEntities and shove them to the queue since they would still like to be in a physical world.
203            for (std::set<WorldEntity*>::const_iterator it = this->physicalObjects_.begin();
204                it != this->physicalObjects_.end(); ++it)
205            {
206                this->physicalWorld_->removeRigidBody((*it)->physicalBody_);
207                this->physicalObjectQueue_.insert(*it);
208            }
209            this->physicalObjects_.clear();
210
211            delete this->physicalWorld_;
212            delete this->solver_;
213            delete this->dispatcher_;
214            delete this->collisionConfig_;
215            delete this->broadphase_;
216            this->physicalWorld_   = 0;
217            this->solver_          = 0;
218            this->dispatcher_      = 0;
219            this->collisionConfig_ = 0;
220            this->broadphase_      = 0;
221        }
222    }
223
224    void Scene::tick(float dt)
225    {
226        if (!GameMode::showsGraphics())
227        {
228            // We need to update the scene nodes if we don't render
229            this->rootSceneNode_->_update(true, false);
230        }
231        if (this->hasPhysics())
232        {
233            // TODO: This here is bad practice! It will slow down the first tick() by ages.
234            //       Rather have an initialise() method as well, called by the Level after everything has been loaded.
235            if (this->physicalObjectQueue_.size() > 0)
236            {
237                // Add all scheduled WorldEntities
238                for (std::set<WorldEntity*>::const_iterator it = this->physicalObjectQueue_.begin();
239                    it != this->physicalObjectQueue_.end(); ++it)
240                {
241                    this->physicalWorld_->addRigidBody((*it)->physicalBody_);
242                    this->physicalObjects_.insert(*it);
243                }
244                this->physicalObjectQueue_.clear();
245            }
246
247            // Note: 60 means that Bullet will do physics correctly down to 1 frames per seconds.
248            //       Under that mark, the simulation will "loose time" and get unusable.
249            physicalWorld_->stepSimulation(dt, 60);
250        }
251    }
252
253    void Scene::setSkybox(const std::string& skybox)
254    {
255        if (GameMode::showsGraphics() && this->sceneManager_)
256            this->sceneManager_->setSkyBox(true, skybox);
257
258        this->skybox_ = skybox;
259    }
260
261    void Scene::setAmbientLight(const ColourValue& colour)
262    {
263        if (GameMode::showsGraphics() && this->sceneManager_)
264            this->sceneManager_->setAmbientLight(colour);
265
266        this->ambientLight_ = colour;
267    }
268
269    void Scene::setShadow(bool bShadow)
270    {
271        if (GameMode::showsGraphics() && this->sceneManager_)
272        {
273            if (bShadow)
274                this->sceneManager_->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
275            else
276                this->sceneManager_->setShadowTechnique(Ogre::SHADOWTYPE_NONE);
277        }
278
279        this->bShadows_ = bShadow;
280    }
281
282    void Scene::addObject(BaseObject* object)
283    {
284        this->objects_.push_back(object);
285        object->setScene(this, this->getObjectID());
286    }
287
288    BaseObject* Scene::getObject(unsigned int index) const
289    {
290        unsigned int i = 0;
291        for (std::list<BaseObject*>::const_iterator it = this->objects_.begin(); it != this->objects_.end(); ++it)
292        {
293            if (i == index)
294                return (*it);
295            ++i;
296        }
297        return 0;
298    }
299
300    void Scene::addPhysicalObject(WorldEntity* object)
301    {
302        if (object)
303        {
304            std::set<WorldEntity*>::iterator it = this->physicalObjects_.find(object);
305            if (it != this->physicalObjects_.end())
306                return;
307
308            this->physicalObjectQueue_.insert(object);
309        }
310    }
311
312    void Scene::removePhysicalObject(WorldEntity* object)
313    {
314        // check queue first
315        std::set<WorldEntity*>::iterator it = this->physicalObjectQueue_.find(object);
316        if (it != this->physicalObjectQueue_.end())
317        {
318            this->physicalObjectQueue_.erase(it);
319            return;
320        }
321
322        it = this->physicalObjects_.find(object);
323        if (it == this->physicalObjects_.end())
324            return;
325        this->physicalObjects_.erase(it);
326
327        if (this->hasPhysics())
328            this->physicalWorld_->removeRigidBody(object->physicalBody_);
329    }
330
331    /*static*/ bool Scene::collisionCallback(btManifoldPoint& cp, const btCollisionObject* colObj0, int partId0,
332                                             int index0, const btCollisionObject* colObj1, int partId1, int index1)
333    {
334        // get the WorldEntity pointers
335        WorldEntity* object0 = static_cast<WorldEntity*>(colObj0->getUserPointer());
336        assert(orxonox_cast<WorldEntity*>(object0));
337        WorldEntity* object1 = static_cast<WorldEntity*>(colObj1->getUserPointer());
338        assert(orxonox_cast<WorldEntity*>(object1));
339
340        // false means that bullet will assume we didn't modify the contact
341        bool modified = false;
342        if (object0->isCollisionCallbackActive())
343        {
344            modified |= object0->collidesAgainst(object1, cp);
345            if (object1->isCollisionCallbackActive())
346                modified |= object1->collidesAgainst(object0, cp);
347        }
348        else
349            modified |= object1->collidesAgainst(object0, cp);
350
351        return modified;
352    }
353}
Note: See TracBrowser for help on using the repository browser.