Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: hyperZOOM

File size: 20.5 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 = name;
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(3);
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(5);
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(10);
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(10);
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(10);
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();
305            this->localCamera->setName ("camera");
306            this->localCamera->lookAt(this->localPlayer);
307            Vector* cameraOffset = new Vector (-2, 2, 0);
308            this->localCamera->setRelCoor (cameraOffset);
309            this->localCamera->setFovy(100);
310           
311            /*monitor progress*/
312            this->glmis->step();           
313
314            // Create SkySphere
315            this->skySphere = new Skysphere("../data/pictures/sky-replace.jpg");
316            this->skySphere->setName("SkySphere");
317            this->localCamera->addChild(this->skySphere);
318            this->skySphere->setMode(PNODE_MOVEMENT);
319
320            /*monitor progress*/
321            this->glmis->step();
322
323           
324            WorldEntity* env = new Environment();
325            env->setName ("env");
326            this->spawn(env);
327
328           
329            Vector* es = new Vector (10, 5, 0);
330            Quaternion* qs = new Quaternion ();
331            WorldEntity* pr = new Primitive(P_CYLINDER);
332            pr->setName("primitive");
333            this->spawn(pr, this->localPlayer, es, qs, PNODE_MOVEMENT);
334           
335
336            /*monitor progress*/
337            this->glmis->step();
338
339            //      trackManager->setBindSlave(env);
340            PNode* tn = trackManager->getTrackNode();
341            tn->addChild(this->localPlayer);
342
343            //localCamera->setParent(TrackNode::getInstance());
344            tn->addChild (this->localCamera);
345            this->localPlayer->setMode(PNODE_ALL);
346            //Vector* cameraOffset = new Vector (0, 5, -10);
347            trackManager->condition(2, LEFTRIGHT, this->localPlayer);
348
349            break;
350          }
351        case DEBUG_WORLD_1:
352          {
353            lightMan->setPosition(.0, .0, .0);
354            lightMan->setAttenuation(1.0, .01, 0.0);
355            lightMan->setSpecularColor(1,0,0);
356            this->nullParent = NullParent::getInstance ();
357            this->nullParent->setName ("NullParent");
358
359            // create a player
360            WorldEntity* myPlayer = new Player();
361            myPlayer->setName ("player");
362            this->spawn(myPlayer);
363            this->localPlayer = myPlayer;           
364           
365            // bind input
366            Orxonox *orx = Orxonox::getInstance();
367            orx->getLocalInput()->bind (myPlayer);
368           
369            // bind camera
370            this->localCamera = new Camera ();
371            this->localCamera->setName ("camera");
372            this->localCamera->lookAt(LightManager::getInstance()->getLight(0));
373            this->localCamera->setParent(this->localPlayer);
374            Vector* cameraOffset = new Vector (-10, 5, 0);
375            this->localCamera->setRelCoor (cameraOffset);
376
377            // Create SkySphere
378            skySphere = new Skysphere("../data/pictures/sky-replace.jpg");
379            this->localPlayer->addChild(this->skySphere);
380
381            Vector* es = new Vector (20, 0, 0);
382            Quaternion* qs = new Quaternion ();
383            WorldEntity* pr = new Primitive(P_SPHERE);
384            pr->setName("primitive");
385            this->spawn(pr, this->localPlayer, es, qs, PNODE_ROTATE_AND_MOVE);
386
387            lightMan->getLight(0)->setParent(trackManager->getTrackNode());
388            break;
389          }
390        default:
391          printf("World::load() - no world with ID %i found", this->debugWorldNr );
392        }
393    }
394  else if(this->worldName != NULL)
395    {
396
397    }
398
399  // initialize debug coord system
400  objectList = glGenLists(1);
401  glNewList (objectList, GL_COMPILE);
402 
403  trackManager->drawGraph(.01);
404  trackManager->debug(2);
405  glEndList();
406
407  terrain = new Terrain("../data/worlds/newGround.obj");
408  terrain->setRelCoor(new Vector(0,-10,0));
409  this->spawn(terrain);
410
411}
412
413
414/**
415   \brief initializes a new World shortly before start
416
417   this is the function, that will be loaded shortly before the world is
418   started
419*/
420ErrorMessage World::init()
421{
422  this->bPause = false;
423  CommandNode* cn = Orxonox::getInstance()->getLocalInput();
424  cn->addToWorld(this);
425  cn->enable(true);
426}
427
428
429/**
430   \brief starts the World
431*/
432ErrorMessage World::start()
433{
434  PRINTF(3)("World::start() - starting current World: nr %i\n", this->debugWorldNr);
435  this->bQuitOrxonox = false;
436  this->bQuitCurrentGame = false;
437  this->mainLoop();
438}
439
440/**
441   \brief stops the world.
442
443   This happens, when the player decides to end the Level.
444*/
445ErrorMessage World::stop()
446{
447  PRINTF(3)("World::stop() - got stop signal\n");
448  this->bQuitCurrentGame = true;
449}
450
451/**
452   \brief pauses the Game
453*/
454ErrorMessage World::pause()
455{
456  this->isPaused = true;
457}
458
459/**
460   \brief ends the pause Phase
461*/
462ErrorMessage World::resume()
463{
464  this->isPaused = false;
465}
466
467/**
468   \brief destroys the World
469*/
470ErrorMessage World::destroy()
471{
472
473}
474
475/**
476   \brief shows the loading screen
477*/
478void World::displayLoadScreen ()
479{
480  PRINTF(3)("World::displayLoadScreen - start\n"); 
481 
482  //GLMenuImageScreen*
483  this->glmis = GLMenuImageScreen::getInstance();
484  this->glmis->init();
485  this->glmis->setMaximum(10);
486  this->glmis->draw();
487 
488  PRINTF(3)("World::displayLoadScreen - end\n"); 
489}
490
491/**
492   \brief removes the loadscreen, and changes over to the game
493
494   \todo take out the delay
495*/
496void World::releaseLoadScreen ()
497{
498  PRINTF(3)("World::releaseLoadScreen - start\n"); 
499  this->glmis->setValue(this->glmis->getMaximum());
500  SDL_Delay(500);
501  PRINTF(3)("World::releaseLoadScreen - end\n"); 
502}
503
504
505/**
506   \brief gets the list of entities from the world
507   \returns entity list
508*/
509tList<WorldEntity>* World::getEntities()
510{
511  return this->entities;
512}
513
514
515/**
516    \brief checks for collisions
517   
518    This method runs through all WorldEntities known to the world and checks for collisions
519    between them. In case of collisions the collide() method of the corresponding entities
520    is called.
521*/
522void World::collide ()
523{
524  /*
525  List *a, *b;
526  WorldEntity *aobj, *bobj;
527   
528  a = entities;
529 
530  while( a != NULL)
531    {
532      aobj = a->nextElement();
533      if( aobj->bCollide && aobj->collisioncluster != NULL)
534        {
535          b = a->nextElement();
536          while( b != NULL )
537            {
538              bobj = b->nextElement();
539              if( bobj->bCollide && bobj->collisioncluster != NULL )
540                {
541                  unsigned long ahitflg, bhitflg;
542                  if( check_collision ( &aobj->place, aobj->collisioncluster,
543                                        &ahitflg, &bobj->place, bobj->collisioncluster,
544                                        &bhitflg) );
545                  {
546                    aobj->collide (bobj, ahitflg, bhitflg);
547                    bobj->collide (aobj, bhitflg, ahitflg);
548                  }
549                }
550              b = b->nextElement();
551            }
552        }
553      a = a->enumerate();
554    }
555  */
556}
557
558/**
559    \brief runs through all entities calling their draw() methods
560*/
561void World::draw ()
562{
563  /* draw entities */
564  WorldEntity* entity;
565  glLoadIdentity();
566
567  entity = this->entities->enumerate();
568  while( entity != NULL ) 
569    { 
570      if( entity->bDraw ) entity->draw();
571      entity = this->entities->nextElement();
572    } 
573 
574  glCallList (objectList);
575  //! \todo skysphere is a WorldEntity and should be inside of the world-entity-list.
576  skySphere->draw();
577
578  testFont->printText(0, 0, 1, "orxonox_" PACKAGE_VERSION);
579
580  lightMan->draw(); // must be at the end of the drawing procedure, otherwise Light cannot be handled as PNodes //
581}
582
583
584/**
585   \brief function to put your own debug stuff into it. it can display informations about
586   the current class/procedure
587*/
588void World::debug()
589{
590  PRINTF(2)("debug() - starting debug\n");
591  PNode* p1 = NullParent::getInstance ();
592  PNode* p2 = new PNode (new Vector(2, 2, 2), p1);
593  PNode* p3 = new PNode (new Vector(4, 4, 4), p1);
594  PNode* p4 = new PNode (new Vector(6, 6, 6), p2);
595
596  p1->debug ();
597  p2->debug ();
598  p3->debug ();
599  p4->debug ();
600
601  p1->shiftCoor (new Vector(-1, -1, -1));
602
603  printf("World::debug() - shift\n");
604  p1->debug ();
605  p2->debug ();
606  p3->debug ();
607  p4->debug ();
608 
609  p1->update ();
610
611  printf ("World::debug() - update\n");
612  p1->debug ();
613  p2->debug ();
614  p3->debug ();
615  p4->debug ();
616
617  p2->shiftCoor (new Vector(-1, -1, -1));
618  p1->update ();
619
620  p1->debug ();
621  p2->debug ();
622  p3->debug ();
623  p4->debug ();
624
625  p2->setAbsCoor (new Vector(1,2,3));
626
627
628 p1->update ();
629
630  p1->debug ();
631  p2->debug ();
632  p3->debug ();
633  p4->debug ();
634
635  delete p1;
636 
637 
638  /*
639  WorldEntity* entity;
640  printf("counting all entities\n");
641  printf("World::debug() - enumerate()\n");
642  entity = entities->enumerate(); 
643  while( entity != NULL )
644    {
645      if( entity->bDraw ) printf("got an entity\n");
646      entity = entities->nextElement();
647    }
648  */
649}
650
651
652/**
653  \brief main loop of the world: executing all world relevant function
654
655  in this loop we synchronize (if networked), handle input events, give the heart-beat to
656  all other member-entities of the world (tick to player, enemies etc.), checking for
657  collisions drawing everything to the screen.
658*/
659void World::mainLoop()
660{
661  this->lastFrame = SDL_GetTicks ();
662  PRINTF(3)("World::mainLoop() - Entering main loop\n");
663  while( !this->bQuitOrxonox && !this->bQuitCurrentGame) /* \todo implement pause */
664    {
665      PRINTF(3)("World::mainloop() - number of entities: %i\n", this->entities->getSize());
666      // Network
667      this->synchronize ();
668      // Process input
669      this->handleInput ();
670      if( this->bQuitCurrentGame || this->bQuitOrxonox)
671          break;
672      // Process time
673      this->tick ();
674      // Update the state
675      this->update ();     
676      // Process collision
677      this->collide ();
678      // Draw
679      this->display ();
680
681      //      for( int i = 0; i < 5000000; i++) {}
682      /* \todo this is to slow down the program for openGl Software emulator computers, reimplement*/
683    }
684  PRINTF(3)("World::mainLoop() - Exiting the main loop\n");
685}
686
687
688/**
689   \brief synchronize local data with remote data
690*/
691void World::synchronize ()
692{
693  // Get remote input
694  // Update synchronizables
695}
696
697
698/**
699   \brief run all input processing
700
701   the command node is the central input event dispatcher. the node uses the even-queue from
702   sdl and has its own event-passing-queue.
703*/
704void World::handleInput ()
705{
706  // localinput
707  CommandNode* cn = Orxonox::getInstance()->getLocalInput();
708  cn->process();
709  // remoteinput
710}
711
712
713/**
714   \brief advance the timeline
715
716   this calculates the time used to process one frame (with all input handling, drawing, etc)
717   the time is mesured in ms and passed to all world-entities and other classes that need
718   a heart-beat.
719*/
720void World::tick ()
721{
722  Uint32 currentFrame = SDL_GetTicks();
723  if(!this->bPause)
724    {
725      Uint32 dt = currentFrame - this->lastFrame;
726     
727      if(dt > 0)
728        {
729          float fps = 1000/dt;
730          PRINTF(3)("fps = %f\n", fps);
731        }
732      else
733        {
734          /* the frame-rate is limited to 100 frames per second, all other things are for
735             nothing.
736          */
737          PRINTF(2)("fps = 1000 - frame rate is adjusted\n");
738          SDL_Delay(10);
739          dt = 10;
740        }
741      //this->timeSlice (dt);
742     
743      /* function to let all entities tick (iterate through list) */
744      WorldEntity* entity;
745      float seconds = dt / 1000.0;     
746      entity = entities->enumerate(); 
747      while( entity != NULL) 
748        { 
749          entity->tick (seconds);
750          entity = entities->nextElement();
751        }
752      //skySphere->updatePosition(localCamera->absCoordinate);
753     
754      /* update tick the rest */
755      this->trackManager->tick(dt);
756    }
757  this->lastFrame = currentFrame;
758}
759
760
761/**
762   \brief this function gives the world a consistant state
763
764   after ticking (updating the world state) this will give a constistant
765   state to the whole system.
766*/
767void World::update()
768{
769  this->nullParent->update ();
770}
771
772
773/**
774   \brief render the current frame
775   
776   clear all buffers and draw the world
777*/
778void World::display ()
779{
780  // clear buffer
781  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
782  // set camera
783  this->localCamera->apply ();
784  // draw world
785  this->draw();
786  // draw HUD
787  /* \todo draw HUD */
788  // flip buffers
789  SDL_GL_SwapBuffers();
790  //SDL_Surface* screen = Orxonox::getInstance()->getScreen ();
791  //SDL_Flip (screen);
792}
793
794
795/**
796   \brief add and spawn a new entity to this world
797   \param entity to be added
798*/
799void World::spawn(WorldEntity* entity)
800{
801  this->entities->add (entity);
802  entity->postSpawn ();
803}
804
805
806/**
807   \brief add and spawn a new entity to this world
808   \param entity to be added
809   \param absCoor At what coordinates to add this entity.
810   \param absDir In which direction should it look.
811*/
812void World::spawn(WorldEntity* entity, Vector* absCoor, Quaternion* absDir)
813{
814  this->entities->add (entity);
815
816  entity->setAbsCoor (absCoor);
817  entity->setAbsDir (absDir);
818
819  entity->postSpawn ();
820}
821
822
823/**
824   \brief add and spawn a new entity to this world
825   \param entity to be added
826   \param entity to be added to (PNode)
827   \param At what relative  coordinates to add this entity.
828   \param In which relative direction should it look.
829*/
830void World::spawn(WorldEntity* entity, PNode* parentNode, 
831                  Vector* relCoor, Quaternion* relDir, 
832                  int parentingMode)
833{
834  this->nullParent = NullParent::getInstance();
835  if( parentNode != NULL)
836    {
837      parentNode->addChild (entity);
838     
839      entity->setRelCoor (relCoor);
840      entity->setRelDir (relDir);
841      entity->setMode(parentingMode);
842     
843      this->entities->add (entity);
844     
845      entity->postSpawn ();
846    }
847}
848
849
850
851/**
852  \brief commands that the world must catch
853  \returns false if not used by the world
854*/
855bool World::command(Command* cmd)
856{
857  return false;
858}
859
Note: See TracBrowser for help on using the repository browser.