Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/story_entities/game_world.cc @ 10401

Last change on this file since 10401 was 10379, checked in by patrick, 18 years ago

merged branche camera to trunk. resolved many conflicts as in the other projects too

File size: 19.1 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Patrick Boenzli
13   main-programmer: Benjamin Grauer
14   co-programmer: Christian Meyer
15
16*/
17
18#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD
19
20#include "game_world.h"
21#include "game_world_data.h"
22
23#include "state.h"
24
25#include "util/loading/game_loader.h"
26#include "util/timer.h"
27
28#include "player.h"
29#include "camera.h"
30#include "environment.h"
31#include "terrain.h"
32#include "test_entity.h"
33#include "terrain.h"
34#include "playable.h"
35#include "environments/mapped_water.h"
36
37#include "light.h"
38
39#include "util/loading/factory.h"
40#include "util/loading/load_param_xml.h"
41#include "loading/fast_factory.h"
42#include "shell_command.h"
43
44#include "graphics_engine.h"
45#include "weather_effects/atmospheric_engine.h"
46#include "event_handler.h"
47#include "sound_engine.h"
48#include "cd_engine.h"
49#include "network_manager.h"
50#include "physics_engine.h"
51
52#include "glmenu_imagescreen.h"
53#include "shell.h"
54
55#include "ogg_player.h"
56#include "shader.h"
57#include "ai_engine.h"
58
59#include "animation_player.h"
60
61#include "game_rules.h"
62
63#include "script_class.h"
64ObjectListDefinition(GameWorld);
65CREATE_SCRIPTABLE_CLASS(GameWorld,
66                        addMethod("setPlaymode", Executor1<GameWorld, lua_State*,const std::string&>(&GameWorld::setPlaymode))
67                        ->addMethod("setSoundtrack", Executor1<GameWorld, lua_State*, const std::string&>(&GameWorld::setSoundtrack))
68                        ->addMethod("getStoryID", Executor0ret<StoryEntity, lua_State*, int>(&StoryEntity::getStoryID))
69                        ->addMethod("setNextStoryName", Executor1ret<StoryEntity, lua_State*, bool, const std::string&>(&StoryEntity::setNextStoryName))
70                        ->addMethod("stop", Executor0ret<GameWorld, lua_State*, bool>(&GameWorld::stop))
71                       );
72
73SHELL_COMMAND(speed, GameWorld, setSpeed) ->describe("set the Speed of the Level");
74SHELL_COMMAND(playmode, GameWorld, setPlaymode)
75->describe("Set the Playmode of the current Level")
76->completionPlugin(0, OrxShell::CompletorStringArray(Playable::playmodeNames, Playable::PlaymodeCount));
77
78SHELL_COMMAND(togglePNodeVisibility, GameWorld, togglePNodeVisibility);
79SHELL_COMMAND(showBVLevel, GameWorld, toggleBVVisibility);
80SHELL_COMMAND(showMountPoints, GameWorld, toggleMPVisibility);
81
82
83GameWorld::GameWorld()
84    : StoryEntity()
85{
86  this->registerObject(this, GameWorld::_objectList);
87  this->setName("Preloaded World - no name yet");
88
89  this->gameTime = 0.0f;
90  this->setSpeed(1.0f);
91  this->shell = NULL;
92
93  this->showPNodes = false;
94  this->showBV = false;
95  this->showBVLevel = 3;
96  this->showMPV = false;
97
98  this->dataXML = NULL;
99  this->gameRules = NULL;
100}
101
102/**
103 *  remove the GameWorld from memory
104 *
105 *  delete everything explicitly, that isn't contained in the parenting tree!
106 *  things contained in the tree are deleted automaticaly
107 */
108GameWorld::~GameWorld ()
109{
110  PRINTF(4)("Deleted GameWorld\n");
111
112}
113
114
115
116/**
117 * loads the parameters of a GameWorld from an XML-element
118 * @param root the XML-element to load from
119 */
120void GameWorld::loadParams(const TiXmlElement* root)
121{
122  StoryEntity::loadParams(root);
123
124  PRINTF(4)("Loaded GameWorld specific stuff\n");
125}
126
127
128/**
129 * this is executed just before load
130 *
131 * since the load function sometimes needs data, that has been initialized
132 * before the load and after the proceeding storyentity has finished
133*/
134ErrorMessage GameWorld::init()
135{
136  /* init the world interface */
137  this->shell = new OrxShell::Shell();
138
139  State::setCurrentStoryEntity(dynamic_cast<StoryEntity*>(this));
140  this->dataTank->init();
141
142  /* initialize some engines and graphical elements */
143  AnimationPlayer::getInstance();
144  PhysicsEngine::getInstance();
145  CoRe::CREngine::getInstance();
146
147  State::setScriptManager(&this->scriptManager);
148
149  return ErrorMessage();
150}
151
152/**
153 *  loads the GameWorld by initializing all resources, and set their default values.
154 */
155ErrorMessage GameWorld::loadData()
156{
157  this->displayLoadScreen();  State::setScriptManager(&this->scriptManager);
158
159
160  PRINTF(4)("Loading the GameWorld\n");
161
162  PRINTF(3)("> Loading world: '%s'\n", getLoadFile().c_str());
163  //  TiXmlElement* element;
164  //  GameLoader* loader = GameLoader::getInstance();
165
166  if( getLoadFile().empty())
167  {
168    PRINTF(1)("GameWorld has no path specified for loading\n");
169    return (ErrorMessage(213,"Path not specified","GameWorld::load()"));
170  }
171
172  TiXmlDocument* XMLDoc = new TiXmlDocument( getLoadFile());
173  // load the xml world file for further loading
174  if( !XMLDoc->LoadFile())
175  {
176    PRINTF(1)("loading XML File: %s @ %s:l%d:c%d\n", XMLDoc->ErrorDesc(), this->getLoadFile().c_str(), XMLDoc->ErrorRow(), XMLDoc->ErrorCol());
177    delete XMLDoc;
178    return ErrorMessage(213,"XML File parsing error","GameWorld::load()");
179  }
180  // check basic validity
181  TiXmlElement* root = XMLDoc->RootElement();
182  assert( root != NULL);
183  if( root == NULL || root->Value() == NULL || strcmp( root->Value(), "WorldDataFile"))
184  {
185    // report an error
186    PRINTF(1)("Specified XML File is not an orxonox world data file (WorldDataFile element missing)\n");
187    delete XMLDoc;
188    return ErrorMessage(213,"Path not a WorldDataFile","GameWorld::load()");
189  }
190  /* the whole loading process for the GameWorld */
191  this->dataTank->loadData(root);
192  this->dataXML = (TiXmlElement*)root->Clone();
193
194  //remove this after finished testing !!!!
195  //Object* obj= new Object();
196  //obj->setName("Obj");
197  //Account* a = new Account();
198  //a->setName("a");
199  //Account *b = new Account(30);
200  //b->setName("b");
201
202
203  LoadParamXML(root, "ScriptManager", &this->scriptManager, ScriptManager, loadParams);
204
205  delete XMLDoc;
206  this->releaseLoadScreen();
207
208  return ErrorMessage();
209}
210
211
212/**
213 *  unload the data of this GameWorld
214 */
215ErrorMessage GameWorld::unloadData()
216{
217
218  PRINTF(3)("GameWorld::~GameWorld() - unloading the current GameWorld\n");
219  this->scriptManager.flush();
220
221  delete this->shell;
222
223  this->dataTank->unloadData();
224
225  this->shell = NULL;
226  delete AnimationPlayer::getInstance();
227  delete PhysicsEngine::getInstance();
228  delete CoRe::CREngine::getInstance();
229
230  State::setCurrentStoryEntity(NULL);
231  if (this->dataXML)
232    delete this->dataXML;
233
234  return ErrorMessage();
235}
236
237
238void GameWorld::setSoundtrack(const std::string& soundTrack)
239{
240  if (this->dataTank != NULL)
241  {
242    this->dataTank->setSoundTrack(soundTrack);
243    this->dataTank->music->play();
244  }
245}
246
247
248/**
249 *  starts the GameWorld
250 */
251bool GameWorld::start()
252{
253  this->bPaused = false;
254  this->bRunning = true;
255  State::setScriptManager(&this->scriptManager); //make sure we have the right script manager
256  this->run();
257
258  return true;
259}
260
261
262/**
263 *  stops the world.
264 */
265bool GameWorld::stop()
266{
267  PRINTF(3)("GameWorld::stop() - got stop signal\n");
268  State::setScriptManager(NULL);
269  return (this->bRunning = false);
270}
271
272
273/**
274 *  pauses the game
275 */
276bool GameWorld::pause()
277{
278  return (this->bPaused = true);
279}
280
281
282/**
283 *  ends the pause Phase
284 */
285bool GameWorld::resume()
286{
287  return(this->bPaused = false);
288}
289
290
291/**
292 *  main loop of the world: executing all world relevant function
293 *
294 * in this loop we synchronize (if networked), handle input events, give the heart-beat to
295 * all other member-entities of the world (tick to player, enemies etc.), checking for
296 * collisions drawing everything to the screen.
297 */
298void GameWorld::run()
299{
300  PRINTF(3)("GameWorld::mainLoop() - Entering main loop\n");
301
302  // initialize Timing
303  this->cycle = 0;
304  for (unsigned int i = 0; i < TICK_SMOOTH_VALUE; i++)
305    this->frameTimes[i] = 0.01f;
306  this->dtS = 0.0f;
307  this->lastFrame = Timer::getNow();
308
309  if (this->dataTank->music != NULL)
310    this->dataTank->music->play();
311
312  PNode::getNullParent()->updateNode(0.01);
313  PNode::getNullParent()->updateNode(0.01);
314
315  bool bNoDraw = true;
316
317  while( this->bRunning) /* @todo implement pause */
318  {
319    /* process intput */
320    this->handleInput ();
321    if( !this->bRunning)
322      break;
323
324    /* network synchronisation */
325    this->synchronize ();
326    /* process time */
327    this->tick ();
328
329
330    /* update the state */
331    //this->update (); /// LESS REDUNDANCY.
332    //      PNode::getNullParent()->updateNode(this->dtS);
333    PNode::getNullParent()->updateNode(this->dtS);
334
335    /* collision detection */
336    this->collisionDetection ();
337    /* collision reaction */
338    this->collisionReaction ();
339
340    /* perform ai check*/
341    this->checkAI();
342
343    /* check the game rules */
344    this->checkGameRules();
345
346    /* update the state */
347    this->update ();
348    /* draw everything */
349    if( bNoDraw)
350      this->display ();
351
352    bNoDraw= !bNoDraw;
353  }
354
355  PRINTF(4)("GameWorld::mainLoop() - Exiting the main loop\n");
356}
357
358
359void GameWorld::setPlaymode(Playable::Playmode playmode)
360{
361  if (this->dataTank->localPlayer &&
362      this->dataTank->localPlayer->getPlayable() &&
363      this->dataTank->localPlayer->getPlayable()->setPlaymode(playmode))
364  {
365    PRINTF(0)("Set Playmode to %d:%s\n", playmode, Playable::playmodeToString(playmode).c_str());
366  }
367  else
368  {
369    PRINTF(0)("Unable to set Playmode %d:'%s'\n", playmode, Playable::playmodeToString(playmode).c_str());
370  }
371}
372
373void GameWorld::setPlaymode(const std::string& playmode)
374{
375  this->setPlaymode(Playable::stringToPlaymode(playmode));
376}
377
378/**
379 *  synchronize local data with remote data
380*/
381void GameWorld::synchronize ()
382{}
383
384
385/**
386 *  run all input processing
387
388   the command node is the central input event dispatcher. the node uses the even-queue from
389   sdl and has its own event-passing-queue.
390*/
391void GameWorld::handleInput ()
392{
393  EventHandler::getInstance()->process();
394}
395
396
397/**
398 * @brief ticks a WorldEntity list
399 * @param entityList list of the WorldEntities
400 * @param dt time passed since last frame
401 */
402void GameWorld::tick(ObjectManager::EntityList entityList, float dt)
403{
404  ObjectManager::EntityList::iterator entity, next;
405  next = entityList.begin();
406  while (next != entityList.end())
407  {
408    entity = next++;
409    (*entity)->tick(dt);
410  }
411}
412
413
414/**
415 *  advance the timeline
416 *
417 * this calculates the time used to process one frame (with all input handling, drawing, etc)
418 * the time is mesured in ms and passed to all world-entities and other classes that need
419 * a heart-beat.
420 */
421void GameWorld::tick ()
422{
423  if( !this->bPaused)
424  {
425    // CALCULATE FRAMERATE
426    Uint32 frameTimesIndex;
427    Uint32 i;
428    double currentFrame = Timer::getNow();
429
430    if (currentFrame - this->lastFrame < .01)
431    {
432      SDL_Delay((int)(1000.0 * (0.01 - (currentFrame - lastFrame))));
433      currentFrame = Timer::getNow();
434    }
435
436
437    frameTimesIndex = this->cycle % TICK_SMOOTH_VALUE;
438    this->frameTimes[frameTimesIndex] = currentFrame - this->lastFrame;
439    this->lastFrame = currentFrame;
440    ++this->cycle;
441    this->dtS = 0.0;
442    for (i = 0; i < TICK_SMOOTH_VALUE; i++)
443      this->dtS += this->frameTimes[i];
444    this->dtS = this->dtS / TICK_SMOOTH_VALUE * speed;
445
446    // TICK everything
447    for (i = 0; i < this->dataTank->tickLists.size(); ++i)
448      this->tick(this->dataTank->objectManager->getEntityList(this->dataTank->tickLists[i]), this->dtS);
449
450    /* update tick the rest */
451    State::getCamera()->tick(this->dtS);
452    AnimationPlayer::getInstance()->tick(this->dtS);
453    PhysicsEngine::getInstance()->tick(this->dtS);
454
455    GraphicsEngine::getInstance()->tick(this->dtS);
456    AtmosphericEngine::getInstance()->tick(this->dtS);
457
458    if( likely(this->dataTank->gameRule != NULL))
459      this->dataTank->gameRule->tick(this->dtS);
460
461  }
462}
463
464
465/**
466 *  this function gives the world a consistant state
467 *
468 * after ticking (updating the world state) this will give a constistant
469 * state to the whole system.
470 */
471void GameWorld::update()
472{
473  PNode::getNullParent()->updateNode (this->dtS);
474  OrxSound::SoundEngine::getInstance()->update();
475
476  this->applyCameraSettings();
477  GraphicsEngine::getInstance()->update(this->dtS);
478}
479
480
481/**
482 * kicks the CDEngine to detect the collisions between the object groups in the world
483 */
484void GameWorld::collisionDetection()
485{
486  // object-object collision detection
487  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_00),
488      this->dataTank->objectManager->getEntityList(OM_GROUP_01_PROJ));
489  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_01),
490      this->dataTank->objectManager->getEntityList(OM_GROUP_00_PROJ));
491  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_01),
492      this->dataTank->objectManager->getEntityList(OM_GROUP_00));
493
494  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_01),
495      this->dataTank->objectManager->getEntityList(OM_GROUP_02));
496  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_02),
497      this->dataTank->objectManager->getEntityList(OM_GROUP_01_PROJ));
498
499
500  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_00),
501      this->dataTank->objectManager->getEntityList(OM_COMMON));
502  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_01),
503      this->dataTank->objectManager->getEntityList(OM_COMMON));
504
505  // ground collision detection: BSP Model
506  CDEngine::getInstance()->checkCollisionGround(this->dataTank->objectManager->getEntityList(OM_GROUP_00));
507  CDEngine::getInstance()->checkCollisionGround(this->dataTank->objectManager->getEntityList(OM_GROUP_01));
508}
509
510
511void GameWorld::collisionReaction()
512{
513  CoRe::CREngine::getInstance()->handleCollisions();
514}
515
516
517
518void GameWorld::checkAI()
519{
520  AIEngine::getInstance()->tick(this->dtS);
521  //AIEngine::getInstance()->tick();
522}
523
524
525/**
526 *  check the game rules: winning conditions, etc.
527 *
528 */
529void GameWorld::checkGameRules()
530{
531  if( this->gameRules)
532    this->gameRules->tick(this->dtS);
533}
534
535
536/**
537 *  render the current frame
538 *
539 * clear all buffers and draw the world
540 */
541void GameWorld::display ()
542{
543
544  // if this server is a dedicated server the game workd does not need to be drawn
545  if( !GraphicsEngine::getInstance()->isDedicated())
546  {
547    // render the reflection texture
548    this->renderPassReflection();
549    // redner the refraction texture
550    this->renderPassRefraction();
551  }
552  // render all
553  this->renderPassAll();
554
555  // flip buffers
556  GraphicsEngine::swapBuffers();
557}
558
559
560/**
561 * @brief draws all entities in the list drawList
562 * @param drawList the List of entities to draw.
563 */
564void GameWorld::drawEntityList(const ObjectManager::EntityList& drawList) const
565{
566  ObjectManager::EntityList::const_iterator entity;
567  for (entity = drawList.begin(); entity != drawList.end(); entity++)
568  {
569    if ((*entity)->isVisible())
570      (*entity)->draw();
571
572    if( unlikely( this->showMPV))
573      (*entity)->debugDrawMountPoints();
574  }
575}
576
577
578void GameWorld::applyCameraSettings()
579{
580
581  State::getCamera()->apply ();
582  State::getCamera()->project ();
583  GraphicsEngine::storeMatrices();
584}
585
586
587
588/**
589 * reflection rendering for water surfaces
590 */
591void GameWorld::renderPassReflection()
592{
593  // clear buffer
594  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
595  //  glLoadIdentity();
596
597  MappedWater* mw;
598
599  for (ObjectList<MappedWater>::const_iterator it = MappedWater::objectList().begin();
600       it != MappedWater::objectList().end();
601       ++it)
602  {
603    mw =  (*it);
604
605    //camera and light
606    //this->dataTank->localCamera->apply ();
607    //this->dataTank->localCamera->project ();
608
609    LightManager::getInstance()->draw();
610
611
612    // prepare for reflection rendering
613    mw->activateReflection();
614
615    // draw everything to be included in the reflection
616    this->drawEntityList(State::getObjectManager()->getReflectionList());
617    //       for (unsigned int i = 0; i < this->dataTank->drawLists.size(); ++i)
618    //         this->drawEntityList(State::getObjectManager()->getEntityList(this->dataTank->drawLists[i]));
619
620    // clean up from reflection rendering
621    mw->deactivateReflection();
622  }
623
624}
625
626
627/**
628 *  refraction rendering for water surfaces
629 */
630void GameWorld::renderPassRefraction()
631{
632  // clear buffer
633  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
634  //glLoadIdentity();
635
636  MappedWater* mw;
637
638  for (ObjectList<MappedWater>::const_iterator it = MappedWater::objectList().begin();
639       it != MappedWater::objectList().end();
640       ++it)
641  {
642    mw =  dynamic_cast<MappedWater*>(*it);
643
644    //camera and light
645    //this->dataTank->localCamera->apply ();
646    //this->dataTank->localCamera->project ();
647    // prepare for reflection rendering
648    mw->activateRefraction();
649
650
651    LightManager::getInstance()->draw();
652    // draw everything to be included in the reflection
653    this->drawEntityList(State::getObjectManager()->getReflectionList());
654    //       for (unsigned int i = 0; i < this->dataTank->drawLists.size(); ++i)
655    //         this->drawEntityList(State::getObjectManager()->getEntityList(this->dataTank->drawLists[i]));
656
657    // clean up from reflection rendering
658    mw->deactivateRefraction();
659  }
660}
661
662
663/**
664 *  this render pass renders the whole wolrd
665 */
666void GameWorld::renderPassAll()
667{
668  // clear buffer
669  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
670  GraphicsEngine* engine = GraphicsEngine::getInstance();
671
672
673  // glEnable(GL_DEPTH_TEST);
674  // glEnable(GL_LIGHTING);
675
676  // set Lighting
677  LightManager::getInstance()->draw();
678
679  // only render the world if its not dedicated mode
680  if( !GraphicsEngine::getInstance()->isDedicated())
681  {
682    /* Draw the BackGround */
683    this->drawEntityList(State::getObjectManager()->getEntityList(OM_BACKGROUND));
684    engine->drawBackgroundElements();
685
686    /* draw all WorldEntiy groups */
687    for (unsigned int i = 0; i < this->dataTank->drawLists.size(); ++i)
688      this->drawEntityList(State::getObjectManager()->getEntityList(this->dataTank->drawLists[i]));
689
690    AtmosphericEngine::getInstance()->draw();
691
692    if( unlikely( this->showBV))
693    {
694      CDEngine* engine = CDEngine::getInstance();
695      for (unsigned int i = 0; i < this->dataTank->drawLists.size(); ++i)
696        engine->drawBV(State::getObjectManager()->getEntityList(this->dataTank->drawLists[i]), this->showBVLevel);
697    }
698
699
700    if( unlikely(this->showPNodes))
701      PNode::getNullParent()->debugDraw(0);
702
703    // draw the game ruls
704    if( likely(this->dataTank->gameRule != NULL))
705      this->dataTank->gameRule->draw();
706  }
707
708  engine->draw();
709}
710
711
712/**
713 *  shows the loading screen
714 */
715void GameWorld::displayLoadScreen ()
716{
717  PRINTF(3)("GameWorld::displayLoadScreen - start\n");
718  this->dataTank->glmis = new GLMenuImageScreen();
719  this->dataTank->glmis->setMaximum(8);
720  PRINTF(3)("GameWorld::displayLoadScreen - end\n");
721}
722
723
724/**
725 *  removes the loadscreen, and changes over to the game
726 */
727void GameWorld::releaseLoadScreen()
728{
729  PRINTF(3)("GameWorld::releaseLoadScreen - start\n");
730  this->dataTank->glmis->setValue(this->dataTank->glmis->getMaximum());
731  PRINTF(3)("GameWorld::releaseLoadScreen - end\n");
732}
733
734
735
736/**
737 * @brief toggles the PNode visibility in the world (drawn as boxes)
738 */
739void GameWorld::togglePNodeVisibility()
740{
741  this->showPNodes = !this->showPNodes;
742};
743
744
745/**
746 * @brief toggles the bounding volume (BV) visibility
747*/
748void GameWorld::toggleBVVisibility(int level)
749{
750  if( level < 1)
751    this->showBV = false;
752  else
753  {
754    this->showBV = true;
755    this->showBVLevel = level;
756  }
757
758};
759
Note: See TracBrowser for help on using the repository browser.