Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/orxonox/Orxonox.cc @ 1481

Last change on this file since 1481 was 1466, checked in by janise, 17 years ago

compositors and shader work with hacks. added a directional light

File size: 13.2 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 *      Benjamin Knecht <beni_at_orxonox.net>, (C) 2007
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30 @file
31 @brief Orxonox Main Class
32 */
33
34// Precompiled Headers
35#include "OrxonoxStableHeaders.h"
36#include "Orxonox.h"
37
38//****** STD *******
39#include <deque>
40
41//****** OGRE ******
42#include <OgreFrameListener.h>
43#include <OgreOverlay.h>
44#include <OgreOverlayManager.h>
45#include <OgreRoot.h>
46#include <OgreTimer.h>
47#include <OgreWindowEventUtilities.h>
48
49//***** ORXONOX ****
50// util
51//#include "util/Sleep.h"
52#include "util/ArgReader.h"
53
54// core
55#include "core/ConfigFileManager.h"
56#include "core/ConsoleCommand.h"
57#include "core/Debug.h"
58#include "core/Loader.h"
59#include "core/Tickable.h"
60#include "core/InputManager.h"
61#include "core/TclBind.h"
62
63// audio
64#include "audio/AudioManager.h"
65
66// network
67#include "network/Server.h"
68#include "network/Client.h"
69
70// objects and tools
71#include "hud/HUD.h"
72#include <Ogre.h>
73
74#include "GraphicsEngine.h"
75
76// FIXME: is this really file scope?
77// globals for the server or client
78network::Client *client_g;
79network::Server *server_g;
80
81namespace orxonox
82{
83  SetConsoleCommandShortcut(Orxonox, exit).setKeybindMode(KeybindMode::OnPress);
84  SetConsoleCommandShortcut(Orxonox, slomo).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0).setAxisParamIndex(0).setIsAxisRelative(false);
85  SetConsoleCommandShortcut(Orxonox, setTimeFactor).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0);
86
87  /**
88    @brief Reference to the only instance of the class.
89  */
90  Orxonox *Orxonox::singletonRef_s = 0;
91
92  /**
93   * Create a new instance of Orxonox. Avoid doing any actual work here.
94   */
95  Orxonox::Orxonox() :
96    ogre_(0),
97    //auMan_(0),
98    timer_(0),
99    // turn on frame smoothing by setting a value different from 0
100    frameSmoothingTime_(0.0f),
101    orxonoxHUD_(0),
102    bAbort_(false),
103    timefactor_(1.0f),
104    mode_(STANDALONE),
105    serverIp_(""),
106    serverPort_(NETWORK_PORT)
107  {
108  }
109
110  /**
111   * Destruct Orxonox.
112   */
113  Orxonox::~Orxonox()
114  {
115    // keep in mind: the order of deletion is very important!
116//    if (this->orxonoxHUD_)
117//      delete this->orxonoxHUD_;
118    Loader::close();
119    InputManager::destroy();
120    //if (this->auMan_)
121    //  delete this->auMan_;
122    if (this->timer_)
123      delete this->timer_;
124    GraphicsEngine::getSingleton().destroy();
125
126    if (network::Client::getSingleton())
127      network::Client::destroySingleton();
128    if (server_g)
129      delete server_g;
130  }
131
132
133  /**
134    Asks the mainloop nicely to abort.
135  */
136  void Orxonox::abortRequest()
137  {
138    COUT(3) << "Orxonox: Abort requested." << std::endl;
139    bAbort_ = true;
140  }
141
142  /**
143   * @return singleton reference
144   */
145  Orxonox* Orxonox::getSingleton()
146  {
147    if (!singletonRef_s)
148      singletonRef_s = new Orxonox();
149    return singletonRef_s;
150  }
151
152  /**
153    @brief Destroys the Orxonox singleton.
154  */
155  void Orxonox::destroySingleton()
156  {
157    if (singletonRef_s)
158      delete singletonRef_s;
159    singletonRef_s = 0;
160  }
161
162  /**
163   * initialization of Orxonox object
164   * @param argc argument counter
165   * @param argv list of argumenst
166   * @param path path to config (in home dir or something)
167   */
168  bool Orxonox::init(int argc, char **argv, std::string path)
169  {
170    //TODO: find config file (assuming executable directory)
171    //TODO: read config file
172    //TODO: give config file to Ogre
173    std::string mode;
174    std::string dataPath;
175
176    ArgReader ar(argc, argv);
177    ar.checkArgument("mode", mode, false);
178    ar.checkArgument("data", dataPath, false);
179    ar.checkArgument("ip", serverIp_, false);
180    ar.checkArgument("port", serverPort_, false);
181    if(ar.errorHandling())
182      return false;
183
184    if (mode == "client")
185      mode_ = CLIENT;
186    else if (mode == "server")
187      mode_ = SERVER;
188    else
189    {
190      mode = "standalone";
191      mode_ = STANDALONE;
192    }
193    COUT(3) << "Orxonox: Mode is " << mode << "." << std::endl;
194
195    //if (mode_ == DEDICATED)
196      // TODO: decide what to do here
197    //else
198
199    // for playable server, client and standalone, the startup
200    // procedure until the GUI is identical
201
202    ConfigFileManager::getSingleton()->setFile(CFT_Settings, "orxonox.ini");
203    Factory::createClassHierarchy();
204
205    ogre_ = &GraphicsEngine::getSingleton();
206    if (!ogre_->setup(path))       // creates ogre root and other essentials
207      return false;
208
209    return true;
210  }
211
212  /**
213   * start modules
214   */
215  bool Orxonox::start()
216  {
217    //if (mode == DEDICATED)
218    // do something else
219    //else
220
221    if (!ogre_->loadRenderer())    // creates the render window
222      return false;
223
224    // Calls the InputManager which sets up the input devices.
225    // The render window width and height are used to set up the mouse movement.
226    if (!InputManager::initialise(ogre_->getWindowHandle(),
227          ogre_->getWindowWidth(), ogre_->getWindowHeight(), true, true, true))
228      return false;
229
230    // TODO: Spread this so that this call only initialises things needed for the GUI
231    if (!ogre_->initialiseResources())
232      return false;
233
234    // TOOD: load the GUI here
235    // set InputManager to GUI mode
236    InputManager::setInputState(InputManager::IS_GUI);
237    // TODO: run GUI here
238
239    // The following lines depend very much on the GUI output, so they're probably misplaced here..
240
241    InputManager::setInputState(InputManager::IS_NONE);
242
243    if (!loadPlayground())
244      return false;
245
246    switch (mode_)
247    {
248    case SERVER:
249      if (!serverLoad())
250        return false;
251      break;
252    case CLIENT:
253      if (!clientLoad())
254        return false;
255      break;
256    default:
257      if (!standaloneLoad())
258        return false;
259    }
260
261    InputManager::setInputState(InputManager::IS_NORMAL);
262
263    return startRenderLoop();
264  }
265
266  /**
267   * Loads everything in the scene except for the actual objects.
268   * This includes HUD, Console..
269   */
270  bool Orxonox::loadPlayground()
271  {
272    ogre_->createNewScene();
273
274          // Init audio
275    //auMan_ = new audio::AudioManager();
276    //auMan_->ambientAdd("a1");
277    //auMan_->ambientAdd("a2");
278    //auMan_->ambientAdd("a3");
279    //auMan->ambientAdd("ambient1");
280    //auMan_->ambientStart();
281
282    // Load the HUD
283    COUT(3) << "Orxonox: Loading HUD..." << std::endl;
284    orxonoxHUD_ = &HUD::getSingleton();
285    return true;
286  }
287
288  /**
289   * Level loading method for server mode.
290   */
291  bool Orxonox::serverLoad()
292  {
293    COUT(2) << "Loading level in server mode" << std::endl;
294
295    server_g = new network::Server(serverPort_);
296
297    if (!loadScene())
298      return false;
299
300    server_g->open();
301
302    return true;
303  }
304
305  /**
306   * Level loading method for client mode.
307   */
308  bool Orxonox::clientLoad()
309  {
310    COUT(2) << "Loading level in client mode" << std::endl;\
311
312    if (serverIp_.compare("") == 0)
313      client_g = network::Client::createSingleton();
314    else
315
316      client_g = network::Client::createSingleton(serverIp_, serverPort_);
317
318    if(!client_g->establishConnection())
319      return false;
320    client_g->tick(0);
321
322    return true;
323  }
324
325  /**
326   * Level loading method for standalone mode.
327   */
328  bool Orxonox::standaloneLoad()
329  {
330    COUT(2) << "Loading level in standalone mode" << std::endl;
331
332    if (!loadScene())
333      return false;
334
335    return true;
336  }
337
338  /**
339   * Helper method to load a level.
340   */
341  bool Orxonox::loadScene()
342  {
343    Level* startlevel = new Level("levels/sample.oxw");
344    Loader::open(startlevel);
345   
346
347    Ogre::SceneManager* mSceneMgr = GraphicsEngine::getSingleton().getSceneManager();
348    mSceneMgr->setAmbientLight(ColourValue(0.4,0.4,0.4));
349    Ogre::Light* dirlight = mSceneMgr->createLight("Light1");
350
351       dirlight->setType(Ogre::Light::LT_DIRECTIONAL);
352       dirlight->setDirection(Vector3( 0, 1, 5 ));
353       dirlight->setDiffuseColour(ColourValue(0.6, 0.6, 0.4));
354       dirlight->setSpecularColour(ColourValue(1.0, 1.0, 1.0));
355   
356    return true;
357  }
358
359
360  /**
361    Main loop of the orxonox game.
362    About the loop: The design is almost exactly like the one in ogre, so that
363    if any part of ogre registers a framelisteners, it will still behave
364    correctly. Furthermore the time smoothing feature from ogre has been
365    implemented too. If turned on (see orxonox constructor), it will calculate
366    the dt_n by means of the recent most dt_n-1, dt_n-2, etc.
367  */
368  bool Orxonox::startRenderLoop()
369  {
370    // first check whether ogre root object has been created
371    if (Ogre::Root::getSingletonPtr() == 0)
372    {
373      COUT(2) << "Orxonox Error: Could not start rendering. No Ogre root object found" << std::endl;
374      return false;
375    }
376    Ogre::Root& ogreRoot = Ogre::Root::getSingleton();
377
378
379    // Contains the times of recently fired events
380    // eventTimes[4] is the list for the times required for the fps counter
381    std::deque<unsigned long> eventTimes[3];
382    // Clear event times
383    for (int i = 0; i < 3; ++i)
384      eventTimes[i].clear();
385
386    // use the ogre timer class to measure time.
387    if (!timer_)
388      timer_ = new Ogre::Timer();
389    timer_->reset();
390
391    float renderTime = 0.0f;
392    float frameTime = 0.0f;
393    clock_t time = 0;
394
395    //Ogre::SceneManager* mSceneMgr = GraphicsEngine::getSingleton().getSceneManager();
396    //Ogre::Viewport* mViewport = mSceneMgr->getCurrentViewport();
397   
398    //Ogre::CompositorManager::getSingleton().addCompositor(mViewport, "Bloom");
399    //Ogre::CompositorManager::getSingleton().addCompositor(mViewport, "MotionBlur");
400
401    COUT(3) << "Orxonox: Starting the main loop." << std::endl;
402          while (!bAbort_)
403          {
404                  // Pump messages in all registered RenderWindows
405      // This calls the WindowEventListener objects.
406      Ogre::WindowEventUtilities::messagePump();
407
408      // get current time
409      unsigned long now = timer_->getMilliseconds();
410
411      // create an event to pass to the frameStarted method in ogre
412      Ogre::FrameEvent evt;
413      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
414      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[1]);
415      frameTime += evt.timeSinceLastFrame;
416
417      // show the current time in the HUD
418      // HUD::getSingleton().setTime(now);
419      if (frameTime > 0.4f)
420      {
421        HUD::getSingleton().setRenderTimeRatio(renderTime / frameTime);
422        frameTime = 0.0f;
423        renderTime = 0.0f;
424      }
425
426      // Call those objects that need the real time
427      for (Iterator<TickableReal> it = ObjectList<TickableReal>::start(); it; ++it)
428        it->tick((float)evt.timeSinceLastFrame);
429      // Call the scene objects
430      for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; ++it)
431        it->tick((float)evt.timeSinceLastFrame * this->timefactor_);
432
433      // don't forget to call _fireFrameStarted in ogre to make sure
434      // everything goes smoothly
435      ogreRoot._fireFrameStarted(evt);
436
437      // get current time
438      now = timer_->getMilliseconds();
439      calculateEventTime(now, eventTimes[2]);
440
441      ogreRoot._updateAllRenderTargets(); // only render in non-server mode
442
443      // get current time
444      now = timer_->getMilliseconds();
445
446      // create an event to pass to the frameEnded method in ogre
447      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
448      renderTime += calculateEventTime(now, eventTimes[2]);
449
450      // again, just to be sure ogre works fine
451      ogreRoot._fireFrameEnded(evt);
452          }
453
454    if (mode_==CLIENT)
455      network::Client::getSingleton()->closeConnection();
456    else if (mode_==SERVER)
457      server_g->close();
458
459    return true;
460  }
461
462  /**
463    Method for calculating the average time between recently fired events.
464    Code directly taken from OgreRoot.cc
465    @param now The current time in ms.
466    @param type The type of event to be considered.
467  */
468  float Orxonox::calculateEventTime(unsigned long now, std::deque<unsigned long> &times)
469  {
470    // Calculate the average time passed between events of the given type
471    // during the last frameSmoothingTime_ seconds.
472
473    times.push_back(now);
474
475    if(times.size() == 1)
476      return 0;
477
478    // Times up to frameSmoothingTime_ seconds old should be kept
479    unsigned long discardThreshold = (unsigned long)(frameSmoothingTime_ * 1000.0f);
480
481    // Find the oldest time to keep
482    std::deque<unsigned long>::iterator it  = times.begin();
483    // We need at least two times
484    std::deque<unsigned long>::iterator end = times.end() - 2;
485
486    while(it != end)
487    {
488      if (now - *it > discardThreshold)
489        ++it;
490      else
491        break;
492    }
493
494    // Remove old times
495    times.erase(times.begin(), it);
496
497    return (float)(times.back() - times.front()) / ((times.size() - 1) * 1000);
498  }
499}
Note: See TracBrowser for help on using the repository browser.