Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network2/src/orxonox/Orxonox.cc @ 1339

Last change on this file since 1339 was 1150, checked in by dumenim, 17 years ago

either i'm wrong or the hud is. it seems to create a segfault in startRenderLoop, don't know if only in network branch. there are some std::couts commented with 3 / (blue :-) and the hud calls are commented out too. now it goes a bit further untill the next segfault.

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