Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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