]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_screen.c
Tomaz added r_skyscroll1/2 to the menu
[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         if (jpeg)
688                 sprintf(filename, "%s%06d.jpg", base, shotnumber);
689         else
690                 sprintf(filename, "%s%06d.tga", base, shotnumber);
691
692         buffer1 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3);
693         buffer2 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3);
694         buffer3 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3 + 18);
695
696         if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, vid.realx, vid.realy, vid.realwidth, vid.realheight, false, false, false, jpeg))
697                 Con_Printf("Wrote %s\n", filename);
698         else
699                 Con_Printf("unable to write %s\n", filename);
700
701         Mem_Free (buffer1);
702         Mem_Free (buffer2);
703         Mem_Free (buffer3);
704
705         shotnumber++;
706 }
707
708 static int cl_avidemo_frame = 0;
709
710 void SCR_CaptureAVIDemo(void)
711 {
712         static qbyte *avi_buffer1 = NULL;
713         static qbyte *avi_buffer2 = NULL;
714         static qbyte *avi_buffer3 = NULL;
715         char filename[32];
716         qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
717
718         if (cl_avidemo.integer)
719         {
720                 if (avi_buffer1 == NULL)
721                 {
722                         avi_buffer1 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3);
723                         avi_buffer2 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3);
724                         avi_buffer3 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3 + 18);
725                 }
726         }
727         else
728         {
729                 if (avi_buffer1 != NULL)
730                 {
731                         Mem_Free (avi_buffer1);
732                         Mem_Free (avi_buffer2);
733                         Mem_Free (avi_buffer3);
734                         avi_buffer1 = NULL;
735                         avi_buffer2 = NULL;
736                         avi_buffer3 = NULL;
737                 }
738                 cl_avidemo_frame = 0;
739                 return;
740         }
741
742         if (jpeg)
743                 sprintf(filename, "video/dp%06d.jpg", cl_avidemo_frame);
744         else
745                 sprintf(filename, "video/dp%06d.tga", cl_avidemo_frame);
746
747         if (SCR_ScreenShot(filename, avi_buffer1, avi_buffer2, avi_buffer3, vid.realx, vid.realy, vid.realwidth, vid.realheight, false, false, false, jpeg))
748                 cl_avidemo_frame++;
749         else
750         {
751                 Cvar_SetValueQuick(&cl_avidemo, 0);
752                 Con_Printf("avi saving failed on frame %i, out of disk space? stopping avi demo capture.\n", cl_avidemo_frame);
753                 cl_avidemo_frame = 0;
754         }
755 }
756
757 /*
758 ===============
759 R_Envmap_f
760
761 Grab six views for environment mapping tests
762 ===============
763 */
764 struct
765 {
766         float angles[3];
767         char *name;
768         qboolean flipx, flipy, flipdiagonaly;
769 }
770 envmapinfo[12] =
771 {
772         {{  0,   0, 0}, "rt",  true, false, false},
773         {{  0,  90, 0}, "ft",  true, false, false},
774         {{  0, 180, 0}, "lf",  true, false, false},
775         {{  0, 270, 0}, "bk",  true, false, false},
776         {{-90, 180, 0}, "up", false,  true, false},
777         {{ 90, 180, 0}, "dn", false,  true, false},
778
779         {{  0,   0, 0}, "px",  true,  true,  true},
780         {{  0,  90, 0}, "py", false,  true, false},
781         {{  0, 180, 0}, "nx", false, false,  true},
782         {{  0, 270, 0}, "ny",  true, false, false},
783         {{-90, 180, 0}, "pz", false, false,  true},
784         {{ 90, 180, 0}, "nz", false, false,  true}
785 };
786
787 static void R_Envmap_f (void)
788 {
789         int j, size;
790         char filename[256], basename[256];
791         qbyte *buffer1;
792         qbyte *buffer2;
793         qbyte *buffer3;
794
795         if (Cmd_Argc() != 3)
796         {
797                 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");
798                 return;
799         }
800
801         strlcpy (basename, Cmd_Argv(1), sizeof (basename));
802         size = atoi(Cmd_Argv(2));
803         if (size != 128 && size != 256 && size != 512 && size != 1024)
804         {
805                 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
806                 return;
807         }
808         if (size > vid.realwidth || size > vid.realheight)
809         {
810                 Con_Print("envmap: your resolution is not big enough to render that size\n");
811                 return;
812         }
813
814         envmap = true;
815
816         r_refdef.x = 0;
817         r_refdef.y = 0;
818         r_refdef.width = size;
819         r_refdef.height = size;
820
821         r_refdef.fov_x = 90;
822         r_refdef.fov_y = 90;
823
824         buffer1 = Mem_Alloc(tempmempool, size * size * 3);
825         buffer2 = Mem_Alloc(tempmempool, size * size * 3);
826         buffer3 = Mem_Alloc(tempmempool, size * size * 3 + 18);
827
828         for (j = 0;j < 12;j++)
829         {
830                 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
831                 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);
832                 R_ClearScreen();
833                 R_Mesh_Start();
834                 R_RenderView();
835                 R_Mesh_Finish();
836                 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);
837         }
838
839         Mem_Free (buffer1);
840         Mem_Free (buffer2);
841         Mem_Free (buffer3);
842
843         envmap = false;
844 }
845
846 //=============================================================================
847
848 // LordHavoc: SHOWLMP stuff
849 #define SHOWLMP_MAXLABELS 256
850 typedef struct showlmp_s
851 {
852         qboolean        isactive;
853         float           x;
854         float           y;
855         char            label[32];
856         char            pic[128];
857 }
858 showlmp_t;
859
860 showlmp_t showlmp[SHOWLMP_MAXLABELS];
861
862 void SHOWLMP_decodehide(void)
863 {
864         int i;
865         qbyte *lmplabel;
866         lmplabel = MSG_ReadString();
867         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
868                 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
869                 {
870                         showlmp[i].isactive = false;
871                         return;
872                 }
873 }
874
875 void SHOWLMP_decodeshow(void)
876 {
877         int i, k;
878         qbyte lmplabel[256], picname[256];
879         float x, y;
880         strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
881         strlcpy (picname, MSG_ReadString(), sizeof (picname));
882         if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
883         {
884                 x = MSG_ReadByte();
885                 y = MSG_ReadByte();
886         }
887         else
888         {
889                 x = MSG_ReadShort();
890                 y = MSG_ReadShort();
891         }
892         k = -1;
893         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
894                 if (showlmp[i].isactive)
895                 {
896                         if (strcmp(showlmp[i].label, lmplabel) == 0)
897                         {
898                                 k = i;
899                                 break; // drop out to replace it
900                         }
901                 }
902                 else if (k < 0) // find first empty one to replace
903                         k = i;
904         if (k < 0)
905                 return; // none found to replace
906         // change existing one
907         showlmp[k].isactive = true;
908         strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
909         strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
910         showlmp[k].x = x;
911         showlmp[k].y = y;
912 }
913
914 void SHOWLMP_drawall(void)
915 {
916         int i;
917         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
918                 if (showlmp[i].isactive)
919                         DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
920 }
921
922 void SHOWLMP_clear(void)
923 {
924         int i;
925         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
926                 showlmp[i].isactive = false;
927 }
928
929 void CL_SetupScreenSize(void)
930 {
931         float conwidth, conheight;
932
933         VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
934
935         VID_UpdateGamma(false);
936
937         conwidth = bound(320, vid_conwidth.value, 2048);
938         conheight = bound(200, vid_conheight.value, 1536);
939         if (vid_conwidth.value != conwidth)
940                 Cvar_SetValue("vid_conwidth", conwidth);
941         if (vid_conheight.value != conheight)
942                 Cvar_SetValue("vid_conheight", conheight);
943
944         vid.conwidth = vid_conwidth.integer;
945         vid.conheight = vid_conheight.integer;
946
947 /*      if (vid.realheight > 240)
948         {
949                 vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
950                 vid.conheight = bound(240, vid.conheight, vid.realheight);
951         }
952         else
953                 vid.conheight = 240;*/
954
955         SCR_SetUpToDrawConsole();
956 }
957
958 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
959 void CL_UpdateScreen(void)
960 {
961         if (!scr_initialized || !con_initialized || vid_hidden)
962                 return;                         // not initialized yet
963
964         SCR_CaptureAVIDemo();
965
966         if (cls.signon == SIGNONS)
967                 R_TimeReport("other");
968
969         CL_SetupScreenSize();
970
971         DrawQ_Clear();
972
973         if (cls.signon == SIGNONS)
974                 R_TimeReport("setup");
975
976         //FIXME: force menu if nothing else to look at?
977         //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
978
979         if (scr_drawloading)
980         {
981                 scr_drawloading = false;
982                 SCR_DrawLoading();
983         }
984         else
985         {
986                 if (cls.signon == SIGNONS)
987                 {
988                         SCR_DrawNet ();
989                         SCR_DrawTurtle ();
990                         SCR_DrawPause ();
991                         Sbar_Draw();
992                         SHOWLMP_drawall();
993                         SCR_CheckDrawCenterString();
994                 }
995                 MR_Draw();
996                 UI_Callback_Draw();
997                 CL_DrawVideo();
998                 //ui_draw();
999                 if (cls.signon == SIGNONS)
1000                 {
1001                         R_TimeReport("2d");
1002                         R_TimeReport_End();
1003                         R_TimeReport_Start();
1004                 }
1005                 R_Shadow_EditLights_DrawSelectedLightProperties();
1006         }
1007         SCR_DrawConsole();
1008
1009         SCR_UpdateScreen();
1010 }
1011
1012 void CL_Screen_NewMap(void)
1013 {
1014         SHOWLMP_clear();
1015 }