]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - cl_screen.c
Tomaz's patch to name screenshots based on gamemode or -game if specified
[xonotic/darkplaces.git] / cl_screen.c
1
2 #include "quakedef.h"
3 #include "cl_video.h"
4 #include "jpeg.h"
5 #include "cl_collision.h"
6
7 cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100"};
8 cvar_t scr_fov = {CVAR_SAVE, "fov","90"};       // 1 - 170
9 cvar_t scr_conspeed = {CVAR_SAVE, "scr_conspeed","900"}; // LordHavoc: quake used 300
10 cvar_t scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1"};
11 cvar_t scr_conbrightness = {CVAR_SAVE, "scr_conbrightness", "0.2"};
12 cvar_t scr_conforcewhiledisconnected = {CVAR_SAVE, "scr_conforcewhiledisconnected", "1"};
13 cvar_t scr_centertime = {0, "scr_centertime","2"};
14 cvar_t scr_showram = {CVAR_SAVE, "showram","1"};
15 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0"};
16 cvar_t scr_showpause = {CVAR_SAVE, "showpause","1"};
17 cvar_t scr_printspeed = {0, "scr_printspeed","8"};
18 cvar_t vid_conwidth = {CVAR_SAVE, "vid_conwidth", "640"};
19 cvar_t vid_conheight = {CVAR_SAVE, "vid_conheight", "480"};
20 cvar_t scr_screenshot_jpeg = {CVAR_SAVE, "scr_screenshot_jpeg","0"};
21 cvar_t scr_screenshot_jpeg_quality = {CVAR_SAVE, "scr_screenshot_jpeg_quality","0.9"};
22 cvar_t scr_screenshot_name = {0, "scr_screenshot_name","dp"};
23 cvar_t cl_avidemo = {0, "cl_avidemo", "0"};
24
25 int jpeg_supported = false;
26
27 qboolean        scr_initialized;                // ready to draw
28
29 float           scr_con_current;
30 float           scr_conlines;           // lines of console to display
31
32 int                     clearconsole;
33 int                     clearnotify;
34
35 qboolean        scr_drawloading = false;
36
37 void DrawCrosshair(int num);
38 static void SCR_ScreenShot_f (void);
39 static void R_Envmap_f (void);
40
41 // backend
42 void R_ClearScreen(void);
43
44 /*
45 ===============================================================================
46
47 CENTER PRINTING
48
49 ===============================================================================
50 */
51
52 char            scr_centerstring[1024];
53 float           scr_centertime_start;   // for slow victory printing
54 float           scr_centertime_off;
55 int                     scr_center_lines;
56 int                     scr_erase_lines;
57 int                     scr_erase_center;
58
59 /*
60 ==============
61 SCR_CenterPrint
62
63 Called for important messages that should stay in the center of the screen
64 for a few moments
65 ==============
66 */
67 void SCR_CenterPrint(char *str)
68 {
69         strlcpy (scr_centerstring, str, sizeof (scr_centerstring));
70         scr_centertime_off = scr_centertime.value;
71         scr_centertime_start = cl.time;
72
73 // count the number of lines for centering
74         scr_center_lines = 1;
75         while (*str)
76         {
77                 if (*str == '\n')
78                         scr_center_lines++;
79                 str++;
80         }
81 }
82
83
84 void SCR_DrawCenterString (void)
85 {
86         char    *start;
87         int             l;
88         int             x, y;
89         int             remaining;
90
91 // the finale prints the characters one at a time
92         if (cl.intermission)
93                 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
94         else
95                 remaining = 9999;
96
97         scr_erase_center = 0;
98         start = scr_centerstring;
99
100         if (scr_center_lines <= 4)
101                 y = vid.conheight*0.35;
102         else
103                 y = 48;
104
105         do
106         {
107         // scan the width of the line
108                 for (l=0 ; l<40 ; l++)
109                         if (start[l] == '\n' || !start[l])
110                                 break;
111                 x = (vid.conwidth - l*8)/2;
112                 if (l > 0)
113                 {
114                         if (remaining < l)
115                                 l = remaining;
116                         DrawQ_String(x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
117                         remaining -= l;
118                         if (remaining <= 0)
119                                 return;
120                 }
121
122                 y += 8;
123
124                 while (*start && *start != '\n')
125                         start++;
126
127                 if (!*start)
128                         break;
129                 start++;                // skip the \n
130         } while (1);
131 }
132
133 void SCR_CheckDrawCenterString (void)
134 {
135         if (scr_center_lines > scr_erase_lines)
136                 scr_erase_lines = scr_center_lines;
137
138         scr_centertime_off -= host_frametime;
139
140         // don't draw if this is a normal stats-screen intermission,
141         // only if it is not an intermission, or a finale intermission
142         if (cl.intermission == 1)
143                 return;
144         if (scr_centertime_off <= 0 && !cl.intermission)
145                 return;
146         if (key_dest != key_game)
147                 return;
148
149         SCR_DrawCenterString ();
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, "gfx/turtle.lmp", 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, "gfx/net.lmp", 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         pic = Draw_CachePic ("gfx/loading.lmp");
231         DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/loading.lmp", 0, 0, 1, 1, 1, 1, 0);
232 }
233
234
235
236 //=============================================================================
237
238
239 /*
240 ==================
241 SCR_SetUpToDrawConsole
242 ==================
243 */
244 void SCR_SetUpToDrawConsole (void)
245 {
246         Con_CheckResize ();
247
248         if (key_dest == key_game && cls.signon != SIGNONS && scr_conforcewhiledisconnected.integer)
249                 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
250         else
251                 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
252
253 // decide on the height of the console
254         if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
255                 scr_conlines = vid.conheight; // full screen
256         else if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
257                 scr_conlines = vid.conheight/2; // half screen
258         else
259                 scr_conlines = 0;                               // none visible
260
261         if (scr_conspeed.value)
262         {
263                 if (scr_conlines < scr_con_current)
264                 {
265                         scr_con_current -= scr_conspeed.value*host_realframetime;
266                         if (scr_conlines > scr_con_current)
267                                 scr_con_current = scr_conlines;
268
269                 }
270                 else if (scr_conlines > scr_con_current)
271                 {
272                         scr_con_current += scr_conspeed.value*host_realframetime;
273                         if (scr_conlines < scr_con_current)
274                                 scr_con_current = scr_conlines;
275                 }
276         }
277         else
278                 scr_con_current = scr_conlines;
279 }
280
281 /*
282 ==================
283 SCR_DrawConsole
284 ==================
285 */
286 void SCR_DrawConsole (void)
287 {
288         if (scr_con_current)
289         {
290                 Con_DrawConsole (scr_con_current);
291                 clearconsole = 0;
292         }
293         else
294         {
295                 if (key_dest == key_game || key_dest == key_message)
296                         Con_DrawNotify ();      // only draw notify in game
297         }
298 }
299
300 /*
301 ===============
302 SCR_BeginLoadingPlaque
303
304 ================
305 */
306 void SCR_BeginLoadingPlaque (void)
307 {
308         if (scr_drawloading)
309                 return;
310
311         S_StopAllSounds (true);
312
313         scr_drawloading = true;
314         CL_UpdateScreen ();
315         scr_drawloading = true;
316         CL_UpdateScreen ();
317 }
318
319 //=============================================================================
320
321 char r_speeds_string[1024];
322 int speedstringcount, r_timereport_active;
323 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
324
325 void R_TimeReport(char *desc)
326 {
327         char tempbuf[256];
328         int length;
329         int t;
330
331         if (!r_timereport_active)
332                 return;
333
334         r_timereport_temp = r_timereport_current;
335         r_timereport_current = Sys_DoubleTime();
336         t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
337
338         sprintf(tempbuf, "%8i %s", t, desc);
339         length = strlen(tempbuf);
340         while (length < 20)
341                 tempbuf[length++] = ' ';
342         tempbuf[length] = 0;
343         if (speedstringcount + length > (vid.conwidth / 8))
344         {
345                 strcat(r_speeds_string, "\n");
346                 speedstringcount = 0;
347         }
348         // skip the space at the beginning if it's the first on the line
349         if (speedstringcount == 0)
350         {
351                 strcat(r_speeds_string, tempbuf + 1);
352                 speedstringcount = length - 1;
353         }
354         else
355         {
356                 strcat(r_speeds_string, tempbuf);
357                 speedstringcount += length;
358         }
359 }
360
361 extern int c_rt_lights, c_rt_clears, c_rt_scissored;
362 extern int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
363 extern int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
364 void R_TimeReport_Start(void)
365 {
366         r_timereport_active = r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected;
367         r_speeds_string[0] = 0;
368         if (r_timereport_active)
369         {
370                 speedstringcount = 0;
371                 sprintf(r_speeds_string,
372                         "org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n"
373                         "world:%6i faces%6i nodes%6i leafs%6i dlitwalls\n"
374                         "%5i models%5i bmodels%5i sprites%6i particles%4i dlights\n"
375                         "%6i modeltris%6i meshs%6i meshtris\n",
376                         r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], r_viewforward[0], r_viewforward[1], r_viewforward[2],
377                         c_faces, c_nodes, c_leafs, c_light_polys,
378                         c_models, c_bmodels, c_sprites, c_particles, c_dlights,
379                         c_alias_polys, c_meshs, c_meshelements / 3);
380
381                 sprintf(r_speeds_string + strlen(r_speeds_string),
382                         "realtime lighting:%4i lights%4i clears%4i scissored\n"
383                         "dynamic: %6i shadowmeshes%6i shadowtris%6i lightmeshes%6i lighttris\n"
384                         "precomputed: %6i shadowmeshes%6i shadowtris\n",
385                         c_rt_lights, c_rt_clears, c_rt_scissored,
386                         c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris,
387                         c_rtcached_shadowmeshes, c_rtcached_shadowtris);
388
389                 c_alias_polys = 0;
390                 c_light_polys = 0;
391                 c_faces = 0;
392                 c_nodes = 0;
393                 c_leafs = 0;
394                 c_models = 0;
395                 c_bmodels = 0;
396                 c_sprites = 0;
397                 c_particles = 0;
398                 c_meshs = 0;
399                 c_meshelements = 0;
400
401                 r_timereport_start = Sys_DoubleTime();
402         }
403 }
404
405 void R_TimeReport_End(void)
406 {
407         r_timereport_current = r_timereport_start;
408         R_TimeReport("total");
409
410         if (r_timereport_active)
411         {
412                 int i, j, lines, y;
413                 lines = 1;
414                 for (i = 0;r_speeds_string[i];i++)
415                         if (r_speeds_string[i] == '\n')
416                                 lines++;
417                 y = vid.conheight - sb_lines - lines * 8;
418                 i = j = 0;
419                 DrawQ_Fill(0, y, vid.conwidth, lines * 8, 0, 0, 0, 0.5, 0);
420                 while (r_speeds_string[i])
421                 {
422                         j = i;
423                         while (r_speeds_string[i] && r_speeds_string[i] != '\n')
424                                 i++;
425                         if (i - j > 0)
426                                 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
427                         if (r_speeds_string[i] == '\n')
428                                 i++;
429                         y += 8;
430                 }
431         }
432 }
433
434 /*
435 =================
436 SCR_SizeUp_f
437
438 Keybinding command
439 =================
440 */
441 void SCR_SizeUp_f (void)
442 {
443         Cvar_SetValue ("viewsize",scr_viewsize.value+10);
444 }
445
446
447 /*
448 =================
449 SCR_SizeDown_f
450
451 Keybinding command
452 =================
453 */
454 void SCR_SizeDown_f (void)
455 {
456         Cvar_SetValue ("viewsize",scr_viewsize.value-10);
457 }
458
459 void CL_Screen_Init(void)
460 {
461         Cvar_RegisterVariable (&scr_fov);
462         Cvar_RegisterVariable (&scr_viewsize);
463         Cvar_RegisterVariable (&scr_conspeed);
464         Cvar_RegisterVariable (&scr_conalpha);
465         Cvar_RegisterVariable (&scr_conbrightness);
466         Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
467         Cvar_RegisterVariable (&scr_showram);
468         Cvar_RegisterVariable (&scr_showturtle);
469         Cvar_RegisterVariable (&scr_showpause);
470         Cvar_RegisterVariable (&scr_centertime);
471         Cvar_RegisterVariable (&scr_printspeed);
472         Cvar_RegisterVariable (&vid_conwidth);
473         Cvar_RegisterVariable (&vid_conheight);
474         Cvar_RegisterVariable (&scr_screenshot_jpeg);
475         Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
476         Cvar_RegisterVariable (&cl_avidemo);
477
478         Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
479         Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
480         Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
481         Cmd_AddCommand ("envmap", R_Envmap_f);
482
483         scr_initialized = true;
484 }
485
486 void DrawQ_Clear(void)
487 {
488         r_refdef.drawqueuesize = 0;
489 }
490
491 static int picelements[6] = {0, 1, 2, 0, 2, 3};
492 void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
493 {
494         DrawQ_SuperPic(x,y,picname,width,height,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags);
495 }
496
497 void DrawQ_String(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
498 {
499         int size, len;
500         drawqueue_t *dq;
501         char *out;
502         if (alpha < (1.0f / 255.0f))
503                 return;
504         if (maxlen < 1)
505                 len = strlen(string);
506         else
507                 for (len = 0;len < maxlen && string[len];len++);
508         for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
509         for (;len > 0 && string[len - 1] == ' ';len--);
510         if (len < 1)
511                 return;
512         if (x >= vid.conwidth || y >= vid.conheight || x < (-scalex * maxlen) || y < (-scaley))
513                 return;
514         size = sizeof(*dq) + ((len + 1 + 3) & ~3);
515         if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
516                 return;
517         red = bound(0, red, 1);
518         green = bound(0, green, 1);
519         blue = bound(0, blue, 1);
520         alpha = bound(0, alpha, 1);
521         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
522         dq->size = size;
523         dq->command = DRAWQUEUE_STRING;
524         dq->flags = flags;
525         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));
526         dq->x = x;
527         dq->y = y;
528         dq->scalex = scalex;
529         dq->scaley = scaley;
530         out = (char *)(dq + 1);
531         memcpy(out, string, len);
532         out[len] = 0;
533         r_refdef.drawqueuesize += dq->size;
534 }
535
536 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
537 {
538         DrawQ_SuperPic(x,y,NULL,w,h,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags);
539 }
540
541 void DrawQ_SuperPic(float x, float y, char *picname, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags)
542 {
543         float floats[36];
544         cachepic_t *pic;
545         drawqueuemesh_t mesh;
546         memset(&mesh, 0, sizeof(mesh));
547         if (picname && picname[0])
548         {
549                 pic = Draw_CachePic(picname);
550                 if (width == 0)
551                         width = pic->width;
552                 if (height == 0)
553                         height = pic->height;
554                 mesh.texture = pic->tex;
555         }
556         mesh.num_triangles = 2;
557         mesh.num_vertices = 4;
558         mesh.data_element3i = picelements;
559         mesh.data_vertex3f = floats;
560         mesh.data_texcoord2f = floats + 12;
561         mesh.data_color4f = floats + 20;
562         memset(floats, 0, sizeof(floats));
563         mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
564         mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
565         mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
566         mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
567         mesh.data_texcoord2f[0] = s1;mesh.data_texcoord2f[1] = t1;mesh.data_color4f[ 0] = r1;mesh.data_color4f[ 1] = g1;mesh.data_color4f[ 2] = b1;mesh.data_color4f[ 3] = a1;
568         mesh.data_texcoord2f[2] = s2;mesh.data_texcoord2f[3] = t2;mesh.data_color4f[ 4] = r2;mesh.data_color4f[ 5] = g2;mesh.data_color4f[ 6] = b2;mesh.data_color4f[ 7] = a2;
569         mesh.data_texcoord2f[4] = s4;mesh.data_texcoord2f[5] = t4;mesh.data_color4f[ 8] = r4;mesh.data_color4f[ 9] = g4;mesh.data_color4f[10] = b4;mesh.data_color4f[11] = a4;
570         mesh.data_texcoord2f[6] = s3;mesh.data_texcoord2f[7] = t3;mesh.data_color4f[12] = r3;mesh.data_color4f[13] = g3;mesh.data_color4f[14] = b3;mesh.data_color4f[15] = a3;
571         DrawQ_Mesh (&mesh, flags);
572 }
573
574 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
575 {
576         int size;
577         void *p;
578         drawqueue_t *dq;
579         drawqueuemesh_t *m;
580         size = sizeof(*dq);
581         size += sizeof(drawqueuemesh_t);
582         size += sizeof(int[3]) * mesh->num_triangles;
583         size += sizeof(float[3]) * mesh->num_vertices;
584         size += sizeof(float[2]) * mesh->num_vertices;
585         size += sizeof(float[4]) * mesh->num_vertices;
586         if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
587                 return;
588         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
589         dq->size = size;
590         dq->command = DRAWQUEUE_MESH;
591         dq->flags = flags;
592         dq->color = 0;
593         dq->x = 0;
594         dq->y = 0;
595         dq->scalex = 0;
596         dq->scaley = 0;
597         p = (void *)(dq + 1);
598         m = p;p = (qbyte*)p + sizeof(drawqueuemesh_t);
599         m->num_triangles = mesh->num_triangles;
600         m->num_vertices = mesh->num_vertices;
601         m->texture = mesh->texture;
602         m->data_element3i  = p;memcpy(m->data_element3i , mesh->data_element3i , m->num_triangles * sizeof(int[3]));p = (qbyte*)p + m->num_triangles * sizeof(int[3]);
603         m->data_vertex3f   = p;memcpy(m->data_vertex3f  , mesh->data_vertex3f  , m->num_vertices * sizeof(float[3]));p = (qbyte*)p + m->num_vertices * sizeof(float[3]);
604         m->data_texcoord2f = p;memcpy(m->data_texcoord2f, mesh->data_texcoord2f, m->num_vertices * sizeof(float[2]));p = (qbyte*)p + m->num_vertices * sizeof(float[2]);
605         m->data_color4f    = p;memcpy(m->data_color4f   , mesh->data_color4f   , m->num_vertices * sizeof(float[4]));p = (qbyte*)p + m->num_vertices * sizeof(float[4]);
606         r_refdef.drawqueuesize += dq->size;
607 }
608
609 void DrawQ_SetClipArea(float x, float y, float width, float height)
610 {
611         drawqueue_t * dq;
612         if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
613         {
614                 Con_DPrint("DrawQueue full !\n");
615                 return;
616         }
617         dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
618         dq->size = sizeof(*dq);
619         dq->command = DRAWQUEUE_SETCLIP;
620         dq->x = x;
621         dq->y = y;
622         dq->scalex = width;
623         dq->scaley = height;
624         dq->flags = 0;
625         dq->color = 0;
626
627         r_refdef.drawqueuesize += dq->size;
628 }
629
630 void DrawQ_ResetClipArea(void)
631 {
632         drawqueue_t *dq;
633         if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
634         {
635                 Con_DPrint("DrawQueue full !\n");
636                 return;
637         }
638         dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
639         dq->size = sizeof(*dq);
640         dq->command = DRAWQUEUE_RESETCLIP;
641         dq->x = 0;
642         dq->y = 0;
643         dq->scalex = 0;
644         dq->scaley = 0;
645         dq->flags = 0;
646         dq->color = 0;
647
648         r_refdef.drawqueuesize += dq->size;
649 }
650
651 /*
652 ==================
653 SCR_ScreenShot_f
654 ==================
655 */
656 void SCR_ScreenShot_f (void)
657 {
658         int shotnumber;
659         char base[MAX_QPATH];
660         char filename[MAX_QPATH];
661         qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
662
663         sprintf (base, "screenshots/%s", scr_screenshot_name.string);
664         
665         // find a file name to save it to
666         for (shotnumber=0;shotnumber < 1000000;shotnumber++)
667                 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
668                         break;
669         if (shotnumber >= 1000000)
670         {
671                 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
672                 return;
673         }
674
675         if (jpeg)
676                 sprintf(filename, "%s%06d.jpg", base, shotnumber);
677         else
678                 sprintf(filename, "%s%06d.tga", base, shotnumber);
679
680         if (SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight, jpeg))
681                 Con_Printf("Wrote %s\n", filename);
682         else
683                 Con_Printf("unable to write %s\n", filename);
684         shotnumber++;
685 }
686
687 static int cl_avidemo_frame = 0;
688
689 void SCR_CaptureAVIDemo(void)
690 {
691         char filename[32];
692         qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
693
694         if (jpeg)
695                 sprintf(filename, "video/dp%06d.jpg", cl_avidemo_frame);
696         else
697                 sprintf(filename, "video/dp%06d.tga", cl_avidemo_frame);
698
699         if (SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight, jpeg))
700                 cl_avidemo_frame++;
701         else
702         {
703                 Cvar_SetValueQuick(&cl_avidemo, 0);
704                 Con_Printf("avi saving failed on frame %i, out of disk space?  stopping avi demo catpure.\n", cl_avidemo_frame);
705                 cl_avidemo_frame = 0;
706         }
707 }
708
709 /*
710 ===============
711 R_Envmap_f
712
713 Grab six views for environment mapping tests
714 ===============
715 */
716 struct
717 {
718         float angles[3];
719         char *name;
720 }
721 envmapinfo[6] =
722 {
723         {{  0,   0, 0}, "ft"},
724         {{  0,  90, 0}, "rt"},
725         {{  0, 180, 0}, "bk"},
726         {{  0, 270, 0}, "lf"},
727         {{-90,  90, 0}, "up"},
728         {{ 90,  90, 0}, "dn"}
729 };
730
731 static void R_Envmap_f (void)
732 {
733         int j, size;
734         char filename[256], basename[256];
735
736         if (Cmd_Argc() != 3)
737         {
738                 Con_Print("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");
739                 return;
740         }
741
742         strlcpy (basename, Cmd_Argv(1), sizeof (basename));
743         size = atoi(Cmd_Argv(2));
744         if (size != 128 && size != 256 && size != 512 && size != 1024)
745         {
746                 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
747                 return;
748         }
749         if (size > vid.realwidth || size > vid.realheight)
750         {
751                 Con_Print("envmap: your resolution is not big enough to render that size\n");
752                 return;
753         }
754
755         envmap = true;
756
757         r_refdef.x = 0;
758         r_refdef.y = 0;
759         r_refdef.width = size;
760         r_refdef.height = size;
761
762         r_refdef.fov_x = 90;
763         r_refdef.fov_y = 90;
764
765         for (j = 0;j < 6;j++)
766         {
767                 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
768                 Matrix4x4_CreateFromQuakeEntity(&r_refdef.viewentitymatrix, r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], envmapinfo[j].angles[0], envmapinfo[j].angles[1], envmapinfo[j].angles[2], 1);
769                 R_ClearScreen();
770                 R_RenderView();
771                 SCR_ScreenShot(filename, vid.realx, vid.realy + vid.realheight - (r_refdef.y + r_refdef.height), size, size, false);
772         }
773
774         envmap = false;
775 }
776
777 //=============================================================================
778
779 // LordHavoc: SHOWLMP stuff
780 #define SHOWLMP_MAXLABELS 256
781 typedef struct showlmp_s
782 {
783         qboolean        isactive;
784         float           x;
785         float           y;
786         char            label[32];
787         char            pic[128];
788 }
789 showlmp_t;
790
791 showlmp_t showlmp[SHOWLMP_MAXLABELS];
792
793 void SHOWLMP_decodehide(void)
794 {
795         int i;
796         qbyte *lmplabel;
797         lmplabel = MSG_ReadString();
798         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
799                 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
800                 {
801                         showlmp[i].isactive = false;
802                         return;
803                 }
804 }
805
806 void SHOWLMP_decodeshow(void)
807 {
808         int i, k;
809         qbyte lmplabel[256], picname[256];
810         float x, y;
811         strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
812         strlcpy (picname, MSG_ReadString(), sizeof (picname));
813         if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
814         {
815                 x = MSG_ReadByte();
816                 y = MSG_ReadByte();
817         }
818         else
819         {
820                 x = MSG_ReadShort();
821                 y = MSG_ReadShort();
822         }
823         k = -1;
824         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
825                 if (showlmp[i].isactive)
826                 {
827                         if (strcmp(showlmp[i].label, lmplabel) == 0)
828                         {
829                                 k = i;
830                                 break; // drop out to replace it
831                         }
832                 }
833                 else if (k < 0) // find first empty one to replace
834                         k = i;
835         if (k < 0)
836                 return; // none found to replace
837         // change existing one
838         showlmp[k].isactive = true;
839         strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
840         strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
841         showlmp[k].x = x;
842         showlmp[k].y = y;
843 }
844
845 void SHOWLMP_drawall(void)
846 {
847         int i;
848         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
849                 if (showlmp[i].isactive)
850                         DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
851 }
852
853 void SHOWLMP_clear(void)
854 {
855         int i;
856         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
857                 showlmp[i].isactive = false;
858 }
859
860 void CL_SetupScreenSize(void)
861 {
862         float conwidth, conheight;
863
864         VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
865
866         VID_UpdateGamma(false);
867
868         conwidth = bound(320, vid_conwidth.value, 2048);
869         conheight = bound(200, vid_conheight.value, 1536);
870         if (vid_conwidth.value != conwidth)
871                 Cvar_SetValue("vid_conwidth", conwidth);
872         if (vid_conheight.value != conheight)
873                 Cvar_SetValue("vid_conheight", conheight);
874
875         vid.conwidth = vid_conwidth.integer;
876         vid.conheight = vid_conheight.integer;
877
878 /*      if (vid.realheight > 240)
879         {
880                 vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
881                 vid.conheight = bound(240, vid.conheight, vid.realheight);
882         }
883         else
884                 vid.conheight = 240;*/
885
886         SCR_SetUpToDrawConsole();
887 }
888
889 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
890 void CL_UpdateScreen(void)
891 {
892         if (!scr_initialized || !con_initialized || vid_hidden)
893                 return;                         // not initialized yet
894
895         if (cl_avidemo.integer)
896                 SCR_CaptureAVIDemo();
897         else
898                 cl_avidemo_frame = 0;
899
900         if (cls.signon == SIGNONS)
901                 R_TimeReport("other");
902
903         CL_SetupScreenSize();
904
905         DrawQ_Clear();
906
907         if (cls.signon == SIGNONS)
908                 R_TimeReport("setup");
909
910         //FIXME: force menu if nothing else to look at?
911         //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
912
913         if (scr_drawloading)
914         {
915                 scr_drawloading = false;
916                 SCR_DrawLoading();
917         }
918         else
919         {
920                 if (cls.signon == SIGNONS)
921                 {
922                         SCR_DrawNet ();
923                         SCR_DrawTurtle ();
924                         SCR_DrawPause ();
925                         Sbar_Draw();
926                         SHOWLMP_drawall();
927                         SCR_CheckDrawCenterString();
928                 }
929                 MR_Draw();
930                 UI_Callback_Draw();
931                 CL_DrawVideo();
932                 //ui_draw();
933                 if (cls.signon == SIGNONS)
934                 {
935                         R_TimeReport("2d");
936                         R_TimeReport_End();
937                         R_TimeReport_Start();
938                 }
939                 R_Shadow_EditLights_DrawSelectedLightProperties();
940         }
941         SCR_DrawConsole();
942
943         SCR_UpdateScreen();
944 }
945
946 void CL_Screen_NewMap(void)
947 {
948         SHOWLMP_clear();
949 }