Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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