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