Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1024 was 1024, checked in by rgrieder, 16 years ago

merged input back into trunk
note: I have created an asylum with obsolete code, please check the files

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#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    // use the ogre timer class to measure time.
351    if (!timer_)
352      timer_ = new Ogre::Timer();
353    timer_->reset();
354
355    // Contains the times of recently fired events
356    std::deque<unsigned long> eventTimes[3];
357    // Clear event times
358    for (int i = 0; i < 3; ++i)
359      eventTimes[i].clear();
360
361          while (!bAbort_)
362          {
363                  // Pump messages in all registered RenderWindows
364      Ogre::WindowEventUtilities::messagePump();
365
366      // get current time
367      unsigned long now = timer_->getMilliseconds();
368
369      // create an event to pass to the frameStarted method in ogre
370      Ogre::FrameEvent evt;
371      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
372      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[1]);
373
374      // show the current time in the HUD
375      orxonoxHUD_->setTime((int)now, 0);
376
377      // Iterate through all Tickables and call their tick(dt) function
378      for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; )
379        (it++)->tick((float)evt.timeSinceLastFrame);
380
381      // don't forget to call _fireFrameStarted in ogre to make sure
382      // everything goes smoothly
383      ogre_->frameStarted(evt);
384
385      if (mode_ != SERVER)
386        ogre_->renderOneFrame(); // only render in non-server mode
387
388      // get current time
389      now = timer_->getMilliseconds();
390
391      // create an event to pass to the frameEnded method in ogre
392      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
393      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[2]);
394
395      // again, just to be sure ogre works fine
396      ogre_->frameEnded(evt);
397          }
398  }
399
400  /**
401    Method for calculating the average time between recently fired events.
402    Code directly taken from OgreRoot.cc
403    @param now The current time in ms.
404    @param type The type of event to be considered.
405  */
406  float Orxonox::calculateEventTime(unsigned long now, std::deque<unsigned long> &times)
407  {
408    // Calculate the average time passed between events of the given type
409    // during the last mFrameSmoothingTime seconds.
410
411    times.push_back(now);
412
413    if(times.size() == 1)
414      return 0;
415
416    // Times up to mFrameSmoothingTime seconds old should be kept
417    unsigned long discardThreshold =
418      static_cast<unsigned long>(frameSmoothingTime_ * 1000.0f);
419
420    // Find the oldest time to keep
421    std::deque<unsigned long>::iterator it = times.begin(),
422      end = times.end()-2; // We need at least two times
423    while(it != end)
424    {
425      if (now - *it > discardThreshold)
426        ++it;
427      else
428        break;
429    }
430
431    // Remove old times
432    times.erase(times.begin(), it);
433
434    return (float)(times.back() - times.front()) / ((times.size()-1) * 1000);
435  }
436
437  /**
438    @brief Test method for the InputHandler.
439    But: Is actually responsible for catching an exit event..
440  */
441  void Orxonox::eventOccured(InputEvent &evt)
442  {
443    if (evt.id == 1)
444      this->abortRequest();
445  }
446}
Note: See TracBrowser for help on using the repository browser.