Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/script/src/orxonox/Orxonox.cc @ 1019

Last change on this file since 1019 was 934, checked in by rgrieder, 17 years ago
  • added debug output to the InputHandler
  • fixed singleton issues
  • cleaned up Main.cc (replaced WinMain by main)
File size: 11.7 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    client_g->establishConnection();
265    client_g->tick(0);
266   
267   
268    //setupInputSystem();
269   
270    startRenderLoop();
271  }
272 
273  void Orxonox::serverStart(){
274    //TODO: start modules
275    ogre_->initialise();
276    //TODO: run engine
277    Factory::createClassHierarchy();
278    createScene();
279    setupInputSystem();
280   
281    server_g->open();
282   
283    startRenderLoop();
284  }
285 
286  void Orxonox::standaloneStart(){
287    //TODO: start modules
288    ogre_->initialise();
289    //TODO: run engine
290    Factory::createClassHierarchy();
291    createScene();
292    setupInputSystem();
293   
294    startRenderLoop();
295  }
296
297  void Orxonox::createScene(void)
298  {
299          // Init audio
300    auMan_ = new audio::AudioManager();
301
302    bulletMgr_ = new BulletManager();
303
304    // load this file from config
305    Level* startlevel = new Level("levels/sample.oxw");
306    Loader::open(startlevel);
307
308    Ogre::Overlay* hudOverlay = Ogre::OverlayManager::getSingleton().getByName("Orxonox/HUD1.2");
309    orxonoxHUD_ = new HUD();
310    orxonoxHUD_->setEnergyValue(20);
311    orxonoxHUD_->setEnergyDistr(20,20,60);
312    hudOverlay->show();
313
314        /*
315    auMan_->ambientAdd("a1");
316    auMan_->ambientAdd("a2");
317    auMan_->ambientAdd("a3");
318    //auMan->ambientAdd("ambient1");
319    auMan_->ambientStart();
320  */
321  }
322
323  /**
324    @brief Calls the InputHandler which sets up the input devices.
325    The render window width and height are used to set up the mouse movement.
326  */
327  void Orxonox::setupInputSystem()
328  {
329    inputHandler_ = InputHandler::getSingleton();
330    if (!inputHandler_->initialise(ogre_->getWindowHandle(),
331          ogre_->getWindowWidth(), ogre_->getWindowHeight()))
332      abortImmediate();
333  }
334
335  /**
336    Main loop of the orxonox game.
337    This is a new solution, using the ogre engine instead of being used by it.
338    An alternative solution would be to simply use the timer of the Root object,
339    but that implies using Ogre in any case. There would be no way to test
340    our code without the help of the root object.
341    There's even a chance that we can dispose of the root object entirely
342    in server mode.
343    About the loop: The design is almost exactly like the one in ogre, so that
344    if any part of ogre registers a framelisteners, it will still behave
345    correctly. Furthermore I have taken over the time smoothing feature from
346    ogre. If turned on (see orxonox constructor), it will calculate the dt_n by
347    means of the recent most dt_n-1, dt_n-2, etc.
348  */
349  void Orxonox::startRenderLoop()
350  {
351    // use the ogre timer class to measure time.
352    if (!timer_)
353      timer_ = new Ogre::Timer();
354    timer_->reset();
355
356    // Contains the times of recently fired events
357    std::deque<unsigned long> eventTimes[3];
358    // Clear event times
359    for (int i = 0; i < 3; ++i)
360      eventTimes[i].clear();
361
362          while (!bAbort_)
363          {
364                  // Pump messages in all registered RenderWindows
365      Ogre::WindowEventUtilities::messagePump();
366
367      // get current time
368      unsigned long now = timer_->getMilliseconds();
369
370      // create an event to pass to the frameStarted method in ogre
371      Ogre::FrameEvent evt;
372      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
373      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[1]);
374
375      // show the current time in the HUD
376      orxonoxHUD_->setTime((int)now, 0);
377
378      // Iterate through all Tickables and call their tick(dt) function
379      for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; )
380        (it++)->tick((float)evt.timeSinceLastFrame);
381
382      // don't forget to call _fireFrameStarted in ogre to make sure
383      // everything goes smoothly
384      ogre_->frameStarted(evt);
385
386      if (mode_ != SERVER)
387        ogre_->renderOneFrame(); // only render in non-server mode
388
389      // get current time
390      now = timer_->getMilliseconds();
391
392      // create an event to pass to the frameEnded method in ogre
393      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
394      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[2]);
395
396      // again, just to be sure ogre works fine
397      ogre_->frameEnded(evt);
398          }
399  }
400
401  /**
402    Method for calculating the average time between recently fired events.
403    Code directly taken from OgreRoot.cc
404    @param now The current time in ms.
405    @param type The type of event to be considered.
406  */
407  float Orxonox::calculateEventTime(unsigned long now, std::deque<unsigned long> &times)
408  {
409    // Calculate the average time passed between events of the given type
410    // during the last mFrameSmoothingTime seconds.
411
412    times.push_back(now);
413
414    if(times.size() == 1)
415      return 0;
416
417    // Times up to mFrameSmoothingTime seconds old should be kept
418    unsigned long discardThreshold =
419      static_cast<unsigned long>(frameSmoothingTime_ * 1000.0f);
420
421    // Find the oldest time to keep
422    std::deque<unsigned long>::iterator it = times.begin(),
423      end = times.end()-2; // We need at least two times
424    while(it != end)
425    {
426      if (now - *it > discardThreshold)
427        ++it;
428      else
429        break;
430    }
431
432    // Remove old times
433    times.erase(times.begin(), it);
434
435    return (float)(times.back() - times.front()) / ((times.size()-1) * 1000);
436  }
437
438  /**
439    @brief Test method for the InputHandler.
440    But: Is actually responsible for catching an exit event..
441  */
442  void Orxonox::eventOccured(InputEvent &evt)
443  {
444    if (evt.id == 1)
445      this->abortRequest();
446  }
447}
Note: See TracBrowser for help on using the repository browser.