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