]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_screen.c
fixed unterminated character constant in my last fix
[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 cvar_t r_textshadow = {0, "r_textshadow", "0"};
26
27 int jpeg_supported = false;
28
29 qboolean        scr_initialized;                // ready to draw
30
31 float           scr_con_current;
32 float           scr_conlines;           // lines of console to display
33
34 int                     clearconsole;
35 int                     clearnotify;
36
37 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         {
292                 Con_DrawConsole (scr_con_current);
293                 clearconsole = 0;
294         }
295         else
296         {
297                 if (key_dest == key_game || key_dest == key_message)
298                         Con_DrawNotify ();      // only draw notify in game
299         }
300 }
301
302 /*
303 ===============
304 SCR_BeginLoadingPlaque
305
306 ================
307 */
308 void SCR_BeginLoadingPlaque (void)
309 {
310         if (scr_drawloading)
311                 return;
312
313         S_StopAllSounds (true);
314
315         scr_drawloading = true;
316         CL_UpdateScreen ();
317         scr_drawloading = true;
318         CL_UpdateScreen ();
319 }
320
321 //=============================================================================
322
323 char r_speeds_string[1024];
324 int speedstringcount, r_timereport_active;
325 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
326
327 void R_TimeReport(char *desc)
328 {
329         char tempbuf[256];
330         int length;
331         int t;
332
333         if (!r_timereport_active)
334                 return;
335
336         r_timereport_temp = r_timereport_current;
337         r_timereport_current = Sys_DoubleTime();
338         t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
339
340         sprintf(tempbuf, "%8i %s", t, desc);
341         length = strlen(tempbuf);
342         while (length < 20)
343                 tempbuf[length++] = ' ';
344         tempbuf[length] = 0;
345         if (speedstringcount + length > (vid.conwidth / 8))
346         {
347                 strcat(r_speeds_string, "\n");
348                 speedstringcount = 0;
349         }
350         // skip the space at the beginning if it's the first on the line
351         if (speedstringcount == 0)
352         {
353                 strcat(r_speeds_string, tempbuf + 1);
354                 speedstringcount = length - 1;
355         }
356         else
357         {
358                 strcat(r_speeds_string, tempbuf);
359                 speedstringcount += length;
360         }
361 }
362
363 extern int c_rt_lights, c_rt_clears, c_rt_scissored;
364 extern int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
365 extern int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
366 void R_TimeReport_Start(void)
367 {
368         r_timereport_active = r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected;
369         r_speeds_string[0] = 0;
370         if (r_timereport_active)
371         {
372                 speedstringcount = 0;
373                 sprintf(r_speeds_string,
374                         "org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n"
375                         "world:%6i faces%6i nodes%6i leafs%6i dlitwalls\n"
376                         "%5i models%5i bmodels%5i sprites%6i particles%4i dlights\n"
377                         "%6i modeltris%6i meshs%6i meshtris\n",
378                         r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], r_viewforward[0], r_viewforward[1], r_viewforward[2],
379                         c_faces, c_nodes, c_leafs, c_light_polys,
380                         c_models, c_bmodels, c_sprites, c_particles, c_dlights,
381                         c_alias_polys, c_meshs, c_meshelements / 3);
382
383                 sprintf(r_speeds_string + strlen(r_speeds_string),
384                         "realtime lighting:%4i lights%4i clears%4i scissored\n"
385                         "dynamic: %6i shadowmeshes%6i shadowtris%6i lightmeshes%6i lighttris\n"
386                         "precomputed: %6i shadowmeshes%6i shadowtris\n",
387                         c_rt_lights, c_rt_clears, c_rt_scissored,
388                         c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris,
389                         c_rtcached_shadowmeshes, c_rtcached_shadowtris);
390
391                 c_alias_polys = 0;
392                 c_light_polys = 0;
393                 c_faces = 0;
394                 c_nodes = 0;
395                 c_leafs = 0;
396                 c_models = 0;
397                 c_bmodels = 0;
398                 c_sprites = 0;
399                 c_particles = 0;
400                 c_meshs = 0;
401                 c_meshelements = 0;
402
403                 r_timereport_start = Sys_DoubleTime();
404         }
405 }
406
407 void R_TimeReport_End(void)
408 {
409         r_timereport_current = r_timereport_start;
410         R_TimeReport("total");
411
412         if (r_timereport_active)
413         {
414                 int i, j, lines, y;
415                 lines = 1;
416                 for (i = 0;r_speeds_string[i];i++)
417                         if (r_speeds_string[i] == '\n')
418                                 lines++;
419                 y = vid.conheight - sb_lines - lines * 8;
420                 i = j = 0;
421                 DrawQ_Fill(0, y, vid.conwidth, lines * 8, 0, 0, 0, 0.5, 0);
422                 while (r_speeds_string[i])
423                 {
424                         j = i;
425                         while (r_speeds_string[i] && r_speeds_string[i] != '\n')
426                                 i++;
427                         if (i - j > 0)
428                                 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
429                         if (r_speeds_string[i] == '\n')
430                                 i++;
431                         y += 8;
432                 }
433         }
434 }
435
436 /*
437 =================
438 SCR_SizeUp_f
439
440 Keybinding command
441 =================
442 */
443 void SCR_SizeUp_f (void)
444 {
445         Cvar_SetValue ("viewsize",scr_viewsize.value+10);
446 }
447
448
449 /*
450 =================
451 SCR_SizeDown_f
452
453 Keybinding command
454 =================
455 */
456 void SCR_SizeDown_f (void)
457 {
458         Cvar_SetValue ("viewsize",scr_viewsize.value-10);
459 }
460
461 void CL_Screen_Init(void)
462 {
463         Cvar_RegisterVariable (&scr_fov);
464         Cvar_RegisterVariable (&scr_viewsize);
465         Cvar_RegisterVariable (&scr_conspeed);
466         Cvar_RegisterVariable (&scr_conalpha);
467         Cvar_RegisterVariable (&scr_conbrightness);
468         Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
469         Cvar_RegisterVariable (&scr_showram);
470         Cvar_RegisterVariable (&scr_showturtle);
471         Cvar_RegisterVariable (&scr_showpause);
472         Cvar_RegisterVariable (&scr_centertime);
473         Cvar_RegisterVariable (&scr_printspeed);
474         Cvar_RegisterVariable (&vid_conwidth);
475         Cvar_RegisterVariable (&vid_conheight);
476         Cvar_RegisterVariable (&vid_pixelaspect);
477         Cvar_RegisterVariable (&scr_screenshot_jpeg);
478         Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
479         Cvar_RegisterVariable (&cl_avidemo);
480         Cvar_RegisterVariable (&r_textshadow);
481
482         Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
483         Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
484         Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
485         Cmd_AddCommand ("envmap", R_Envmap_f);
486
487         scr_initialized = true;
488 }
489
490 void DrawQ_Clear(void)
491 {
492         r_refdef.drawqueuesize = 0;
493 }
494
495 static int picelements[6] = {0, 1, 2, 0, 2, 3};
496 void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
497 {
498         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);
499 }
500
501 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)
502 {
503         int size, len;
504         drawqueue_t *dq;
505         char *out;
506         if (alpha < (1.0f / 255.0f))
507                 return;
508         if (maxlen < 1)
509                 len = strlen(string);
510         else
511                 for (len = 0;len < maxlen && string[len];len++);
512         for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
513         for (;len > 0 && string[len - 1] == ' ';len--);
514         if (len < 1)
515                 return;
516         if (x >= vid.conwidth || y >= vid.conheight || x < (-scalex * maxlen) || y < (-scaley))
517                 return;
518         size = sizeof(*dq) + ((len + 1 + 3) & ~3);
519         if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
520                 return;
521         red = bound(0, red, 1);
522         green = bound(0, green, 1);
523         blue = bound(0, blue, 1);
524         alpha = bound(0, alpha, 1);
525         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
526         dq->size = size;
527         dq->command = DRAWQUEUE_STRING;
528         dq->flags = flags;
529         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));
530         dq->x = x;
531         dq->y = y;
532         dq->scalex = scalex;
533         dq->scaley = scaley;
534         out = (char *)(dq + 1);
535         memcpy(out, string, len);
536         out[len] = 0;
537         r_refdef.drawqueuesize += dq->size;
538 }
539
540 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)
541 {
542         if (r_textshadow.integer)
543                 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
544
545         DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags); 
546 }
547
548 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
549 {
550         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);
551 }
552
553 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)
554 {
555         float floats[36];
556         cachepic_t *pic;
557         drawqueuemesh_t mesh;
558         memset(&mesh, 0, sizeof(mesh));
559         if (picname && picname[0])
560         {
561                 pic = Draw_CachePic(picname);
562                 if (width == 0)
563                         width = pic->width;
564                 if (height == 0)
565                         height = pic->height;
566                 mesh.texture = pic->tex;
567         }
568         mesh.num_triangles = 2;
569         mesh.num_vertices = 4;
570         mesh.data_element3i = picelements;
571         mesh.data_vertex3f = floats;
572         mesh.data_texcoord2f = floats + 12;
573         mesh.data_color4f = floats + 20;
574         memset(floats, 0, sizeof(floats));
575         mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
576         mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
577         mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
578         mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
579         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;
580         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;
581         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;
582         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;
583         DrawQ_Mesh (&mesh, flags);
584 }
585
586 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
587 {
588         int size;
589         void *p;
590         drawqueue_t *dq;
591         drawqueuemesh_t *m;
592         size = sizeof(*dq);
593         size += sizeof(drawqueuemesh_t);
594         size += sizeof(int[3]) * mesh->num_triangles;
595         size += sizeof(float[3]) * mesh->num_vertices;
596         size += sizeof(float[2]) * mesh->num_vertices;
597         size += sizeof(float[4]) * mesh->num_vertices;
598         if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
599                 return;
600         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
601         dq->size = size;
602         dq->command = DRAWQUEUE_MESH;
603         dq->flags = flags;
604         dq->color = 0;
605         dq->x = 0;
606         dq->y = 0;
607         dq->scalex = 0;
608         dq->scaley = 0;
609         p = (void *)(dq + 1);
610         m = p;p = (qbyte*)p + sizeof(drawqueuemesh_t);
611         m->num_triangles = mesh->num_triangles;
612         m->num_vertices = mesh->num_vertices;
613         m->texture = mesh->texture;
614         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]);
615         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]);
616         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]);
617         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]);
618         r_refdef.drawqueuesize += dq->size;
619 }
620
621 void DrawQ_SetClipArea(float x, float y, float width, float height)
622 {
623         drawqueue_t * dq;
624         if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
625         {
626                 Con_DPrint("DrawQueue full !\n");
627                 return;
628         }
629         dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
630         dq->size = sizeof(*dq);
631         dq->command = DRAWQUEUE_SETCLIP;
632         dq->x = x;
633         dq->y = y;
634         dq->scalex = width;
635         dq->scaley = height;
636         dq->flags = 0;
637         dq->color = 0;
638
639         r_refdef.drawqueuesize += dq->size;
640 }
641
642 void DrawQ_ResetClipArea(void)
643 {
644         drawqueue_t *dq;
645         if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
646         {
647                 Con_DPrint("DrawQueue full !\n");
648                 return;
649         }
650         dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
651         dq->size = sizeof(*dq);
652         dq->command = DRAWQUEUE_RESETCLIP;
653         dq->x = 0;
654         dq->y = 0;
655         dq->scalex = 0;
656         dq->scaley = 0;
657         dq->flags = 0;
658         dq->color = 0;
659
660         r_refdef.drawqueuesize += dq->size;
661 }
662
663 /*
664 ==================
665 SCR_ScreenShot_f
666 ==================
667 */
668 void SCR_ScreenShot_f (void)
669 {
670         static int shotnumber;
671         static char oldname[MAX_QPATH];
672         char base[MAX_QPATH];
673         char filename[MAX_QPATH];
674         qbyte *buffer1;
675         qbyte *buffer2;
676         qbyte *buffer3;
677         qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
678
679         sprintf (base, "screenshots/%s", scr_screenshot_name.string);
680
681         if (strcmp (oldname, scr_screenshot_name.string))
682         {
683                 sprintf(oldname, "%s", scr_screenshot_name.string);
684                 shotnumber = 0;
685         }
686
687         // find a file name to save it to
688         for (;shotnumber < 1000000;shotnumber++)
689                 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
690                         break;
691         if (shotnumber >= 1000000)
692         {
693                 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
694                 return;
695         }
696
697         sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
698
699         buffer1 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3);
700         buffer2 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3);
701         buffer3 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3 + 18);
702
703         if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, vid.realx, vid.realy, vid.realwidth, vid.realheight, false, false, false, jpeg))
704                 Con_Printf("Wrote %s\n", filename);
705         else
706                 Con_Printf("unable to write %s\n", filename);
707
708         Mem_Free (buffer1);
709         Mem_Free (buffer2);
710         Mem_Free (buffer3);
711
712         shotnumber++;
713 }
714
715 static int cl_avidemo_frame = 0;
716
717 void SCR_CaptureAVIDemo(void)
718 {
719         static qbyte *avi_buffer1 = NULL;
720         static qbyte *avi_buffer2 = NULL;
721         static qbyte *avi_buffer3 = NULL;
722         char filename[32];
723         qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
724
725         if (!cl_avidemo.integer)
726         {
727                 if (avi_buffer1 != NULL)
728                 {
729                         Mem_Free (avi_buffer1);
730                         Mem_Free (avi_buffer2);
731                         Mem_Free (avi_buffer3);
732                         avi_buffer1 = NULL;
733                         avi_buffer2 = NULL;
734                         avi_buffer3 = NULL;
735                 }
736                 cl_avidemo_frame = 0;
737                 return;
738         }
739
740         if (avi_buffer1 == NULL)
741         {
742                 avi_buffer1 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3);
743                 avi_buffer2 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3);
744                 avi_buffer3 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3 + 18);
745         }
746
747         sprintf(filename, "video/dp%06d.%s", cl_avidemo_frame, jpeg ? "jpg" : "tga");
748
749         if (SCR_ScreenShot(filename, avi_buffer1, avi_buffer2, avi_buffer3, vid.realx, vid.realy, vid.realwidth, vid.realheight, false, false, false, jpeg))
750                 cl_avidemo_frame++;
751         else
752         {
753                 Cvar_SetValueQuick(&cl_avidemo, 0);
754                 Con_Printf("avi saving failed on frame %i, out of disk space? stopping avi demo capture.\n", cl_avidemo_frame);
755                 cl_avidemo_frame = 0;
756         }
757 }
758
759 /*
760 ===============
761 R_Envmap_f
762
763 Grab six views for environment mapping tests
764 ===============
765 */
766 struct
767 {
768         float angles[3];
769         char *name;
770         qboolean flipx, flipy, flipdiagonaly;
771 }
772 envmapinfo[12] =
773 {
774         {{  0,   0, 0}, "rt",  true, false, false},
775         {{  0,  90, 0}, "ft",  true, false, false},
776         {{  0, 180, 0}, "lf",  true, false, false},
777         {{  0, 270, 0}, "bk",  true, false, false},
778         {{-90, 180, 0}, "up", false,  true, false},
779         {{ 90, 180, 0}, "dn", false,  true, false},
780
781         {{  0,   0, 0}, "px",  true,  true,  true},
782         {{  0,  90, 0}, "py", false,  true, false},
783         {{  0, 180, 0}, "nx", false, false,  true},
784         {{  0, 270, 0}, "ny",  true, false, false},
785         {{-90, 180, 0}, "pz", false, false,  true},
786         {{ 90, 180, 0}, "nz", false, false,  true}
787 };
788
789 static void R_Envmap_f (void)
790 {
791         int j, size;
792         char filename[256], basename[256];
793         qbyte *buffer1;
794         qbyte *buffer2;
795         qbyte *buffer3;
796
797         if (Cmd_Argc() != 3)
798         {
799                 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");
800                 return;
801         }
802
803         strlcpy (basename, Cmd_Argv(1), sizeof (basename));
804         size = atoi(Cmd_Argv(2));
805         if (size != 128 && size != 256 && size != 512 && size != 1024)
806         {
807                 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
808                 return;
809         }
810         if (size > vid.realwidth || size > vid.realheight)
811         {
812                 Con_Print("envmap: your resolution is not big enough to render that size\n");
813                 return;
814         }
815
816         envmap = true;
817
818         r_refdef.x = 0;
819         r_refdef.y = 0;
820         r_refdef.width = size;
821         r_refdef.height = size;
822
823         r_refdef.fov_x = 90;
824         r_refdef.fov_y = 90;
825
826         buffer1 = Mem_Alloc(tempmempool, size * size * 3);
827         buffer2 = Mem_Alloc(tempmempool, size * size * 3);
828         buffer3 = Mem_Alloc(tempmempool, size * size * 3 + 18);
829
830         for (j = 0;j < 12;j++)
831         {
832                 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
833                 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);
834                 R_ClearScreen();
835                 R_Mesh_Start();
836                 R_RenderView();
837                 R_Mesh_Finish();
838                 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);
839         }
840
841         Mem_Free (buffer1);
842         Mem_Free (buffer2);
843         Mem_Free (buffer3);
844
845         envmap = false;
846 }
847
848 //=============================================================================
849
850 // LordHavoc: SHOWLMP stuff
851 #define SHOWLMP_MAXLABELS 256
852 typedef struct showlmp_s
853 {
854         qboolean        isactive;
855         float           x;
856         float           y;
857         char            label[32];
858         char            pic[128];
859 }
860 showlmp_t;
861
862 showlmp_t showlmp[SHOWLMP_MAXLABELS];
863
864 void SHOWLMP_decodehide(void)
865 {
866         int i;
867         qbyte *lmplabel;
868         lmplabel = MSG_ReadString();
869         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
870                 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
871                 {
872                         showlmp[i].isactive = false;
873                         return;
874                 }
875 }
876
877 void SHOWLMP_decodeshow(void)
878 {
879         int i, k;
880         qbyte lmplabel[256], picname[256];
881         float x, y;
882         strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
883         strlcpy (picname, MSG_ReadString(), sizeof (picname));
884         if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
885         {
886                 x = MSG_ReadByte();
887                 y = MSG_ReadByte();
888         }
889         else
890         {
891                 x = MSG_ReadShort();
892                 y = MSG_ReadShort();
893         }
894         k = -1;
895         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
896                 if (showlmp[i].isactive)
897                 {
898                         if (strcmp(showlmp[i].label, lmplabel) == 0)
899                         {
900                                 k = i;
901                                 break; // drop out to replace it
902                         }
903                 }
904                 else if (k < 0) // find first empty one to replace
905                         k = i;
906         if (k < 0)
907                 return; // none found to replace
908         // change existing one
909         showlmp[k].isactive = true;
910         strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
911         strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
912         showlmp[k].x = x;
913         showlmp[k].y = y;
914 }
915
916 void SHOWLMP_drawall(void)
917 {
918         int i;
919         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
920                 if (showlmp[i].isactive)
921                         DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
922 }
923
924 void SHOWLMP_clear(void)
925 {
926         int i;
927         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
928                 showlmp[i].isactive = false;
929 }
930
931 void CL_SetupScreenSize(void)
932 {
933         float conwidth, conheight;
934
935         VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
936
937         VID_UpdateGamma(false);
938
939         conwidth = bound(320, vid_conwidth.value, 2048);
940         conheight = bound(200, vid_conheight.value, 1536);
941         if (vid_conwidth.value != conwidth)
942                 Cvar_SetValue("vid_conwidth", conwidth);
943         if (vid_conheight.value != conheight)
944                 Cvar_SetValue("vid_conheight", conheight);
945
946         vid.conwidth = vid_conwidth.integer;
947         vid.conheight = vid_conheight.integer;
948
949 /*      if (vid.realheight > 240)
950         {
951                 vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
952                 vid.conheight = bound(240, vid.conheight, vid.realheight);
953         }
954         else
955                 vid.conheight = 240;*/
956
957         SCR_SetUpToDrawConsole();
958 }
959
960 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
961 void CL_UpdateScreen(void)
962 {
963         if (!scr_initialized || !con_initialized || vid_hidden)
964                 return;                         // not initialized yet
965
966         SCR_CaptureAVIDemo();
967
968         if (cls.signon == SIGNONS)
969                 R_TimeReport("other");
970
971         CL_SetupScreenSize();
972
973         DrawQ_Clear();
974
975         if (cls.signon == SIGNONS)
976                 R_TimeReport("setup");
977
978         //FIXME: force menu if nothing else to look at?
979         //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
980
981         if (scr_drawloading)
982         {
983                 scr_drawloading = false;
984                 SCR_DrawLoading();
985         }
986         else
987         {
988                 if (cls.signon == SIGNONS)
989                 {
990                         SCR_DrawNet ();
991                         SCR_DrawTurtle ();
992                         SCR_DrawPause ();
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 }