]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_screen.c
Tomaz renamed all R_Model_Brush functions to R_Q1BSP
[divverent/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, false, false, false, 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, false, false, false, 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         qboolean flipx, flipy;
721 }
722 envmapinfo[6] =
723 {
724         {{  0,   0, 0}, "rt",  true, false},
725         {{  0,  90, 0}, "ft",  true, false},
726         {{  0, 180, 0}, "lf",  true, false},
727         {{  0, 270, 0}, "bk",  true, false},
728         {{-90, 180, 0}, "up", false,  true},
729         {{ 90, 180, 0}, "dn", false,  true}
730 };
731
732 static void R_Envmap_f (void)
733 {
734         int j, size;
735         char filename[256], basename[256];
736
737         if (Cmd_Argc() != 3)
738         {
739                 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");
740                 return;
741         }
742
743         strlcpy (basename, Cmd_Argv(1), sizeof (basename));
744         size = atoi(Cmd_Argv(2));
745         if (size != 128 && size != 256 && size != 512 && size != 1024)
746         {
747                 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
748                 return;
749         }
750         if (size > vid.realwidth || size > vid.realheight)
751         {
752                 Con_Print("envmap: your resolution is not big enough to render that size\n");
753                 return;
754         }
755
756         envmap = true;
757
758         r_refdef.x = 0;
759         r_refdef.y = 0;
760         r_refdef.width = size;
761         r_refdef.height = size;
762
763         r_refdef.fov_x = 90;
764         r_refdef.fov_y = 90;
765
766         for (j = 0;j < 6;j++)
767         {
768                 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
769                 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);
770                 R_ClearScreen();
771                 R_Mesh_Start();
772                 R_RenderView();
773                 R_Mesh_Finish();
774                 SCR_ScreenShot(filename, vid.realx, vid.realy + vid.realheight - (r_refdef.y + r_refdef.height), size, size, envmapinfo[j].flipx, envmapinfo[j].flipy, false, false);
775         }
776
777         envmap = false;
778 }
779
780 //=============================================================================
781
782 // LordHavoc: SHOWLMP stuff
783 #define SHOWLMP_MAXLABELS 256
784 typedef struct showlmp_s
785 {
786         qboolean        isactive;
787         float           x;
788         float           y;
789         char            label[32];
790         char            pic[128];
791 }
792 showlmp_t;
793
794 showlmp_t showlmp[SHOWLMP_MAXLABELS];
795
796 void SHOWLMP_decodehide(void)
797 {
798         int i;
799         qbyte *lmplabel;
800         lmplabel = MSG_ReadString();
801         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
802                 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
803                 {
804                         showlmp[i].isactive = false;
805                         return;
806                 }
807 }
808
809 void SHOWLMP_decodeshow(void)
810 {
811         int i, k;
812         qbyte lmplabel[256], picname[256];
813         float x, y;
814         strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
815         strlcpy (picname, MSG_ReadString(), sizeof (picname));
816         if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
817         {
818                 x = MSG_ReadByte();
819                 y = MSG_ReadByte();
820         }
821         else
822         {
823                 x = MSG_ReadShort();
824                 y = MSG_ReadShort();
825         }
826         k = -1;
827         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
828                 if (showlmp[i].isactive)
829                 {
830                         if (strcmp(showlmp[i].label, lmplabel) == 0)
831                         {
832                                 k = i;
833                                 break; // drop out to replace it
834                         }
835                 }
836                 else if (k < 0) // find first empty one to replace
837                         k = i;
838         if (k < 0)
839                 return; // none found to replace
840         // change existing one
841         showlmp[k].isactive = true;
842         strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
843         strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
844         showlmp[k].x = x;
845         showlmp[k].y = y;
846 }
847
848 void SHOWLMP_drawall(void)
849 {
850         int i;
851         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
852                 if (showlmp[i].isactive)
853                         DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
854 }
855
856 void SHOWLMP_clear(void)
857 {
858         int i;
859         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
860                 showlmp[i].isactive = false;
861 }
862
863 void CL_SetupScreenSize(void)
864 {
865         float conwidth, conheight;
866
867         VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
868
869         VID_UpdateGamma(false);
870
871         conwidth = bound(320, vid_conwidth.value, 2048);
872         conheight = bound(200, vid_conheight.value, 1536);
873         if (vid_conwidth.value != conwidth)
874                 Cvar_SetValue("vid_conwidth", conwidth);
875         if (vid_conheight.value != conheight)
876                 Cvar_SetValue("vid_conheight", conheight);
877
878         vid.conwidth = vid_conwidth.integer;
879         vid.conheight = vid_conheight.integer;
880
881 /*      if (vid.realheight > 240)
882         {
883                 vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
884                 vid.conheight = bound(240, vid.conheight, vid.realheight);
885         }
886         else
887                 vid.conheight = 240;*/
888
889         SCR_SetUpToDrawConsole();
890 }
891
892 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
893 void CL_UpdateScreen(void)
894 {
895         if (!scr_initialized || !con_initialized || vid_hidden)
896                 return;                         // not initialized yet
897
898         if (cl_avidemo.integer)
899                 SCR_CaptureAVIDemo();
900         else
901                 cl_avidemo_frame = 0;
902
903         if (cls.signon == SIGNONS)
904                 R_TimeReport("other");
905
906         CL_SetupScreenSize();
907
908         DrawQ_Clear();
909
910         if (cls.signon == SIGNONS)
911                 R_TimeReport("setup");
912
913         //FIXME: force menu if nothing else to look at?
914         //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
915
916         if (scr_drawloading)
917         {
918                 scr_drawloading = false;
919                 SCR_DrawLoading();
920         }
921         else
922         {
923                 if (cls.signon == SIGNONS)
924                 {
925                         SCR_DrawNet ();
926                         SCR_DrawTurtle ();
927                         SCR_DrawPause ();
928                         Sbar_Draw();
929                         SHOWLMP_drawall();
930                         SCR_CheckDrawCenterString();
931                 }
932                 MR_Draw();
933                 UI_Callback_Draw();
934                 CL_DrawVideo();
935                 //ui_draw();
936                 if (cls.signon == SIGNONS)
937                 {
938                         R_TimeReport("2d");
939                         R_TimeReport_End();
940                         R_TimeReport_Start();
941                 }
942                 R_Shadow_EditLights_DrawSelectedLightProperties();
943         }
944         SCR_DrawConsole();
945
946         SCR_UpdateScreen();
947 }
948
949 void CL_Screen_NewMap(void)
950 {
951         SHOWLMP_clear();
952 }