]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_screen.c
added Texture Combine option to menu
[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         CL_UpdateScreen ();
324         scr_drawloading = false;
325
326 //      scr_disabled_for_loading = true;
327 //      scr_disabled_time = realtime;
328 }
329
330 /*
331 ===============
332 SCR_EndLoadingPlaque
333
334 ================
335 */
336 void SCR_EndLoadingPlaque (void)
337 {
338         if (!scr_drawloading)
339                 return;
340
341 //      scr_disabled_for_loading = false;
342         scr_drawloading = false;
343         Con_ClearNotify ();
344 }
345
346 //=============================================================================
347
348 char    *scr_notifystring;
349
350 void SCR_DrawNotifyString (void)
351 {
352         char    *start;
353         int             l;
354         int             x, y;
355
356         start = scr_notifystring;
357
358         y = vid.conheight*0.35;
359
360         do
361         {
362         // scan the width of the line
363                 for (l=0 ; l<40 ; l++)
364                         if (start[l] == '\n' || !start[l])
365                                 break;
366                 x = (vid.conwidth - l*8)/2;
367                 DrawQ_String (x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
368
369                 y += 8;
370
371                 while (*start && *start != '\n')
372                         start++;
373
374                 if (!*start)
375                         break;
376                 start++;                // skip the \n
377         }
378         while (1);
379 }
380
381 char r_speeds_string[1024];
382 int speedstringcount, r_timereport_active;
383 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
384
385 void R_TimeReport(char *desc)
386 {
387         char tempbuf[256];
388         int length;
389         int t;
390
391         if (!r_timereport_active)
392                 return;
393
394         r_timereport_temp = r_timereport_current;
395         r_timereport_current = Sys_DoubleTime();
396         t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
397
398         sprintf(tempbuf, "%8i %s", t, desc);
399         length = strlen(tempbuf);
400         while (length < 20)
401                 tempbuf[length++] = ' ';
402         tempbuf[length] = 0;
403         if (speedstringcount + length > (vid.conwidth / 8))
404         {
405                 strcat(r_speeds_string, "\n");
406                 speedstringcount = 0;
407         }
408         // skip the space at the beginning if it's the first on the line
409         if (speedstringcount == 0)
410         {
411                 strcat(r_speeds_string, tempbuf + 1);
412                 speedstringcount = length - 1;
413         }
414         else
415         {
416                 strcat(r_speeds_string, tempbuf);
417                 speedstringcount += length;
418         }
419 }
420
421 void R_TimeReport_Start(void)
422 {
423         r_timereport_active = r_speeds.integer && cl.worldmodel && cls.state == ca_connected;
424         r_speeds_string[0] = 0;
425         if (r_timereport_active)
426         {
427                 speedstringcount = 0;
428                 AngleVectors (r_refdef.viewangles, vpn, NULL, NULL);
429                 //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",
430                 //      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]),
431                 //      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]),
432                 //      vpn[0] < 0 ? '-' : ' ', fabs(vpn[0]), vpn[1] < 0 ? '-' : ' ', fabs(vpn[1]), vpn[2] < 0 ? '-' : ' ', fabs(vpn[2]),
433                 sprintf(r_speeds_string,
434                         "org:'%+8.2f %+8.2f %+8.2f' ang:'%+4.0f %+4.0f %+4.0f' dir:'%+2.3f %+2.3f %+2.3f'\n"
435                         "world:%6i faces%6i nodes%6i leafs%6i walls%6i dlitwalls\n"
436                         "%5i models%5i bmodels%5i sprites%6i particles%4i dlights\n"
437                         "%6i modeltris%6i transmeshs%6i transtris%6i meshs%6i meshtris\n",
438                         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],
439                         c_faces, c_nodes, c_leafs, c_brush_polys, c_light_polys,
440                         c_models, c_bmodels, c_sprites, c_particles, c_dlights,
441                         c_alias_polys, c_transmeshs, c_transtris, c_meshs, c_meshtris);
442
443                 c_brush_polys = 0;
444                 c_alias_polys = 0;
445                 c_light_polys = 0;
446                 c_faces = 0;
447                 c_nodes = 0;
448                 c_leafs = 0;
449                 c_models = 0;
450                 c_bmodels = 0;
451                 c_sprites = 0;
452                 c_particles = 0;
453         //      c_dlights = 0;
454
455                 r_timereport_start = Sys_DoubleTime();
456         }
457 }
458
459 void R_TimeReport_End(void)
460 {
461         r_timereport_current = r_timereport_start;
462         R_TimeReport("total");
463
464         if (r_timereport_active)
465         {
466                 int i, j, lines, y;
467                 lines = 1;
468                 for (i = 0;r_speeds_string[i];i++)
469                         if (r_speeds_string[i] == '\n')
470                                 lines++;
471                 y = vid.conheight - sb_lines - lines * 8/* - 8*/;
472                 i = j = 0;
473                 DrawQ_Fill(0, y, vid.conwidth, lines * 8, 0, 0, 0, 0.5, 0);
474                 while (r_speeds_string[i])
475                 {
476                         j = i;
477                         while (r_speeds_string[i] && r_speeds_string[i] != '\n')
478                                 i++;
479                         if (i - j > 0)
480                                 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
481                         if (r_speeds_string[i] == '\n')
482                                 i++;
483                         y += 8;
484                 }
485         }
486 }
487
488 /*
489 =================
490 SCR_SizeUp_f
491
492 Keybinding command
493 =================
494 */
495 void SCR_SizeUp_f (void)
496 {
497         Cvar_SetValue ("viewsize",scr_viewsize.value+10);
498 }
499
500
501 /*
502 =================
503 SCR_SizeDown_f
504
505 Keybinding command
506 =================
507 */
508 void SCR_SizeDown_f (void)
509 {
510         Cvar_SetValue ("viewsize",scr_viewsize.value-10);
511 }
512
513 void CL_Screen_Init(void)
514 {
515         qpic_t *dat;
516
517         Cvar_RegisterVariable (&scr_fov);
518         Cvar_RegisterVariable (&scr_viewsize);
519         Cvar_RegisterVariable (&scr_conspeed);
520         Cvar_RegisterVariable (&scr_showram);
521         Cvar_RegisterVariable (&scr_showturtle);
522         Cvar_RegisterVariable (&scr_showpause);
523         Cvar_RegisterVariable (&scr_centertime);
524         Cvar_RegisterVariable (&scr_printspeed);
525         Cvar_RegisterVariable(&scr_2dresolution);
526
527         Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
528         Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
529         Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
530         Cmd_AddCommand ("envmap", R_Envmap_f);
531
532         scr_initialized = true;
533
534         // HACK HACK HACK
535         // load the image data for the player image in the config menu
536         dat = (qpic_t *)COM_LoadFile ("gfx/menuplyr.lmp", false);
537         if (!dat)
538                 Sys_Error("unable to load gfx/menuplyr.lmp");
539         SwapPic (dat);
540
541         if (dat->width*dat->height <= 4096)
542                 memcpy (menuplyr_pixels, dat->data, dat->width * dat->height);
543         else
544                 Con_Printf("gfx/menuplyr.lmp larger than 4k buffer");
545         Mem_Free(dat);
546 }
547
548 void DrawQ_Clear(void)
549 {
550         r_refdef.drawqueuesize = 0;
551 }
552
553 void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
554 {
555         int size;
556         drawqueue_t *dq;
557         if (alpha < (1.0f / 255.0f))
558                 return;
559         size = sizeof(*dq) + ((strlen(picname) + 1 + 3) & ~3);
560         if (r_refdef.drawqueuesize + size > MAX_DRAWQUEUE)
561                 return;
562         red = bound(0, red, 1);
563         green = bound(0, green, 1);
564         blue = bound(0, blue, 1);
565         alpha = bound(0, alpha, 1);
566         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
567         dq->size = size;
568         dq->command = DRAWQUEUE_PIC;
569         dq->flags = flags;
570         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));
571         dq->x = x;
572         dq->y = y;
573         // if these are not zero, they override the pic's size
574         dq->scalex = width;
575         dq->scaley = height;
576         strcpy((char *)(dq + 1), picname);
577         r_refdef.drawqueuesize += dq->size;
578 }
579
580 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)
581 {
582         int size, len;
583         drawqueue_t *dq;
584         char *out;
585         if (alpha < (1.0f / 255.0f))
586                 return;
587         if (maxlen < 1)
588                 len = strlen(string);
589         else
590                 for (len = 0;len < maxlen && string[len];len++);
591         for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
592         for (;len > 0 && string[len - 1] == ' ';len--);
593         if (len < 1)
594                 return;
595         if (x >= vid.conwidth || y >= vid.conheight || x < (-scalex * maxlen) || y < (-scaley))
596                 return;
597         size = sizeof(*dq) + ((len + 1 + 3) & ~3);
598         if (r_refdef.drawqueuesize + size > MAX_DRAWQUEUE)
599                 return;
600         red = bound(0, red, 1);
601         green = bound(0, green, 1);
602         blue = bound(0, blue, 1);
603         alpha = bound(0, alpha, 1);
604         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
605         dq->size = size;
606         dq->command = DRAWQUEUE_STRING;
607         dq->flags = flags;
608         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));
609         dq->x = x;
610         dq->y = y;
611         dq->scalex = scalex;
612         dq->scaley = scaley;
613         out = (char *)(dq + 1);
614         memcpy(out, string, len);
615         out[len] = 0;
616         r_refdef.drawqueuesize += dq->size;
617 }
618
619 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
620 {
621         int size;
622         drawqueue_t *dq;
623         if (alpha < (1.0f / 255.0f))
624                 return;
625         size = sizeof(*dq) + 4;
626         if (r_refdef.drawqueuesize + size > MAX_DRAWQUEUE)
627                 return;
628         red = bound(0, red, 1);
629         green = bound(0, green, 1);
630         blue = bound(0, blue, 1);
631         alpha = bound(0, alpha, 1);
632         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
633         dq->size = size;
634         dq->command = DRAWQUEUE_PIC;
635         dq->flags = flags;
636         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));
637         dq->x = x;
638         dq->y = y;
639         dq->scalex = w;
640         dq->scaley = h;
641         // empty pic name
642         *((char *)(dq + 1)) = 0;
643         r_refdef.drawqueuesize += dq->size;
644 }
645
646 //only used for the player color selection menu
647 void DrawQ_PicTranslate (int x, int y, char *picname, qbyte *translation)
648 {
649         int i, c;
650         unsigned int trans[4096];
651         cachepic_t *pic;
652
653         pic = Draw_CachePic(picname);
654         if (pic == NULL)
655                 return;
656
657         c = pic->width * pic->height;
658         if (c > 4096)
659         {
660                 Con_Printf("DrawQ_PicTranslate: image larger than 4k buffer\n");
661                 return;
662         }
663
664         for (i = 0;i < c;i++)
665                 trans[i] = d_8to24table[translation[menuplyr_pixels[i]]];
666
667         // FIXME: this is renderer stuff?
668         R_UpdateTexture (pic->tex, (qbyte *)trans);
669
670         DrawQ_Pic(x, y, picname, 0, 0, 1, 1, 1, 1, 0);
671 }
672
673
674 /*
675 ====================
676 CalcFov
677 ====================
678 */
679 float CalcFov (float fov_x, float width, float height)
680 {
681         // calculate vision size and alter by aspect, then convert back to angle
682         return atan (height / (width / tan(fov_x/360*M_PI))) * 360 / M_PI;
683 }
684
685 /*
686 =================
687 SCR_CalcRefdef
688
689 Must be called whenever vid changes
690 Internal use only
691 =================
692 */
693 static void SCR_CalcRefdef (void)
694 {
695         float size;
696         int contents;
697
698 //========================================
699
700 // bound viewsize
701         if (scr_viewsize.value < 30)
702                 Cvar_Set ("viewsize","30");
703         if (scr_viewsize.value > 120)
704                 Cvar_Set ("viewsize","120");
705
706 // bound field of view
707         if (scr_fov.value < 10)
708                 Cvar_Set ("fov","10");
709         if (scr_fov.value > 170)
710                 Cvar_Set ("fov","170");
711
712 // intermission is always full screen
713         if (cl.intermission)
714         {
715                 size = 1;
716                 sb_lines = 0;
717         }
718         else
719         {
720                 if (scr_viewsize.value >= 120)
721                         sb_lines = 0;           // no status bar at all
722                 else if (scr_viewsize.value >= 110)
723                         sb_lines = 24;          // no inventory
724                 else
725                         sb_lines = 24+16+8;
726                 size = scr_viewsize.value * (1.0 / 100.0);
727         }
728
729         if (size >= 1)
730         {
731                 r_refdef.width = vid.realwidth;
732                 r_refdef.height = vid.realheight;
733                 r_refdef.x = 0;
734                 r_refdef.y = 0;
735         }
736         else
737         {
738                 r_refdef.width = vid.realwidth * size;
739                 r_refdef.height = vid.realheight * size;
740                 r_refdef.x = (vid.realwidth - r_refdef.width)/2;
741                 r_refdef.y = (vid.realheight - r_refdef.height)/2;
742         }
743
744         r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
745         r_refdef.height = bound(0, r_refdef.height, vid.realheight);
746         r_refdef.x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width) + vid.realx;
747         r_refdef.y = bound(0, r_refdef.y, vid.realheight - r_refdef.height) + vid.realy;
748
749         // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
750         r_refdef.fov_x = scr_fov.value * cl.viewzoom;
751         r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.width, r_refdef.height);
752
753         if (cl.worldmodel)
754         {
755                 Mod_CheckLoaded(cl.worldmodel);
756                 contents = Mod_PointInLeaf(r_refdef.vieworg, cl.worldmodel)->contents;
757                 if (contents != CONTENTS_EMPTY && contents != CONTENTS_SOLID)
758                 {
759                         r_refdef.fov_x *= (sin(cl.time * 4.7) * 0.015 + 0.985);
760                         r_refdef.fov_y *= (sin(cl.time * 3.0) * 0.015 + 0.985);
761                 }
762         }
763 }
764
765 /*
766 ==================
767 SCR_ScreenShot_f
768 ==================
769 */
770 void SCR_ScreenShot_f (void)
771 {
772         int i;
773         char filename[16];
774         char checkname[MAX_OSPATH];
775 //
776 // find a file name to save it to
777 //
778         strcpy(filename, "dp0000.tga");
779
780         for (i=0 ; i<=9999 ; i++)
781         {
782                 filename[2] = (i/1000)%10 + '0';
783                 filename[3] = (i/ 100)%10 + '0';
784                 filename[4] = (i/  10)%10 + '0';
785                 filename[5] = (i/   1)%10 + '0';
786                 sprintf (checkname, "%s/%s", com_gamedir, filename);
787                 if (Sys_FileTime(checkname) == -1)
788                         break;  // file doesn't exist
789         }
790         if (i==10000)
791         {
792                 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
793                 return;
794         }
795
796         SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight);
797         Con_Printf ("Wrote %s\n", filename);
798 }
799
800 /*
801 ===============
802 R_Envmap_f
803
804 Grab six views for environment mapping tests
805 ===============
806 */
807 struct
808 {
809         float angles[3];
810         char *name;
811 }
812 envmapinfo[6] =
813 {
814         {{  0,   0, 0}, "ft"},
815         {{  0,  90, 0}, "rt"},
816         {{  0, 180, 0}, "bk"},
817         {{  0, 270, 0}, "lf"},
818         {{-90,  90, 0}, "up"},
819         {{ 90,  90, 0}, "dn"}
820 };
821
822 static void R_Envmap_f (void)
823 {
824         int j, size;
825         char filename[256], basename[256];
826
827         if (Cmd_Argc() != 3)
828         {
829                 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");
830                 return;
831         }
832
833         strcpy(basename, Cmd_Argv(1));
834         size = atoi(Cmd_Argv(2));
835         if (size != 128 && size != 256 && size != 512 && size != 1024)
836         {
837                 Con_Printf("envmap: size must be one of 128, 256, 512, or 1024\n");
838                 return;
839         }
840         if (size > vid.realwidth || size > vid.realheight)
841         {
842                 Con_Printf("envmap: your resolution is not big enough to render that size\n");
843                 return;
844         }
845
846         envmap = true;
847
848         r_refdef.x = 0;
849         r_refdef.y = 0;
850         r_refdef.width = size;
851         r_refdef.height = size;
852
853         r_refdef.fov_x = 90;
854         r_refdef.fov_y = 90;
855
856         for (j = 0;j < 6;j++)
857         {
858                 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
859                 VectorCopy(envmapinfo[j].angles, r_refdef.viewangles);
860                 R_ClearScreen();
861                 R_RenderView ();
862                 SCR_ScreenShot(filename, vid.realx, vid.realy, size, size);
863         }
864
865         envmap = false;
866 }
867
868 //=============================================================================
869
870 // LordHavoc: SHOWLMP stuff
871 #define SHOWLMP_MAXLABELS 256
872 typedef struct showlmp_s
873 {
874         qboolean        isactive;
875         float           x;
876         float           y;
877         char            label[32];
878         char            pic[128];
879 }
880 showlmp_t;
881
882 showlmp_t showlmp[SHOWLMP_MAXLABELS];
883
884 void SHOWLMP_decodehide(void)
885 {
886         int i;
887         qbyte *lmplabel;
888         lmplabel = MSG_ReadString();
889         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
890                 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
891                 {
892                         showlmp[i].isactive = false;
893                         return;
894                 }
895 }
896
897 void SHOWLMP_decodeshow(void)
898 {
899         int i, k;
900         qbyte lmplabel[256], picname[256];
901         float x, y;
902         strcpy(lmplabel,MSG_ReadString());
903         strcpy(picname, MSG_ReadString());
904         if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
905         {
906                 x = MSG_ReadByte();
907                 y = MSG_ReadByte();
908         }
909         else
910         {
911                 x = MSG_ReadShort();
912                 y = MSG_ReadShort();
913         }
914         k = -1;
915         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
916                 if (showlmp[i].isactive)
917                 {
918                         if (strcmp(showlmp[i].label, lmplabel) == 0)
919                         {
920                                 k = i;
921                                 break; // drop out to replace it
922                         }
923                 }
924                 else if (k < 0) // find first empty one to replace
925                         k = i;
926         if (k < 0)
927                 return; // none found to replace
928         // change existing one
929         showlmp[k].isactive = true;
930         strcpy(showlmp[k].label, lmplabel);
931         strcpy(showlmp[k].pic, picname);
932         showlmp[k].x = x;
933         showlmp[k].y = y;
934 }
935
936 void SHOWLMP_drawall(void)
937 {
938         int i;
939         if (cl.worldmodel)
940                 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
941                         if (showlmp[i].isactive)
942                                 DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
943 }
944
945 void SHOWLMP_clear(void)
946 {
947         int i;
948         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
949                 showlmp[i].isactive = false;
950 }
951
952 void CL_SetupScreenSize(void)
953 {
954         static float old2dresolution = -1;
955
956         VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
957
958         VID_UpdateGamma(false);
959
960         if (scr_2dresolution.value != old2dresolution)
961         {
962                 Cvar_SetValue("scr_2dresolution", bound(0.0f, scr_2dresolution.value, 1.0f));
963                 old2dresolution = scr_2dresolution.value;
964         }
965
966         if (vid.realwidth > 320)
967         {
968                 vid.conwidth = (vid.realwidth - 320) * scr_2dresolution.value + 320;
969                 vid.conwidth = bound(320, vid.conwidth, vid.realwidth);
970         }
971         else
972                 vid.conwidth = 320;
973
974         if (vid.realheight > 240)
975         {
976                 vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
977                 vid.conheight = bound(240, vid.conheight, vid.realheight);
978         }
979         else
980                 vid.conheight = 240;
981
982         SCR_SetUpToDrawConsole();
983
984         // determine size of refresh window
985         SCR_CalcRefdef();
986 }
987
988 void CL_UpdateScreen(void)
989 {
990         if (!scr_initialized || !con_initialized)
991                 return;                         // not initialized yet
992
993
994         R_TimeReport("other");
995
996         CL_SetupScreenSize();
997
998         DrawQ_Clear();
999
1000         V_UpdateBlends();
1001         V_CalcRefdef ();
1002
1003         R_TimeReport("setup");
1004
1005         if (scr_drawloading)
1006         {
1007                 scr_con_current = vid.conheight;
1008                 DrawQ_Clear();
1009                 SCR_DrawLoading();
1010                 SCR_UpdateScreen();
1011                 return;
1012         }
1013
1014         SCR_DrawRam();
1015         SCR_DrawNet();
1016         SCR_DrawTurtle();
1017         SCR_DrawPause();
1018         SCR_CheckDrawCenterString();
1019         Sbar_Draw();
1020         SHOWLMP_drawall();
1021
1022         SCR_DrawConsole();
1023
1024         ui_draw();
1025
1026         /*
1027         if (scr_drawloading)
1028         {
1029                 SCR_DrawLoading();
1030                 if (
1031         }
1032         */
1033
1034         R_TimeReport("2d");
1035
1036         // add r_speeds text to queue
1037         R_TimeReport_End();
1038
1039         // start a new timing run
1040         R_TimeReport_Start();
1041
1042         // make menu fade everything else on the screen
1043         M_Draw();
1044
1045         SCR_UpdateScreen();
1046 }
1047
1048 void CL_Screen_NewMap(void)
1049 {
1050         SHOWLMP_clear();
1051 }