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