Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/Orxonox.cc @ 1037

Last change on this file since 1037 was 1035, checked in by rgrieder, 17 years ago
  • minor Singleton changes
File size: 12.6 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *
4 *
5 *   License notice:
6 *
7 *   This program is free software; you can redistribute it and/or
8 *   modify it under the terms of the GNU General Public License
9 *   as published by the Free Software Foundation; either version 2
10 *   of the License, or (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with this program; if not, write to the Free Software
19 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 *
21 *   Author:
22 *      Benjamin Knecht <beni_at_orxonox.net>, (C) 2007
23 *   Co-authors:
24 *      ...
25 *
26 */
27
28/**
29 @file
30 @brief Orxonox Main Class
31 */
32
33// Precompiled Headers
34#include "OrxonoxStableHeaders.h"
35
36//****** STD *******
37//#include <iostream>
38//#include <exception>
39#include <deque>
40
41//****** OGRE ******
42//#include <OgreException.h>
43#include <OgreFrameListener.h>
44#include <OgreOverlay.h>
45#include <OgreOverlayManager.h>
46#include <OgreRoot.h>
47#include <OgreTimer.h>
48#include <OgreWindowEventUtilities.h>
49
50//***** ORXONOX ****
51// util
52//#include "util/Sleep.h"
53#include "util/ArgReader.h"
54
55// core
56#include "core/Debug.h"
57#include "core/Factory.h"
58#include "core/Loader.h"
59#include "core/Tickable.h"
60#include "core/InputManager.h"
61
62// audio
63#include "audio/AudioManager.h"
64
65// network
66#include "network/Server.h"
67#include "network/Client.h"
68
69// objects and tools
70#include "tools/Timer.h"
71#include "hud/HUD.h"
72//#include "objects/weapon/BulletManager.h"
73
74#include "Orxonox.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  /**
84    @brief Reference to the only instance of the class.
85  */
86  Orxonox *Orxonox::singletonRef_s = 0;
87
88  /**
89   * create a new instance of Orxonox
90   */
91  Orxonox::Orxonox()
92  {
93    this->ogre_ = &GraphicsEngine::getSingleton();
94    this->timer_ = 0;
95    this->dataPath_ = "";
96    this->auMan_ = 0;
97    this->inputHandler_ = 0;
98    //this->root_ = 0;
99    // turn on frame smoothing by setting a value different from 0
100    this->frameSmoothingTime_ = 0.0f;
101    this->bAbort_ = false;
102  }
103
104  /**
105   * destruct Orxonox
106   */
107  Orxonox::~Orxonox()
108  {
109    // keep in mind: the order of deletion is very important!
110//    if (this->bulletMgr_)
111//      delete this->bulletMgr_;
112    if (this->orxonoxHUD_)
113      delete this->orxonoxHUD_;
114    Loader::close();
115    InputManager::getSingleton().destroy();
116    if (this->auMan_)
117      delete this->auMan_;
118    if (this->timer_)
119      delete this->timer_;
120    GraphicsEngine::getSingleton().destroy();
121
122    if (client_g)
123      delete client_g;
124    if (server_g)
125      delete server_g;
126  }
127
128  /**
129   * error kills orxonox
130   */
131  void Orxonox::abortImmediate(/* some error code */)
132  {
133    //TODO: destroy and destruct everything and print nice error msg
134    delete this;
135  }
136
137  /**
138    Asks the mainloop nicely to abort.
139  */
140  void Orxonox::abortRequest()
141  {
142    bAbort_ = true;
143  }
144
145  /**
146   * @return singleton object
147   */
148  Orxonox* Orxonox::getSingleton()
149  {
150    if (!singletonRef_s)
151      singletonRef_s = new Orxonox();
152    return singletonRef_s;
153  }
154
155  /**
156    @brief Destroys the Orxonox singleton.
157  */
158  void Orxonox::destroySingleton()
159  {
160    if (singletonRef_s)
161      delete singletonRef_s;
162    singletonRef_s = 0;
163  }
164
165  /**
166   * initialization of Orxonox object
167   * @param argc argument counter
168   * @param argv list of argumenst
169   * @param path path to config (in home dir or something)
170   */
171  void Orxonox::init(int argc, char **argv, std::string path)
172  {
173    //TODO: find config file (assuming executable directory)
174    //TODO: read config file
175    //TODO: give config file to Ogre
176    std::string mode;
177
178    ArgReader ar(argc, argv);
179    ar.checkArgument("mode", mode, false);
180    ar.checkArgument("data", this->dataPath_, false);
181    ar.checkArgument("ip", serverIp_, false);
182    if(ar.errorHandling()) abortImmediate();
183    if(mode == std::string("client"))
184    {
185      mode_ = CLIENT;
186      clientInit(path);
187    }
188    else if(mode== std::string("server")){
189      mode_ = SERVER;
190      serverInit(path);
191    }
192    else{
193      mode_ = STANDALONE;
194      standaloneInit(path);
195    }
196  }
197
198  void Orxonox::serverInit(std::string path)
199  {
200    COUT(2) << "initialising server" << std::endl;
201   
202    ogre_->setConfigPath(path);
203    ogre_->setup();
204    //root_ = ogre_->getRoot();
205    if(!ogre_->load(this->dataPath_)) abortImmediate(/* unable to load */);
206   
207    server_g = new network::Server();
208  }
209
210  void Orxonox::clientInit(std::string path)
211  {
212    COUT(2) << "initialising client" << std::endl;\
213   
214    ogre_->setConfigPath(path);
215    ogre_->setup();
216    if(serverIp_.compare("")==0)
217      client_g = new network::Client();
218    else
219      client_g = new network::Client(serverIp_, NETWORK_PORT);
220    if(!ogre_->load(this->dataPath_)) abortImmediate(/* unable to load */);
221  }
222 
223  void Orxonox::standaloneInit(std::string path)
224  {
225    COUT(2) << "initialising standalone mode" << std::endl;
226   
227    ogre_->setConfigPath(path);
228    ogre_->setup();
229    //root_ = ogre_->getRoot();
230    if(!ogre_->load(this->dataPath_)) abortImmediate(/* unable to load */);
231  }
232 
233  /**
234   * start modules
235   */
236  void Orxonox::start()
237  {
238    switch(mode_){
239    case CLIENT:
240      clientStart();
241      break;
242    case SERVER:
243      serverStart();
244      break;
245    default:
246      standaloneStart();
247    }
248  }
249 
250  void Orxonox::clientStart(){
251    ogre_->initialise();
252    Factory::createClassHierarchy();
253   
254   
255    auMan_ = new audio::AudioManager();
256
257    //bulletMgr_ = new BulletManager();
258   
259    Ogre::Overlay* hudOverlay = Ogre::OverlayManager::getSingleton().getByName("Orxonox/HUD1.2");
260    HUD* orxonoxHud;
261    orxonoxHud = new HUD();
262    orxonoxHud->setEnergyValue(20);
263    orxonoxHud->setEnergyDistr(20,20,60);
264    hudOverlay->show();
265   
266    client_g->establishConnection();
267    client_g->tick(0);
268   
269   
270    //setupInputSystem();
271   
272    startRenderLoop();
273  }
274 
275  void Orxonox::serverStart(){
276    //TODO: start modules
277    ogre_->initialise();
278    //TODO: run engine
279    Factory::createClassHierarchy();
280    createScene();
281    setupInputSystem();
282   
283    server_g->open();
284   
285    startRenderLoop();
286  }
287 
288  void Orxonox::standaloneStart(){
289    //TODO: start modules
290    ogre_->initialise();
291    //TODO: run engine
292    Factory::createClassHierarchy();
293    createScene();
294    setupInputSystem();
295   
296    startRenderLoop();
297  }
298
299  void Orxonox::createScene(void)
300  {
301          // Init audio
302    auMan_ = new audio::AudioManager();
303
304    //bulletMgr_ = new BulletManager();
305
306    // load this file from config
307    Level* startlevel = new Level("levels/sample.oxw");
308    Loader::open(startlevel);
309
310    Ogre::Overlay* hudOverlay = Ogre::OverlayManager::getSingleton().getByName("Orxonox/HUD1.2");
311    orxonoxHUD_ = new HUD();
312    orxonoxHUD_->setEnergyValue(20);
313    orxonoxHUD_->setEnergyDistr(20,20,60);
314    hudOverlay->show();
315
316        /*
317    auMan_->ambientAdd("a1");
318    auMan_->ambientAdd("a2");
319    auMan_->ambientAdd("a3");
320    //auMan->ambientAdd("ambient1");
321    auMan_->ambientStart();
322  */
323  }
324
325  /**
326    @brief Calls the InputHandler which sets up the input devices.
327    The render window width and height are used to set up the mouse movement.
328  */
329  void Orxonox::setupInputSystem()
330  {
331    inputHandler_ = &InputManager::getSingleton();
332    if (!inputHandler_->initialise(ogre_->getWindowHandle(),
333          ogre_->getWindowWidth(), ogre_->getWindowHeight()))
334      abortImmediate();
335    inputHandler_->setInputMode(IM_INGAME);
336  }
337
338  /**
339    Main loop of the orxonox game.
340    This is a new solution, using the ogre engine instead of being used by it.
341    An alternative solution would be to simply use the timer of the Root object,
342    but that implies using Ogre in any case. There would be no way to test
343    our code without the help of the root object.
344    There's even a chance that we can dispose of the root object entirely
345    in server mode.
346    About the loop: The design is almost exactly like the one in ogre, so that
347    if any part of ogre registers a framelisteners, it will still behave
348    correctly. Furthermore the time smoothing feature from ogre has been
349    implemented too. If turned on (see orxonox constructor), it will calculate
350    the dt_n by means of the recent most dt_n-1, dt_n-2, etc.
351  */
352  void Orxonox::startRenderLoop()
353  {
354    // first check whether ogre root object has been created
355    if (Ogre::Root::getSingletonPtr() == 0)
356    {
357      COUT(2) << "Error: Could not start rendering. No Ogre root object found" << std::endl;
358      return;
359    }
360
361    // Contains the times of recently fired events
362    // eventTimes[4] is the list for the times required for the fps counter
363    std::deque<unsigned long> eventTimes[4];
364    // Clear event times
365    for (int i = 0; i < 4; ++i)
366      eventTimes[i].clear();
367    // fill the fps time list with zeros
368    for (int i = 0; i < 20; i++)
369      eventTimes[3].push_back(0);
370
371    // use the ogre timer class to measure time.
372    if (!timer_)
373      timer_ = new Ogre::Timer();
374    timer_->reset();
375
376          while (!bAbort_)
377          {
378                  // Pump messages in all registered RenderWindows
379      Ogre::WindowEventUtilities::messagePump();
380
381      // get current time
382      unsigned long now = timer_->getMilliseconds();
383      eventTimes[3].push_back(now);
384      eventTimes[3].erase(eventTimes[3].begin());
385
386      // create an event to pass to the frameStarted method in ogre
387      Ogre::FrameEvent evt;
388      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
389      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[1]);
390
391      // show the current time in the HUD
392      orxonoxHUD_->setTime((int)now, 0);
393      if (eventTimes[3].back() - eventTimes[3].front() != 0)
394        orxonoxHUD_->setRocket1((int)(20000.0f/(eventTimes[3].back() - eventTimes[3].front())));
395
396      // Iterate through all Tickables and call their tick(dt) function
397      for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; )
398        (it++)->tick((float)evt.timeSinceLastFrame);
399
400      // don't forget to call _fireFrameStarted in ogre to make sure
401      // everything goes smoothly
402      Ogre::Root::getSingleton()._fireFrameStarted(evt);
403
404      // server still renders at the moment
405      //if (mode_ != SERVER)
406      Ogre::Root::getSingleton()._updateAllRenderTargets(); // only render in non-server mode
407
408      // get current time
409      now = timer_->getMilliseconds();
410
411      // create an event to pass to the frameEnded method in ogre
412      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
413      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[2]);
414
415      // again, just to be sure ogre works fine
416      Ogre::Root::getSingleton()._fireFrameEnded(evt);
417          }
418  }
419
420  /**
421    Method for calculating the average time between recently fired events.
422    Code directly taken from OgreRoot.cc
423    @param now The current time in ms.
424    @param type The type of event to be considered.
425  */
426  float Orxonox::calculateEventTime(unsigned long now, std::deque<unsigned long> &times)
427  {
428    // Calculate the average time passed between events of the given type
429    // during the last frameSmoothingTime_ seconds.
430
431    times.push_back(now);
432
433    if(times.size() == 1)
434      return 0;
435
436    // Times up to frameSmoothingTime_ seconds old should be kept
437    unsigned long discardThreshold = (unsigned long)frameSmoothingTime_ * 1000.0f;
438
439    // Find the oldest time to keep
440    std::deque<unsigned long>::iterator it  = times.begin();
441    // We need at least two times
442    std::deque<unsigned long>::iterator end = times.end() - 2;
443
444    while(it != end)
445    {
446      if (now - *it > discardThreshold)
447        ++it;
448      else
449        break;
450    }
451
452    // Remove old times
453    times.erase(times.begin(), it);
454
455    return (float)(times.back() - times.front()) / ((times.size() - 1) * 1000);
456  }
457
458  /**
459    @brief Test method for the InputHandler.
460    But: Is actually responsible for catching an exit event..
461  */
462  void Orxonox::eventOccured(InputEvent &evt)
463  {
464    if (evt.id == 1)
465      this->abortRequest();
466  }
467}
Note: See TracBrowser for help on using the repository browser.