Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 3629 was 3629, checked in by patrick, 19 years ago

orxonox/trunk: some changes in the storyentity framework: added a preLoad() function, since there is some stuff to be initialized before load(). written some comments to level loading doxygen stuff. now the worldinterface works

File size: 20.4 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
21#include "orxonox.h"
22
23#include "p_node.h"
24#include "null_parent.h"
25#include "helper_parent.h"
26#include "track_node.h"
27#include "world_entity.h"
28#include "track_manager.h"
29#include "player.h"
30#include "camera.h"
31#include "environment.h"
32#include "primitive.h"
33#include "skysphere.h"
34#include "terrain.h"
35#include "light.h"
36
37#include "command_node.h"
38#include "glmenu_imagescreen.h"
39#include "fontset.h"
40#include "list.h"
41
42
43
44using namespace std;
45
46
47WorldInterface* WorldInterface::singletonRef = 0;
48
49
50/**
51   \brief private constructor because of singleton
52*/
53WorldInterface::WorldInterface()
54{
55  this->worldIsInitialized = false;
56  this->worldReference = NULL;
57}
58
59/**
60   \brief public deconstructor
61*/
62WorldInterface::~WorldInterface()
63{
64  this->singletonRef = NULL;
65  this->worldIsInitialized = false;
66  this->worldReference = NULL;
67}
68
69/**
70   \brief gets the singleton instance
71   \returns singleton instance
72*/
73WorldInterface* WorldInterface::getInstance()
74{
75  if( singletonRef == NULL)
76    singletonRef = new WorldInterface();
77  return singletonRef;
78}
79
80
81/**
82   \brief initializes the interface
83   \param reference to the world
84
85   if the worldinterface is not initilizes, there wont be any
86   useable interface
87*/
88void WorldInterface::init(World* world)
89{
90  this->worldReference = world;
91  if( world != NULL)
92    {
93      this->worldIsInitialized = true;
94      PRINTF(3)("WorldInterface up and running\n");
95    }
96}
97
98
99/**
100   \brief gets the entity list from the world
101   \return entity list
102*/
103tList<WorldEntity>* WorldInterface::getEntityList()
104{
105  if( this->worldIsInitialized)
106    return this->worldReference->getEntities();
107  PRINT(1)("Someone tried to use the WorldInterface before it has been initizlized! this can result in SEGFAULTs!\n");
108  return NULL;
109}
110
111
112
113/**
114    \brief create a new World
115   
116    This creates a new empty world!
117*/
118World::World (char* name)
119{
120  this->init(name, -1);
121  //NullParent* np = NullParent::getInstance();
122}
123
124/**
125   \brief creates a new World...
126   \param worldID with this ID
127*/
128World::World (int worldID)
129{
130  printf(">>>>>>>>>>>>>>>>>WORLD::WORLD called NEW WORLD created\n");
131  this->init(NULL, worldID);
132}
133
134/**
135    \brief remove the World from memory
136   
137    delete everything explicitly, that isn't contained in the parenting tree!
138    things contained in the tree are deleted automaticaly
139*/
140World::~World ()
141{
142  PRINTF(3)("World::~World() - deleting current world\n");
143  CommandNode* cn = Orxonox::getInstance()->getLocalInput();
144  cn->unbind(this->localPlayer);
145  cn->reset();
146
147  delete WorldInterface::getInstance();
148
149  delete this->nullParent;
150  delete this->entities;
151  delete this->lightMan;
152  delete this->trackManager;
153}
154
155/**
156   \brief initializes the world.
157
158   set all stuff here that is world generic and does not use to much memory
159   because the real init() function StoryEntity::init() will be called
160   shortly before start of the game. 
161   since all worlds are initiated/referenced before they will be started.
162   NO LEVEL LOADING HERE - NEVER!
163*/
164void World::init(char* name, int worldID)
165{
166  this->setClassName ("World");
167
168  this->worldName = "Just a test level";
169  this->debugWorldNr = worldID;
170  this->entities = new tList<WorldEntity>();
171}
172
173
174/**
175   \brief this is executed before load
176
177   since the load function sometimes needs data, that has been init before
178   the load and after the proceeding storyentity has finished
179*/
180ErrorMessage World::preLoad()
181{
182  /* init the world interface */
183  WorldInterface* wi = WorldInterface::getInstance();
184  wi->init(this);
185}
186
187
188/**
189   \brief loads the World by initializing all resources, and set their default values.
190*/
191ErrorMessage World::load()
192{
193  //  BezierCurve* tmpCurve = new BezierCurve();
194  if(this->debugWorldNr != -1)
195    {
196      // initializing Font
197      testFont = new FontSet();
198      testFont->buildFont("../data/pictures/font.tga");
199
200      // initializing the TrackManager
201      trackManager = TrackManager::getInstance();
202      trackManager->addPoint(Vector(0,0,0));
203      trackManager->addPoint(Vector(100, -40, 5));
204      trackManager->addPoint(Vector(200,-40,-8));
205      trackManager->addPoint(Vector(250, -35, -2));
206      trackManager->addPoint(Vector(320,-33,-.55));
207      trackManager->setDuration(1);
208      trackManager->setSavePoint();
209      trackManager->addPoint(Vector(410, 0, 0));
210      trackManager->addPoint(Vector(510, 20, -10));
211      trackManager->addPoint(Vector(550, 20, -10));
212      trackManager->addPoint(Vector(570, 20, -10));
213      trackManager->setDuration(1);
214     
215      int fork11, fork12;
216      trackManager->fork(2, &fork11, &fork12);
217      trackManager->workOn(fork11);
218      trackManager->addPoint(Vector(640, 25, -30));
219      trackManager->addPoint(Vector(700, 40, -120));
220      trackManager->addPoint(Vector(800, 50, -150));
221      trackManager->addPoint(Vector(900, 60, -100));
222      trackManager->addPoint(Vector(900, 60, -70));
223      trackManager->addPoint(Vector(990, 65, -15));
224      trackManager->addPoint(Vector(1050, 65, -10));
225      trackManager->addPoint(Vector(1100, 65, -20));
226      trackManager->setDuration(4);
227
228      trackManager->workOn(fork12);
229      trackManager->addPoint(Vector(640, 25, 20));
230      trackManager->addPoint(Vector(670, 50, 120));
231      trackManager->addPoint(Vector(700, 70, 80));
232      trackManager->addPoint(Vector(800, 70, 65));
233      trackManager->addPoint(Vector(850, 65, 65));
234      trackManager->addPoint(Vector(920, 35, 40));
235      trackManager->addPoint(Vector(945, 40, 40));
236      trackManager->addPoint(Vector(970, 24, 40));
237      trackManager->addPoint(Vector(1000, 40, -7));
238      trackManager->setDuration(4);
239     
240
241      trackManager->join(2, fork11, fork12);
242
243      trackManager->workOn(5);
244      trackManager->addPoint(Vector(1200, 60, -50));
245      trackManager->addPoint(Vector(1300, 50, -50));
246      trackManager->addPoint(Vector(1400, 40, -50));
247      trackManager->addPoint(Vector(1500, 40, -60));
248      trackManager->addPoint(Vector(1600, 35, -55));
249      trackManager->addPoint(Vector(1700, 45, -40));
250      trackManager->addPoint(Vector(1750, 60, -40));
251      trackManager->addPoint(Vector(1770, 80, -40));
252      trackManager->addPoint(Vector(1800, 100, -40));
253      trackManager->setDuration(4);
254
255      trackManager->finalize();
256
257     
258      /*monitor progress*/
259      this->glmis->step();
260
261      // LIGHT initialisation
262      lightMan = LightManager::getInstance();
263      lightMan->setAmbientColor(.1,.1,.1);
264      lightMan->addLight();
265      //      lightMan->setAttenuation(1.0, .01, 0.0);
266      //      lightMan->setDiffuseColor(1,1,1);
267      //  lightMan->addLight(1);
268      //  lightMan->setPosition(20, 10, -20);
269      //  lightMan->setDiffuseColor(0,0,0);
270      lightMan->debug();
271
272      switch(this->debugWorldNr)
273        {
274          /*
275            this loads the hard-coded debug world. this only for simplicity and will be
276            removed by a reald world-loader, which interprets a world-file.
277            if you want to add an own debug world, just add a case DEBUG_WORLD_[nr] and
278            make whatever you want...
279           */
280        case DEBUG_WORLD_0:
281          {
282            lightMan->setPosition(-5.0, 10.0, -40.0);
283            this->nullParent = NullParent::getInstance ();
284            this->nullParent->setName ("NullParent");
285
286            // !\todo old track-system has to be removed
287
288            //create helper for player
289            //HelperParent* hp = new HelperParent ();
290            /* the player has to be added to this helper */
291
292            // create a player
293            this->localPlayer = new Player ();
294            this->localPlayer->setName ("player");
295            this->spawn (this->localPlayer);
296            /*monitor progress*/
297            this->glmis->step();           
298
299            // bind input
300            Orxonox *orx = Orxonox::getInstance ();
301            orx->getLocalInput()->bind (this->localPlayer);
302           
303            // bind camera
304            this->localCamera = new Camera(this);
305            this->localCamera->setName ("camera");
306            this->localCamera->bind (this->localPlayer);
307            /*monitor progress*/
308            this->glmis->step();           
309
310            // Create SkySphere
311            this->skySphere = new Skysphere("../data/pictures/sky-replace.jpg");
312            this->skySphere->setName("SkySphere");
313            this->localCamera->addChild(this->skySphere);
314            this->skySphere->setMode(PNODE_MOVEMENT);
315
316            /*monitor progress*/
317            this->glmis->step();
318
319           
320            WorldEntity* env = new Environment();
321            env->setName ("env");
322            this->spawn(env);
323
324           
325            Vector* es = new Vector (10, 5, 0);
326            Quaternion* qs = new Quaternion ();
327            WorldEntity* pr = new Primitive(P_CYLINDER);
328            pr->setName("primitive");
329            this->spawn(pr, this->localPlayer, es, qs, PNODE_MOVEMENT);
330           
331
332            /*monitor progress*/
333            this->glmis->step();
334
335            //      trackManager->setBindSlave(env);
336            PNode* tn = trackManager->getTrackNode();
337            tn->addChild(this->localPlayer);
338
339            //localCamera->setParent(TrackNode::getInstance());
340            tn->addChild (this->localCamera);
341            this->localPlayer->setMode(PNODE_ROTATE_AND_MOVE);
342            //Vector* cameraOffset = new Vector (0, 5, -10);
343            Vector* cameraOffset = new Vector (-10, 5, 0);
344            this->localCamera->setRelCoor (cameraOffset);
345            trackManager->condition(2, LEFTRIGHT, this->localPlayer);
346
347            break;
348          }
349        case DEBUG_WORLD_1:
350          {
351            lightMan->setPosition(.0, .0, .0);
352            lightMan->setAttenuation(1.0, .01, 0.0);
353            lightMan->setSpecularColor(1,0,0);
354            this->nullParent = NullParent::getInstance ();
355            this->nullParent->setName ("NullParent");
356
357            // create a player
358            WorldEntity* myPlayer = new Player();
359            myPlayer->setName ("player");
360            this->spawn(myPlayer);
361            this->localPlayer = myPlayer;           
362           
363            // bind input
364            Orxonox *orx = Orxonox::getInstance();
365            orx->getLocalInput()->bind (myPlayer);
366           
367            // bind camera
368            this->localCamera = new Camera (this);
369            this->localCamera->setName ("camera");
370            this->localCamera->bind (myPlayer); 
371            this->localPlayer->addChild (this->localCamera);
372
373            // Create SkySphere
374            skySphere = new Skysphere("../data/pictures/sky-replace.jpg");
375            this->localPlayer->addChild(this->skySphere);
376
377            Vector* es = new Vector (20, 0, 0);
378            Quaternion* qs = new Quaternion ();
379            WorldEntity* pr = new Primitive(P_SPHERE);
380            pr->setName("primitive");
381            this->spawn(pr, this->localPlayer, es, qs, PNODE_ROTATE_AND_MOVE);
382
383            lightMan->getLight(0)->setParent(trackManager->getTrackNode());
384            break;
385          }
386        default:
387          printf("World::load() - no world with ID %i found", this->debugWorldNr );
388        }
389    }
390  else if(this->worldName != NULL)
391    {
392
393    }
394
395  // initialize debug coord system
396  objectList = glGenLists(1);
397  glNewList (objectList, GL_COMPILE);
398 
399  trackManager->drawGraph(.01);
400  trackManager->debug(2);
401  glEndList();
402
403  terrain = new Terrain("../data/worlds/newGround.obj");
404  terrain->setRelCoor(new Vector(0,-10,0));
405  this->spawn(terrain);
406
407}
408
409
410/**
411   \brief initializes a new World shortly before start
412
413   this is the function, that will be loaded shortly before the world is
414   started
415*/
416ErrorMessage World::init()
417{
418  this->bPause = false;
419  CommandNode* cn = Orxonox::getInstance()->getLocalInput();
420  cn->addToWorld(this);
421  cn->enable(true);
422}
423
424
425/**
426   \brief starts the World
427*/
428ErrorMessage World::start()
429{
430  PRINTF(3)("World::start() - starting current World: nr %i\n", this->debugWorldNr);
431  this->bQuitOrxonox = false;
432  this->bQuitCurrentGame = false;
433  this->mainLoop();
434}
435
436/**
437   \brief stops the world.
438
439   This happens, when the player decides to end the Level.
440*/
441ErrorMessage World::stop()
442{
443  PRINTF(3)("World::stop() - got stop signal\n");
444  this->bQuitCurrentGame = true;
445}
446
447/**
448   \brief pauses the Game
449*/
450ErrorMessage World::pause()
451{
452  this->isPaused = true;
453}
454
455/**
456   \brief ends the pause Phase
457*/
458ErrorMessage World::resume()
459{
460  this->isPaused = false;
461}
462
463/**
464   \brief destroys the World
465*/
466ErrorMessage World::destroy()
467{
468
469}
470
471/**
472   \brief shows the loading screen
473*/
474void World::displayLoadScreen ()
475{
476  PRINTF(3)("World::displayLoadScreen - start\n"); 
477 
478  //GLMenuImageScreen*
479  this->glmis = GLMenuImageScreen::getInstance();
480  this->glmis->init();
481  this->glmis->setMaximum(10);
482  this->glmis->draw();
483 
484  PRINTF(3)("World::displayLoadScreen - end\n"); 
485}
486
487/**
488   \brief removes the loadscreen, and changes over to the game
489
490   \todo take out the delay
491*/
492void World::releaseLoadScreen ()
493{
494  PRINTF(3)("World::releaseLoadScreen - start\n"); 
495  this->glmis->setValue(this->glmis->getMaximum());
496  SDL_Delay(500);
497  PRINTF(3)("World::releaseLoadScreen - end\n"); 
498}
499
500
501/**
502   \brief gets the list of entities from the world
503   \returns entity list
504*/
505tList<WorldEntity>* World::getEntities()
506{
507  return this->entities;
508}
509
510
511/**
512    \brief checks for collisions
513   
514    This method runs through all WorldEntities known to the world and checks for collisions
515    between them. In case of collisions the collide() method of the corresponding entities
516    is called.
517*/
518void World::collide ()
519{
520  /*
521  List *a, *b;
522  WorldEntity *aobj, *bobj;
523   
524  a = entities;
525 
526  while( a != NULL)
527    {
528      aobj = a->nextElement();
529      if( aobj->bCollide && aobj->collisioncluster != NULL)
530        {
531          b = a->nextElement();
532          while( b != NULL )
533            {
534              bobj = b->nextElement();
535              if( bobj->bCollide && bobj->collisioncluster != NULL )
536                {
537                  unsigned long ahitflg, bhitflg;
538                  if( check_collision ( &aobj->place, aobj->collisioncluster,
539                                        &ahitflg, &bobj->place, bobj->collisioncluster,
540                                        &bhitflg) );
541                  {
542                    aobj->collide (bobj, ahitflg, bhitflg);
543                    bobj->collide (aobj, bhitflg, ahitflg);
544                  }
545                }
546              b = b->nextElement();
547            }
548        }
549      a = a->enumerate();
550    }
551  */
552}
553
554/**
555    \brief runs through all entities calling their draw() methods
556*/
557void World::draw ()
558{
559  /* draw entities */
560  WorldEntity* entity;
561  glLoadIdentity();
562
563  entity = this->entities->enumerate();
564  while( entity != NULL ) 
565    { 
566      if( entity->bDraw ) entity->draw();
567      entity = this->entities->nextElement();
568    } 
569 
570  glCallList (objectList);
571  //! \todo skysphere is a WorldEntity and should be inside of the world-entity-list.
572  skySphere->draw();
573
574  testFont->printText(0, 0, 1, "orxonox_" PACKAGE_VERSION);
575
576  lightMan->draw(); // must be at the end of the drawing procedure, otherwise Light cannot be handled as PNodes //
577}
578
579
580/**
581   \brief function to put your own debug stuff into it. it can display informations about
582   the current class/procedure
583*/
584void World::debug()
585{
586  PRINTF(2)("debug() - starting debug\n");
587  PNode* p1 = NullParent::getInstance ();
588  PNode* p2 = new PNode (new Vector(2, 2, 2), p1);
589  PNode* p3 = new PNode (new Vector(4, 4, 4), p1);
590  PNode* p4 = new PNode (new Vector(6, 6, 6), p2);
591
592  p1->debug ();
593  p2->debug ();
594  p3->debug ();
595  p4->debug ();
596
597  p1->shiftCoor (new Vector(-1, -1, -1));
598
599  printf("World::debug() - shift\n");
600  p1->debug ();
601  p2->debug ();
602  p3->debug ();
603  p4->debug ();
604 
605  p1->update ();
606
607  printf ("World::debug() - update\n");
608  p1->debug ();
609  p2->debug ();
610  p3->debug ();
611  p4->debug ();
612
613  p2->shiftCoor (new Vector(-1, -1, -1));
614  p1->update ();
615
616  p1->debug ();
617  p2->debug ();
618  p3->debug ();
619  p4->debug ();
620
621  p2->setAbsCoor (new Vector(1,2,3));
622
623
624 p1->update ();
625
626  p1->debug ();
627  p2->debug ();
628  p3->debug ();
629  p4->debug ();
630
631  delete p1;
632 
633 
634  /*
635  WorldEntity* entity;
636  printf("counting all entities\n");
637  printf("World::debug() - enumerate()\n");
638  entity = entities->enumerate(); 
639  while( entity != NULL )
640    {
641      if( entity->bDraw ) printf("got an entity\n");
642      entity = entities->nextElement();
643    }
644  */
645}
646
647
648/**
649  \brief main loop of the world: executing all world relevant function
650
651  in this loop we synchronize (if networked), handle input events, give the heart-beat to
652  all other member-entities of the world (tick to player, enemies etc.), checking for
653  collisions drawing everything to the screen.
654*/
655void World::mainLoop()
656{
657  this->lastFrame = SDL_GetTicks ();
658  PRINTF(3)("World::mainLoop() - Entering main loop\n");
659  while( !this->bQuitOrxonox && !this->bQuitCurrentGame) /* \todo implement pause */
660    {
661      PRINTF(3)("World::mainloop() - number of entities: %i\n", this->entities->getSize());
662      // Network
663      this->synchronize ();
664      // Process input
665      this->handleInput ();
666      if( this->bQuitCurrentGame || this->bQuitOrxonox)
667          break;
668      // Process time
669      this->tick ();
670      // Update the state
671      this->update ();     
672      // Process collision
673      this->collide ();
674      // Draw
675      this->display ();
676
677      //      for( int i = 0; i < 5000000; i++) {}
678      /* \todo this is to slow down the program for openGl Software emulator computers, reimplement*/
679    }
680  PRINTF(3)("World::mainLoop() - Exiting the main loop\n");
681}
682
683
684/**
685   \brief synchronize local data with remote data
686*/
687void World::synchronize ()
688{
689  // Get remote input
690  // Update synchronizables
691}
692
693
694/**
695   \brief run all input processing
696
697   the command node is the central input event dispatcher. the node uses the even-queue from
698   sdl and has its own event-passing-queue.
699*/
700void World::handleInput ()
701{
702  // localinput
703  CommandNode* cn = Orxonox::getInstance()->getLocalInput();
704  cn->process();
705  // remoteinput
706}
707
708
709/**
710   \brief advance the timeline
711
712   this calculates the time used to process one frame (with all input handling, drawing, etc)
713   the time is mesured in ms and passed to all world-entities and other classes that need
714   a heart-beat.
715*/
716void World::tick ()
717{
718  Uint32 currentFrame = SDL_GetTicks();
719  if(!this->bPause)
720    {
721      Uint32 dt = currentFrame - this->lastFrame;
722     
723      if(dt > 0)
724        {
725          float fps = 1000/dt;
726          PRINTF(3)("fps = %f\n", fps);
727        }
728      else
729        {
730          /* the frame-rate is limited to 100 frames per second, all other things are for
731             nothing.
732          */
733          PRINTF(2)("fps = 1000 - frame rate is adjusted\n");
734          SDL_Delay(10);
735          dt = 10;
736        }
737      //this->timeSlice (dt);
738     
739      /* function to let all entities tick (iterate through list) */
740      WorldEntity* entity;
741      float seconds = dt / 1000.0;     
742      entity = entities->enumerate(); 
743      while( entity != NULL) 
744        { 
745          entity->tick (seconds);
746          entity = entities->nextElement();
747        }
748      //skySphere->updatePosition(localCamera->absCoordinate);
749     
750      /* update tick the rest */
751      this->localCamera->tick(dt);
752      this->trackManager->tick(dt);
753    }
754  this->lastFrame = currentFrame;
755}
756
757
758/**
759   \brief this function gives the world a consistant state
760
761   after ticking (updating the world state) this will give a constistant
762   state to the whole system.
763*/
764void World::update()
765{
766  this->nullParent->update ();
767}
768
769
770/**
771   \brief render the current frame
772   
773   clear all buffers and draw the world
774*/
775void World::display ()
776{
777  // clear buffer
778  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
779  // set camera
780  this->localCamera->apply ();
781  // draw world
782  this->draw();
783  // draw HUD
784  /* \todo draw HUD */
785  // flip buffers
786  SDL_GL_SwapBuffers();
787  //SDL_Surface* screen = Orxonox::getInstance()->getScreen ();
788  //SDL_Flip (screen);
789}
790
791
792/**
793   \brief add and spawn a new entity to this world
794   \param entity to be added
795*/
796void World::spawn(WorldEntity* entity)
797{
798  this->entities->add (entity);
799  entity->postSpawn ();
800}
801
802
803/**
804   \brief add and spawn a new entity to this world
805   \param entity to be added
806   \param absCoor At what coordinates to add this entity.
807   \param absDir In which direction should it look.
808*/
809void World::spawn(WorldEntity* entity, Vector* absCoor, Quaternion* absDir)
810{
811  this->entities->add (entity);
812
813  entity->setAbsCoor (absCoor);
814  entity->setAbsDir (absDir);
815
816  entity->postSpawn ();
817}
818
819
820/**
821   \brief add and spawn a new entity to this world
822   \param entity to be added
823   \param entity to be added to (PNode)
824   \param At what relative  coordinates to add this entity.
825   \param In which relative direction should it look.
826*/
827void World::spawn(WorldEntity* entity, PNode* parentNode, 
828                  Vector* relCoor, Quaternion* relDir, 
829                  int parentingMode)
830{
831  this->nullParent = NullParent::getInstance();
832  if( parentNode != NULL)
833    {
834      parentNode->addChild (entity);
835     
836      entity->setRelCoor (relCoor);
837      entity->setRelDir (relDir);
838      entity->setMode(parentingMode);
839     
840      this->entities->add (entity);
841     
842      entity->postSpawn ();
843    }
844}
845
846
847
848/**
849  \brief commands that the world must catch
850  \returns false if not used by the world
851*/
852bool World::command(Command* cmd)
853{
854  return false;
855}
856
Note: See TracBrowser for help on using the repository browser.