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