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