Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/story_entities/world.cc @ 6317

Last change on this file since 6317 was 6316, checked in by bensch, 19 years ago

orxonox/trunk: now painting the BV's again…. no error due to my change in the static model…. puh :)

File size: 18.6 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   co-programmer: Christian Meyer
14   co-programmer: Benjamin Grauer
15*/
16
17#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD
18
19#include "world.h"
20
21#include "shell_command.h"
22#include "resource_manager.h"
23#include "state.h"
24
25#include "p_node.h"
26#include "world_entity.h"
27#include "player.h"
28#include "camera.h"
29#include "environment.h"
30#include "terrain.h"
31
32#include "test_entity.h"
33#include "terrain.h"
34#include "light.h"
35#include "load_param.h"
36#include "shell.h"
37
38#include "fast_factory.h"
39#include "animation_player.h"
40#include "particle_engine.h"
41#include "graphics_engine.h"
42#include "physics_engine.h"
43#include "fields.h"
44
45#include "md2Model.h"
46
47#include "glmenu_imagescreen.h"
48#include "game_loader.h"
49
50#include "animation3d.h"
51
52#include "substring.h"
53
54#include "factory.h"
55
56#include "weapons/projectile.h"
57#include "event_handler.h"
58#include "sound_engine.h"
59#include "ogg_player.h"
60
61#include "class_list.h"
62
63#include "cd_engine.h"
64#include "npcs/npc_test1.h"
65#include "shader.h"
66
67#include "playable.h"
68#include "network_manager.h"
69#include "playable.h"
70
71
72SHELL_COMMAND(speed, World, setSpeed);
73SHELL_COMMAND(togglePNodeVisibility, World, togglePNodeVisibility);
74SHELL_COMMAND(toggleBVVisibility, World, toggleBVVisibility);
75
76using namespace std;
77
78//! This creates a Factory to fabricate a World
79CREATE_FACTORY(World, CL_WORLD);
80
81World::World(const TiXmlElement* root)
82{
83  this->constuctorInit("", -1);
84  this->path = NULL;
85
86  this->loadParams(root);
87}
88
89/**
90 *  remove the World from memory
91 *
92 *  delete everything explicitly, that isn't contained in the parenting tree!
93 *  things contained in the tree are deleted automaticaly
94 */
95World::~World ()
96{
97  delete this->shell;
98  PRINTF(3)("World::~World() - deleting current world\n");
99
100  delete this->localPlayer;
101
102  // delete all the initialized Engines.
103  FastFactory::flushAll(true);
104  delete LightManager::getInstance();
105  delete ParticleEngine::getInstance();
106  delete AnimationPlayer::getInstance();
107  delete PhysicsEngine::getInstance();
108
109  // external engines initialized by the orxonox-class get deleted
110  SoundEngine::getInstance()->flushAllBuffers();
111  SoundEngine::getInstance()->flushAllSources();
112
113  if (State::getObjectManager() == &this->objectManager)
114    State::setObjectManager(NULL);
115  // erease everything that is left.
116  delete PNode::getNullParent();
117
118  //secondary cleanup of PNodes;
119  const std::list<BaseObject*>* nodeList = ClassList::getList(CL_PARENT_NODE);
120  if (nodeList != NULL)
121    while (!nodeList->empty())
122      delete nodeList->front();
123
124  Shader::suspendShader();
125
126  // unload the resources !!
127  ResourceManager::getInstance()->unloadAllByPriority(RP_LEVEL);
128}
129
130/**
131 * initializes the world.
132 * @param name the name of the world
133 * @param worldID the ID of this world
134 *
135 * set all stuff here that is world generic and does not use to much memory
136 * because the real init() function StoryEntity::init() will be called
137 * shortly before start of the game.
138 * since all worlds are initiated/referenced before they will be started.
139 * NO LEVEL LOADING HERE - NEVER!
140*/
141void World::constuctorInit(const char* name, int worldID)
142{
143  this->setClassID(CL_WORLD, "World");
144
145  this->setName(name);
146  this->gameTime = 0.0f;
147  this->setSpeed(1.0);
148  this->music = NULL;
149  this->shell = NULL;
150  this->localPlayer = NULL;
151  this->localCamera = NULL;
152
153  this->showPNodes = false;
154  this->showBV = false;
155}
156
157/**
158 * loads the parameters of a World from an XML-element
159 * @param root the XML-element to load from
160 */
161void World::loadParams(const TiXmlElement* root)
162{
163  PRINTF(4)("Creating a World\n");
164
165  LoadParam(root, "identifier", this, World, setStoryID)
166    .describe("Sets the StoryID of this world");
167
168  LoadParam(root, "nextid", this, World, setNextStoryID)
169    .describe("Sets the ID of the next world");
170
171  LoadParam(root, "path", this, World, setPath)
172    .describe("The Filename of this World (relative from the data-dir)");
173}
174
175/**
176 * this is executed just before load
177 *
178 * since the load function sometimes needs data, that has been initialized
179 * before the load and after the proceeding storyentity has finished
180*/
181ErrorMessage World::preLoad()
182{
183  State::setObjectManager(&this->objectManager);
184  this->cycle = 0;
185
186  /* init the world interface */
187  this->shell = new Shell();
188
189  LightManager::getInstance();
190  PNode::getNullParent();
191
192  AnimationPlayer::getInstance(); // initializes the animationPlayer
193  ParticleEngine::getInstance();
194  PhysicsEngine::getInstance();
195
196  this->localCamera = new Camera();
197  this->localCamera->setName ("World-Camera");
198
199  State::setCamera(this->localCamera, this->localCamera->getTarget());
200
201  GraphicsEngine::getInstance()->displayFPS(true);
202  this->displayLoadScreen();
203}
204
205
206/**
207 *  loads the World by initializing all resources, and set their default values.
208 */
209ErrorMessage World::load()
210{
211  PRINTF(3)("> Loading world: '%s'\n", getPath());
212  TiXmlElement* element;
213  GameLoader* loader = GameLoader::getInstance();
214
215  if( getPath() == NULL)
216    {
217      PRINTF(1)("World has no path specified for loading");
218      return (ErrorMessage){213,"Path not specified","World::load()"};
219    }
220
221  TiXmlDocument* XMLDoc = new TiXmlDocument( getPath());
222  // load the campaign document
223  if( !XMLDoc->LoadFile())
224  {
225    // report an error
226    PRINTF(1)("loading XML File: %s @ %s:l%d:c%d\n", XMLDoc->ErrorDesc(), this->getPath(), XMLDoc->ErrorRow(), XMLDoc->ErrorCol());
227    delete XMLDoc;
228    return (ErrorMessage){213,"XML File parsing error","World::load()"};
229  }
230
231  // check basic validity
232  TiXmlElement* root = XMLDoc->RootElement();
233  assert( root != NULL);
234
235  if( root == NULL || root->Value() == NULL || strcmp( root->Value(), "WorldDataFile"))
236    {
237      // report an error
238      PRINTF(1)("Specified XML File is not an orxonox world data file (WorldDataFile element missing)\n");
239      delete XMLDoc;
240      return (ErrorMessage){213,"Path not a WorldDataFile","World::load()"};
241    }
242
243  // load the parameters
244  // name
245  const char* string = grabParameter( root, "name");
246  if( string == NULL)
247    {
248      PRINTF(2)("World is missing a proper 'name'\n");
249      this->setName("Unknown");
250    }
251  else
252    {
253      this->setName(string);
254    }
255
256  ////////////////
257  // LOADSCREEN //
258  ////////////////
259  element = root->FirstChildElement("LoadScreen");
260  if (element == NULL)
261    {
262      PRINTF(2)("no LoadScreen specified, loading default\n");
263
264      glmis->setBackgroundImage("pictures/load_screen.jpg");
265      this->glmis->setMaximum(8);
266      this->glmis->draw();
267    }
268  else
269    {
270      this->glmis->loadParams(element);
271      this->glmis->draw();
272    }
273  this->glmis->draw();
274
275  ////////////////////////
276  // find WorldEntities //
277  ////////////////////////
278
279  element = root->FirstChildElement("WorldEntities");
280
281  if( element == NULL)
282    {
283      PRINTF(1)("World is missing 'WorldEntities'\n");
284    }
285  else
286    {
287      element = element->FirstChildElement();
288      // load Players/Objects/Whatever
289      PRINTF(4)("Loading WorldEntities\n");
290      while( element != NULL)
291        {
292          BaseObject* created = Factory::fabricate(element);
293          if( created != NULL )
294          {
295            if(created->isA(CL_WORLD_ENTITY))
296              this->spawn(dynamic_cast<WorldEntity*>(created));
297            printf("Created a %s: %s\n", created->getClassName(), created->getName());
298          }
299
300          // if we load a 'Player' we use it as localPlayer
301
302
303          //todo do this more elegant
304          if( element->Value() != NULL && !strcmp( element->Value(), "SkyBox"))
305            this->sky = dynamic_cast<WorldEntity*>(created);
306          if( element->Value() != NULL && !strcmp( element->Value(), "Terrain"))
307          {
308            terrain = dynamic_cast<Terrain*>(created);
309            CDEngine::getInstance()->setTerrain(terrain);
310          }
311          element = element->NextSiblingElement();
312          glmis->step(); //! @todo temporary
313        }
314      PRINTF(4)("Done loading WorldEntities\n");
315    }
316
317    //////////////////////////////
318    // LOADING ADDITIONAL STUFF //
319    //////////////////////////////
320
321    LoadParamXML(root, "LightManager", LightManager::getInstance(), LightManager, loadParams);
322
323   LoadParamXML(root, "ParticleEngine", ParticleEngine::getInstance(), ParticleEngine, loadParams);
324//   LoadParamXML(root, "PhysicsEngine", PhysicsEngine::getInstance(), PhysicsEngine, loadParams);
325
326  // free the XML data
327
328  delete XMLDoc;
329  /* GENERIC LOADING PROCESS FINISHED */
330
331
332  // Create a Player
333  this->localPlayer = new Player();
334
335  Playable* playable;
336  const list<BaseObject*>* playableList = ClassList::getList(CL_PLAYABLE);
337  if (playableList != NULL)
338  {
339    playable = dynamic_cast<Playable*>(playableList->front());
340    this->localPlayer->setControllable(playable);
341  }
342
343
344//   //localCamera->setParent(TrackNode::getInstance());
345//  tn->addChild(this->localCamera);
346  localCamera->setClipRegion(1, 10000.0);
347//  localCamera->lookAt(playable);
348//  this->localPlayer->setParentMode(PNODE_ALL);
349  if (this->sky != NULL)
350  {
351    this->localCamera->addChild(sky);
352  }
353  SoundEngine::getInstance()->setListener(this->localCamera);
354
355
356
357  ////////////
358  // STATIC //
359  ////////////
360
361
362//   TestEntity* testEntity = new TestEntity();
363//   testEntity->setRelCoor(Vector(570, 10, -15));
364//   testEntity->setRelDir(Quaternion(M_PI, Vector(0, 1, 0)));
365//   this->spawn(testEntity);
366
367  for(int i = 0; i < 100; i++)
368  {
369    WorldEntity* tmp = new NPCTest1();
370    char npcChar[10];
371    sprintf (npcChar, "NPC_%d", i);
372        tmp->setName(npcChar);
373    tmp->setAbsCoor(((float)rand()/RAND_MAX) * 5000, 50/*+ (float)rand()/RAND_MAX*20*/, ((float)rand()/RAND_MAX -.5) *30);
374    this->spawn(tmp);
375  }
376
377  this->music = NULL;
378  //(OggPlayer*)ResourceManager::getInstance()->load("sound/00-luke_grey_-_hypermode.ogg", OGG, RP_LEVEL);
379  //music->playback();
380}
381
382ErrorMessage World::postLoad()
383{
384  this->releaseLoadScreen();
385}
386
387
388/**
389 *  initializes a new World shortly before start
390 *
391 * this is the function, that will be loaded shortly before the world is
392 * started
393*/
394ErrorMessage World::preStart()
395{
396  this->bPause = false;
397
398  /* update the object position before game start - so there are no wrong coordinates used in the first processing */
399  PNode::getNullParent()->updateNode (0.001f);
400  PNode::getNullParent()->updateNode (0.001f);
401}
402
403
404/**
405 *  starts the World
406 */
407ErrorMessage World::start()
408{
409  this->bQuitWorld = false;
410  this->mainLoop();
411}
412
413/**
414 *  stops the world.
415
416   This happens, when the player decides to end the Level.
417*/
418ErrorMessage World::stop()
419{
420  PRINTF(3)("World::stop() - got stop signal\n");
421  this->bQuitWorld= true;
422}
423
424/**
425 *  pauses the Game
426*/
427ErrorMessage World::pause()
428{
429  this->isPaused = true;
430}
431
432/**
433 *  ends the pause Phase
434*/
435ErrorMessage World::resume()
436{
437  this->isPaused = false;
438}
439
440/**
441 *  destroys the World
442*/
443ErrorMessage World::destroy()
444{
445
446}
447
448/**
449 *  shows the loading screen
450*/
451void World::displayLoadScreen ()
452{
453  PRINTF(3)("World::displayLoadScreen - start\n");
454
455  //GLMenuImageScreen*
456  this->glmis = new GLMenuImageScreen();
457  this->glmis->setMaximum(8);
458
459  PRINTF(3)("World::displayLoadScreen - end\n");
460}
461
462/**
463 * @brief removes the loadscreen, and changes over to the game
464 *
465 * @todo take out the delay
466*/
467void World::releaseLoadScreen ()
468{
469  PRINTF(3)("World::releaseLoadScreen - start\n");
470  this->glmis->setValue(this->glmis->getMaximum());
471  PRINTF(3)("World::releaseLoadScreen - end\n");
472  delete this->glmis;
473}
474
475
476/**
477 *  this returns the current game time
478 * @returns elapsed game time
479*/
480double World::getGameTime()
481{
482  return this->gameTime;
483}
484
485
486
487/**
488 *  synchronize local data with remote data
489*/
490void World::synchronize ()
491{
492  // Get remote input
493  // Update synchronizables
494/*  NetworkManager::getInstance()->synchronize();*/
495}
496
497
498/**
499 *  run all input processing
500
501   the command node is the central input event dispatcher. the node uses the even-queue from
502   sdl and has its own event-passing-queue.
503*/
504void World::handleInput ()
505{
506  EventHandler::getInstance()->process();
507
508  // remoteinput
509}
510
511void World::tick(std::list<WorldEntity*> entityList, float dt)
512{
513  std::list<WorldEntity*>::iterator entity;
514  for (entity = entityList.begin(); entity != entityList.end(); entity++)
515    (*entity)->tick(dt);
516
517}
518
519/**
520 *  advance the timeline
521
522   this calculates the time used to process one frame (with all input handling, drawing, etc)
523   the time is mesured in ms and passed to all world-entities and other classes that need
524   a heart-beat.
525*/
526void World::tick ()
527{
528  Uint32 currentFrame = SDL_GetTicks();
529  if(!this->bPause)
530    {
531      this->dt = currentFrame - this->lastFrame;
532
533      if( this->dt > 10)
534        {
535          float fps = 1000/dt;
536
537          // temporary, only for showing how fast the text-engine is
538          char tmpChar[20];
539          sprintf(tmpChar, "fps: %4.0f", fps);
540        }
541      else
542        {
543          /* the frame-rate is limited to 100 frames per second, all other things are for
544             nothing.
545          */
546          PRINTF(3)("fps = 1000 - frame rate is adjusted\n");
547          SDL_Delay(10-dt);
548          this->dt = 10;
549        }
550
551      this->dtS = (float)this->dt / 1000.0 * this->speed;
552      this->gameTime += this->dtS;
553
554      this->tick(this->objectManager.getObjectList(OM_DEAD_TICK), this->dtS);
555      this->tick(this->objectManager.getObjectList(OM_COMMON), this->dtS);
556      this->tick(this->objectManager.getObjectList(OM_GROUP_00), this->dtS);
557      this->tick(this->objectManager.getObjectList(OM_GROUP_01), this->dtS);
558      this->tick(this->objectManager.getObjectList(OM_GROUP_01_PROJ), this->dtS);
559
560      /* update tick the rest */
561      this->localCamera->tick(this->dtS);
562      // tick the engines
563      AnimationPlayer::getInstance()->tick(this->dtS);
564//      if (this->cycle > 5)
565        PhysicsEngine::getInstance()->tick(this->dtS);
566
567      ParticleEngine::getInstance()->tick(this->dtS);
568
569
570      /** actualy the Graphics Engine should tick the world not the other way around...
571         but since we like the things not too complicated we got it this way around
572         until there is need or time to do it the other way around.
573         @todo: GraphicsEngine ticks world: separation of processes and data...
574
575        bensch: in my opinion the GraphicsEngine could draw the world, but not tick it,
576         beceause graphics have nothing(or at least not much) to do with Motion.
577      */
578      GraphicsEngine::getInstance()->tick(this->dtS);
579    }
580  this->lastFrame = currentFrame;
581}
582
583
584/**
585 *  this function gives the world a consistant state
586
587   after ticking (updating the world state) this will give a constistant
588   state to the whole system.
589*/
590void World::update()
591{
592  GraphicsEngine::getInstance()->update(this->dtS);
593  PNode::getNullParent()->updateNode (this->dtS);
594  SoundEngine::getInstance()->update();
595  //music->update();
596}
597
598
599void World::collide()
600{
601  CDEngine::getInstance()->checkCollisions(this->objectManager.getObjectList(OM_GROUP_00),
602                                            this->objectManager.getObjectList(OM_GROUP_01_PROJ));
603  CDEngine::getInstance()->checkCollisions(this->objectManager.getObjectList(OM_GROUP_01),
604                                            this->objectManager.getObjectList(OM_COMMON));
605}
606
607/**
608 *  render the current frame
609
610   clear all buffers and draw the world
611*/
612void World::display ()
613{
614  // clear buffer
615  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
616  // set camera
617  this->localCamera->apply ();
618  // draw world
619  this->draw();
620  // draw HUD
621  /** @todo draw HUD */
622  // flip buffers
623  GraphicsEngine::swapBuffers();
624  //SDL_Surface* screen = Orxonox::getInstance()->getScreen ();
625  //SDL_Flip (screen);
626}
627
628
629/**
630 *  runs through all entities calling their draw() methods
631 */
632void World::draw ()
633{
634  GraphicsEngine* engine = GraphicsEngine::getInstance();
635  engine->draw(State::getObjectManager()->getObjectList(OM_ENVIRON_NOTICK));
636  engine->draw(State::getObjectManager()->getObjectList(OM_ENVIRON));
637  engine->draw(State::getObjectManager()->getObjectList(OM_COMMON));
638  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_00));
639  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_01));
640  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_01_PROJ));
641
642   if( unlikely( this->showBV))  // to draw the bounding boxes of the objects at level 2 for debug purp
643   {
644     CDEngine* engine = CDEngine::getInstance();
645     engine->drawBV(State::getObjectManager()->getObjectList(OM_ENVIRON_NOTICK));
646     engine->drawBV(State::getObjectManager()->getObjectList(OM_ENVIRON));
647     engine->drawBV(State::getObjectManager()->getObjectList(OM_COMMON));
648     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_00));
649     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_01));
650     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_01_PROJ));
651   }
652
653//   {
654//     if( entity->isVisible() ) entity->draw();
655  //FIXME
656//     entity = iterator->nextElement();
657//   }
658
659  ParticleEngine::getInstance()->draw();
660
661  if (unlikely(this->showPNodes))
662    PNode::getNullParent()->debugDraw(0);
663
664  engine->draw();
665  //TextEngine::getInstance()->draw();
666}
667
668
669/**
670 * \brief main loop of the world: executing all world relevant function
671 *
672 * in this loop we synchronize (if networked), handle input events, give the heart-beat to
673 * all other member-entities of the world (tick to player, enemies etc.), checking for
674 * collisions drawing everything to the screen.
675 */
676void World::mainLoop()
677{
678  this->lastFrame = SDL_GetTicks ();
679  PRINTF(3)("World::mainLoop() - Entering main loop\n");
680
681  while(!this->bQuitWorld) /* @todo implement pause */
682  {
683    ++this->cycle;
684      // Network
685    this->synchronize ();
686      // Process input
687    this->handleInput ();
688    if( this->bQuitWorld)
689      break;
690      // Process time
691    this->tick ();
692      // Process collision
693    this->collide ();
694      // Update the state
695    this->update ();
696      // Draw
697    this->display ();
698  }
699
700  PRINTF(3)("World::mainLoop() - Exiting the main loop\n");
701}
702
703
704
705/**
706 *  add and spawn a new entity to this world
707 * @param entity to be added
708*/
709void World::spawn(WorldEntity* entity)
710{
711//   this->entities->add (entity);
712  entity->postSpawn ();
713}
714
715void World::setPath( const char* name)
716{
717  if (this->path)
718    delete this->path;
719  if (ResourceManager::isFile(name))
720  {
721    this->path = new char[strlen(name)+1];
722    strcpy(this->path, name);
723  }
724  else
725    {
726      this->path = new char[strlen(ResourceManager::getInstance()->getDataDir()) + strlen(name) +1];
727      sprintf(this->path, "%s%s", ResourceManager::getInstance()->getDataDir(), name);
728    }
729}
730
731const char* World::getPath( void)
732{
733  return path;
734}
Note: See TracBrowser for help on using the repository browser.