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