Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/Orxonox.cc @ 1054

Last change on this file since 1054 was 1054, checked in by landauf, 16 years ago

included ConfigFileManager

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
30 @brief Orxonox Main Class
31 */
32
33// Precompiled Headers
34#include "OrxonoxStableHeaders.h"
35#include "Orxonox.h"
36
37//****** STD *******
38//#include <iostream>
39//#include <exception>
40#include <deque>
41
42//****** OGRE ******
43//#include <OgreException.h>
44#include <OgreFrameListener.h>
45#include <OgreOverlay.h>
46#include <OgreOverlayManager.h>
47#include <OgreRoot.h>
48#include <OgreTimer.h>
49#include <OgreWindowEventUtilities.h>
50
51//***** ORXONOX ****
52// util
53//#include "util/Sleep.h"
54#include "util/ArgReader.h"
55
56// core
57#include "core/ConfigFileManager.h"
58#include "core/ConsoleCommand.h"
59#include "core/Debug.h"
60#include "core/Factory.h"
61#include "core/Loader.h"
62#include "core/Tickable.h"
63#include "core/InputBuffer.h"
64#include "core/InputManager.h"
65
66// audio
67#include "audio/AudioManager.h"
68
69// network
70#include "network/Server.h"
71#include "network/Client.h"
72
73// objects and tools
74#include "tools/Timer.h"
75#include "hud/HUD.h"
76//#include "objects/weapon/BulletManager.h"
77
78// FIXME: is this really file scope?
79// globals for the server or client
80network::Client *client_g;
81network::Server *server_g;
82
83namespace orxonox
84{
85  ConsoleCommand(Orxonox, exit, AccessLevel::None, true);
86  ConsoleCommand(Orxonox, slomo, AccessLevel::Offline, true).setDefaultValue(0, 1.0);
87  ConsoleCommand(Orxonox, setTimeFactor, AccessLevel::Offline, false).setDefaultValue(0, 1.0);
88
89  class Testconsole : public InputBufferListener
90  {
91    public:
92      Testconsole(InputBuffer* ib) : ib_(ib) {}
93      void listen() const
94      {
95        std::cout << "> " << this->ib_->get() << std::endl;
96      }
97      void execute() const
98      {
99        std::cout << ">> " << this->ib_->get() << std::endl;
100        if (!CommandExecutor::execute(this->ib_->get()))
101          std::cout << "Error" << std::endl;
102        this->ib_->clear();
103      }
104      void hintandcomplete() const
105      {
106        std::cout << CommandExecutor::hint(this->ib_->get()) << std::endl;
107        this->ib_->set(CommandExecutor::complete(this->ib_->get()));
108      }
109      void clear() const
110      {
111        this->ib_->clear();
112      }
113      void removeLast() const
114      {
115        this->ib_->removeLast();
116      }
117
118    private:
119      InputBuffer* ib_;
120  };
121
122  /**
123    @brief Reference to the only instance of the class.
124  */
125  Orxonox *Orxonox::singletonRef_s = 0;
126
127  /**
128   * create a new instance of Orxonox
129   */
130  Orxonox::Orxonox()
131  {
132    this->ogre_ = &GraphicsEngine::getSingleton();
133    this->timer_ = 0;
134    this->dataPath_ = "";
135    this->auMan_ = 0;
136    this->inputHandler_ = 0;
137    //this->root_ = 0;
138    // turn on frame smoothing by setting a value different from 0
139    this->frameSmoothingTime_ = 0.0f;
140    this->bAbort_ = false;
141    this->timefactor_ = 1.0f;
142  }
143
144  /**
145   * destruct Orxonox
146   */
147  Orxonox::~Orxonox()
148  {
149    // keep in mind: the order of deletion is very important!
150//    if (this->bulletMgr_)
151//      delete this->bulletMgr_;
152    if (this->orxonoxHUD_)
153      delete this->orxonoxHUD_;
154    Loader::close();
155    InputManager::getSingleton().destroy();
156    if (this->auMan_)
157      delete this->auMan_;
158    if (this->timer_)
159      delete this->timer_;
160    GraphicsEngine::getSingleton().destroy();
161
162    if (client_g)
163      delete client_g;
164    if (server_g)
165      delete server_g;
166  }
167
168  /**
169   * error kills orxonox
170   */
171  void Orxonox::abortImmediate(/* some error code */)
172  {
173    //TODO: destroy and destruct everything and print nice error msg
174    delete this;
175  }
176
177  /**
178    Asks the mainloop nicely to abort.
179  */
180  void Orxonox::abortRequest()
181  {
182    bAbort_ = true;
183  }
184
185  /**
186   * @return singleton object
187   */
188  Orxonox* Orxonox::getSingleton()
189  {
190    if (!singletonRef_s)
191      singletonRef_s = new Orxonox();
192    return singletonRef_s;
193  }
194
195  /**
196    @brief Destroys the Orxonox singleton.
197  */
198  void Orxonox::destroySingleton()
199  {
200    if (singletonRef_s)
201      delete singletonRef_s;
202    singletonRef_s = 0;
203  }
204
205  /**
206   * initialization of Orxonox object
207   * @param argc argument counter
208   * @param argv list of argumenst
209   * @param path path to config (in home dir or something)
210   */
211  void Orxonox::init(int argc, char **argv, std::string path)
212  {
213    //TODO: find config file (assuming executable directory)
214    //TODO: read config file
215    //TODO: give config file to Ogre
216    std::string mode;
217
218    ArgReader ar(argc, argv);
219    ar.checkArgument("mode", mode, false);
220    ar.checkArgument("data", this->dataPath_, false);
221    ar.checkArgument("ip", serverIp_, false);
222    if(ar.errorHandling()) abortImmediate();
223    if(mode == std::string("client"))
224    {
225      mode_ = CLIENT;
226      clientInit(path);
227    }
228    else if(mode== std::string("server")){
229      mode_ = SERVER;
230      serverInit(path);
231    }
232    else{
233      mode_ = STANDALONE;
234      standaloneInit(path);
235    }
236  }
237
238  void Orxonox::serverInit(std::string path)
239  {
240    COUT(2) << "initialising server" << std::endl;
241
242    ogre_->setConfigPath(path);
243    ogre_->setup();
244    //root_ = ogre_->getRoot();
245    if(!ogre_->load(this->dataPath_)) abortImmediate(/* unable to load */);
246
247    server_g = new network::Server();
248  }
249
250  void Orxonox::clientInit(std::string path)
251  {
252    COUT(2) << "initialising client" << std::endl;\
253
254    ogre_->setConfigPath(path);
255    ogre_->setup();
256    if(serverIp_.compare("")==0)
257      client_g = new network::Client();
258    else
259      client_g = new network::Client(serverIp_, NETWORK_PORT);
260    if(!ogre_->load(this->dataPath_)) abortImmediate(/* unable to load */);
261  }
262
263  void Orxonox::standaloneInit(std::string path)
264  {
265    COUT(2) << "initialising standalone mode" << std::endl;
266
267    ogre_->setConfigPath(path);
268    ogre_->setup();
269    //root_ = ogre_->getRoot();
270    if(!ogre_->load(this->dataPath_)) abortImmediate(/* unable to load */);
271  }
272
273  /**
274   * start modules
275   */
276  void Orxonox::start()
277  {
278    switch(mode_){
279    case CLIENT:
280      clientStart();
281      break;
282    case SERVER:
283      serverStart();
284      break;
285    default:
286      standaloneStart();
287    }
288  }
289
290  void Orxonox::clientStart(){
291    ogre_->initialise();
292    ConfigFileManager::getSingleton()->setFile(CFT_Settings, "orxonox.ini");
293    Factory::createClassHierarchy();
294
295
296    auMan_ = new audio::AudioManager();
297
298    //bulletMgr_ = new BulletManager();
299
300    Ogre::Overlay* hudOverlay = Ogre::OverlayManager::getSingleton().getByName("Orxonox/HUD1.2");
301    HUD* orxonoxHud;
302    orxonoxHud = new HUD();
303    orxonoxHud->setEnergyValue(20);
304    orxonoxHud->setEnergyDistr(20,20,60);
305    hudOverlay->show();
306
307    client_g->establishConnection();
308    client_g->tick(0);
309
310
311    //setupInputSystem();
312
313    startRenderLoop();
314  }
315
316  void Orxonox::serverStart(){
317    //TODO: start modules
318    ogre_->initialise();
319    //TODO: run engine
320    ConfigFileManager::getSingleton()->setFile(CFT_Settings, "orxonox.ini");
321    Factory::createClassHierarchy();
322    createScene();
323    setupInputSystem();
324
325    server_g->open();
326
327    startRenderLoop();
328  }
329
330  void Orxonox::standaloneStart(){
331    //TODO: start modules
332    ogre_->initialise();
333    //TODO: run engine
334    ConfigFileManager::getSingleton()->setFile(CFT_Settings, "orxonox.ini");
335    Factory::createClassHierarchy();
336    createScene();
337    setupInputSystem();
338
339    startRenderLoop();
340  }
341
342  void Orxonox::createScene(void)
343  {
344          // Init audio
345    auMan_ = new audio::AudioManager();
346
347    //bulletMgr_ = new BulletManager();
348
349    // load this file from config
350    Level* startlevel = new Level("levels/sample.oxw");
351    Loader::open(startlevel);
352
353    Ogre::Overlay* hudOverlay = Ogre::OverlayManager::getSingleton().getByName("Orxonox/HUD1.2");
354    orxonoxHUD_ = new HUD();
355    orxonoxHUD_->setEnergyValue(20);
356    orxonoxHUD_->setEnergyDistr(20,20,60);
357    hudOverlay->show();
358
359        /*
360    auMan_->ambientAdd("a1");
361    auMan_->ambientAdd("a2");
362    auMan_->ambientAdd("a3");
363    //auMan->ambientAdd("ambient1");
364    auMan_->ambientStart();
365  */
366  }
367
368  /**
369    @brief Calls the InputHandler which sets up the input devices.
370    The render window width and height are used to set up the mouse movement.
371  */
372  void Orxonox::setupInputSystem()
373  {
374    inputHandler_ = &InputManager::getSingleton();
375    if (!inputHandler_->initialise(ogre_->getWindowHandle(),
376          ogre_->getWindowWidth(), ogre_->getWindowHeight()))
377      abortImmediate();
378    inputHandler_->setInputMode(IM_INGAME);
379  }
380
381  /**
382    Main loop of the orxonox game.
383    This is a new solution, using the ogre engine instead of being used by it.
384    An alternative solution would be to simply use the timer of the Root object,
385    but that implies using Ogre in any case. There would be no way to test
386    our code without the help of the root object.
387    There's even a chance that we can dispose of the root object entirely
388    in server mode.
389    About the loop: The design is almost exactly like the one in ogre, so that
390    if any part of ogre registers a framelisteners, it will still behave
391    correctly. Furthermore the time smoothing feature from ogre has been
392    implemented too. If turned on (see orxonox constructor), it will calculate
393    the dt_n by means of the recent most dt_n-1, dt_n-2, etc.
394  */
395  void Orxonox::startRenderLoop()
396  {
397    InputBuffer* ib = new InputBuffer();
398    Testconsole* console = new Testconsole(ib);
399    ib->registerListener(console, &Testconsole::listen, true);
400    ib->registerListener(console, &Testconsole::execute, '\r', false);
401    ib->registerListener(console, &Testconsole::hintandcomplete, '\t', true);
402    ib->registerListener(console, &Testconsole::clear, '§', true);
403    ib->registerListener(console, &Testconsole::removeLast, '\b', true);
404
405    // first check whether ogre root object has been created
406    if (Ogre::Root::getSingletonPtr() == 0)
407    {
408      COUT(2) << "Error: Could not start rendering. No Ogre root object found" << std::endl;
409      return;
410    }
411
412    // Contains the times of recently fired events
413    // eventTimes[4] is the list for the times required for the fps counter
414    std::deque<unsigned long> eventTimes[4];
415    // Clear event times
416    for (int i = 0; i < 4; ++i)
417      eventTimes[i].clear();
418    // fill the fps time list with zeros
419    for (int i = 0; i < 20; i++)
420      eventTimes[3].push_back(0);
421
422    // use the ogre timer class to measure time.
423    if (!timer_)
424      timer_ = new Ogre::Timer();
425    timer_->reset();
426
427          while (!bAbort_)
428          {
429                  // Pump messages in all registered RenderWindows
430      Ogre::WindowEventUtilities::messagePump();
431
432      // get current time
433      unsigned long now = timer_->getMilliseconds();
434      eventTimes[3].push_back(now);
435      eventTimes[3].erase(eventTimes[3].begin());
436
437      // create an event to pass to the frameStarted method in ogre
438      Ogre::FrameEvent evt;
439      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
440      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[1]);
441
442      // show the current time in the HUD
443      orxonoxHUD_->setTime((int)now, 0);
444      if (eventTimes[3].back() - eventTimes[3].front() != 0)
445        orxonoxHUD_->setRocket1((int)(20000.0f/(eventTimes[3].back() - eventTimes[3].front())));
446
447      // Iterate through all Tickables and call their tick(dt) function
448      for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; )
449        (it++)->tick((float)evt.timeSinceLastFrame * this->timefactor_);
450
451      // don't forget to call _fireFrameStarted in ogre to make sure
452      // everything goes smoothly
453      Ogre::Root::getSingleton()._fireFrameStarted(evt);
454
455      // server still renders at the moment
456      //if (mode_ != SERVER)
457      Ogre::Root::getSingleton()._updateAllRenderTargets(); // only render in non-server mode
458
459      // get current time
460      now = timer_->getMilliseconds();
461
462      // create an event to pass to the frameEnded method in ogre
463      evt.timeSinceLastEvent = calculateEventTime(now, eventTimes[0]);
464      evt.timeSinceLastFrame = calculateEventTime(now, eventTimes[2]);
465
466      // again, just to be sure ogre works fine
467      Ogre::Root::getSingleton()._fireFrameEnded(evt);
468          }
469  }
470
471  /**
472    Method for calculating the average time between recently fired events.
473    Code directly taken from OgreRoot.cc
474    @param now The current time in ms.
475    @param type The type of event to be considered.
476  */
477  float Orxonox::calculateEventTime(unsigned long now, std::deque<unsigned long> &times)
478  {
479    // Calculate the average time passed between events of the given type
480    // during the last frameSmoothingTime_ seconds.
481
482    times.push_back(now);
483
484    if(times.size() == 1)
485      return 0;
486
487    // Times up to frameSmoothingTime_ seconds old should be kept
488    unsigned long discardThreshold = (unsigned long)(frameSmoothingTime_ * 1000.0f);
489
490    // Find the oldest time to keep
491    std::deque<unsigned long>::iterator it  = times.begin();
492    // We need at least two times
493    std::deque<unsigned long>::iterator end = times.end() - 2;
494
495    while(it != end)
496    {
497      if (now - *it > discardThreshold)
498        ++it;
499      else
500        break;
501    }
502
503    // Remove old times
504    times.erase(times.begin(), it);
505
506    return (float)(times.back() - times.front()) / ((times.size() - 1) * 1000);
507  }
508
509  /**
510    @brief Test method for the InputHandler.
511    But: Is actually responsible for catching an exit event..
512  */
513  void Orxonox::eventOccured(InputEvent &evt)
514  {
515    if (evt.id == 1)
516      this->abortRequest();
517  }
518}
Note: See TracBrowser for help on using the repository browser.