9b70f0fce4781d3706872ea82e0bc6ab20b0610f
[xonotic/darkplaces.git] / cl_main.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // cl_main.c  -- client main loop
21
22 #include "quakedef.h"
23 #include "cl_collision.h"
24 #include "cl_video.h"
25
26 // we need to declare some mouse variables here, because the menu system
27 // references them even when on a unix system.
28
29 // these two are not intended to be set directly
30 cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player"};
31 cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0"};
32 cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0"};
33
34 cvar_t cl_shownet = {0, "cl_shownet","0"};
35 cvar_t cl_nolerp = {0, "cl_nolerp", "0"};
36
37 cvar_t cl_itembobheight = {0, "cl_itembobheight", "8"};
38 cvar_t cl_itembobspeed = {0, "cl_itembobspeed", "0.5"};
39
40 cvar_t lookspring = {CVAR_SAVE, "lookspring","0"};
41 cvar_t lookstrafe = {CVAR_SAVE, "lookstrafe","0"};
42 cvar_t sensitivity = {CVAR_SAVE, "sensitivity","3", 1, 30};
43
44 cvar_t m_pitch = {CVAR_SAVE, "m_pitch","0.022"};
45 cvar_t m_yaw = {CVAR_SAVE, "m_yaw","0.022"};
46 cvar_t m_forward = {CVAR_SAVE, "m_forward","1"};
47 cvar_t m_side = {CVAR_SAVE, "m_side","0.8"};
48
49 cvar_t freelook = {CVAR_SAVE, "freelook", "1"};
50
51 cvar_t r_draweffects = {0, "r_draweffects", "1"};
52
53 cvar_t cl_explosions = {CVAR_SAVE, "cl_explosions", "1"};
54 cvar_t cl_stainmaps = {CVAR_SAVE, "cl_stainmaps", "1"};
55
56 cvar_t cl_beams_polygons = {CVAR_SAVE, "cl_beams_polygons", "1"};
57 cvar_t cl_beams_relative = {CVAR_SAVE, "cl_beams_relative", "1"};
58
59 cvar_t cl_noplayershadow = {CVAR_SAVE, "cl_noplayershadow", "0"};
60
61 mempool_t *cl_scores_mempool;
62 mempool_t *cl_refdef_mempool;
63 mempool_t *cl_entities_mempool;
64
65 client_static_t cls;
66 client_state_t  cl;
67
68 int cl_max_entities;
69 int cl_max_static_entities;
70 int cl_max_temp_entities;
71 int cl_max_effects;
72 int cl_max_beams;
73 int cl_max_dlights;
74 int cl_max_lightstyle;
75 int cl_max_brushmodel_entities;
76
77 entity_t *cl_entities;
78 qbyte *cl_entities_active;
79 entity_t *cl_static_entities;
80 entity_t *cl_temp_entities;
81 cl_effect_t *cl_effects;
82 beam_t *cl_beams;
83 dlight_t *cl_dlights;
84 lightstyle_t *cl_lightstyle;
85 entity_render_t **cl_brushmodel_entities;
86
87 int cl_num_entities;
88 int cl_num_static_entities;
89 int cl_num_temp_entities;
90 int cl_num_brushmodel_entities;
91
92 /*
93 =====================
94 CL_ClearState
95
96 =====================
97 */
98 void CL_ClearState (void)
99 {
100         int i;
101
102         if (!sv.active)
103                 Host_ClearMemory ();
104
105         Mem_EmptyPool(cl_scores_mempool);
106         Mem_EmptyPool(cl_entities_mempool);
107
108 // wipe the entire cl structure
109         memset (&cl, 0, sizeof(cl));
110
111         SZ_Clear (&cls.message);
112
113         cl_num_entities = 0;
114         cl_num_static_entities = 0;
115         cl_num_temp_entities = 0;
116         cl_num_brushmodel_entities = 0;
117
118         // tweak these if the game runs out
119         cl_max_entities = MAX_EDICTS;
120         cl_max_static_entities = 256;
121         cl_max_temp_entities = 512;
122         cl_max_effects = 256;
123         cl_max_beams = 24;
124         cl_max_dlights = MAX_DLIGHTS;
125         cl_max_lightstyle = MAX_LIGHTSTYLES;
126         cl_max_brushmodel_entities = MAX_EDICTS;
127
128         cl_entities = Mem_Alloc(cl_entities_mempool, cl_max_entities * sizeof(entity_t));
129         cl_entities_active = Mem_Alloc(cl_entities_mempool, cl_max_entities * sizeof(qbyte));
130         cl_static_entities = Mem_Alloc(cl_entities_mempool, cl_max_static_entities * sizeof(entity_t));
131         cl_temp_entities = Mem_Alloc(cl_entities_mempool, cl_max_temp_entities * sizeof(entity_t));
132         cl_effects = Mem_Alloc(cl_entities_mempool, cl_max_effects * sizeof(cl_effect_t));
133         cl_beams = Mem_Alloc(cl_entities_mempool, cl_max_beams * sizeof(beam_t));
134         cl_dlights = Mem_Alloc(cl_entities_mempool, cl_max_dlights * sizeof(dlight_t));
135         cl_lightstyle = Mem_Alloc(cl_entities_mempool, cl_max_lightstyle * sizeof(lightstyle_t));
136         cl_brushmodel_entities = Mem_Alloc(cl_entities_mempool, cl_max_brushmodel_entities * sizeof(entity_render_t *));
137
138         CL_Screen_NewMap();
139
140         CL_Particles_Clear();
141
142         // LordHavoc: have to set up the baseline info for alpha and other stuff
143         for (i = 0;i < cl_max_entities;i++)
144         {
145                 ClearStateToDefault(&cl_entities[i].state_baseline);
146                 ClearStateToDefault(&cl_entities[i].state_previous);
147                 ClearStateToDefault(&cl_entities[i].state_current);
148         }
149
150         CL_CGVM_Clear();
151 }
152
153 /*
154 =====================
155 CL_Disconnect
156
157 Sends a disconnect message to the server
158 This is also called on Host_Error, so it shouldn't cause any errors
159 =====================
160 */
161 void CL_Disconnect (void)
162 {
163         if (cls.state == ca_dedicated)
164                 return;
165
166 // stop sounds (especially looping!)
167         S_StopAllSounds (true);
168
169         // clear contents blends
170         cl.cshifts[0].percent = 0;
171         cl.cshifts[1].percent = 0;
172         cl.cshifts[2].percent = 0;
173         cl.cshifts[3].percent = 0;
174
175         cl.worldmodel = NULL;
176
177         if (cls.demoplayback)
178                 CL_StopPlayback ();
179         else if (cls.state == ca_connected)
180         {
181                 if (cls.demorecording)
182                         CL_Stop_f ();
183
184                 Con_DPrintf ("Sending clc_disconnect\n");
185                 SZ_Clear (&cls.message);
186                 MSG_WriteByte (&cls.message, clc_disconnect);
187                 NET_SendUnreliableMessage (cls.netcon, &cls.message);
188                 SZ_Clear (&cls.message);
189                 NET_Close (cls.netcon);
190                 cls.state = ca_disconnected; // prevent this code from executing again during Host_ShutdownServer
191                 // if running a local server, shut it down
192                 if (sv.active)
193                         Host_ShutdownServer(false);
194         }
195         cls.state = ca_disconnected;
196
197         cls.demoplayback = cls.timedemo = false;
198         cls.signon = 0;
199 }
200
201 void CL_Disconnect_f (void)
202 {
203         CL_Disconnect ();
204         if (sv.active)
205                 Host_ShutdownServer (false);
206 }
207
208
209
210
211 /*
212 =====================
213 CL_EstablishConnection
214
215 Host should be either "local" or a net address to be passed on
216 =====================
217 */
218 void CL_EstablishConnection (char *host)
219 {
220         if (cls.state == ca_dedicated)
221                 return;
222
223         if (cls.demoplayback)
224                 return;
225
226         CL_Disconnect ();
227
228         cls.netcon = NET_Connect (host);
229         if (!cls.netcon)
230                 Host_Error ("CL_Connect: connect failed\n");
231         Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
232
233         cls.demonum = -1;                       // not in the demo loop now
234         cls.state = ca_connected;
235         cls.signon = 0;                         // need all the signon messages before playing
236
237         CL_ClearState ();
238 }
239
240 /*
241 ==============
242 CL_PrintEntities_f
243 ==============
244 */
245 static void CL_PrintEntities_f (void)
246 {
247         entity_t *ent;
248         int i, j;
249         char name[32];
250
251         for (i = 0, ent = cl_entities;i < cl_num_entities;i++, ent++)
252         {
253                 if (!ent->state_current.active)
254                         continue;
255
256                 if (ent->render.model)
257                         strncpy(name, ent->render.model->name, 25);
258                 else
259                         strcpy(name, "--no model--");
260                 name[25] = 0;
261                 for (j = strlen(name);j < 25;j++)
262                         name[j] = ' ';
263                 Con_Printf ("%3i: %s:%04i (%5i %5i %5i) [%3i %3i %3i] %4.2f %5.3f\n", i, name, ent->render.frame, (int) ent->render.origin[0], (int) ent->render.origin[1], (int) ent->render.origin[2], (int) ent->render.angles[0] % 360, (int) ent->render.angles[1] % 360, (int) ent->render.angles[2] % 360, ent->render.scale, ent->render.alpha);
264         }
265 }
266
267 //static const vec3_t nomodelmins = {-16, -16, -16};
268 //static const vec3_t nomodelmaxs = {16, 16, 16};
269 void CL_BoundingBoxForEntity(entity_render_t *ent)
270 {
271         if (ent->model)
272         {
273                 //if (ent->angles[0] || ent->angles[2])
274                 if (ent->matrix.m[2][0] != 0 || ent->matrix.m[2][1] != 0)
275                 {
276                         // pitch or roll
277                         ent->mins[0] = ent->matrix.m[0][3] + ent->model->rotatedmins[0];
278                         ent->mins[1] = ent->matrix.m[1][3] + ent->model->rotatedmins[1];
279                         ent->mins[2] = ent->matrix.m[2][3] + ent->model->rotatedmins[2];
280                         ent->maxs[0] = ent->matrix.m[0][3] + ent->model->rotatedmaxs[0];
281                         ent->maxs[1] = ent->matrix.m[1][3] + ent->model->rotatedmaxs[1];
282                         ent->maxs[2] = ent->matrix.m[2][3] + ent->model->rotatedmaxs[2];
283                         //VectorAdd(ent->origin, ent->model->rotatedmins, ent->mins);
284                         //VectorAdd(ent->origin, ent->model->rotatedmaxs, ent->maxs);
285                 }
286                 //else if (ent->angles[1])
287                 else if (ent->matrix.m[0][1] != 0 || ent->matrix.m[1][0] != 0)
288                 {
289                         // yaw
290                         ent->mins[0] = ent->matrix.m[0][3] + ent->model->yawmins[0];
291                         ent->mins[1] = ent->matrix.m[1][3] + ent->model->yawmins[1];
292                         ent->mins[2] = ent->matrix.m[2][3] + ent->model->yawmins[2];
293                         ent->maxs[0] = ent->matrix.m[0][3] + ent->model->yawmaxs[0];
294                         ent->maxs[1] = ent->matrix.m[1][3] + ent->model->yawmaxs[1];
295                         ent->maxs[2] = ent->matrix.m[2][3] + ent->model->yawmaxs[2];
296                         //VectorAdd(ent->origin, ent->model->yawmins, ent->mins);
297                         //VectorAdd(ent->origin, ent->model->yawmaxs, ent->maxs);
298                 }
299                 else
300                 {
301                         ent->mins[0] = ent->matrix.m[0][3] + ent->model->normalmins[0];
302                         ent->mins[1] = ent->matrix.m[1][3] + ent->model->normalmins[1];
303                         ent->mins[2] = ent->matrix.m[2][3] + ent->model->normalmins[2];
304                         ent->maxs[0] = ent->matrix.m[0][3] + ent->model->normalmaxs[0];
305                         ent->maxs[1] = ent->matrix.m[1][3] + ent->model->normalmaxs[1];
306                         ent->maxs[2] = ent->matrix.m[2][3] + ent->model->normalmaxs[2];
307                         //VectorAdd(ent->origin, ent->model->normalmins, ent->mins);
308                         //VectorAdd(ent->origin, ent->model->normalmaxs, ent->maxs);
309                 }
310         }
311         else
312         {
313                 ent->mins[0] = ent->matrix.m[0][3] - 16;
314                 ent->mins[1] = ent->matrix.m[1][3] - 16;
315                 ent->mins[2] = ent->matrix.m[2][3] - 16;
316                 ent->maxs[0] = ent->matrix.m[0][3] + 16;
317                 ent->maxs[1] = ent->matrix.m[1][3] + 16;
318                 ent->maxs[2] = ent->matrix.m[2][3] + 16;
319                 //VectorAdd(ent->origin, nomodelmins, ent->mins);
320                 //VectorAdd(ent->origin, nomodelmaxs, ent->maxs);
321         }
322 }
323
324 void CL_LerpUpdate(entity_t *e)
325 {
326         entity_persistent_t *p;
327         entity_render_t *r;
328         p = &e->persistent;
329         r = &e->render;
330
331         if (p->modelindex != e->state_current.modelindex)
332         {
333                 // reset all interpolation information
334                 p->modelindex = e->state_current.modelindex;
335                 p->frame1 = p->frame2 = e->state_current.frame;
336                 p->frame1time = p->frame2time = cl.time;
337                 p->framelerp = 1;
338         }
339         else if (p->frame2 != e->state_current.frame)
340         {
341                 // transition to new frame
342                 p->frame1 = p->frame2;
343                 p->frame1time = p->frame2time;
344                 p->frame2 = e->state_current.frame;
345                 p->frame2time = cl.time;
346                 p->framelerp = 0;
347         }
348         else
349         {
350                 // update transition
351                 p->framelerp = (cl.time - p->frame2time) * 10;
352                 p->framelerp = bound(0, p->framelerp, 1);
353         }
354
355         r->model = cl.model_precache[e->state_current.modelindex];
356         Mod_CheckLoaded(r->model);
357         r->frame = e->state_current.frame;
358         r->frame1 = p->frame1;
359         r->frame2 = p->frame2;
360         r->framelerp = p->framelerp;
361         r->frame1time = p->frame1time;
362         r->frame2time = p->frame2time;
363 }
364
365 /*
366 ===============
367 CL_LerpPoint
368
369 Determines the fraction between the last two messages that the objects
370 should be put at.
371 ===============
372 */
373 static float CL_LerpPoint (void)
374 {
375         float f;
376
377         // dropped packet, or start of demo
378         if (cl.mtime[1] < cl.mtime[0] - 0.1)
379                 cl.mtime[1] = cl.mtime[0] - 0.1;
380
381         cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]);
382
383         // LordHavoc: lerp in listen games as the server is being capped below the client (usually)
384         f = cl.mtime[0] - cl.mtime[1];
385         if (!f || cl_nolerp.integer || cls.timedemo || (sv.active && svs.maxclients == 1))
386         {
387                 cl.time = cl.mtime[0];
388                 return 1;
389         }
390
391         f = (cl.time - cl.mtime[1]) / f;
392         return bound(0, f, 1);
393 }
394
395 void CL_ClearTempEntities (void)
396 {
397         cl_num_temp_entities = 0;
398 }
399
400 entity_t *CL_NewTempEntity (void)
401 {
402         entity_t *ent;
403
404         if (r_refdef.numentities >= r_refdef.maxentities)
405                 return NULL;
406         if (cl_num_temp_entities >= cl_max_temp_entities)
407                 return NULL;
408         ent = &cl_temp_entities[cl_num_temp_entities++];
409         memset (ent, 0, sizeof(*ent));
410         r_refdef.entities[r_refdef.numentities++] = &ent->render;
411
412         ent->render.colormap = -1; // no special coloring
413         ent->render.scale = 1;
414         ent->render.alpha = 1;
415         return ent;
416 }
417
418 void CL_AllocDlight (entity_render_t *ent, vec3_t org, float radius, float red, float green, float blue, float decay, float lifetime)
419 {
420         int i;
421         dlight_t *dl;
422
423         /*
424 // first look for an exact key match
425         if (ent)
426         {
427                 dl = cl_dlights;
428                 for (i = 0;i < MAX_DLIGHTS;i++, dl++)
429                         if (dl->ent == ent)
430                                 goto dlightsetup;
431         }
432         */
433
434 // then look for anything else
435         dl = cl_dlights;
436         for (i = 0;i < MAX_DLIGHTS;i++, dl++)
437                 if (!dl->radius)
438                         goto dlightsetup;
439
440         // unable to find one
441         return;
442
443 dlightsetup:
444         //Con_Printf("dlight %i : %f %f %f : %f %f %f\n", i, org[0], org[1], org[2], red * radius, green * radius, blue * radius);
445         memset (dl, 0, sizeof(*dl));
446         dl->ent = ent;
447         VectorCopy(org, dl->origin);
448         dl->radius = radius;
449         dl->color[0] = red;
450         dl->color[1] = green;
451         dl->color[2] = blue;
452         dl->decay = decay;
453         if (lifetime)
454                 dl->die = cl.time + lifetime;
455         else
456                 dl->die = 0;
457 }
458
459 void CL_DecayLights (void)
460 {
461         int i;
462         dlight_t *dl;
463         float time;
464
465         time = cl.time - cl.oldtime;
466
467         dl = cl_dlights;
468         for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
469         {
470                 if (!dl->radius)
471                         continue;
472                 if (dl->die < cl.time)
473                 {
474                         dl->radius = 0;
475                         continue;
476                 }
477
478                 dl->radius -= time*dl->decay;
479                 if (dl->radius < 0)
480                         dl->radius = 0;
481         }
482 }
483
484 void CL_RelinkWorld (void)
485 {
486         entity_t *ent = &cl_entities[0];
487         if (cl_num_entities < 1)
488                 cl_num_entities = 1;
489         cl_brushmodel_entities[cl_num_brushmodel_entities++] = &ent->render;
490         Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, ent->render.origin[0], ent->render.origin[1], ent->render.origin[2], ent->render.angles[0], ent->render.angles[1], ent->render.angles[2], ent->render.scale);
491         Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
492         CL_BoundingBoxForEntity(&ent->render);
493 }
494
495 static void CL_RelinkStaticEntities(void)
496 {
497         int i;
498         for (i = 0;i < cl_num_static_entities && r_refdef.numentities < r_refdef.maxentities;i++)
499         {
500                 Mod_CheckLoaded(cl_static_entities[i].render.model);
501                 r_refdef.entities[r_refdef.numentities++] = &cl_static_entities[i].render;
502         }
503 }
504
505 /*
506 ===============
507 CL_RelinkEntities
508 ===============
509 */
510 extern qboolean Nehahrademcompatibility;
511 #define MAXVIEWMODELS 32
512 entity_t *viewmodels[MAXVIEWMODELS];
513 int numviewmodels;
514 static void CL_RelinkNetworkEntities(void)
515 {
516         entity_t *ent;
517         int i, effects, temp;
518         float d, bobjrotate, bobjoffset, lerp;
519         vec3_t oldorg, neworg, delta, dlightcolor, v, v2, mins, maxs;
520
521         numviewmodels = 0;
522
523         bobjrotate = ANGLEMOD(100*cl.time);
524         if (cl_itembobheight.value)
525                 bobjoffset = (cos(cl.time * cl_itembobspeed.value * (2.0 * M_PI)) + 1.0) * 0.5 * cl_itembobheight.value;
526         else
527                 bobjoffset = 0;
528
529         // start on the entity after the world
530         for (i = 1, ent = cl_entities + 1;i < MAX_EDICTS;i++, ent++)
531         {
532                 // if the object isn't active in the current network frame, skip it
533                 if (!cl_entities_active[i])
534                         continue;
535                 if (!ent->state_current.active)
536                 {
537                         cl_entities_active[i] = false;
538                         continue;
539                 }
540
541                 VectorCopy(ent->persistent.trail_origin, oldorg);
542
543                 if (!ent->state_previous.active)
544                 {
545                         // only one state available
546                         VectorCopy (ent->persistent.neworigin, neworg);
547                         VectorCopy (ent->persistent.newangles, ent->render.angles);
548                         VectorCopy (neworg, oldorg);
549                 }
550                 else
551                 {
552                         // if the delta is large, assume a teleport and don't lerp
553                         VectorSubtract(ent->persistent.neworigin, ent->persistent.oldorigin, delta);
554                         if (ent->persistent.lerpdeltatime > 0)
555                         {
556                                 lerp = (cl.time - ent->persistent.lerpstarttime) / ent->persistent.lerpdeltatime;
557                                 if (lerp < 1)
558                                 {
559                                         // interpolate the origin and angles
560                                         VectorMA(ent->persistent.oldorigin, lerp, delta, neworg);
561                                         VectorSubtract(ent->persistent.newangles, ent->persistent.oldangles, delta);
562                                         if (delta[0] < -180) delta[0] += 360;else if (delta[0] >= 180) delta[0] -= 360;
563                                         if (delta[1] < -180) delta[1] += 360;else if (delta[1] >= 180) delta[1] -= 360;
564                                         if (delta[2] < -180) delta[2] += 360;else if (delta[2] >= 180) delta[2] -= 360;
565                                         VectorMA(ent->persistent.oldangles, lerp, delta, ent->render.angles);
566                                 }
567                                 else
568                                 {
569                                         // no interpolation
570                                         VectorCopy (ent->persistent.neworigin, neworg);
571                                         VectorCopy (ent->persistent.newangles, ent->render.angles);
572                                 }
573                         }
574                         else
575                         {
576                                 // no interpolation
577                                 VectorCopy (ent->persistent.neworigin, neworg);
578                                 VectorCopy (ent->persistent.newangles, ent->render.angles);
579                         }
580                 }
581
582                 if (!ent->render.model || ent->render.model->type != mod_brush)
583                         ent->render.angles[0] = -ent->render.angles[0];
584
585                 VectorCopy (neworg, ent->persistent.trail_origin);
586                 // persistent.modelindex will be updated by CL_LerpUpdate
587                 if (ent->state_current.modelindex != ent->persistent.modelindex || !ent->state_previous.active)
588                         VectorCopy(neworg, oldorg);
589
590                 VectorCopy (neworg, ent->render.origin);
591                 ent->render.flags = ent->state_current.flags;
592                 if (i == cl.viewentity)
593                         ent->render.flags |= RENDER_EXTERIORMODEL;
594                 ent->render.effects = effects = ent->state_current.effects;
595                 if (ent->state_current.flags & RENDER_COLORMAPPED)
596                         ent->render.colormap = ent->state_current.colormap;
597                 else if (cl.scores == NULL || !ent->state_current.colormap)
598                         ent->render.colormap = -1; // no special coloring
599                 else
600                         ent->render.colormap = cl.scores[ent->state_current.colormap - 1].colors; // color it
601                 ent->render.skinnum = ent->state_current.skin;
602                 ent->render.alpha = ent->state_current.alpha * (1.0f / 255.0f); // FIXME: interpolate?
603                 ent->render.scale = ent->state_current.scale * (1.0f / 16.0f); // FIXME: interpolate?
604
605                 if (ent->render.model && ent->render.model->flags & EF_ROTATE)
606                 {
607                         ent->render.angles[1] = bobjrotate;
608                         ent->render.origin[2] += bobjoffset;
609                 }
610
611                 Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, ent->render.origin[0], ent->render.origin[1], ent->render.origin[2], ent->render.angles[0], ent->render.angles[1], ent->render.angles[2], ent->render.scale);
612
613                 // update interpolation info
614                 CL_LerpUpdate(ent);
615
616                 // handle effects now...
617                 dlightcolor[0] = 0;
618                 dlightcolor[1] = 0;
619                 dlightcolor[2] = 0;
620
621                 // LordHavoc: if the entity has no effects, don't check each
622                 if (effects)
623                 {
624                         if (effects & EF_BRIGHTFIELD)
625                         {
626                                 if (gamemode == GAME_NEXIUZ)
627                                 {
628                                         dlightcolor[0] += 100.0f;
629                                         dlightcolor[1] += 200.0f;
630                                         dlightcolor[2] += 400.0f;
631                                         // don't do trail if we have no previous location
632                                         if (ent->state_previous.active)
633                                                 CL_RocketTrail (oldorg, neworg, 8, ent);
634                                 }
635                                 else
636                                         CL_EntityParticles (ent);
637                         }
638                         if (effects & EF_MUZZLEFLASH)
639                                 ent->persistent.muzzleflash = 100.0f;
640                         if (effects & EF_DIMLIGHT)
641                         {
642                                 dlightcolor[0] += 200.0f;
643                                 dlightcolor[1] += 200.0f;
644                                 dlightcolor[2] += 200.0f;
645                         }
646                         if (effects & EF_BRIGHTLIGHT)
647                         {
648                                 dlightcolor[0] += 400.0f;
649                                 dlightcolor[1] += 400.0f;
650                                 dlightcolor[2] += 400.0f;
651                         }
652                         // LordHavoc: added EF_RED and EF_BLUE
653                         if (effects & EF_RED) // red
654                         {
655                                 dlightcolor[0] += 200.0f;
656                                 dlightcolor[1] +=  20.0f;
657                                 dlightcolor[2] +=  20.0f;
658                         }
659                         if (effects & EF_BLUE) // blue
660                         {
661                                 dlightcolor[0] +=  20.0f;
662                                 dlightcolor[1] +=  20.0f;
663                                 dlightcolor[2] += 200.0f;
664                         }
665                         if (effects & EF_FLAME)
666                         {
667                                 if (ent->render.model)
668                                 {
669                                         mins[0] = neworg[0] - 16.0f;
670                                         mins[1] = neworg[1] - 16.0f;
671                                         mins[2] = neworg[2] - 16.0f;
672                                         maxs[0] = neworg[0] + 16.0f;
673                                         maxs[1] = neworg[1] + 16.0f;
674                                         maxs[2] = neworg[2] + 16.0f;
675                                         // how many flames to make
676                                         temp = (int) (cl.time * 300) - (int) (cl.oldtime * 300);
677                                         CL_FlameCube(mins, maxs, temp);
678                                 }
679                                 d = lhrandom(200, 250);
680                                 dlightcolor[0] += d * 1.0f;
681                                 dlightcolor[1] += d * 0.7f;
682                                 dlightcolor[2] += d * 0.3f;
683                         }
684                         if (effects & EF_STARDUST)
685                         {
686                                 if (ent->render.model)
687                                 {
688                                         mins[0] = neworg[0] - 16.0f;
689                                         mins[1] = neworg[1] - 16.0f;
690                                         mins[2] = neworg[2] - 16.0f;
691                                         maxs[0] = neworg[0] + 16.0f;
692                                         maxs[1] = neworg[1] + 16.0f;
693                                         maxs[2] = neworg[2] + 16.0f;
694                                         // how many particles to make
695                                         temp = (int) (cl.time * 200) - (int) (cl.oldtime * 200);
696                                         CL_Stardust(mins, maxs, temp);
697                                 }
698                                 d = 100;
699                                 dlightcolor[0] += d * 1.0f;
700                                 dlightcolor[1] += d * 0.7f;
701                                 dlightcolor[2] += d * 0.3f;
702                         }
703                 }
704
705                 if (ent->persistent.muzzleflash > 0)
706                 {
707                         v2[0] = ent->render.matrix.m[0][0] * 18 + neworg[0];
708                         v2[1] = ent->render.matrix.m[0][1] * 18 + neworg[1];
709                         v2[2] = ent->render.matrix.m[0][2] * 18 + neworg[2] + 16;
710                         CL_TraceLine(neworg, v2, v, NULL, 0, true, NULL);
711
712                         CL_AllocDlight (NULL, v, ent->persistent.muzzleflash, 1, 1, 1, 0, 0);
713                         ent->persistent.muzzleflash -= cl.frametime * 1000;
714                 }
715
716                 // LordHavoc: if the model has no flags, don't check each
717                 if (ent->render.model && ent->render.model->flags)
718                 {
719                         // note: EF_ROTATE handled above, above matrix calculation
720                         // only do trails if present in the previous frame as well
721                         if (ent->state_previous.active)
722                         {
723                                 if (ent->render.model->flags & EF_GIB)
724                                         CL_RocketTrail (oldorg, neworg, 2, ent);
725                                 else if (ent->render.model->flags & EF_ZOMGIB)
726                                         CL_RocketTrail (oldorg, neworg, 4, ent);
727                                 else if (ent->render.model->flags & EF_TRACER)
728                                 {
729                                         CL_RocketTrail (oldorg, neworg, 3, ent);
730                                         dlightcolor[0] += 0x10;
731                                         dlightcolor[1] += 0x40;
732                                         dlightcolor[2] += 0x10;
733                                 }
734                                 else if (ent->render.model->flags & EF_TRACER2)
735                                 {
736                                         CL_RocketTrail (oldorg, neworg, 5, ent);
737                                         dlightcolor[0] += 0x50;
738                                         dlightcolor[1] += 0x30;
739                                         dlightcolor[2] += 0x10;
740                                 }
741                                 else if (ent->render.model->flags & EF_ROCKET)
742                                 {
743                                         CL_RocketTrail (oldorg, ent->render.origin, 0, ent);
744                                         dlightcolor[0] += 200.0f;
745                                         dlightcolor[1] += 160.0f;
746                                         dlightcolor[2] +=  80.0f;
747                                 }
748                                 else if (ent->render.model->flags & EF_GRENADE)
749                                 {
750                                         if (ent->render.alpha == -1) // LordHavoc: Nehahra dem compatibility (cigar smoke)
751                                                 CL_RocketTrail (oldorg, neworg, 7, ent);
752                                         else
753                                                 CL_RocketTrail (oldorg, neworg, 1, ent);
754                                 }
755                                 else if (ent->render.model->flags & EF_TRACER3)
756                                 {
757                                         CL_RocketTrail (oldorg, neworg, 6, ent);
758                                         dlightcolor[0] += 0x50;
759                                         dlightcolor[1] += 0x20;
760                                         dlightcolor[2] += 0x40;
761                                 }
762                         }
763                 }
764                 // LordHavoc: customizable glow
765                 if (ent->state_current.glowsize)
766                 {
767                         // * 4 for the expansion from 0-255 to 0-1023 range,
768                         // / 255 to scale down byte colors
769                         VectorMA(dlightcolor, ent->state_current.glowsize * (4.0f / 255.0f), (qbyte *)&palette_complete[ent->state_current.glowcolor], dlightcolor);
770                 }
771                 // LordHavoc: customizable trail
772                 if (ent->render.flags & RENDER_GLOWTRAIL)
773                         CL_RocketTrail2 (oldorg, neworg, ent->state_current.glowcolor, ent);
774
775                 if (dlightcolor[0] || dlightcolor[1] || dlightcolor[2])
776                 {
777                         VectorCopy(neworg, v);
778                         // hack to make glowing player light shine on their gun
779                         if (i == cl.viewentity/* && !chase_active.integer*/)
780                                 v[2] += 30;
781                         CL_AllocDlight (&ent->render, v, 1, dlightcolor[0], dlightcolor[1], dlightcolor[2], 0, 0);
782                 }
783
784                 if (chase_active.integer && (ent->render.flags & RENDER_VIEWMODEL))
785                         continue;
786
787                 // don't show entities with no modelindex (note: this still shows
788                 // entities which have a modelindex that resolved to a NULL model)
789                 if (!ent->state_current.modelindex)
790                         continue;
791                 if (effects & EF_NODRAW)
792                         continue;
793
794                 // store a list of view-relative entities for later adjustment in view code
795                 if (ent->render.flags & RENDER_VIEWMODEL)
796                 {
797                         if (numviewmodels < MAXVIEWMODELS)
798                                 viewmodels[numviewmodels++] = ent;
799                         continue;
800                 }
801
802                 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
803
804                 CL_BoundingBoxForEntity(&ent->render);
805                 if (ent->render.model && ent->render.model->name[0] == '*' && ent->render.model->type == mod_brush)
806                         cl_brushmodel_entities[cl_num_brushmodel_entities++] = &ent->render;
807
808                 // note: the cl.viewentity and intermission check is to hide player
809                 // shadow during intermission and during the Nehahra movie and
810                 // Nehahra cinematics
811                 if (!(ent->state_current.effects & EF_NOSHADOW)
812                  && !(ent->state_current.effects & EF_ADDITIVE)
813                  && (ent->state_current.alpha == 255)
814                  && !(ent->render.flags & RENDER_VIEWMODEL)
815                  && (i != cl.viewentity || (!cl.intermission && !Nehahrademcompatibility && !cl_noplayershadow.integer)))
816                         ent->render.flags |= RENDER_SHADOW;
817
818                 if (r_refdef.numentities < r_refdef.maxentities)
819                         r_refdef.entities[r_refdef.numentities++] = &ent->render;
820
821                 if (cl_num_entities < i + 1)
822                         cl_num_entities = i + 1;
823         }
824 }
825
826 void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate)
827 {
828         int i;
829         cl_effect_t *e;
830         if (!modelindex) // sanity check
831                 return;
832         for (i = 0, e = cl_effects;i < cl_max_effects;i++, e++)
833         {
834                 if (e->active)
835                         continue;
836                 e->active = true;
837                 VectorCopy(org, e->origin);
838                 e->modelindex = modelindex;
839                 e->starttime = cl.time;
840                 e->startframe = startframe;
841                 e->endframe = startframe + framecount;
842                 e->framerate = framerate;
843
844                 e->frame = 0;
845                 e->frame1time = cl.time;
846                 e->frame2time = cl.time;
847                 break;
848         }
849 }
850
851 static void CL_RelinkEffects(void)
852 {
853         int i, intframe;
854         cl_effect_t *e;
855         entity_t *ent;
856         float frame;
857
858         for (i = 0, e = cl_effects;i < cl_max_effects;i++, e++)
859         {
860                 if (e->active)
861                 {
862                         frame = (cl.time - e->starttime) * e->framerate + e->startframe;
863                         intframe = frame;
864                         if (intframe < 0 || intframe >= e->endframe)
865                         {
866                                 e->active = false;
867                                 memset(e, 0, sizeof(*e));
868                                 continue;
869                         }
870
871                         if (intframe != e->frame)
872                         {
873                                 e->frame = intframe;
874                                 e->frame1time = e->frame2time;
875                                 e->frame2time = cl.time;
876                         }
877
878                         // if we're drawing effects, get a new temp entity
879                         // (NewTempEntity adds it to the render entities list for us)
880                         if (r_draweffects.integer && (ent = CL_NewTempEntity()))
881                         {
882                                 // interpolation stuff
883                                 ent->render.frame1 = intframe;
884                                 ent->render.frame2 = intframe + 1;
885                                 if (ent->render.frame2 >= e->endframe)
886                                         ent->render.frame2 = -1; // disappear
887                                 ent->render.framelerp = frame - intframe;
888                                 ent->render.frame1time = e->frame1time;
889                                 ent->render.frame2time = e->frame2time;
890
891                                 // normal stuff
892                                 //VectorCopy(e->origin, ent->render.origin);
893                                 ent->render.model = cl.model_precache[e->modelindex];
894                                 ent->render.frame = ent->render.frame2;
895                                 ent->render.colormap = -1; // no special coloring
896                                 //ent->render.scale = 1;
897                                 ent->render.alpha = 1;
898
899                                 Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, e->origin[0], e->origin[1], e->origin[2], 0, 0, 0, 1);
900                                 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
901                                 CL_BoundingBoxForEntity(&ent->render);
902                         }
903                 }
904         }
905 }
906
907 void CL_RelinkBeams (void)
908 {
909         int i;
910         beam_t *b;
911         vec3_t dist, org;
912         float d;
913         entity_t *ent;
914         float yaw, pitch;
915         float forward;
916
917         for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
918         {
919                 if (!b->model || b->endtime < cl.time)
920                         continue;
921
922                 // if coming from the player, update the start position
923                 //if (b->entity == cl.viewentity)
924                 //      VectorCopy (cl_entities[cl.viewentity].render.origin, b->start);
925                 if (cl_beams_relative.integer && b->entity && cl_entities[b->entity].state_current.active && b->relativestartvalid)
926                 {
927                         entity_state_t *p = &cl_entities[b->entity].state_previous;
928                         //entity_state_t *c = &cl_entities[b->entity].state_current;
929                         entity_render_t *r = &cl_entities[b->entity].render;
930                         matrix4x4_t matrix, imatrix;
931                         if (b->relativestartvalid == 2)
932                         {
933                                 // not really valid yet, we need to get the orientation now
934                                 // (ParseBeam flagged this because it is received before
935                                 //  entities are received, by now they have been received)
936                                 // note: because players create lightning in their think
937                                 // function (which occurs before movement), they actually
938                                 // have some lag in it's location, so compare to the
939                                 // previous player state, not the latest
940                                 if (b->entity == cl.viewentity)
941                                         Matrix4x4_CreateFromQuakeEntity(&matrix, cl.viewentoriginold[0], cl.viewentoriginold[1], cl.viewentoriginold[2] + 16, cl.viewangles[0], cl.viewangles[1], cl.viewangles[2], 1);
942                                 else
943                                         Matrix4x4_CreateFromQuakeEntity(&matrix, p->origin[0], p->origin[1], p->origin[2] + 16, p->angles[0], p->angles[1], p->angles[2], 1);
944                                 Matrix4x4_Invert_Simple(&imatrix, &matrix);
945                                 Matrix4x4_Transform(&imatrix, b->start, b->relativestart);
946                                 Matrix4x4_Transform(&imatrix, b->end, b->relativeend);
947                                 b->relativestartvalid = 1;
948                         }
949                         else
950                         {
951                                 if (b->entity == cl.viewentity)
952                                         Matrix4x4_CreateFromQuakeEntity(&matrix, cl.viewentorigin[0], cl.viewentorigin[1], cl.viewentorigin[2] + 16, cl.viewangles[0], cl.viewangles[1], cl.viewangles[2], 1);
953                                 else
954                                         Matrix4x4_CreateFromQuakeEntity(&matrix, r->origin[0], r->origin[1], r->origin[2] + 16, r->angles[0], r->angles[1], r->angles[2], 1);
955                                 Matrix4x4_Transform(&matrix, b->relativestart, b->start);
956                                 Matrix4x4_Transform(&matrix, b->relativeend, b->end);
957                         }
958                 }
959
960                 if (b->lightning && cl_beams_polygons.integer)
961                         continue;
962
963                 // calculate pitch and yaw
964                 VectorSubtract (b->end, b->start, dist);
965
966                 if (dist[1] == 0 && dist[0] == 0)
967                 {
968                         yaw = 0;
969                         if (dist[2] > 0)
970                                 pitch = 90;
971                         else
972                                 pitch = 270;
973                 }
974                 else
975                 {
976                         yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
977                         if (yaw < 0)
978                                 yaw += 360;
979
980                         forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
981                         pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
982                         if (pitch < 0)
983                                 pitch += 360;
984                 }
985
986                 // add new entities for the lightning
987                 VectorCopy (b->start, org);
988                 d = VectorNormalizeLength(dist);
989                 while (d > 0)
990                 {
991                         ent = CL_NewTempEntity ();
992                         if (!ent)
993                                 return;
994                         //VectorCopy (org, ent->render.origin);
995                         ent->render.model = b->model;
996                         ent->render.effects = EF_FULLBRIGHT;
997                         //ent->render.angles[0] = pitch;
998                         //ent->render.angles[1] = yaw;
999                         //ent->render.angles[2] = rand()%360;
1000                         Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, org[0], org[1], org[2], pitch, yaw, lhrandom(0, 360), 1);
1001                         Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
1002                         CL_BoundingBoxForEntity(&ent->render);
1003                         VectorMA(org, 30, dist, org);
1004                         d -= 30;
1005                 }
1006         }
1007 }
1008
1009 cvar_t r_lightningbeam_thickness = {CVAR_SAVE, "r_lightningbeam_thickness", "4"};
1010 cvar_t r_lightningbeam_scroll = {CVAR_SAVE, "r_lightningbeam_scroll", "5"};
1011 cvar_t r_lightningbeam_repeatdistance = {CVAR_SAVE, "r_lightningbeam_repeatdistance", "1024"};
1012 cvar_t r_lightningbeam_color_red = {CVAR_SAVE, "r_lightningbeam_color_red", "1"};
1013 cvar_t r_lightningbeam_color_green = {CVAR_SAVE, "r_lightningbeam_color_green", "1"};
1014 cvar_t r_lightningbeam_color_blue = {CVAR_SAVE, "r_lightningbeam_color_blue", "1"};
1015
1016 rtexture_t *r_lightningbeamtexture;
1017 rtexturepool_t *r_lightningbeamtexturepool;
1018
1019 int r_lightningbeamelements[18] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11};
1020
1021 void r_lightningbeams_start(void)
1022 {
1023         float r, g, b, intensity, fx, width, center;
1024         int x, y;
1025         qbyte *data, *noise1, *noise2;
1026         data = Mem_Alloc(tempmempool, 32 * 512 * 4);
1027         noise1 = Mem_Alloc(tempmempool, 512 * 512);
1028         noise2 = Mem_Alloc(tempmempool, 512 * 512);
1029         fractalnoise(noise1, 512, 8);
1030         fractalnoise(noise2, 512, 16);
1031
1032         for (y = 0;y < 512;y++)
1033         {
1034                 width = noise1[y * 512] * (1.0f / 256.0f) * 3.0f + 3.0f;
1035                 center = (noise1[y * 512 + 64] / 256.0f) * (32.0f - (width + 1.0f) * 2.0f) + (width + 1.0f);
1036                 for (x = 0;x < 32;x++, fx++)
1037                 {
1038                         fx = (x - center) / width;
1039                         intensity = (1.0f - fx * fx) * (noise2[y*512+x] * (1.0f / 256.0f) * 0.33f + 0.66f);
1040                         intensity = bound(0, intensity, 1);
1041                         r = intensity * 2.0f - 1.0f;
1042                         g = intensity * 3.0f - 1.0f;
1043                         b = intensity * 3.0f;
1044                         data[(y * 32 + x) * 4 + 0] = (qbyte)(bound(0, r, 1) * 255.0f);
1045                         data[(y * 32 + x) * 4 + 1] = (qbyte)(bound(0, g, 1) * 255.0f);
1046                         data[(y * 32 + x) * 4 + 2] = (qbyte)(bound(0, b, 1) * 255.0f);
1047                         data[(y * 32 + x) * 4 + 3] = (qbyte)255;
1048                 }
1049         }
1050
1051         r_lightningbeamtexturepool = R_AllocTexturePool();
1052         r_lightningbeamtexture = R_LoadTexture2D(r_lightningbeamtexturepool, "lightningbeam", 32, 512, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
1053         Mem_Free(noise1);
1054         Mem_Free(noise2);
1055         Mem_Free(data);
1056 }
1057
1058 void r_lightningbeams_shutdown(void)
1059 {
1060         r_lightningbeamtexture = NULL;
1061         R_FreeTexturePool(&r_lightningbeamtexturepool);
1062 }
1063
1064 void r_lightningbeams_newmap(void)
1065 {
1066 }
1067
1068 void R_LightningBeams_Init(void)
1069 {
1070         Cvar_RegisterVariable(&r_lightningbeam_thickness);
1071         Cvar_RegisterVariable(&r_lightningbeam_scroll);
1072         Cvar_RegisterVariable(&r_lightningbeam_repeatdistance);
1073         Cvar_RegisterVariable(&r_lightningbeam_color_red);
1074         Cvar_RegisterVariable(&r_lightningbeam_color_green);
1075         Cvar_RegisterVariable(&r_lightningbeam_color_blue);
1076         R_RegisterModule("R_LightningBeams", r_lightningbeams_start, r_lightningbeams_shutdown, r_lightningbeams_newmap);
1077 }
1078
1079 void R_CalcLightningBeamPolygonVertices(float *v, float *tc, const float *start, const float *end, const float *offset, float t1, float t2)
1080 {
1081         // near right corner
1082         VectorAdd     (start, offset, (v +  0));tc[ 0] = 0;tc[ 1] = t1;
1083         // near left corner
1084         VectorSubtract(start, offset, (v +  4));tc[ 4] = 1;tc[ 5] = t1;
1085         // far left corner
1086         VectorSubtract(end  , offset, (v +  8));tc[ 8] = 1;tc[ 9] = t2;
1087         // far right corner
1088         VectorAdd     (end  , offset, (v + 12));tc[12] = 0;tc[13] = t2;
1089 }
1090
1091 void R_FogLightningBeamColors(const float *v, float *c, int numverts, float r, float g, float b, float a)
1092 {
1093         int i;
1094         vec3_t fogvec;
1095         float ifog;
1096         for (i = 0;i < numverts;i++, v += 4, c += 4)
1097         {
1098                 VectorSubtract(v, r_origin, fogvec);
1099                 ifog = 1 - exp(fogdensity/DotProduct(fogvec,fogvec));
1100                 c[0] = r * ifog;
1101                 c[1] = g * ifog;
1102                 c[2] = b * ifog;
1103                 c[3] = a;
1104         }
1105 }
1106
1107 float beamrepeatscale;
1108
1109 void R_DrawLightningBeamCallback(const void *calldata1, int calldata2)
1110 {
1111         const beam_t *b = calldata1;
1112         rmeshstate_t m;
1113         vec3_t beamdir, right, up, offset;
1114         float length, t1, t2;
1115         memset(&m, 0, sizeof(m));
1116         m.blendfunc1 = GL_SRC_ALPHA;
1117         m.blendfunc2 = GL_ONE;
1118         m.tex[0] = R_GetTexture(r_lightningbeamtexture);
1119         R_Mesh_State(&m);
1120         R_Mesh_Matrix(&r_identitymatrix);
1121
1122         // calculate beam direction (beamdir) vector and beam length
1123         // get difference vector
1124         VectorSubtract(b->end, b->start, beamdir);
1125         // find length of difference vector
1126         length = sqrt(DotProduct(beamdir, beamdir));
1127         // calculate scale to make beamdir a unit vector (normalized)
1128         t1 = 1.0f / length;
1129         // scale beamdir so it is now normalized
1130         VectorScale(beamdir, t1, beamdir);
1131
1132         // calculate up vector such that it points toward viewer, and rotates around the beamdir
1133         // get direction from start of beam to viewer
1134         VectorSubtract(r_origin, b->start, up);
1135         // remove the portion of the vector that moves along the beam
1136         // (this leaves only a vector pointing directly away from the beam)
1137         t1 = -DotProduct(up, beamdir);
1138         VectorMA(up, t1, beamdir, up);
1139         // now we have a vector pointing away from the beam, now we need to normalize it
1140         VectorNormalizeFast(up);
1141         // generate right vector from forward and up, the result is already normalized
1142         // (CrossProduct returns a vector of multiplied length of the two inputs)
1143         CrossProduct(beamdir, up, right);
1144
1145         // calculate T coordinate scrolling (start and end texcoord along the beam)
1146         t1 = cl.time * -r_lightningbeam_scroll.value + beamrepeatscale * DotProduct(b->start, beamdir);
1147         t1 = t1 - (int) t1;
1148         t2 = t1 + beamrepeatscale * length;
1149
1150         // the beam is 3 polygons in this configuration:
1151         //  *   2
1152         //   * *
1153         // 1******
1154         //   * *
1155         //  *   3
1156         // they are showing different portions of the beam texture, creating an
1157         // illusion of a beam that appears to curl around in 3D space
1158         // (and realize that the whole polygon assembly orients itself to face
1159         //  the viewer)
1160
1161         R_Mesh_GetSpace(12);
1162
1163         // polygon 1, verts 0-3
1164         VectorScale(right, r_lightningbeam_thickness.value, offset);
1165         R_CalcLightningBeamPolygonVertices(varray_vertex, varray_texcoord[0], b->start, b->end, offset, t1, t2);
1166
1167         // polygon 2, verts 4-7
1168         VectorAdd(right, up, offset);
1169         VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
1170         R_CalcLightningBeamPolygonVertices(varray_vertex + 16, varray_texcoord[0] + 16, b->start, b->end, offset, t1 + 0.33, t2 + 0.33);
1171
1172         // polygon 3, verts 8-11
1173         VectorSubtract(right, up, offset);
1174         VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
1175         R_CalcLightningBeamPolygonVertices(varray_vertex + 32, varray_texcoord[0] + 32, b->start, b->end, offset, t1 + 0.66, t2 + 0.66);
1176
1177         if (fogenabled)
1178         {
1179                 // per vertex colors if fog is used
1180                 GL_UseColorArray();
1181                 R_FogLightningBeamColors(varray_vertex, varray_color, 12, r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1);
1182         }
1183         else
1184         {
1185                 // solid color if fog is not used
1186                 GL_Color(r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1);
1187         }
1188
1189         // draw the 3 polygons as one batch of 6 triangles using the 12 vertices
1190         R_Mesh_Draw(12, 6, r_lightningbeamelements);
1191 }
1192
1193 void R_DrawLightningBeams (void)
1194 {
1195         int i;
1196         beam_t *b;
1197         vec3_t org;
1198
1199         if (!cl_beams_polygons.integer)
1200                 return;
1201
1202         beamrepeatscale = 1.0f / r_lightningbeam_repeatdistance.value;
1203         for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
1204         {
1205                 if (b->model && b->endtime >= cl.time && b->lightning)
1206                 {
1207                         VectorAdd(b->start, b->end, org);
1208                         VectorScale(org, 0.5f, org);
1209                         R_MeshQueue_AddTransparent(org, R_DrawLightningBeamCallback, b, 0);
1210                 }
1211         }
1212 }
1213
1214
1215 void CL_LerpPlayer(float frac)
1216 {
1217         int i;
1218         float d;
1219
1220         if (cl.entitydatabase.numframes && cl.viewentity == cl.playerentity)
1221         {
1222                 cl.viewentorigin[0] = cl.viewentoriginold[0] + frac * (cl.viewentoriginnew[0] - cl.viewentoriginold[0]);
1223                 cl.viewentorigin[1] = cl.viewentoriginold[1] + frac * (cl.viewentoriginnew[1] - cl.viewentoriginold[1]);
1224                 cl.viewentorigin[2] = cl.viewentoriginold[2] + frac * (cl.viewentoriginnew[2] - cl.viewentoriginold[2]);
1225         }
1226         else
1227         {
1228                 VectorCopy (cl_entities[cl.viewentity].state_previous.origin, cl.viewentoriginold);
1229                 VectorCopy (cl_entities[cl.viewentity].state_current.origin, cl.viewentoriginnew);
1230                 VectorCopy (cl_entities[cl.viewentity].render.origin, cl.viewentorigin);
1231         }
1232
1233         cl.viewzoom = cl.viewzoomold + frac * (cl.viewzoomnew - cl.viewzoomold);
1234
1235         for (i = 0;i < 3;i++)
1236                 cl.velocity[i] = cl.mvelocity[1][i] + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);
1237
1238         if (cls.demoplayback)
1239         {
1240                 // interpolate the angles
1241                 for (i = 0;i < 3;i++)
1242                 {
1243                         d = cl.mviewangles[0][i] - cl.mviewangles[1][i];
1244                         if (d > 180)
1245                                 d -= 360;
1246                         else if (d < -180)
1247                                 d += 360;
1248                         cl.viewangles[i] = cl.mviewangles[1][i] + frac * d;
1249                 }
1250         }
1251 }
1252
1253 void CL_RelinkEntities (void)
1254 {
1255         float frac;
1256
1257         // fraction from previous network update to current
1258         frac = CL_LerpPoint();
1259
1260         CL_ClearTempEntities();
1261         CL_DecayLights();
1262         CL_RelinkWorld();
1263         CL_RelinkStaticEntities();
1264         CL_RelinkNetworkEntities();
1265         CL_RelinkEffects();
1266         CL_MoveParticles();
1267
1268         CL_LerpPlayer(frac);
1269
1270         CL_RelinkBeams();
1271 }
1272
1273
1274 /*
1275 ===============
1276 CL_ReadFromServer
1277
1278 Read all incoming data from the server
1279 ===============
1280 */
1281 int CL_ReadFromServer (void)
1282 {
1283         int ret, netshown;
1284
1285         cl.oldtime = cl.time;
1286         cl.time += cl.frametime;
1287
1288         netshown = false;
1289         do
1290         {
1291                 ret = CL_GetMessage ();
1292                 if (ret == -1)
1293                         Host_Error ("CL_ReadFromServer: lost server connection");
1294                 if (!ret)
1295                         break;
1296
1297                 cl.last_received_message = realtime;
1298
1299                 if (cl_shownet.integer)
1300                         netshown = true;
1301
1302                 CL_ParseServerMessage ();
1303         }
1304         while (ret && cls.state == ca_connected);
1305
1306         if (netshown)
1307                 Con_Printf ("\n");
1308
1309         r_refdef.numentities = 0;
1310         cl_num_entities = 0;
1311         cl_num_brushmodel_entities = 0;
1312
1313         if (cls.state == ca_connected && cls.signon == SIGNONS)
1314         {
1315                 CL_RelinkEntities ();
1316
1317                 // run cgame code (which can add more entities)
1318                 CL_CGVM_Frame();
1319         }
1320
1321 //
1322 // bring the links up to date
1323 //
1324         return 0;
1325 }
1326
1327 /*
1328 =================
1329 CL_SendCmd
1330 =================
1331 */
1332 void CL_SendCmd (void)
1333 {
1334         usercmd_t               cmd;
1335
1336         if (cls.state != ca_connected)
1337                 return;
1338
1339         if (cls.signon == SIGNONS)
1340         {
1341         // get basic movement from keyboard
1342                 CL_BaseMove (&cmd);
1343
1344                 IN_PreMove(); // OS independent code
1345
1346         // allow mice or other external controllers to add to the move
1347                 IN_Move (&cmd);
1348
1349                 IN_PostMove(); // OS independent code
1350
1351         // send the unreliable message
1352                 CL_SendMove (&cmd);
1353         }
1354 #ifndef NOROUTINGFIX
1355         else if (cls.signon == 0 && !cls.demoplayback)
1356         {
1357                 // LordHavoc: fix for NAT routing of netquake:
1358                 // bounce back a clc_nop message to the newly allocated server port,
1359                 // to establish a routing connection for incoming frames,
1360                 // the server waits for this before sending anything
1361                 if (realtime > cl.sendnoptime)
1362                 {
1363                         cl.sendnoptime = realtime + 3;
1364                         Con_DPrintf("sending clc_nop to get server's attention\n");
1365                         {
1366                                 sizebuf_t buf;
1367                                 qbyte data[128];
1368                                 buf.maxsize = 128;
1369                                 buf.cursize = 0;
1370                                 buf.data = data;
1371                                 MSG_WriteByte(&buf, clc_nop);
1372                                 if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
1373                                 {
1374                                         Con_Printf ("CL_SendCmd: lost server connection\n");
1375                                         CL_Disconnect ();
1376                                 }
1377                         }
1378                 }
1379         }
1380 #endif
1381
1382         if (cls.demoplayback)
1383         {
1384                 SZ_Clear (&cls.message);
1385                 return;
1386         }
1387
1388 // send the reliable message
1389         if (!cls.message.cursize)
1390                 return;         // no message at all
1391
1392         if (!NET_CanSendMessage (cls.netcon))
1393         {
1394                 Con_DPrintf ("CL_WriteToServer: can't send\n");
1395                 if (developer.integer)
1396                         SZ_HexDumpToConsole(&cls.message);
1397                 return;
1398         }
1399
1400         if (NET_SendMessage (cls.netcon, &cls.message) == -1)
1401                 Host_Error ("CL_WriteToServer: lost server connection");
1402
1403         SZ_Clear (&cls.message);
1404 }
1405
1406 // LordHavoc: pausedemo command
1407 static void CL_PauseDemo_f (void)
1408 {
1409         cls.demopaused = !cls.demopaused;
1410         if (cls.demopaused)
1411                 Con_Printf("Demo paused\n");
1412         else
1413                 Con_Printf("Demo unpaused\n");
1414 }
1415
1416 /*
1417 ======================
1418 CL_PModel_f
1419 LordHavoc: Intended for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1420 ======================
1421 */
1422 static void CL_PModel_f (void)
1423 {
1424         int i;
1425         eval_t *val;
1426
1427         if (Cmd_Argc () == 1)
1428         {
1429                 Con_Printf ("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1430                 return;
1431         }
1432         i = atoi(Cmd_Argv(1));
1433
1434         if (cmd_source == src_command)
1435         {
1436                 if (cl_pmodel.integer == i)
1437                         return;
1438                 Cvar_SetValue ("_cl_pmodel", i);
1439                 if (cls.state == ca_connected)
1440                         Cmd_ForwardToServer ();
1441                 return;
1442         }
1443
1444         host_client->pmodel = i;
1445         if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_pmodel)))
1446                 val->_float = i;
1447 }
1448
1449 /*
1450 ======================
1451 CL_Fog_f
1452 ======================
1453 */
1454 static void CL_Fog_f (void)
1455 {
1456         if (Cmd_Argc () == 1)
1457         {
1458                 Con_Printf ("\"fog\" is \"%f %f %f %f\"\n", fog_density, fog_red, fog_green, fog_blue);
1459                 return;
1460         }
1461         fog_density = atof(Cmd_Argv(1));
1462         fog_red = atof(Cmd_Argv(2));
1463         fog_green = atof(Cmd_Argv(3));
1464         fog_blue = atof(Cmd_Argv(4));
1465 }
1466
1467 /*
1468 =================
1469 CL_Init
1470 =================
1471 */
1472 void CL_Init (void)
1473 {
1474         cl_scores_mempool = Mem_AllocPool("client player info");
1475         cl_entities_mempool = Mem_AllocPool("client entities");
1476         cl_refdef_mempool = Mem_AllocPool("refdef");
1477
1478         memset(&r_refdef, 0, sizeof(r_refdef));
1479         // max entities sent to renderer per frame
1480         r_refdef.maxentities = MAX_EDICTS + 256 + 512;
1481         r_refdef.entities = Mem_Alloc(cl_refdef_mempool, sizeof(entity_render_t *) * r_refdef.maxentities);
1482         // 256k drawqueue buffer
1483         r_refdef.maxdrawqueuesize = 256 * 1024;
1484         r_refdef.drawqueue = Mem_Alloc(cl_refdef_mempool, r_refdef.maxdrawqueuesize);
1485
1486         SZ_Alloc (&cls.message, 1024, "cls.message");
1487
1488         CL_InitInput ();
1489         CL_InitTEnts ();
1490
1491 //
1492 // register our commands
1493 //
1494         Cvar_RegisterVariable (&cl_name);
1495         Cvar_RegisterVariable (&cl_color);
1496         if (gamemode == GAME_NEHAHRA)
1497                 Cvar_RegisterVariable (&cl_pmodel);
1498         Cvar_RegisterVariable (&cl_upspeed);
1499         Cvar_RegisterVariable (&cl_forwardspeed);
1500         Cvar_RegisterVariable (&cl_backspeed);
1501         Cvar_RegisterVariable (&cl_sidespeed);
1502         Cvar_RegisterVariable (&cl_movespeedkey);
1503         Cvar_RegisterVariable (&cl_yawspeed);
1504         Cvar_RegisterVariable (&cl_pitchspeed);
1505         Cvar_RegisterVariable (&cl_anglespeedkey);
1506         Cvar_RegisterVariable (&cl_shownet);
1507         Cvar_RegisterVariable (&cl_nolerp);
1508         Cvar_RegisterVariable (&lookspring);
1509         Cvar_RegisterVariable (&lookstrafe);
1510         Cvar_RegisterVariable (&sensitivity);
1511         Cvar_RegisterVariable (&freelook);
1512
1513         Cvar_RegisterVariable (&m_pitch);
1514         Cvar_RegisterVariable (&m_yaw);
1515         Cvar_RegisterVariable (&m_forward);
1516         Cvar_RegisterVariable (&m_side);
1517
1518         Cvar_RegisterVariable (&cl_itembobspeed);
1519         Cvar_RegisterVariable (&cl_itembobheight);
1520
1521         Cmd_AddCommand ("entities", CL_PrintEntities_f);
1522         Cmd_AddCommand ("disconnect", CL_Disconnect_f);
1523         Cmd_AddCommand ("record", CL_Record_f);
1524         Cmd_AddCommand ("stop", CL_Stop_f);
1525         Cmd_AddCommand ("playdemo", CL_PlayDemo_f);
1526         Cmd_AddCommand ("timedemo", CL_TimeDemo_f);
1527
1528         Cmd_AddCommand ("fog", CL_Fog_f);
1529
1530         // LordHavoc: added pausedemo
1531         Cmd_AddCommand ("pausedemo", CL_PauseDemo_f);
1532         if (gamemode == GAME_NEHAHRA)
1533                 Cmd_AddCommand ("pmodel", CL_PModel_f);
1534
1535         Cvar_RegisterVariable(&r_draweffects);
1536         Cvar_RegisterVariable(&cl_explosions);
1537         Cvar_RegisterVariable(&cl_stainmaps);
1538         Cvar_RegisterVariable(&cl_beams_polygons);
1539         Cvar_RegisterVariable(&cl_beams_relative);
1540         Cvar_RegisterVariable(&cl_noplayershadow);
1541
1542         R_LightningBeams_Init();
1543
1544         CL_Parse_Init();
1545         CL_Particles_Init();
1546         CL_Screen_Init();
1547         CL_CGVM_Init();
1548
1549         CL_Video_Init();
1550 }
1551