Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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