Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: now dynamic FOV. still working

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