Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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