Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ogre1.9/src/orxonox/Scene.cc @ 11131

Last change on this file since 11131 was 11131, checked in by landauf, 8 years ago

initialize overlay component

  • Property svn:eol-style set to native
File size: 16.9 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/**
31@file Scene.cc
32@brief Implementation of Scene Class
33*/
34
35
36#include "Scene.h"
37
38#include <OgreRoot.h>
39#include <OgreSceneManager.h>
40#include <OgreSceneManagerEnumerator.h>
41#include <OgreSceneNode.h>
42#if OGRE_VERSION >= 0x010900
43#   include <Overlay/OgreOverlaySystem.h>
44#endif
45
46#include <BulletCollision/BroadphaseCollision/btAxisSweep3.h>
47#include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
48#include <BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h>
49#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
50
51#include "core/CoreIncludes.h"
52#include "core/GameMode.h"
53#include "core/GUIManager.h"
54#include "core/XMLPort.h"
55#include "core/command/ConsoleCommandIncludes.h"
56#include "tools/BulletConversions.h"
57#include "tools/BulletDebugDrawer.h"
58#include "tools/DebugDrawer.h"
59#include "Radar.h"
60#include "worldentities/WorldEntity.h"
61#include "Level.h"
62#include "RenderQueueListener.h"
63#include "graphics/GlobalShader.h"
64
65namespace orxonox
66{
67    RegisterClass(Scene);
68   
69    /**
70    @brief
71        Constructor, it sets common standard paramters for a scene depending on whether it will be rendered or not.
72        It also makes sure we user our own render queue listener for rendering instead of the standard listener provided by Ogre
73    */
74    SetConsoleCommand("Scene", "debugDrawPhysics", &Scene::consoleCommand_debugDrawPhysics).addShortcut().defaultValue(1, true).defaultValue(2, 0.5f);
75
76    Scene::Scene(Context* context) : BaseObject(context), Synchronisable(context), Context(context)
77    {
78        RegisterObject(Scene);
79
80        this->setScene(WeakPtr<Scene>(this), this->getObjectID()); // store a weak-pointer to itself (a strong-pointer would create a recursive dependency)
81
82        this->bShadows_ = true;
83        this->bDebugDrawPhysics_ = false;
84        this->debugDrawer_ = nullptr;
85        this->soundReferenceDistance_ = 20.0;
86        this->bIsUpdatingPhysics_ = false;
87
88        if (GameMode::showsGraphics())
89        {
90            assert(Ogre::Root::getSingletonPtr());
91            this->sceneManager_ = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
92            this->rootSceneNode_ = this->sceneManager_->getRootSceneNode();
93            this->renderQueueListener_ = new RenderQueueListener();
94            this->sceneManager_->addRenderQueueListener(this->renderQueueListener_);//add our own renderQueueListener
95#if OGRE_VERSION >= 0x010900
96            this->overlaySystem_ = new Ogre::OverlaySystem();
97            this->sceneManager_->addRenderQueueListener(this->overlaySystem_);
98#endif
99
100            this->radar_ = new Radar();
101            this->glowShader_ = new GlobalShader(this);
102            this->glowShader_->setScene(WeakPtr<Scene>(this), this->getObjectID()); // avoid circular reference
103            this->glowShader_->getShader().setCompositorName("Glow");
104        }
105        else
106        {
107            // create a dummy SceneManager of our own since we don't have Ogre::Root.
108            this->sceneManager_ = new Ogre::DefaultSceneManager("");
109            this->rootSceneNode_ = this->sceneManager_->getRootSceneNode();
110
111            this->renderQueueListener_ = nullptr;
112            this->radar_ = nullptr;
113            this->glowShader_ = nullptr;
114        }
115
116        // No physics yet, XMLPort will do that.
117        const float defaultMaxWorldSize = 100000.0f;
118        this->negativeWorldRange_ = Vector3::UNIT_SCALE * -defaultMaxWorldSize;
119        this->positiveWorldRange_ = Vector3::UNIT_SCALE *  defaultMaxWorldSize;
120        this->gravity_ = Vector3::ZERO;
121        this->physicalWorld_   = nullptr;
122        this->solver_          = nullptr;
123        this->dispatcher_      = nullptr;
124        this->collisionConfig_ = nullptr;
125        this->broadphase_      = nullptr;
126
127        this->registerVariables();
128    }
129
130    Scene::~Scene()
131    {
132        if (this->isInitialized())
133        {
134            this->setPhysicalWorld(false);
135
136            if (this->radar_)
137                this->radar_->destroy();
138            if (this->glowShader_)
139                this->glowShader_->destroy();
140
141            if (GameMode::showsGraphics())
142            {
143#if OGRE_VERSION >= 0x010900
144                this->sceneManager_->removeRenderQueueListener(this->overlaySystem_);
145                delete this->overlaySystem_;
146#endif
147                this->sceneManager_->removeRenderQueueListener(this->renderQueueListener_);
148                delete this->renderQueueListener_;
149                Ogre::Root::getSingleton().destroySceneManager(this->sceneManager_);
150            }
151            else
152                delete this->sceneManager_;
153        }
154    }
155
156    void Scene::XMLPort(Element& xmlelement, XMLPort::Mode mode)
157    {
158        SUPER(Scene, XMLPort, xmlelement, mode);
159
160        XMLPortParam(Scene, "skybox", setSkybox, getSkybox, xmlelement, mode);
161        XMLPortParam(Scene, "ambientlight", setAmbientLight, getAmbientLight, xmlelement, mode).defaultValues(ColourValue(0.2f, 0.2f, 0.2f, 1.0f));
162        XMLPortParam(Scene, "shadow", setShadow, getShadow, xmlelement, mode).defaultValues(true);
163        XMLPortParam(Scene, "soundReferenceDistance", setSoundReferenceDistance, getSoundReferenceDistance, xmlelement, mode);
164
165        XMLPortParam(Scene, "gravity", setGravity, getGravity, xmlelement, mode);
166        XMLPortParam(Scene, "negativeWorldRange", setNegativeWorldRange, getNegativeWorldRange, xmlelement, mode);
167        XMLPortParam(Scene, "positiveWorldRange", setPositiveWorldRange, getPositiveWorldRange, xmlelement, mode);
168        XMLPortParam(Scene, "hasPhysics", setPhysicalWorld, hasPhysics, xmlelement, mode).defaultValues(true);
169
170        XMLPortObjectExtended(Scene, BaseObject, "", addObject, getObject, xmlelement, mode, true, false);
171    }
172
173    void Scene::registerVariables()
174    {
175        registerVariable(this->skybox_,             VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applySkybox));
176        registerVariable(this->ambientLight_,       VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applyAmbientLight));
177        registerVariable(this->negativeWorldRange_, VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_negativeWorldRange));
178        registerVariable(this->positiveWorldRange_, VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_positiveWorldRange));
179        registerVariable(this->gravity_,            VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_gravity));
180        registerVariable(this->bHasPhysics_,        VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_hasPhysics));
181        registerVariable(this->bShadows_,           VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applyShadows));
182    }
183
184    void Scene::setNegativeWorldRange(const Vector3& range)
185    {
186        if (range.length() < 10.0f)
187        {
188            orxout(internal_warning) << "Setting the negative world range to a very small value: "
189                                     << multi_cast<std::string>(range) << endl;
190        }
191        if (this->hasPhysics())
192        {
193            orxout(internal_warning) << "Attempting to set the physical world range at run time. "
194                                     << "This causes a complete physical reload which might take some time." << endl;
195            this->setPhysicalWorld(false);
196            this->negativeWorldRange_ = range;
197            this->setPhysicalWorld(true);
198        }
199        else
200            this->negativeWorldRange_ = range;
201    }
202
203    void Scene::setPositiveWorldRange(const Vector3& range)
204    {
205        if (range.length() < 10.0f)
206        {
207            orxout(internal_warning) << "Setting the positive world range to a very small value: "
208                                     << multi_cast<std::string>(range) << endl;
209        }
210        if (this->hasPhysics())
211        {
212            orxout(internal_warning) << "Attempting to set the physical world range at run time. "
213                                     << "This causes a complete physical reload which might take some time." << endl;
214            this->setPhysicalWorld(false);
215            this->positiveWorldRange_ = range;
216            this->setPhysicalWorld(true);
217        }
218        else
219            this->positiveWorldRange_ = range;
220    }
221
222    void Scene::setGravity(const Vector3& gravity)
223    {
224        this->gravity_ = gravity;
225        if (this->hasPhysics())
226            this->physicalWorld_->setGravity(multi_cast<btVector3>(this->gravity_));
227    }
228
229    void Scene::setPhysicalWorld(bool wantPhysics)
230    {
231        this->bHasPhysics_ = wantPhysics;
232        if (wantPhysics && !hasPhysics())
233        {
234            // Note: These are all little known default classes and values.
235            //       It would require further investigation to properly dertermine the right choices.
236            this->broadphase_      = new bt32BitAxisSweep3(
237                multi_cast<btVector3>(this->negativeWorldRange_), multi_cast<btVector3>(this->positiveWorldRange_));
238            this->collisionConfig_ = new btDefaultCollisionConfiguration();
239            this->dispatcher_      = new btCollisionDispatcher(this->collisionConfig_);
240            this->solver_          = new btSequentialImpulseConstraintSolver();
241
242            this->physicalWorld_   = new btDiscreteDynamicsWorld(this->dispatcher_, this->broadphase_, this->solver_, this->collisionConfig_);
243            this->physicalWorld_->setGravity(multi_cast<btVector3>(this->gravity_));
244
245            if (GameMode::showsGraphics() && this->sceneManager_)
246            {
247                this->debugDrawer_ = new BulletDebugDrawer(this->sceneManager_);
248                this->physicalWorld_->setDebugDrawer(this->debugDrawer_);
249            }
250
251            // also set the collision callback variable.
252            // Note: This is a global variable which we assign a static function.
253            // TODO: Check whether this (or anything about Bullet) works with multiple physics engine instances.
254            gContactAddedCallback = &Scene::collisionCallback;
255        }
256        else if (!wantPhysics && hasPhysics())
257        {
258            // Remove all WorldEntities and shove them to the queue since they would still like to be in a physical world.
259            for (WorldEntity* object : this->physicalObjects_)
260            {
261                this->physicalWorld_->removeRigidBody(object->physicalBody_);
262                this->physicalObjectQueue_.insert(object);
263            }
264            this->physicalObjects_.clear();
265
266            delete this->debugDrawer_;
267            delete this->physicalWorld_;
268            delete this->solver_;
269            delete this->dispatcher_;
270            delete this->collisionConfig_;
271            delete this->broadphase_;
272            this->physicalWorld_   = nullptr;
273            this->solver_          = nullptr;
274            this->dispatcher_      = nullptr;
275            this->collisionConfig_ = nullptr;
276            this->broadphase_      = nullptr;
277        }
278    }
279
280    void Scene::tick(float dt)
281    {
282        if (!GameMode::showsGraphics())
283        {
284            // We need to update the scene nodes if we don't render
285            this->rootSceneNode_->_update(true, false);
286        }
287        if (this->hasPhysics())
288        {
289            // TODO: This here is bad practice! It will slow down the first tick() by ages.
290            //       Rather have an initialise() method as well, called by the Level after everything has been loaded.
291            if (this->physicalObjectQueue_.size() > 0)
292            {
293                // Add all scheduled WorldEntities
294                for (WorldEntity* object : this->physicalObjectQueue_)
295                {
296                    this->physicalWorld_->addRigidBody(object->physicalBody_);
297                    this->physicalObjects_.insert(object);
298                }
299                this->physicalObjectQueue_.clear();
300            }
301
302            // Note: 60 means that Bullet will do physics correctly down to 1 frames per seconds.
303            //       Under that mark, the simulation will "loose time" and get unusable.
304            this->bIsUpdatingPhysics_ = true;
305            this->physicalWorld_->stepSimulation(dt, 60);
306            this->bIsUpdatingPhysics_ = false;
307
308            if (this->bDebugDrawPhysics_)
309                this->physicalWorld_->debugDrawWorld();
310        }
311    }
312
313    void Scene::setSkybox(const std::string& skybox)
314    {
315        try
316        {
317            if (GameMode::showsGraphics() && this->sceneManager_)
318                this->sceneManager_->setSkyBox(true, skybox);
319        }
320        catch (const Ogre::Exception&)
321        {
322            orxout(internal_error) << "Could not load skybox '" << skybox << "':" << endl;
323            orxout(internal_error) << Exception::handleMessage() << endl;
324        }
325
326        this->skybox_ = skybox;
327    }
328
329    void Scene::setAmbientLight(const ColourValue& colour)
330    {
331        if (GameMode::showsGraphics() && this->sceneManager_)
332            this->sceneManager_->setAmbientLight(colour);
333
334        this->ambientLight_ = colour;
335    }
336
337    void Scene::setShadow(bool bShadow)
338    {
339        if (GameMode::showsGraphics() && this->sceneManager_)
340        {
341            if (bShadow)
342                this->sceneManager_->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
343            else
344                this->sceneManager_->setShadowTechnique(Ogre::SHADOWTYPE_NONE);
345        }
346
347        this->bShadows_ = bShadow;
348    }
349
350    void Scene::addObject(BaseObject* object)
351    {
352        this->objects_.push_back(object);
353    }
354
355    BaseObject* Scene::getObject(unsigned int index) const
356    {
357        unsigned int i = 0;
358        for (BaseObject* object : this->objects_)
359        {
360            if (i == index)
361                return object;
362            ++i;
363        }
364        return nullptr;
365    }
366
367    void Scene::addPhysicalObject(WorldEntity* object)
368    {
369        if (object)
370        {
371            std::set<WorldEntity*>::iterator it = this->physicalObjects_.find(object);
372            if (it != this->physicalObjects_.end())
373                return;
374
375            this->physicalObjectQueue_.insert(object);
376        }
377    }
378
379    void Scene::removePhysicalObject(WorldEntity* object)
380    {
381        // check queue first
382        std::set<WorldEntity*>::iterator it = this->physicalObjectQueue_.find(object);
383        if (it != this->physicalObjectQueue_.end())
384        {
385            this->physicalObjectQueue_.erase(it);
386            return;
387        }
388
389        it = this->physicalObjects_.find(object);
390        if (it == this->physicalObjects_.end())
391            return;
392        this->physicalObjects_.erase(it);
393
394        if (this->hasPhysics())
395            this->physicalWorld_->removeRigidBody(object->physicalBody_);
396    }
397
398    /*static*/ bool Scene::collisionCallback(btManifoldPoint& cp, const btCollisionObject* colObj0, int partId0,
399                                             int index0, const btCollisionObject* colObj1, int partId1, int index1)
400    {
401        // get the WorldEntity pointers
402        StrongPtr<WorldEntity> object0 = static_cast<WorldEntity*>(colObj0->getUserPointer());
403        StrongPtr<WorldEntity> object1 = static_cast<WorldEntity*>(colObj1->getUserPointer());
404
405        // get the CollisionShape pointers
406        const btCollisionShape* cs0 = colObj0->getCollisionShape();
407        const btCollisionShape* cs1 = colObj1->getCollisionShape();
408
409        // false means that bullet will assume we didn't modify the contact
410        bool modified = false;
411        if (object0->isCollisionCallbackActive())
412            modified |= object0->collidesAgainst(object1, cs1, cp);
413        if (object1->isCollisionCallbackActive())
414            modified |= object1->collidesAgainst(object0, cs0, cp);
415
416        return modified;
417    }
418
419    void Scene::setDebugDrawPhysics(bool bDraw, bool bFill, float fillAlpha)
420    {
421        this->bDebugDrawPhysics_ = bDraw;
422        if (this->debugDrawer_)
423            this->debugDrawer_->configure(bFill, fillAlpha);
424    }
425
426    /*static*/ void Scene::consoleCommand_debugDrawPhysics(bool bDraw, bool bFill, float fillAlpha)
427    {
428        for (Scene* scene : ObjectList<Scene>())
429            scene->setDebugDrawPhysics(bDraw, bFill, fillAlpha);
430    }
431}
Note: See TracBrowser for help on using the repository browser.