Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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