Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/input/src/orxonox/Orxonox.cc @ 916

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