Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 3622 was 3621, checked in by bensch, 21 years ago

orxonox/trunk: doxygen-tags and some minor stuff

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