1 //-----------------------------------------------------------------------------
2 // World
3 //-----------------------------------------------------------------------------
4 
5 #include "world.h"
6 #include "console.h"
7 #include "timer.h"
8 #include "vars.h"
9 #include "overlay.h"
10 #include "render.h"
11 #include "math.h"
12 #include "sound.h"
13 #include "entity.h"
14 #include "system.h"
15 #include "client.h"
16 
17 Var v_showclientbox("v_showclientbox", 0);
18 
World(void)19 World::World(void)
20 {
21   bsp = NULL;
22 
23   gravity = 800.f;
24   maxvspeed = 2000.f;
25 
26   gVars->RegisterVar(v_showclientbox);
27 }
28 
~World(void)29 World::~World(void)
30 {
31   gVars->UnregisterVar(v_showclientbox);
32 }
33 
GetBSP(void)34 Q3BSP* World::GetBSP(void)
35 {
36   return bsp;
37 }
38 
AddMap(const char * name)39 int World::AddMap(const char *name)
40 {
41   int result;
42 
43   memset(mapname, '\0', 32);
44   strncpy(mapname, name, 32);
45 
46   char mappath[1024] = { '\0' };
47   strncpy(mappath, gVars->StringForKey("r_mapsubdir"), 1023);
48   if (mappath[strlen(mappath)-1] != '/') sprintf(mappath, "%s/", mappath);
49   strcat(mappath, name);
50 
51   // replace extension
52   f_StripExtension(mappath);
53   strcat(mappath, ".bsp");
54 
55   // Stop and delete music and sounds
56   freeBGMusic();
57 
58   bsp = new Q3BSP(mappath, this, &result);
59 
60   if (!result) bsp = NULL;
61 
62   return result;
63 }
64 
65 // FIXME: heap gets corrupted here:
Init(void)66 void World::Init(void)
67 {
68   bsp->DisplayLoadingMessage("Loading... shaders");
69 
70   // load shader that have been referenced, and load also his textures
71   // (shaders must be loaded before any other object)
72   gConsole->Insertln("Updating world shaders...");
73   shaders.Update();
74 
75   // TODO: every object should get the current pointer to his shaders in the
76   //     initialization instead of calling GetShader every frame.
77   bsp->Init();
78 }
79 
Shut(void)80 void World::Shut(void)
81 {
82   gConsole->Insertln("Shuting world...");
83 
84   // Stop and delete music
85   freeBGMusic();
86 
87   if (bsp) delete bsp;
88   bsp = NULL;
89 
90   shaders.ResetAll();
91   shaders.Update();
92 }
93 
Render(Client * clients,int numclients)94 void World::Render(Client *clients, int numclients)
95 {
96   int i;
97   bool waterstate;
98 
99   // All clients are updated before rendering
100   for (i = 0; i < numclients; ++i)
101   {
102     if (clients[i].active_client)
103     {
104       clients[i].Update(bsp, this);           // update client
105     }
106   }
107 
108   // Render the clients
109   for (i = 0; i < numclients; ++i)
110   {
111     gRender->InitializeViewPort();
112 
113     gRender->current_camera = &clients[i].cam;
114     waterstate = gRender->current_camera->inWater;
115 
116     clients[i].cam.UpdateRotation();
117     clients[i].cam.UpdatePosition();
118     clients[i].cam.UpdateProjection();
119     clients[i].cam.UpdateViewport();
120     clients[i].cam.UpdateFrustum(); // set up frustum planes
121 
122     // TODO: Only update entities that are in current PVS
123     bsp->GetEntities()->UpdateEntities(&clients[i]);
124 
125     bsp->Update();                      // update the scene (moving objects, visibility determination)
126 
127     if (clients[i].isCurrent)
128       SoundUpdate(clients[i].cam.pos, clients[i].cam.forward);  // update sound settings for current client
129 
130     // FIXME: Put this in a better place
131     if (!waterstate && gRender->current_camera->inWater) clients[i].Water(0);
132     else if (waterstate && !gRender->current_camera->inWater) clients[i].Water(1);
133 
134     bsp->Render();
135 
136     gRender->ForceFlush();
137 
138     // Draw the camera box
139     if (v_showclientbox.ivalue)
140     {
141       colour_t colorline = { 255, 255, 255, 255 };
142       colour_t colorface;
143       bboxf_t clbox;
144       for (int j = 0; j < numclients; ++j)
145       {
146         VectorAdd(clients[j].mins, clients[j].cam.pos, &clbox[0]);
147         VectorAdd(clients[j].maxs, clients[j].cam.pos, &clbox[3]);
148         if (i == j) ColorClear(colorface);
149         else ColorCopy(clients[j].color, colorface);
150         Q3BSP::DrawBoundingBox(clbox, colorline, colorface);
151       }
152       gRender->ForceFlush();
153     }
154   }
155 }
156 
157 // Find the first spawn point in the entities list
SetStartPos(Client * c,int n)158 void World::SetStartPos(Client *c, int n)
159 {
160   if (!bsp || !c) return;
161 
162   EntityManager *entman = bsp->GetEntities();
163   int i = entman->Find_entity(ET_INFO_PLAYER_DEATHMATCH, n);
164   if (i < 0) return;
165 
166   Entity* ent = entman->entities+i;
167 
168   c->ResetMovement();
169   c->cam.rot[PITCH] = 90;
170   c->cam.rot[YAW] = ent->angle-90;
171   c->cam.rot[ROLL] = 0;
172   c->TeleportTo(ent->origin, ent->angle, 0);
173 }
174 
175 // TODO: Optimize by caching the diffrent elements of entities and sorting the different entities
GetNumStartPos(void)176 int World::GetNumStartPos(void)
177 {
178   if (!bsp) return 0;
179   int i, res = 0;
180   EntityManager *entman = bsp->GetEntities();
181   if (!entman) ThrowException(NULL_POINTER, "World::GetNumStartPos.entman");
182   for (i = 0; i < entman->num_entities; ++i)
183   {
184     if (entman->entities[i].enttype == ET_INFO_PLAYER_DEATHMATCH) ++res;
185   }
186   return res;
187 }
188