Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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