Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6177 was 6155, checked in by bensch, 19 years ago

typo

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