Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/levelloader/src/story_entities/world.cc @ 3606

Last change on this file since 3606 was 3606, checked in by chris, 19 years ago

orxonox/branches/levelloader: fixed world.cc after trunk remerge

File size: 16.2 KB
Line 
1
2/*
3   orxonox - the future of 3D-vertical-scrollers
4
5   Copyright (C) 2004 orx
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2, or (at your option)
10   any later version.
11
12   ### File Specific:
13   main-programmer: Patrick Boenzli
14   co-programmer: Christian Meyer
15*/
16
17#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD
18
19#include "world.h"
20#include "world_entity.h"
21#include "track_manager.h"
22#include "player.h"
23#include "command_node.h"
24#include "camera.h"
25#include "environment.h"
26#include "primitive.h"
27#include "p_node.h"
28#include "null_parent.h"
29#include "helper_parent.h"
30#include "glmenu_imagescreen.h"
31#include "skysphere.h"
32#include "light.h"
33#include "fontset.h"
34#include "factory.h"
35#include "game_loader.h"
36#include "track_node.h"
37#include "terrain.h"
38
39using namespace std;
40
41CREATE_FACTORY(World);
42
43World::World( TiXmlElement* root)
44{
45        const char *string;
46        char *name;
47        int id;
48
49        PRINTF0("Creating a World\n");
50       
51        // identifier
52        string = grabParameter( root, "identifier");
53        if( string == NULL || sscanf(string, "%d", &id) != 1)
54        {
55                PRINTF0("World is missing a proper 'identifier'\n");
56                this->setStoryID( -1);
57        }
58        else setStoryID( id);
59       
60        // path
61        string = grabParameter( root, "path");
62        if( string == NULL)
63        {
64                PRINTF0("World is missing a proper 'path'\n");
65                this->setPath( NULL);
66        }
67        else
68        {
69                name = new char[strlen(string + 2)];
70                strcpy( name, string);
71                this->setPath( name);
72        }
73       
74        localPlayer = NULL;
75  this->entities = new tList<WorldEntity>();
76               
77}
78
79/**
80    \brief create a new World
81   
82    This creates a new empty world!
83*/
84World::World (char* name)
85{
86  this->init(name, -1);
87  //NullParent* np = NullParent::getInstance();
88}
89
90/**
91   \brief creates a new World...
92   \param worldID with this ID
93*/
94World::World (int worldID)
95{
96  this->init(NULL, worldID);
97}
98
99/**
100    \brief remove the World from memory
101   
102    delete everything explicitly, that isn't contained in the parenting tree!
103    things contained in the tree are deleted automaticaly
104*/
105World::~World ()
106{
107  PRINTF(3)("World::~World() - deleting current world\n");
108  CommandNode* cn = Orxonox::getInstance()->getLocalInput();
109  cn->unbind(this->localPlayer);
110  cn->reset();
111
112  delete this->nullParent;
113  delete this->entities;
114  delete this->lightMan;
115  delete this->trackManager;
116  if( this->worldName) delete this->worldName;
117  if( this->path) delete this->path;
118}
119
120/**
121   \brief initializes a new World
122*/
123void World::init(char* name, int worldID)
124{
125  this->setClassName ("World");
126
127  this->worldName = name;
128  this->debugWorldNr = worldID;
129  this->entities = new tList<WorldEntity>();
130
131  // Enable default GL stuff
132  glEnable(GL_DEPTH_TEST);
133
134}
135
136
137/**
138   \brief loads the World by initializing all resources, and set their default values.
139*/
140ErrorMessage World::load()
141{       
142        PRINTF0("> Loading world: '%s'\n", getPath());
143       
144        GameLoader* loader = GameLoader::getInstance();
145       
146  if( getPath() == NULL)
147  {
148                PRINTF0("World has no path specified for loading");
149                return (ErrorMessage){213,"Path not specified","World::load()"};
150  }
151 
152        TiXmlDocument* XMLDoc = new TiXmlDocument( path);
153        // load the campaign document
154        if( !XMLDoc->LoadFile())
155
156        {
157                // report an error
158                PRINTF0("Error loading XML File: %s @ %d:%d\n", XMLDoc->ErrorDesc(), XMLDoc->ErrorRow(), XMLDoc->ErrorCol());
159                delete XMLDoc;
160                return (ErrorMessage){213,"XML File parsing error","World::load()"};
161        }
162       
163        // check basic validity
164        TiXmlElement* root = XMLDoc->RootElement();
165        assert( root != NULL);
166       
167        if( root == NULL || root->Value() == NULL || strcmp( root->Value(), "WorldDataFile"))
168        {
169                // report an error
170                PRINTF0("Specified XML File is not an orxonox world data file (WorldDataFile element missing)\n");
171                delete XMLDoc;
172                return (ErrorMessage){213,"Path not a WorldDataFile","World::load()"};
173        }
174       
175        // load the parameters
176                // name
177        char* temp;
178        const char* string = grabParameter( root, "name");
179        if( string == NULL)
180        {
181                PRINTF0("World is missing a proper 'name'\n");
182                string = "Unknown";
183                temp = new char[strlen(string + 2)];
184                strcpy( temp, string);
185                this->worldName = temp;
186        }
187        else
188        {
189                temp = new char[strlen(string + 2)];
190                strcpy( temp, string);
191                this->worldName = temp;
192        }
193       
194       
195        // find WorldEntities
196  TiXmlElement* element = root->FirstChildElement( "WorldEntities");
197 
198  if( element == NULL)
199  {
200                PRINTF0("World is missing 'WorldEntities'\n");
201  }
202  else
203  {
204        element = element->FirstChildElement();
205          // load Players/Objects/Whatever
206                PRINTF0("Loading WorldEntities\n");
207                while( element != NULL)
208                {
209                        WorldEntity* created = (WorldEntity*) loader->fabricate( element);
210                        if( created != NULL) this->spawn( created);
211                                // if we load a 'Player' we use it as localPlayer
212                                //todo do this more elegant
213                         if( element->Value() != NULL && !strcmp( element->Value(), "Player")) localPlayer = (Player*) created;
214                        element = element->NextSiblingElement();
215                }
216                PRINTF0("Done loading WorldEntities\n");
217        }
218       
219        // find Track
220  element = root->FirstChildElement( "Track");
221  if( element == NULL)
222  {
223                PRINTF0("World is missing a 'Track'\n");
224  }
225  else
226  {     
227        //load track
228                PRINTF0("Loading Track\n");
229                trackManager = TrackManager::getInstance();
230        trackManager->loadTrack( element);
231        trackManager->finalize();
232                PRINTF0("Done loading Track\n");
233        }
234       
235        // free the XML data
236        delete XMLDoc;
237       
238        // finalize world
239          // initialize Font
240          testFont = new FontSet();
241          testFont->buildFont("../data/pictures/font.tga");
242       
243                // create null parent
244    this->nullParent = NullParent::getInstance ();
245    this->nullParent->setName ("NullParent");
246   
247    // finalize myPlayer
248                if( localPlayer == NULL)
249                {
250                        PRINTF0("No Player specified in World '%s'\n", this->worldName);
251                        return (ErrorMessage){213,"No Player defined","World::load()"};
252                }
253               
254        // bind input
255    Orxonox *orx = Orxonox::getInstance ();
256    orx->getLocalInput()->bind (localPlayer);
257   
258        // bind camera
259    this->localCamera = new Camera(this);
260    this->localCamera->setName ("camera");
261    this->localCamera->bind (localPlayer);
262    this->localPlayer->addChild (this->localCamera);
263
264       
265        // stuff beyond this point remains to be loaded properly
266       
267      /*monitor progress*/
268  //  this->glmis->step();
269
270            // Create SkySphere
271            this->skySphere = new Skysphere("../data/pictures/sky-replace.jpg");
272            this->skySphere->setName("SkySphere");
273            this->localCamera->addChild(this->skySphere);
274            this->skySphere->setMode(PNODE_MOVEMENT);
275
276            /*monitor progress*/
277          //  this->glmis->step();
278         
279          //  trackManager->setBindSlave(env);
280
281  // initialize debug coord system
282  objectList = glGenLists(1);
283  glNewList (objectList, GL_COMPILE);
284 
285  trackManager->drawGraph(.01);
286  trackManager->debug(2);
287  glEndList();
288
289  terrain = new Terrain("../data/worlds/newGround.obj");
290  terrain->setRelCoor(new Vector(0,-10,0));
291  this->spawn(terrain);
292
293}
294
295/**
296   \brief initializes a new World
297*/
298ErrorMessage World::init()
299{
300  this->bPause = false;
301  CommandNode* cn = Orxonox::getInstance()->getLocalInput();
302  cn->addToWorld(this);
303  cn->enable(true);
304
305PRINTF0("> Done Loading world: '%s'\n", getPath());
306}
307
308
309/**
310   \brief starts the World
311*/
312ErrorMessage World::start()
313{
314  PRINTF(3)("World::start() - starting current World: nr %i\n", this->debugWorldNr);
315  this->bQuitOrxonox = false;
316  this->bQuitCurrentGame = false;
317  this->mainLoop();
318}
319
320/**
321   \brief stops the world.
322
323   This happens, when the player decides to end the Level.
324*/
325ErrorMessage World::stop()
326{
327  PRINTF(3)("World::stop() - got stop signal\n");
328  this->bQuitCurrentGame = true;
329}
330
331/**
332   \brief pauses the Game
333*/
334ErrorMessage World::pause()
335{
336  this->isPaused = true;
337}
338
339/**
340   \brief ends the pause Phase
341*/
342ErrorMessage World::resume()
343{
344  this->isPaused = false;
345}
346
347/**
348   \brief destroys the World
349*/
350ErrorMessage World::destroy()
351{
352
353}
354
355/**
356   \brief shows the loading screen
357*/
358void World::displayLoadScreen ()
359{
360  PRINTF(3)("World::displayLoadScreen - start\n"); 
361 
362  //GLMenuImageScreen*
363  this->glmis = GLMenuImageScreen::getInstance();
364  this->glmis->init();
365  this->glmis->setMaximum(10);
366  this->glmis->draw();
367 
368  PRINTF(3)("World::displayLoadScreen - end\n"); 
369}
370
371/**
372   \brief removes the loadscreen, and changes over to the game
373
374   \todo take out the delay
375*/
376void World::releaseLoadScreen ()
377{
378  PRINTF(3)("World::releaseLoadScreen - start\n"); 
379  this->glmis->setValue(this->glmis->getMaximum());
380  SDL_Delay(500);
381  PRINTF(3)("World::releaseLoadScreen - end\n"); 
382}
383
384
385/**
386    \brief checks for collisions
387   
388    This method runs through all WorldEntities known to the world and checks for collisions
389    between them. In case of collisions the collide() method of the corresponding entities
390    is called.
391*/
392void World::collide ()
393{
394  /*
395  List *a, *b;
396  WorldEntity *aobj, *bobj;
397   
398  a = entities;
399 
400  while( a != NULL)
401    {
402      aobj = a->nextElement();
403      if( aobj->bCollide && aobj->collisioncluster != NULL)
404        {
405          b = a->nextElement();
406          while( b != NULL )
407            {
408              bobj = b->nextElement();
409              if( bobj->bCollide && bobj->collisioncluster != NULL )
410                {
411                  unsigned long ahitflg, bhitflg;
412                  if( check_collision ( &aobj->place, aobj->collisioncluster,
413                                        &ahitflg, &bobj->place, bobj->collisioncluster,
414                                        &bhitflg) );
415                  {
416                    aobj->collide (bobj, ahitflg, bhitflg);
417                    bobj->collide (aobj, bhitflg, ahitflg);
418                  }
419                }
420              b = b->nextElement();
421            }
422        }
423      a = a->enumerate();
424    }
425  */
426}
427
428/**
429    \brief runs through all entities calling their draw() methods
430*/
431void World::draw ()
432{
433  /* draw entities */
434  WorldEntity* entity;
435  glLoadIdentity();
436
437  entity = this->entities->enumerate();
438  while( entity != NULL ) 
439    { 
440      if( entity->bDraw ) entity->draw();
441      entity = this->entities->nextElement();
442    } 
443 
444  glCallList (objectList);
445  //! \todo skysphere is a WorldEntity and should be inside of the world-entity-list.
446  skySphere->draw();
447
448  testFont->printText(0, 0, 1, "orxonox_" PACKAGE_VERSION);
449
450  lightMan->draw(); // must be at the end of the drawing procedure, otherwise Light cannot be handled as PNodes //
451}
452
453
454/**
455   \brief function to put your own debug stuff into it. it can display informations about
456   the current class/procedure
457*/
458void World::debug()
459{
460  PRINTF(2)("debug() - starting debug\n");
461  PNode* p1 = NullParent::getInstance ();
462  PNode* p2 = new PNode (new Vector(2, 2, 2), p1);
463  PNode* p3 = new PNode (new Vector(4, 4, 4), p1);
464  PNode* p4 = new PNode (new Vector(6, 6, 6), p2);
465
466  p1->debug ();
467  p2->debug ();
468  p3->debug ();
469  p4->debug ();
470
471  p1->shiftCoor (new Vector(-1, -1, -1));
472
473  printf("World::debug() - shift\n");
474  p1->debug ();
475  p2->debug ();
476  p3->debug ();
477  p4->debug ();
478 
479  p1->update ();
480
481  printf ("World::debug() - update\n");
482  p1->debug ();
483  p2->debug ();
484  p3->debug ();
485  p4->debug ();
486
487  p2->shiftCoor (new Vector(-1, -1, -1));
488  p1->update ();
489
490  p1->debug ();
491  p2->debug ();
492  p3->debug ();
493  p4->debug ();
494
495  p2->setAbsCoor (new Vector(1,2,3));
496
497
498 p1->update ();
499
500  p1->debug ();
501  p2->debug ();
502  p3->debug ();
503  p4->debug ();
504
505  delete p1;
506 
507 
508  /*
509  WorldEntity* entity;
510  printf("counting all entities\n");
511  printf("World::debug() - enumerate()\n");
512  entity = entities->enumerate(); 
513  while( entity != NULL )
514    {
515      if( entity->bDraw ) printf("got an entity\n");
516      entity = entities->nextElement();
517    }
518  */
519}
520
521
522/**
523  \brief main loop of the world: executing all world relevant function
524
525  in this loop we synchronize (if networked), handle input events, give the heart-beat to
526  all other member-entities of the world (tick to player, enemies etc.), checking for
527  collisions drawing everything to the screen.
528*/
529void World::mainLoop()
530{
531  this->lastFrame = SDL_GetTicks ();
532  printf("World::mainLoop() - Entering main loop of '%s'\n", this->worldName);
533  while( !this->bQuitOrxonox && !this->bQuitCurrentGame) /* \todo implement pause */
534    {
535      PRINTF(3)("World::mainloop() - number of entities: %i\n", this->entities->getSize());
536      // Network
537      this->synchronize ();
538      // Process input
539      this->handleInput ();
540      if( this->bQuitCurrentGame || this->bQuitOrxonox)
541          break;
542      // Process time
543      this->tick ();
544      // Update the state
545      this->update ();     
546      // Process collision
547     this->collide ();
548      // Draw
549     this->display ();
550
551      //      for( int i = 0; i < 5000000; i++) {}
552      /* \todo this is to slow down the program for openGl Software emulator computers, reimplement*/
553    }
554  PRINTF(3)("World::mainLoop() - Exiting the main loop\n");
555}
556
557
558/**
559   \brief synchronize local data with remote data
560*/
561void World::synchronize ()
562{
563  // Get remote input
564  // Update synchronizables
565}
566
567
568/**
569   \brief run all input processing
570
571   the command node is the central input event dispatcher. the node uses the even-queue from
572   sdl and has its own event-passing-queue.
573*/
574void World::handleInput ()
575{
576  // localinput
577  CommandNode* cn = Orxonox::getInstance()->getLocalInput();
578  cn->process();
579  // remoteinput
580}
581
582
583/**
584   \brief advance the timeline
585
586   this calculates the time used to process one frame (with all input handling, drawing, etc)
587   the time is mesured in ms and passed to all world-entities and other classes that need
588   a heart-beat.
589*/
590void World::tick ()
591{
592  Uint32 currentFrame = SDL_GetTicks();
593  if(!this->bPause)
594    {
595      Uint32 dt = currentFrame - this->lastFrame;
596     
597      if(dt > 0)
598        {
599          float fps = 1000/dt;
600          PRINTF(3)("fps = %f\n", fps);
601        }
602      else
603        {
604          /* the frame-rate is limited to 100 frames per second, all other things are for
605             nothing.
606          */
607          PRINTF(2)("fps = 1000 - frame rate is adjusted\n");
608          SDL_Delay(10);
609          dt = 10;
610        }
611      //this->timeSlice (dt);
612     
613      /* function to let all entities tick (iterate through list) */
614      WorldEntity* entity;
615      float seconds = dt / 1000.0; 
616      assert( this->nullParent != NULL); 
617      entity = entities->enumerate(); 
618      while( entity != NULL) 
619        { 
620          entity->tick (seconds);
621          entity = entities->nextElement();
622        }
623      /* update tick the rest */
624      assert( this->localCamera != NULL); 
625      assert( this->trackManager != NULL); 
626      this->localCamera->tick(dt);
627
628      this->trackManager->tick(dt);
629    }
630  this->lastFrame = currentFrame;
631}
632
633
634/**
635   \brief this function gives the world a consistant state
636
637   after ticking (updating the world state) this will give a constistant
638   state to the whole system.
639*/
640void World::update()
641{
642  this->nullParent->update ();
643}
644
645
646/**
647   \brief render the current frame
648   
649   clear all buffers and draw the world
650*/
651void World::display ()
652{
653  // clear buffer
654  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
655  // set camera
656  this->localCamera->apply ();
657  // draw world
658  this->draw();
659  // draw HUD
660  /* \todo draw HUD */
661  // flip buffers
662  SDL_GL_SwapBuffers();
663  //SDL_Surface* screen = Orxonox::getInstance()->getScreen ();
664  //SDL_Flip (screen);
665}
666
667
668/**
669   \brief add and spawn a new entity to this world
670   \param entity to be added
671*/
672void World::spawn(WorldEntity* entity)
673{
674  this->entities->add (entity);
675  entity->postSpawn ();
676}
677
678
679/**
680   \brief add and spawn a new entity to this world
681   \param entity to be added
682   \param absCoor At what coordinates to add this entity.
683   \param absDir In which direction should it look.
684*/
685void World::spawn(WorldEntity* entity, Vector* absCoor, Quaternion* absDir)
686{
687  this->entities->add (entity);
688
689  entity->setAbsCoor (absCoor);
690  entity->setAbsDir (absDir);
691
692  entity->postSpawn ();
693}
694
695
696/**
697   \brief add and spawn a new entity to this world
698   \param entity to be added
699   \param entity to be added to (PNode)
700   \param At what relative  coordinates to add this entity.
701   \param In which relative direction should it look.
702*/
703void World::spawn(WorldEntity* entity, PNode* parentNode, 
704                  Vector* relCoor, Quaternion* relDir, 
705                  int parentingMode)
706{
707  this->nullParent = NullParent::getInstance();
708  if( parentNode != NULL)
709    {
710      parentNode->addChild (entity);
711     
712      entity->setRelCoor (relCoor);
713      entity->setRelDir (relDir);
714      entity->setMode(parentingMode);
715     
716      this->entities->add (entity);
717     
718      entity->postSpawn ();
719    }
720}
721
722
723
724/**
725  \brief commands that the world must catch
726  \returns false if not used by the world
727*/
728bool World::command(Command* cmd)
729{
730  return false;
731}
732
733void World::setPath( char* name)
734{
735        path = name;
736}
737
738char* World::getPath()
739{
740        return path;
741}
Note: See TracBrowser for help on using the repository browser.