Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1088 was 1088, checked in by dumenim, 16 years ago

catched some return values

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    @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    InputHandler::destroy();
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    //static Orxonox theOnlyInstance;
150    //return &theOnlyInstance;
151  }
152
153  /**
154    @brief Destroys the Orxonox singleton.
155  */
156  void Orxonox::destroy()
157  {
158    if (singletonRef_s)
159      delete singletonRef_s;
160    singletonRef_s = 0;
161  }
162
163  /**
164   * initialization of Orxonox object
165   * @param argc argument counter
166   * @param argv list of argumenst
167   * @param path path to config (in home dir or something)
168   */
169  void Orxonox::init(int argc, char **argv, std::string path)
170  {
171    //TODO: find config file (assuming executable directory)
172    //TODO: read config file
173    //TODO: give config file to Ogre
174    std::string mode;
175
176    ArgReader ar = ArgReader(argc, argv);
177    ar.checkArgument("mode", mode, false);
178    ar.checkArgument("data", this->dataPath_, false);
179    ar.checkArgument("ip", serverIp_, false);
180    if(ar.errorHandling()) abortImmediate();
181    if(mode == std::string("client"))
182    {
183      mode_ = CLIENT;
184      clientInit(path);
185    }
186    else if(mode== std::string("server")){
187      mode_ = SERVER;
188      serverInit(path);
189    }
190    else{
191      mode_ = STANDALONE;
192      standaloneInit(path);
193    }
194  }
195
196  void Orxonox::serverInit(std::string path)
197  {
198    COUT(2) << "initialising server" << std::endl;
199   
200    ogre_->setConfigPath(path);
201    ogre_->setup();
202    //root_ = ogre_->getRoot();
203    if(!ogre_->load(this->dataPath_)) abortImmediate(/* unable to load */);
204   
205    server_g = new network::Server();
206  }
207
208  void Orxonox::clientInit(std::string path)
209  {
210    COUT(2) << "initialising client" << std::endl;\
211   
212    ogre_->setConfigPath(path);
213    ogre_->setup();
214    if(serverIp_.compare("")==0)
215      client_g = new network::Client();
216    else
217      client_g = new network::Client(serverIp_, NETWORK_PORT);
218    if(!ogre_->load(this->dataPath_)) abortImmediate(/* unable to load */);
219  }
220 
221  void Orxonox::standaloneInit(std::string path)
222  {
223    COUT(2) << "initialising standalone mode" << std::endl;
224   
225    ogre_->setConfigPath(path);
226    ogre_->setup();
227    //root_ = ogre_->getRoot();
228    if(!ogre_->load(this->dataPath_)) abortImmediate(/* unable to load */);
229  }
230 
231  /**
232   * start modules
233   */
234  void Orxonox::start()
235  {
236    switch(mode_){
237    case CLIENT:
238      clientStart();
239      break;
240    case SERVER:
241      serverStart();
242      break;
243    default:
244      standaloneStart();
245    }
246  }
247 
248  void Orxonox::clientStart(){
249    ogre_->initialise();
250    Factory::createClassHierarchy();
251   
252   
253    auMan_ = new audio::AudioManager();
254
255    bulletMgr_ = new BulletManager();
256   
257    Ogre::Overlay* hudOverlay = Ogre::OverlayManager::getSingleton().getByName("Orxonox/HUD1.2");
258    HUD* orxonoxHud;
259    orxonoxHud = new HUD();
260    orxonoxHud->setEnergyValue(20);
261    orxonoxHud->setEnergyDistr(20,20,60);
262    hudOverlay->show();
263   
264    if( !client_g->establishConnection() )
265      COUT(1) <<"CLIENT COULD NOT ESTABLISH CONNECTION" << std::endl;
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_ = InputHandler::getSingleton();
331    if (!inputHandler_->initialise(ogre_->getWindowHandle(),
332          ogre_->getWindowWidth(), ogre_->getWindowHeight()))
333      abortImmediate();
334  }
335
336  /**
337    Main loop of the orxonox game.
338    This is a new solution, using the ogre engine instead of being used by it.
339    An alternative solution would be to simply use the timer of the Root object,
340    but that implies using Ogre in any case. There would be no way to test
341    our code without the help of the root object.
342    There's even a chance that we can dispose of the root object entirely
343    in server mode.
344    About the loop: The design is almost exactly like the one in ogre, so that
345    if any part of ogre registers a framelisteners, it will still behave
346    correctly. Furthermore I have taken over the time smoothing feature from
347    ogre. If turned on (see orxonox constructor), it will calculate the dt_n by
348    means of the recent most dt_n-1, dt_n-2, etc.
349  */
350  void Orxonox::startRenderLoop()
351  {
352    // use the ogre timer class to measure time.
353    if (!timer_)
354      timer_ = new Ogre::Timer();
355    timer_->reset();
356
357    // Contains the times of recently fired events
358    std::deque<unsigned long> eventTimes[3];
359    // Clear event times
360    for (int i = 0; i < 3; ++i)
361      eventTimes[i].clear();
362
363          while (!bAbort_)
364          {
365                  // Pump messages in all registered RenderWindows
366      Ogre::WindowEventUtilities::messagePump();
367
368      // get current time
369      unsigned long now = timer_->getMilliseconds();
370
371      // create an event to pass to the frameStarted method in ogre
372      Ogre::FrameEvent evt;
373      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
374      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[1]);
375
376      // show the current time in the HUD
377      //orxonoxHUD_->setTime((int)now, 0);
378
379      // Iterate through all Tickables and call their tick(dt) function
380      for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; )
381        (it++)->tick((float)evt.timeSinceLastFrame);
382
383      // don't forget to call _fireFrameStarted in ogre to make sure
384      // everything goes smoothly
385      ogre_->frameStarted(evt);
386
387      //if (mode_ != SERVER)
388        ogre_->renderOneFrame(); // only render in non-server mode
389
390      // get current time
391      now = timer_->getMilliseconds();
392
393      // create an event to pass to the frameEnded method in ogre
394      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
395      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[2]);
396
397      // again, just to be sure ogre works fine
398      ogre_->frameEnded(evt);
399          }
400  }
401
402  /**
403    Method for calculating the average time between recently fired events.
404    Code directly taken from OgreRoot.cc
405    @param now The current time in ms.
406    @param type The type of event to be considered.
407  */
408  float Orxonox::calculateEventTime(unsigned long now, std::deque<unsigned long> &times)
409  {
410    // Calculate the average time passed between events of the given type
411    // during the last mFrameSmoothingTime seconds.
412
413    times.push_back(now);
414
415    if(times.size() == 1)
416      return 0;
417
418    // Times up to mFrameSmoothingTime seconds old should be kept
419    unsigned long discardThreshold =
420      static_cast<unsigned long>(frameSmoothingTime_ * 1000.0f);
421
422    // Find the oldest time to keep
423    std::deque<unsigned long>::iterator it = times.begin(),
424      end = times.end()-2; // We need at least two times
425    while(it != end)
426    {
427      if (now - *it > discardThreshold)
428        ++it;
429      else
430        break;
431    }
432
433    // Remove old times
434    times.erase(times.begin(), it);
435
436    return (float)(times.back() - times.front()) / ((times.size()-1) * 1000);
437  }
438
439  /**
440    @brief Test method for the InputHandler.
441    But: Is actually responsible for catching an exit event..
442  */
443  void Orxonox::eventOccured(InputEvent &evt)
444  {
445    if (evt.id == 1)
446      this->abortRequest();
447  }
448}
Note: See TracBrowser for help on using the repository browser.