added viewzoom extension to QC and client (smooth sniper zooming, with sensitivity...
[divverent/darkplaces.git] / cl_screen.c
1
2 #include "quakedef.h"
3
4 cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100"};
5 cvar_t scr_fov = {CVAR_SAVE, "fov","90"};       // 10 - 170
6 cvar_t scr_conspeed = {CVAR_SAVE, "scr_conspeed","900"}; // LordHavoc: quake used 300
7 cvar_t scr_centertime = {0, "scr_centertime","2"};
8 cvar_t scr_showram = {CVAR_SAVE, "showram","1"};
9 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0"};
10 cvar_t scr_showpause = {CVAR_SAVE, "showpause","1"};
11 cvar_t scr_printspeed = {0, "scr_printspeed","8"};
12 cvar_t scr_2dresolution = {CVAR_SAVE, "scr_2dresolution", "1"};
13
14 qboolean        scr_initialized;                // ready to draw
15
16 float           scr_con_current;
17 float           scr_conlines;           // lines of console to display
18
19 int                     clearconsole;
20 int                     clearnotify;
21
22 qboolean        scr_disabled_for_loading;
23 //qboolean      scr_drawloading;
24 //float         scr_disabled_time;
25
26 static byte menuplyr_pixels[4096];
27
28 /*
29 ===============================================================================
30
31 CENTER PRINTING
32
33 ===============================================================================
34 */
35
36 char            scr_centerstring[1024];
37 float           scr_centertime_start;   // for slow victory printing
38 float           scr_centertime_off;
39 int                     scr_center_lines;
40 int                     scr_erase_lines;
41 int                     scr_erase_center;
42
43 /*
44 ==============
45 SCR_CenterPrint
46
47 Called for important messages that should stay in the center of the screen
48 for a few moments
49 ==============
50 */
51 void SCR_CenterPrint (char *str)
52 {
53         strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
54         scr_centertime_off = scr_centertime.value;
55         scr_centertime_start = cl.time;
56
57 // count the number of lines for centering
58         scr_center_lines = 1;
59         while (*str)
60         {
61                 if (*str == '\n')
62                         scr_center_lines++;
63                 str++;
64         }
65 }
66
67
68 void SCR_DrawCenterString (void)
69 {
70         char    *start;
71         int             l;
72         int             x, y;
73         int             remaining;
74
75 // the finale prints the characters one at a time
76         if (cl.intermission)
77                 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
78         else
79                 remaining = 9999;
80
81         scr_erase_center = 0;
82         start = scr_centerstring;
83
84         if (scr_center_lines <= 4)
85                 y = vid.conheight*0.35;
86         else
87                 y = 48;
88
89         do
90         {
91         // scan the width of the line
92                 for (l=0 ; l<40 ; l++)
93                         if (start[l] == '\n' || !start[l])
94                                 break;
95                 x = (vid.conwidth - l*8)/2;
96                 if (l > 0)
97                 {
98                         if (remaining < l)
99                                 l = remaining;
100                         DrawQ_String(x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
101                         remaining -= l;
102                         if (remaining <= 0)
103                                 return;
104                 }
105
106                 y += 8;
107
108                 while (*start && *start != '\n')
109                         start++;
110
111                 if (!*start)
112                         break;
113                 start++;                // skip the \n
114         } while (1);
115 }
116
117 void SCR_CheckDrawCenterString (void)
118 {
119         if (scr_center_lines > scr_erase_lines)
120                 scr_erase_lines = scr_center_lines;
121
122         scr_centertime_off -= host_frametime;
123
124         if (scr_centertime_off <= 0 && !cl.intermission)
125                 return;
126         if (key_dest != key_game)
127                 return;
128
129         SCR_DrawCenterString ();
130 }
131
132 /*
133 ==============
134 SCR_DrawRam
135 ==============
136 */
137 void SCR_DrawRam (void)
138 {
139 //      if (!scr_showram.integer)
140 //              return;
141 //      DrawQ_Pic (32, 0, "ram", 0, 0, 1, 1, 1, 1, 0);
142 }
143
144 /*
145 ==============
146 SCR_DrawTurtle
147 ==============
148 */
149 void SCR_DrawTurtle (void)
150 {
151         static int      count;
152
153         if (cls.state != ca_connected)
154                 return;
155
156         if (!scr_showturtle.integer)
157                 return;
158
159         if (host_frametime < 0.1)
160         {
161                 count = 0;
162                 return;
163         }
164
165         count++;
166         if (count < 3)
167                 return;
168
169         DrawQ_Pic (0, 0, "turtle", 0, 0, 1, 1, 1, 1, 0);
170 }
171
172 /*
173 ==============
174 SCR_DrawNet
175 ==============
176 */
177 void SCR_DrawNet (void)
178 {
179         if (cls.state != ca_connected)
180                 return;
181         if (realtime - cl.last_received_message < 0.3)
182                 return;
183         if (cls.demoplayback)
184                 return;
185
186         DrawQ_Pic (64, 0, "net", 0, 0, 1, 1, 1, 1, 0);
187 }
188
189 /*
190 ==============
191 DrawPause
192 ==============
193 */
194 void SCR_DrawPause (void)
195 {
196         cachepic_t      *pic;
197
198         if (cls.state != ca_connected)
199                 return;
200
201         if (!scr_showpause.integer)             // turn off for screenshots
202                 return;
203
204         if (!cl.paused)
205                 return;
206
207         pic = Draw_CachePic ("gfx/pause.lmp");
208         DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/pause.lmp", 0, 0, 1, 1, 1, 1, 0);
209 }
210
211
212
213 /*
214 ==============
215 SCR_DrawLoading
216 ==============
217 */
218 /*
219 void SCR_DrawLoading (void)
220 {
221         cachepic_t      *pic;
222
223         if (!scr_drawloading)
224                 return;
225
226         pic = Draw_CachePic ("gfx/loading.lmp");
227         DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/loading.lmp", 0, 0, 1, 1, 1, 1, 0);
228 }
229 */
230
231
232
233 //=============================================================================
234
235
236 /*
237 ==================
238 SCR_SetUpToDrawConsole
239 ==================
240 */
241 void SCR_SetUpToDrawConsole (void)
242 {
243         Con_CheckResize ();
244
245 // decide on the height of the console
246         con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
247
248         if (con_forcedup)
249         {
250                 scr_conlines = vid.conheight;           // full screen
251                 scr_con_current = scr_conlines;
252         }
253         else if (key_dest == key_console)
254                 scr_conlines = vid.conheight/2; // half screen
255         else
256                 scr_conlines = 0;                               // none visible
257
258         if (scr_conlines < scr_con_current)
259         {
260                 scr_con_current -= scr_conspeed.value*host_realframetime;
261                 if (scr_conlines > scr_con_current)
262                         scr_con_current = scr_conlines;
263
264         }
265         else if (scr_conlines > scr_con_current)
266         {
267                 scr_con_current += scr_conspeed.value*host_realframetime;
268                 if (scr_conlines < scr_con_current)
269                         scr_con_current = scr_conlines;
270         }
271 }
272
273 /*
274 ==================
275 SCR_DrawConsole
276 ==================
277 */
278 void SCR_DrawConsole (void)
279 {
280         if (scr_con_current)
281         {
282                 Con_DrawConsole (scr_con_current);
283                 clearconsole = 0;
284         }
285         else
286         {
287                 if (key_dest == key_game || key_dest == key_message)
288                         Con_DrawNotify ();      // only draw notify in game
289         }
290 }
291
292 /*
293 ===============
294 SCR_BeginLoadingPlaque
295
296 ================
297 */
298 /*
299 void SCR_BeginLoadingPlaque (void)
300 {
301         S_StopAllSounds (true);
302
303 //      if (cls.state != ca_connected)
304 //              return;
305 //      if (cls.signon != SIGNONS)
306 //              return;
307
308 // redraw with no console and the loading plaque
309 //      Con_ClearNotify ();
310 //      scr_centertime_off = 0;
311 //      scr_con_current = 0;
312
313         scr_drawloading = true;
314         SCR_UpdateScreen ();
315
316 //      scr_disabled_for_loading = true;
317 //      scr_disabled_time = realtime;
318 }
319 */
320
321 /*
322 ===============
323 SCR_EndLoadingPlaque
324
325 ================
326 */
327 /*
328 void SCR_EndLoadingPlaque (void)
329 {
330 //      scr_disabled_for_loading = false;
331         scr_drawloading = false;
332         Con_ClearNotify ();
333 }
334 */
335
336 //=============================================================================
337
338 char    *scr_notifystring;
339
340 void SCR_DrawNotifyString (void)
341 {
342         char    *start;
343         int             l;
344         int             x, y;
345
346         start = scr_notifystring;
347
348         y = vid.conheight*0.35;
349
350         do
351         {
352         // scan the width of the line
353                 for (l=0 ; l<40 ; l++)
354                         if (start[l] == '\n' || !start[l])
355                                 break;
356                 x = (vid.conwidth - l*8)/2;
357                 DrawQ_String (x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
358
359                 y += 8;
360
361                 while (*start && *start != '\n')
362                         start++;
363
364                 if (!*start)
365                         break;
366                 start++;                // skip the \n
367         }
368         while (1);
369 }
370
371 void DrawCrosshair(int num);
372
373 char r_speeds_string[1024];
374 int speedstringcount, r_timereport_active;
375 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
376
377 void R_TimeReport(char *desc)
378 {
379         char tempbuf[256];
380         int length;
381         int t;
382
383         if (!r_timereport_active)
384                 return;
385
386         r_timereport_temp = r_timereport_current;
387         r_timereport_current = Sys_DoubleTime();
388         t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
389
390         sprintf(tempbuf, "%8i %s", t, desc);
391         length = strlen(tempbuf);
392         while (length < 20)
393                 tempbuf[length++] = ' ';
394         tempbuf[length] = 0;
395         if (speedstringcount + length > (vid.conwidth / 8))
396         {
397                 strcat(r_speeds_string, "\n");
398                 speedstringcount = 0;
399         }
400         // skip the space at the beginning if it's the first on the line
401         if (speedstringcount == 0)
402         {
403                 strcat(r_speeds_string, tempbuf + 1);
404                 speedstringcount = length - 1;
405         }
406         else
407         {
408                 strcat(r_speeds_string, tempbuf);
409                 speedstringcount += length;
410         }
411 }
412
413 void R_TimeReport_Start(void)
414 {
415         r_timereport_active = r_speeds.integer && cl.worldmodel && cls.state == ca_connected;
416         r_speeds_string[0] = 0;
417         if (r_timereport_active)
418         {
419                 speedstringcount = 0;
420                 AngleVectors (r_refdef.viewangles, vpn, NULL, NULL);
421                 //sprintf(r_speeds_string, "org:'%c%6.2f %c%6.2f %c%6.2f' ang:'%c%3.0f %c%3.0f %c%3.0f' dir:'%c%2.3f %c%2.3f %c%2.3f'\n%6i walls %6i dlitwalls %7i modeltris %7i meshtris\nBSP: %6i faces %6i nodes %6i leafs\n%4i models %4i bmodels %4i sprites %5i particles %3i dlights\n",
422                 //      r_refdef.vieworg[0] < 0 ? '-' : ' ', fabs(r_refdef.vieworg[0]), r_refdef.vieworg[1] < 0 ? '-' : ' ', fabs(r_refdef.vieworg[1]), r_refdef.vieworg[2] < 0 ? '-' : ' ', fabs(r_refdef.vieworg[2]),
423                 //      r_refdef.viewangles[0] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[0]), r_refdef.viewangles[1] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[1]), r_refdef.viewangles[2] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[2]),
424                 //      vpn[0] < 0 ? '-' : ' ', fabs(vpn[0]), vpn[1] < 0 ? '-' : ' ', fabs(vpn[1]), vpn[2] < 0 ? '-' : ' ', fabs(vpn[2]),
425                 sprintf(r_speeds_string,
426                         "org:'%+8.2f %+8.2f %+8.2f' ang:'%+4.0f %+4.0f %+4.0f' dir:'%+2.3f %+2.3f %+2.3f'\n"
427                         "world:%6i faces%6i nodes%6i leafs%6i walls%6i dlitwalls\n"
428                         "%5i models%5i bmodels%5i sprites%6i particles%4i dlights\n"
429                         "%6i modeltris%6i transmeshs%6i transtris%6i meshs%6i meshtris\n",
430                         r_refdef.vieworg[0], r_refdef.vieworg[1], r_refdef.vieworg[2], r_refdef.viewangles[0], r_refdef.viewangles[1], r_refdef.viewangles[2], vpn[0], vpn[1], vpn[2],
431                         c_faces, c_nodes, c_leafs, c_brush_polys, c_light_polys,
432                         c_models, c_bmodels, c_sprites, c_particles, c_dlights,
433                         c_alias_polys, c_transmeshs, c_transtris, c_meshs, c_meshtris);
434
435                 c_brush_polys = 0;
436                 c_alias_polys = 0;
437                 c_light_polys = 0;
438                 c_faces = 0;
439                 c_nodes = 0;
440                 c_leafs = 0;
441                 c_models = 0;
442                 c_bmodels = 0;
443                 c_sprites = 0;
444                 c_particles = 0;
445         //      c_dlights = 0;
446
447                 r_timereport_start = Sys_DoubleTime();
448         }
449 }
450
451 void R_TimeReport_End(void)
452 {
453         r_timereport_current = r_timereport_start;
454         R_TimeReport("total");
455
456         if (r_timereport_active)
457         {
458                 int i, j, lines, y;
459                 lines = 1;
460                 for (i = 0;r_speeds_string[i];i++)
461                         if (r_speeds_string[i] == '\n')
462                                 lines++;
463                 y = vid.conheight - sb_lines - lines * 8/* - 8*/;
464                 i = j = 0;
465                 DrawQ_Fill(0, y, vid.conwidth, lines * 8, 0, 0, 0, 0.5, 0);
466                 while (r_speeds_string[i])
467                 {
468                         j = i;
469                         while (r_speeds_string[i] && r_speeds_string[i] != '\n')
470                                 i++;
471                         if (i - j > 0)
472                                 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
473                         if (r_speeds_string[i] == '\n')
474                                 i++;
475                         y += 8;
476                 }
477         }
478 }
479
480 /*
481 =================
482 SCR_SizeUp_f
483
484 Keybinding command
485 =================
486 */
487 void SCR_SizeUp_f (void)
488 {
489         Cvar_SetValue ("viewsize",scr_viewsize.value+10);
490 }
491
492
493 /*
494 =================
495 SCR_SizeDown_f
496
497 Keybinding command
498 =================
499 */
500 void SCR_SizeDown_f (void)
501 {
502         Cvar_SetValue ("viewsize",scr_viewsize.value-10);
503 }
504
505 void CL_Screen_Init(void)
506 {
507         qpic_t *dat;
508
509         Cvar_RegisterVariable (&scr_fov);
510         Cvar_RegisterVariable (&scr_viewsize);
511         Cvar_RegisterVariable (&scr_conspeed);
512         Cvar_RegisterVariable (&scr_showram);
513         Cvar_RegisterVariable (&scr_showturtle);
514         Cvar_RegisterVariable (&scr_showpause);
515         Cvar_RegisterVariable (&scr_centertime);
516         Cvar_RegisterVariable (&scr_printspeed);
517         Cvar_RegisterVariable(&scr_2dresolution);
518
519         Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
520         Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
521
522         scr_initialized = true;
523
524         // HACK HACK HACK
525         // load the image data for the player image in the config menu
526         dat = (qpic_t *)COM_LoadFile ("gfx/menuplyr.lmp", false);
527         if (!dat)
528                 Sys_Error("unable to load gfx/menuplyr.lmp");
529         SwapPic (dat);
530
531         if (dat->width*dat->height <= 4096)
532                 memcpy (menuplyr_pixels, dat->data, dat->width * dat->height);
533         else
534                 Con_Printf("gfx/menuplyr.lmp larger than 4k buffer");
535         Mem_Free(dat);
536 }
537
538 void DrawQ_Clear(void)
539 {
540         r_refdef.drawqueuesize = 0;
541 }
542
543 void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
544 {
545         int size;
546         drawqueue_t *dq;
547         if (alpha < (1.0f / 255.0f))
548                 return;
549         size = sizeof(*dq) + ((strlen(picname) + 1 + 3) & ~3);
550         if (r_refdef.drawqueuesize + size > MAX_DRAWQUEUE)
551                 return;
552         red = bound(0, red, 1);
553         green = bound(0, green, 1);
554         blue = bound(0, blue, 1);
555         alpha = bound(0, alpha, 1);
556         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
557         dq->size = size;
558         dq->command = DRAWQUEUE_PIC;
559         dq->flags = flags;
560         dq->color = ((unsigned int) (red * 255.0f) << 24) | ((unsigned int) (green * 255.0f) << 16) | ((unsigned int) (blue * 255.0f) << 8) | ((unsigned int) (alpha * 255.0f));
561         dq->x = x;
562         dq->y = y;
563         // if these are not zero, they override the pic's size
564         dq->scalex = width;
565         dq->scaley = height;
566         strcpy((char *)(dq + 1), picname);
567         r_refdef.drawqueuesize += dq->size;
568 }
569
570 void DrawQ_String(float x, float y, char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
571 {
572         int size, len;
573         drawqueue_t *dq;
574         char *out;
575         if (alpha < (1.0f / 255.0f))
576                 return;
577         if (maxlen < 1)
578                 len = strlen(string);
579         else
580                 for (len = 0;len < maxlen && string[len];len++);
581         for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
582         for (;len > 0 && string[len - 1] == ' ';len--);
583         if (len < 1)
584                 return;
585         if (x >= vid.conwidth || y >= vid.conheight || x < (-scalex * maxlen) || y < (-scaley))
586                 return;
587         size = sizeof(*dq) + ((len + 1 + 3) & ~3);
588         if (r_refdef.drawqueuesize + size > MAX_DRAWQUEUE)
589                 return;
590         red = bound(0, red, 1);
591         green = bound(0, green, 1);
592         blue = bound(0, blue, 1);
593         alpha = bound(0, alpha, 1);
594         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
595         dq->size = size;
596         dq->command = DRAWQUEUE_STRING;
597         dq->flags = flags;
598         dq->color = ((unsigned int) (red * 255.0f) << 24) | ((unsigned int) (green * 255.0f) << 16) | ((unsigned int) (blue * 255.0f) << 8) | ((unsigned int) (alpha * 255.0f));
599         dq->x = x;
600         dq->y = y;
601         dq->scalex = scalex;
602         dq->scaley = scaley;
603         out = (char *)(dq + 1);
604         memcpy(out, string, len);
605         out[len] = 0;
606         r_refdef.drawqueuesize += dq->size;
607 }
608
609 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
610 {
611         int size;
612         drawqueue_t *dq;
613         if (alpha < (1.0f / 255.0f))
614                 return;
615         size = sizeof(*dq) + 4;
616         if (r_refdef.drawqueuesize + size > MAX_DRAWQUEUE)
617                 return;
618         red = bound(0, red, 1);
619         green = bound(0, green, 1);
620         blue = bound(0, blue, 1);
621         alpha = bound(0, alpha, 1);
622         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
623         dq->size = size;
624         dq->command = DRAWQUEUE_PIC;
625         dq->flags = flags;
626         dq->color = ((unsigned int) (red * 255.0f) << 24) | ((unsigned int) (green * 255.0f) << 16) | ((unsigned int) (blue * 255.0f) << 8) | ((unsigned int) (alpha * 255.0f));
627         dq->x = x;
628         dq->y = y;
629         dq->scalex = w;
630         dq->scaley = h;
631         // empty pic name
632         *((char *)(dq + 1)) = 0;
633         r_refdef.drawqueuesize += dq->size;
634 }
635
636 //only used for the player color selection menu
637 void DrawQ_PicTranslate (int x, int y, char *picname, byte *translation)
638 {
639         int i, c;
640         unsigned int trans[4096];
641         cachepic_t *pic;
642
643         pic = Draw_CachePic(picname);
644         if (pic == NULL)
645                 return;
646
647         c = pic->width * pic->height;
648         if (c > 4096)
649         {
650                 Con_Printf("DrawQ_PicTranslate: image larger than 4k buffer\n");
651                 return;
652         }
653
654         for (i = 0;i < c;i++)
655                 trans[i] = d_8to24table[translation[menuplyr_pixels[i]]];
656
657         // FIXME: this is renderer stuff?
658         R_UpdateTexture (pic->tex, (byte *)trans);
659
660         DrawQ_Pic(x, y, picname, 0, 0, 1, 1, 1, 1, 0);
661 }
662
663
664 /*
665 ====================
666 CalcFov
667 ====================
668 */
669 float CalcFov (float fov_x, float width, float height)
670 {
671         // calculate vision size and alter by aspect, then convert back to angle
672         return atan (height / (width / tan(fov_x/360*M_PI))) * 360 / M_PI;
673 }
674
675 /*
676 =================
677 SCR_CalcRefdef
678
679 Must be called whenever vid changes
680 Internal use only
681 =================
682 */
683 static void SCR_CalcRefdef (void)
684 {
685         float size;
686         int contents;
687
688 //========================================
689
690 // bound viewsize
691         if (scr_viewsize.value < 30)
692                 Cvar_Set ("viewsize","30");
693         if (scr_viewsize.value > 120)
694                 Cvar_Set ("viewsize","120");
695
696 // bound field of view
697         if (scr_fov.value < 10)
698                 Cvar_Set ("fov","10");
699         if (scr_fov.value > 170)
700                 Cvar_Set ("fov","170");
701
702 // intermission is always full screen
703         if (cl.intermission)
704         {
705                 size = 1;
706                 sb_lines = 0;
707         }
708         else
709         {
710                 if (scr_viewsize.value >= 120)
711                         sb_lines = 0;           // no status bar at all
712                 else if (scr_viewsize.value >= 110)
713                         sb_lines = 24;          // no inventory
714                 else
715                         sb_lines = 24+16+8;
716                 size = scr_viewsize.value * (1.0 / 100.0);
717         }
718
719         if (size >= 1)
720         {
721                 r_refdef.width = vid.realwidth;
722                 r_refdef.height = vid.realheight;
723                 r_refdef.x = 0;
724                 r_refdef.y = 0;
725         }
726         else
727         {
728                 r_refdef.width = vid.realwidth * size;
729                 r_refdef.height = vid.realheight * size;
730                 r_refdef.x = (vid.realwidth - r_refdef.width)/2;
731                 r_refdef.y = (vid.realheight - r_refdef.height)/2;
732         }
733
734         r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
735         r_refdef.height = bound(0, r_refdef.height, vid.realheight);
736         r_refdef.x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width) + vid.realx;
737         r_refdef.y = bound(0, r_refdef.y, vid.realheight - r_refdef.height) + vid.realy;
738
739         // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
740         r_refdef.fov_x = scr_fov.value * cl.viewzoom;
741         r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.width, r_refdef.height);
742
743         if (cl.worldmodel)
744         {
745                 Mod_CheckLoaded(cl.worldmodel);
746                 contents = Mod_PointInLeaf(r_refdef.vieworg, cl.worldmodel)->contents;
747                 if (contents != CONTENTS_EMPTY && contents != CONTENTS_SOLID)
748                 {
749                         r_refdef.fov_x *= (sin(cl.time * 4.7) * 0.015 + 0.985);
750                         r_refdef.fov_y *= (sin(cl.time * 3.0) * 0.015 + 0.985);
751                 }
752         }
753 }
754
755
756 void V_CalcRefdef (void);
757
758 //=============================================================================
759
760 // LordHavoc: SHOWLMP stuff
761 #define SHOWLMP_MAXLABELS 256
762 typedef struct showlmp_s
763 {
764         qboolean        isactive;
765         float           x;
766         float           y;
767         char            label[32];
768         char            pic[128];
769 }
770 showlmp_t;
771
772 showlmp_t showlmp[SHOWLMP_MAXLABELS];
773
774 void SHOWLMP_decodehide(void)
775 {
776         int i;
777         byte *lmplabel;
778         lmplabel = MSG_ReadString();
779         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
780                 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
781                 {
782                         showlmp[i].isactive = false;
783                         return;
784                 }
785 }
786
787 void SHOWLMP_decodeshow(void)
788 {
789         int i, k;
790         byte lmplabel[256], picname[256];
791         float x, y;
792         strcpy(lmplabel,MSG_ReadString());
793         strcpy(picname, MSG_ReadString());
794         if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
795         {
796                 x = MSG_ReadByte();
797                 y = MSG_ReadByte();
798         }
799         else
800         {
801                 x = MSG_ReadShort();
802                 y = MSG_ReadShort();
803         }
804         k = -1;
805         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
806                 if (showlmp[i].isactive)
807                 {
808                         if (strcmp(showlmp[i].label, lmplabel) == 0)
809                         {
810                                 k = i;
811                                 break; // drop out to replace it
812                         }
813                 }
814                 else if (k < 0) // find first empty one to replace
815                         k = i;
816         if (k < 0)
817                 return; // none found to replace
818         // change existing one
819         showlmp[k].isactive = true;
820         strcpy(showlmp[k].label, lmplabel);
821         strcpy(showlmp[k].pic, picname);
822         showlmp[k].x = x;
823         showlmp[k].y = y;
824 }
825
826 void SHOWLMP_drawall(void)
827 {
828         int i;
829         if (cl.worldmodel)
830                 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
831                         if (showlmp[i].isactive)
832                                 DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
833 }
834
835 void SHOWLMP_clear(void)
836 {
837         int i;
838         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
839                 showlmp[i].isactive = false;
840 }
841
842 void CL_UpdateScreen(void)
843 {
844         static float old2dresolution = -1;
845
846         if (scr_disabled_for_loading)
847                 return;
848
849         if (!scr_initialized || !con_initialized)
850                 return;                         // not initialized yet
851
852         R_TimeReport("other");
853
854         VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
855
856         VID_UpdateGamma(false);
857
858         if (scr_2dresolution.value != old2dresolution)
859         {
860                 Cvar_SetValue("scr_2dresolution", bound(0.0f, scr_2dresolution.value, 1.0f));
861                 old2dresolution = scr_2dresolution.value;
862         }
863
864         if (vid.realwidth > 320)
865         {
866                 vid.conwidth = (vid.realwidth - 320) * scr_2dresolution.value + 320;
867                 vid.conwidth = bound(320, vid.conwidth, vid.realwidth);
868         }
869         else
870                 vid.conwidth = 320;
871
872         if (vid.realheight > 240)
873         {
874                 vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
875                 vid.conheight = bound(240, vid.conheight, vid.realheight);
876         }
877         else
878                 vid.conheight = 240;
879
880         SCR_SetUpToDrawConsole();
881
882         // determine size of refresh window
883         SCR_CalcRefdef();
884
885         DrawQ_Clear();
886
887         V_UpdateBlends();
888         V_CalcRefdef ();
889
890         R_TimeReport("setup");
891
892         SCR_DrawRam();
893         SCR_DrawNet();
894         SCR_DrawTurtle();
895         SCR_DrawPause();
896         SCR_CheckDrawCenterString();
897         Sbar_Draw();
898         SHOWLMP_drawall();
899
900         SCR_DrawConsole();
901
902         ui_draw();
903
904         R_TimeReport("2d");
905
906         // add r_speeds text to queue
907         R_TimeReport_End();
908
909         // start a new timing run
910         R_TimeReport_Start();
911
912         // make menu fade everything else on the screen
913         M_Draw();
914
915         SCR_UpdateScreen();
916 }
917
918 void CL_Screen_NewMap(void)
919 {
920         SHOWLMP_clear();
921 }