Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 920 was 919, checked in by rgrieder, 17 years ago
  • AudioManager is now Tickable
  • NPC update moved to its tick-function
  • corrected CMakeLists
  • added a few window properties to GraphicsEngine
  • OrxListener has been completely replaced
File size: 14.0 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"
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  void Orxonox::setupInputSystem()
377  {
378    inputHandler_ = InputHandler::getSingleton();
379    inputHandler_->initialise(ogre_->getWindowHandle(),
380          ogre_->getWindowWidth(), ogre_->getWindowHeight());
381
382    /*size_t windowHnd = 0;
383    std::ostringstream windowHndStr;
384    OIS::ParamList pl;
385
386    // fixes auto repeat problem
387    #if defined OIS_LINUX_PLATFORM
388      pl.insert(std::make_pair(std::string("XAutoRepeatOn"), std::string("true")));
389    #endif
390
391      Ogre::RenderWindow *win = ogre_->getRoot()->getAutoCreatedWindow();
392    win->getCustomAttribute("WINDOW", &windowHnd);
393    windowHndStr << windowHnd;
394    pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
395    inputManager_ = OIS::InputManager::createInputSystem(pl);
396
397    try
398    {
399      keyboard_ = static_cast<OIS::Keyboard*>(inputManager_->createInputObject(OIS::OISKeyboard, false));
400      mouse_ = static_cast<OIS::Mouse*>(inputManager_->createInputObject(OIS::OISMouse, true));
401    }
402    catch (const OIS::Exception &e)
403    {
404      throw new Ogre::Exception(42, e.eText, "OrxApplication::setupInputSystem");
405    }*/
406  }
407
408  /**
409    Main loop of the orxonox game.
410    This is a new solution, using the ogre engine instead of being used by it.
411    An alternative solution would be to simply use the timer of the Root object,
412    but that implies using Ogre in any case. There would be no way to test
413    our code without the help of the root object.
414    There's even a chance that we can dispose of the root object entirely
415    in server mode.
416    About the loop: The design is almost exactly like the one in ogre, so that
417    if any part of ogre registers a framelisteners, it will still behave
418    correctly. Furthermore I have taken over the time smoothing feature from
419    ogre. If turned on (see orxonox constructor), it will calculate the dt_n by
420    means of the recent most dt_n-1, dt_n-2, etc.
421  */
422  void Orxonox::startRenderLoop()
423  {
424    // use the ogre timer class to measure time.
425    Ogre::Timer *timer = new Ogre::Timer();
426    timer->reset();
427
428    // Contains the times of recently fired events
429    std::deque<unsigned long> eventTimes[3];
430    // Clear event times
431    for (int i = 0; i < 3; ++i)
432      eventTimes[i].clear();
433
434          while (!bAbort_)
435          {
436                  // Pump messages in all registered RenderWindows
437      Ogre::WindowEventUtilities::messagePump();
438
439      // get current time
440      unsigned long now = timer->getMilliseconds();
441
442      // create an event to pass to the frameStarted method in ogre
443      Ogre::FrameEvent evt;
444      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
445      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[1]);
446
447      // show the current time in the HUD
448      orxonoxHUD_->setTime((int)now, 0);
449
450      // don't forget to call _fireFrameStarted in ogre to make sure
451      // everything goes smoothly
452      if (!ogre_->getRoot()->_fireFrameStarted(evt))
453        break;
454
455      // Iterate through all Tickables and call their tick(dt) function
456      for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; )
457        (it++)->tick((float)evt.timeSinceLastFrame);
458
459      if (mode_ != SERVER)
460      {
461        // only render in non-server mode
462        ogre_->getRoot()->_updateAllRenderTargets();
463      }
464
465      // get current time
466      now = timer->getMilliseconds();
467
468      // create an event to pass to the frameEnded method in ogre
469      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
470      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[2]);
471
472      // again, just to be sure ogre works fine
473      if (!ogre_->getRoot()->_fireFrameEnded(evt))
474        break;
475          }
476  }
477
478  /**
479    Method for calculating the average time between recently fired events.
480    Code directly taken from OgreRoot.cc
481    @param now The current time in ms.
482    @param type The type of event to be considered.
483  */
484  float Orxonox::calculateEventTime(unsigned long now, std::deque<unsigned long> &times)
485  {
486    // Calculate the average time passed between events of the given type
487    // during the last mFrameSmoothingTime seconds.
488
489    times.push_back(now);
490
491    if(times.size() == 1)
492      return 0;
493
494    // Times up to mFrameSmoothingTime seconds old should be kept
495    unsigned long discardThreshold =
496      static_cast<unsigned long>(frameSmoothingTime_ * 1000.0f);
497
498    // Find the oldest time to keep
499    std::deque<unsigned long>::iterator it = times.begin(),
500      end = times.end()-2; // We need at least two times
501    while(it != end)
502    {
503      if (now - *it > discardThreshold)
504        ++it;
505      else
506        break;
507    }
508
509    // Remove old times
510    times.erase(times.begin(), it);
511
512    return (float)(times.back() - times.front()) / ((times.size()-1) * 1000);
513  }
514}
Note: See TracBrowser for help on using the repository browser.