Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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