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