Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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