Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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