5 #include "cl_collision.h"
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_capturevideo = {0, "cl_capturevideo", "0"};
25 cvar_t cl_capturevideo_fps = {0, "cl_capturevideo_fps", "30"};
26 cvar_t cl_capturevideo_raw = {0, "cl_capturevideo_raw", "0"};
27 cvar_t r_textshadow = {0, "r_textshadow", "0"};
28 cvar_t r_letterbox = {0, "r_letterbox", "0"};
30 int jpeg_supported = false;
32 qboolean scr_initialized; // ready to draw
34 float scr_con_current;
35 float scr_conlines; // lines of console to display
37 extern int con_vislines;
39 qboolean scr_drawloading = false;
41 void DrawCrosshair(int num);
42 static void SCR_ScreenShot_f (void);
43 static void R_Envmap_f (void);
46 void R_ClearScreen(void);
49 ===============================================================================
53 ===============================================================================
56 char scr_centerstring[1024];
57 float scr_centertime_start; // for slow victory printing
58 float scr_centertime_off;
67 Called for important messages that should stay in the center of the screen
71 void SCR_CenterPrint(char *str)
73 strlcpy (scr_centerstring, str, sizeof (scr_centerstring));
74 scr_centertime_off = scr_centertime.value;
75 scr_centertime_start = cl.time;
77 // count the number of lines for centering
88 void SCR_DrawCenterString (void)
95 // the finale prints the characters one at a time
97 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
101 scr_erase_center = 0;
102 start = scr_centerstring;
104 if (scr_center_lines <= 4)
105 y = vid.conheight*0.35;
111 // scan the width of the line
112 for (l=0 ; l<40 ; l++)
113 if (start[l] == '\n' || !start[l])
115 x = (vid.conwidth - l*8)/2;
120 DrawQ_String(x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
128 while (*start && *start != '\n')
133 start++; // skip the \n
137 void SCR_CheckDrawCenterString (void)
139 if (scr_center_lines > scr_erase_lines)
140 scr_erase_lines = scr_center_lines;
142 scr_centertime_off -= host_frametime;
144 // don't draw if this is a normal stats-screen intermission,
145 // only if it is not an intermission, or a finale intermission
146 if (cl.intermission == 1)
148 if (scr_centertime_off <= 0 && !cl.intermission)
150 if (key_dest != key_game)
153 SCR_DrawCenterString ();
161 void SCR_DrawTurtle (void)
165 if (cls.state != ca_connected)
168 if (!scr_showturtle.integer)
171 if (host_frametime < 0.1)
181 DrawQ_Pic (0, 0, "gfx/turtle.lmp", 0, 0, 1, 1, 1, 1, 0);
189 void SCR_DrawNet (void)
191 if (cls.state != ca_connected)
193 if (realtime - cl.last_received_message < 0.3)
195 if (cls.demoplayback)
198 DrawQ_Pic (64, 0, "gfx/net.lmp", 0, 0, 1, 1, 1, 1, 0);
206 void SCR_DrawPause (void)
210 if (cls.state != ca_connected)
213 if (!scr_showpause.integer) // turn off for screenshots
219 pic = Draw_CachePic ("gfx/pause.lmp");
220 DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/pause.lmp", 0, 0, 1, 1, 1, 1, 0);
230 void SCR_DrawLoading (void)
234 pic = Draw_CachePic ("gfx/loading.lmp");
235 DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/loading.lmp", 0, 0, 1, 1, 1, 1, 0);
240 //=============================================================================
245 SCR_SetUpToDrawConsole
248 void SCR_SetUpToDrawConsole (void)
252 if (key_dest == key_game && cls.signon != SIGNONS && scr_conforcewhiledisconnected.integer)
253 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
255 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
257 // decide on the height of the console
258 if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
259 scr_conlines = vid.conheight; // full screen
260 else if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
261 scr_conlines = vid.conheight/2; // half screen
263 scr_conlines = 0; // none visible
265 if (scr_conspeed.value)
267 if (scr_conlines < scr_con_current)
269 scr_con_current -= scr_conspeed.value*host_realframetime;
270 if (scr_conlines > scr_con_current)
271 scr_con_current = scr_conlines;
274 else if (scr_conlines > scr_con_current)
276 scr_con_current += scr_conspeed.value*host_realframetime;
277 if (scr_conlines < scr_con_current)
278 scr_con_current = scr_conlines;
282 scr_con_current = scr_conlines;
290 void SCR_DrawConsole (void)
293 Con_DrawConsole (scr_con_current);
297 if (key_dest == key_game || key_dest == key_message)
298 Con_DrawNotify (); // only draw notify in game
304 SCR_BeginLoadingPlaque
308 void SCR_BeginLoadingPlaque (void)
315 scr_drawloading = true;
317 scr_drawloading = true;
321 //=============================================================================
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;
327 void R_TimeReport(char *desc)
333 if (!r_timereport_active)
336 r_timereport_temp = r_timereport_current;
337 r_timereport_current = Sys_DoubleTime();
338 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
340 sprintf(tempbuf, "%8i %s", t, desc);
341 length = strlen(tempbuf);
343 tempbuf[length++] = ' ';
345 if (speedstringcount + length > (vid.conwidth / 8))
347 strcat(r_speeds_string, "\n");
348 speedstringcount = 0;
350 // skip the space at the beginning if it's the first on the line
351 if (speedstringcount == 0)
353 strcat(r_speeds_string, tempbuf + 1);
354 speedstringcount = length - 1;
358 strcat(r_speeds_string, tempbuf);
359 speedstringcount += length;
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)
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)
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);
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);
403 r_timereport_start = Sys_DoubleTime();
407 void R_TimeReport_End(void)
409 r_timereport_current = r_timereport_start;
410 R_TimeReport("total");
412 if (r_timereport_active)
416 for (i = 0;r_speeds_string[i];i++)
417 if (r_speeds_string[i] == '\n')
419 y = vid.conheight - sb_lines - lines * 8;
421 DrawQ_Fill(0, y, vid.conwidth, lines * 8, 0, 0, 0, 0.5, 0);
422 while (r_speeds_string[i])
425 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
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')
443 void SCR_SizeUp_f (void)
445 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
456 void SCR_SizeDown_f (void)
458 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
461 void CL_Screen_Init(void)
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_capturevideo);
480 Cvar_RegisterVariable (&cl_capturevideo_fps);
481 Cvar_RegisterVariable (&cl_capturevideo_raw);
482 Cvar_RegisterVariable (&r_textshadow);
483 Cvar_RegisterVariable (&r_letterbox);
485 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
486 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
487 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
488 Cmd_AddCommand ("envmap", R_Envmap_f);
490 scr_initialized = true;
493 void DrawQ_Clear(void)
495 r_refdef.drawqueuesize = 0;
498 static int picelements[6] = {0, 1, 2, 0, 2, 3};
499 void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
501 DrawQ_SuperPic(x,y,picname,width,height,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags);
504 void DrawQ_String_Real(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
509 if (alpha < (1.0f / 255.0f))
512 len = strlen(string);
514 for (len = 0;len < maxlen && string[len];len++);
515 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
516 for (;len > 0 && string[len - 1] == ' ';len--);
519 if (x >= vid.conwidth || y >= vid.conheight || x < (-scalex * maxlen) || y < (-scaley))
521 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
522 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
524 red = bound(0, red, 1);
525 green = bound(0, green, 1);
526 blue = bound(0, blue, 1);
527 alpha = bound(0, alpha, 1);
528 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
530 dq->command = DRAWQUEUE_STRING;
532 dq->color = ((unsigned int) (red * 255.0f) << 24) | ((unsigned int) (green * 255.0f) << 16) | ((unsigned int) (blue * 255.0f) << 8) | ((unsigned int) (alpha * 255.0f));
537 out = (char *)(dq + 1);
538 memcpy(out, string, len);
540 r_refdef.drawqueuesize += dq->size;
543 void DrawQ_String(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
545 if (r_textshadow.integer)
546 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
548 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
551 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
553 DrawQ_SuperPic(x,y,NULL,w,h,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags);
556 void DrawQ_SuperPic(float x, float y, char *picname, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags)
560 drawqueuemesh_t mesh;
561 memset(&mesh, 0, sizeof(mesh));
562 if (picname && picname[0])
564 pic = Draw_CachePic(picname);
568 height = pic->height;
569 mesh.texture = pic->tex;
571 mesh.num_triangles = 2;
572 mesh.num_vertices = 4;
573 mesh.data_element3i = picelements;
574 mesh.data_vertex3f = floats;
575 mesh.data_texcoord2f = floats + 12;
576 mesh.data_color4f = floats + 20;
577 memset(floats, 0, sizeof(floats));
578 mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
579 mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
580 mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
581 mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
582 mesh.data_texcoord2f[0] = s1;mesh.data_texcoord2f[1] = t1;mesh.data_color4f[ 0] = r1;mesh.data_color4f[ 1] = g1;mesh.data_color4f[ 2] = b1;mesh.data_color4f[ 3] = a1;
583 mesh.data_texcoord2f[2] = s2;mesh.data_texcoord2f[3] = t2;mesh.data_color4f[ 4] = r2;mesh.data_color4f[ 5] = g2;mesh.data_color4f[ 6] = b2;mesh.data_color4f[ 7] = a2;
584 mesh.data_texcoord2f[4] = s4;mesh.data_texcoord2f[5] = t4;mesh.data_color4f[ 8] = r4;mesh.data_color4f[ 9] = g4;mesh.data_color4f[10] = b4;mesh.data_color4f[11] = a4;
585 mesh.data_texcoord2f[6] = s3;mesh.data_texcoord2f[7] = t3;mesh.data_color4f[12] = r3;mesh.data_color4f[13] = g3;mesh.data_color4f[14] = b3;mesh.data_color4f[15] = a3;
586 DrawQ_Mesh (&mesh, flags);
589 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
596 size += sizeof(drawqueuemesh_t);
597 size += sizeof(int[3]) * mesh->num_triangles;
598 size += sizeof(float[3]) * mesh->num_vertices;
599 size += sizeof(float[2]) * mesh->num_vertices;
600 size += sizeof(float[4]) * mesh->num_vertices;
601 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
603 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
605 dq->command = DRAWQUEUE_MESH;
612 p = (void *)(dq + 1);
613 m = p;p = (qbyte*)p + sizeof(drawqueuemesh_t);
614 m->num_triangles = mesh->num_triangles;
615 m->num_vertices = mesh->num_vertices;
616 m->texture = mesh->texture;
617 m->data_element3i = p;memcpy(m->data_element3i , mesh->data_element3i , m->num_triangles * sizeof(int[3]));p = (qbyte*)p + m->num_triangles * sizeof(int[3]);
618 m->data_vertex3f = p;memcpy(m->data_vertex3f , mesh->data_vertex3f , m->num_vertices * sizeof(float[3]));p = (qbyte*)p + m->num_vertices * sizeof(float[3]);
619 m->data_texcoord2f = p;memcpy(m->data_texcoord2f, mesh->data_texcoord2f, m->num_vertices * sizeof(float[2]));p = (qbyte*)p + m->num_vertices * sizeof(float[2]);
620 m->data_color4f = p;memcpy(m->data_color4f , mesh->data_color4f , m->num_vertices * sizeof(float[4]));p = (qbyte*)p + m->num_vertices * sizeof(float[4]);
621 r_refdef.drawqueuesize += dq->size;
624 void DrawQ_SetClipArea(float x, float y, float width, float height)
627 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
629 Con_DPrint("DrawQueue full !\n");
632 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
633 dq->size = sizeof(*dq);
634 dq->command = DRAWQUEUE_SETCLIP;
642 r_refdef.drawqueuesize += dq->size;
645 void DrawQ_ResetClipArea(void)
648 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
650 Con_DPrint("DrawQueue full !\n");
653 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
654 dq->size = sizeof(*dq);
655 dq->command = DRAWQUEUE_RESETCLIP;
663 r_refdef.drawqueuesize += dq->size;
671 void SCR_ScreenShot_f (void)
673 static int shotnumber;
674 static char oldname[MAX_QPATH];
675 char base[MAX_QPATH];
676 char filename[MAX_QPATH];
680 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
682 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
684 if (strcmp (oldname, scr_screenshot_name.string))
686 sprintf(oldname, "%s", scr_screenshot_name.string);
690 // find a file name to save it to
691 for (;shotnumber < 1000000;shotnumber++)
692 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
694 if (shotnumber >= 1000000)
696 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
700 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
702 buffer1 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3);
703 buffer2 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3);
704 buffer3 = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * 3 + 18);
706 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, vid.realx, vid.realy, vid.realwidth, vid.realheight, false, false, false, jpeg))
707 Con_Printf("Wrote %s\n", filename);
709 Con_Printf("unable to write %s\n", filename);
718 typedef enum capturevideoformat_e
720 CAPTUREVIDEOFORMAT_TARGA,
721 CAPTUREVIDEOFORMAT_JPEG,
722 CAPTUREVIDEOFORMAT_RAW
724 capturevideoformat_t;
726 qboolean cl_capturevideo_active = false;
727 capturevideoformat_t cl_capturevideo_format;
728 static double cl_capturevideo_starttime = 0;
729 double cl_capturevideo_framerate = 0;
730 static int cl_capturevideo_soundrate = 0;
731 static int cl_capturevideo_frame = 0;
732 static qbyte *cl_capturevideo_buffer = NULL;
733 static qfile_t *cl_capturevideo_videofile = NULL;
734 static qfile_t *cl_capturevideo_soundfile = NULL;
736 void SCR_CaptureVideo_BeginVideo(void)
739 if (cl_capturevideo_active)
741 // soundrate is figured out on the first SoundFrame
742 cl_capturevideo_active = true;
743 cl_capturevideo_starttime = Sys_DoubleTime();
744 cl_capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
745 cl_capturevideo_soundrate = 0;
746 cl_capturevideo_frame = 0;
747 cl_capturevideo_buffer = Mem_Alloc(tempmempool, vid.realwidth * vid.realheight * (3+3+3) + 18);
749 if (cl_capturevideo_raw.integer)
751 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAW;
752 cl_capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false);
754 else if (scr_screenshot_jpeg.integer)
756 cl_capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
757 cl_capturevideo_videofile = NULL;
761 cl_capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
762 cl_capturevideo_videofile = NULL;
765 cl_capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false);
767 // wave header will be filled out when video ends
769 FS_Write (cl_capturevideo_soundfile, out, 44);
772 void SCR_CaptureVideo_EndVideo(void)
776 if (!cl_capturevideo_active)
778 cl_capturevideo_active = false;
780 if (cl_capturevideo_videofile)
782 FS_Close(cl_capturevideo_videofile);
783 cl_capturevideo_videofile = NULL;
786 // finish the wave file
787 if (cl_capturevideo_soundfile)
789 i = FS_Tell (cl_capturevideo_soundfile);
790 //"RIFF", (int) unknown (chunk size), "WAVE",
791 //"fmt ", (int) 16 (chunk size), (short) format 1 (uncompressed PCM), (short) 2 channels, (int) unknown rate, (int) unknown bytes per second, (short) 4 bytes per sample (channels * bytes per channel), (short) 16 bits per channel
792 //"data", (int) unknown (chunk size)
793 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
794 // the length of the whole RIFF chunk
797 out[5] = (n >> 8) & 0xFF;
798 out[6] = (n >> 16) & 0xFF;
799 out[7] = (n >> 24) & 0xFF;
801 n = cl_capturevideo_soundrate;
802 out[24] = (n) & 0xFF;
803 out[25] = (n >> 8) & 0xFF;
804 out[26] = (n >> 16) & 0xFF;
805 out[27] = (n >> 24) & 0xFF;
806 // bytes per second (rate * channels * bytes per channel)
807 n = cl_capturevideo_soundrate * 2 * 2;
808 out[28] = (n) & 0xFF;
809 out[29] = (n >> 8) & 0xFF;
810 out[30] = (n >> 16) & 0xFF;
811 out[31] = (n >> 24) & 0xFF;
812 // the length of the data chunk
814 out[40] = (n) & 0xFF;
815 out[41] = (n >> 8) & 0xFF;
816 out[42] = (n >> 16) & 0xFF;
817 out[43] = (n >> 24) & 0xFF;
818 FS_Seek (cl_capturevideo_soundfile, 0, SEEK_SET);
819 FS_Write (cl_capturevideo_soundfile, out, 44);
820 FS_Close (cl_capturevideo_soundfile);
821 cl_capturevideo_soundfile = NULL;
824 if (cl_capturevideo_buffer)
826 Mem_Free (cl_capturevideo_buffer);
827 cl_capturevideo_buffer = NULL;
830 cl_capturevideo_starttime = 0;
831 cl_capturevideo_framerate = 0;
832 cl_capturevideo_frame = 0;
835 qboolean SCR_CaptureVideo_VideoFrame(void)
837 int x = vid.realx, y = vid.realy, width = vid.realwidth, height = vid.realheight;
839 //return SCR_ScreenShot(filename, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.realwidth * vid.realheight * 3, cl_capturevideo_buffer + vid.realwidth * vid.realheight * 6, vid.realx, vid.realy, vid.realwidth, vid.realheight, false, false, false, jpeg);
840 // speed is critical here, so do saving as directly as possible
841 if (!r_render.integer)
843 switch (cl_capturevideo_format)
845 case CAPTUREVIDEOFORMAT_RAW:
846 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
848 return FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer, width*height*3);
849 case CAPTUREVIDEOFORMAT_JPEG:
850 sprintf(filename, "video/dp%06d.jpg", cl_capturevideo_frame);
851 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
853 return JPEG_SaveImage_preflipped (filename, width, height, cl_capturevideo_buffer);
854 case CAPTUREVIDEOFORMAT_TARGA:
855 //return Image_WriteTGARGB_preflipped (filename, width, height, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.realwidth * vid.realheight * 3, );
856 memset (cl_capturevideo_buffer, 0, 18);
857 cl_capturevideo_buffer[2] = 2; // uncompressed type
858 cl_capturevideo_buffer[12] = (width >> 0) & 0xFF;
859 cl_capturevideo_buffer[13] = (width >> 8) & 0xFF;
860 cl_capturevideo_buffer[14] = (height >> 0) & 0xFF;
861 cl_capturevideo_buffer[15] = (height >> 8) & 0xFF;
862 cl_capturevideo_buffer[16] = 24; // pixel size
863 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cl_capturevideo_buffer + 18);
865 sprintf(filename, "video/dp%06d.tga", cl_capturevideo_frame);
866 return FS_WriteFile (filename, cl_capturevideo_buffer, width*height*3 + 18);
872 void SCR_CaptureVideo_SoundFrame(qbyte *bufstereo16le, size_t length, int rate)
874 cl_capturevideo_soundrate = rate;
875 if (FS_Write (cl_capturevideo_soundfile, bufstereo16le, 4 * length) < 4 * length)
877 Cvar_SetValueQuick(&cl_capturevideo, 0);
878 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
879 SCR_CaptureVideo_EndVideo();
883 void SCR_CaptureVideo(void)
886 if (cl_capturevideo.integer)
888 if (!cl_capturevideo_active)
889 SCR_CaptureVideo_BeginVideo();
890 if (cl_capturevideo_framerate != cl_capturevideo_fps.value)
892 Con_Printf("You can not change the video framerate while recording a video.\n");
893 Cvar_SetValueQuick(&cl_capturevideo_fps, cl_capturevideo_framerate);
895 newframenum = (Sys_DoubleTime() - cl_capturevideo_starttime) * cl_capturevideo_framerate;
896 while (cl_capturevideo_frame < newframenum)
898 if (SCR_CaptureVideo_VideoFrame())
899 cl_capturevideo_frame++;
902 Cvar_SetValueQuick(&cl_capturevideo, 0);
903 Con_Printf("video saving failed on frame %i, out of disk space? stopping avi demo capture.\n", cl_capturevideo_frame);
904 SCR_CaptureVideo_EndVideo();
909 else if (cl_capturevideo_active)
910 SCR_CaptureVideo_EndVideo();
917 Grab six views for environment mapping tests
924 qboolean flipx, flipy, flipdiagonaly;
928 {{ 0, 0, 0}, "rt", true, false, false},
929 {{ 0, 90, 0}, "ft", true, false, false},
930 {{ 0, 180, 0}, "lf", true, false, false},
931 {{ 0, 270, 0}, "bk", true, false, false},
932 {{-90, 180, 0}, "up", false, true, false},
933 {{ 90, 180, 0}, "dn", false, true, false},
935 {{ 0, 0, 0}, "px", true, true, true},
936 {{ 0, 90, 0}, "py", false, true, false},
937 {{ 0, 180, 0}, "nx", false, false, true},
938 {{ 0, 270, 0}, "ny", true, false, false},
939 {{-90, 180, 0}, "pz", false, false, true},
940 {{ 90, 180, 0}, "nz", false, false, true}
943 static void R_Envmap_f (void)
946 char filename[256], basename[256];
953 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");
957 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
958 size = atoi(Cmd_Argv(2));
959 if (size != 128 && size != 256 && size != 512 && size != 1024)
961 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
964 if (size > vid.realwidth || size > vid.realheight)
966 Con_Print("envmap: your resolution is not big enough to render that size\n");
974 r_refdef.width = size;
975 r_refdef.height = size;
980 buffer1 = Mem_Alloc(tempmempool, size * size * 3);
981 buffer2 = Mem_Alloc(tempmempool, size * size * 3);
982 buffer3 = Mem_Alloc(tempmempool, size * size * 3 + 18);
984 for (j = 0;j < 12;j++)
986 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
987 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);
992 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);
1002 //=============================================================================
1004 // LordHavoc: SHOWLMP stuff
1005 #define SHOWLMP_MAXLABELS 256
1006 typedef struct showlmp_s
1016 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1018 void SHOWLMP_decodehide(void)
1022 lmplabel = MSG_ReadString();
1023 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1024 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1026 showlmp[i].isactive = false;
1031 void SHOWLMP_decodeshow(void)
1034 qbyte lmplabel[256], picname[256];
1036 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1037 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1038 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1045 x = MSG_ReadShort();
1046 y = MSG_ReadShort();
1049 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1050 if (showlmp[i].isactive)
1052 if (strcmp(showlmp[i].label, lmplabel) == 0)
1055 break; // drop out to replace it
1058 else if (k < 0) // find first empty one to replace
1061 return; // none found to replace
1062 // change existing one
1063 showlmp[k].isactive = true;
1064 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1065 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1070 void SHOWLMP_drawall(void)
1073 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1074 if (showlmp[i].isactive)
1075 DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
1078 void SHOWLMP_clear(void)
1081 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1082 showlmp[i].isactive = false;
1085 void CL_SetupScreenSize(void)
1087 float conwidth, conheight;
1089 VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
1091 VID_UpdateGamma(false);
1093 conwidth = bound(320, vid_conwidth.value, 2048);
1094 conheight = bound(200, vid_conheight.value, 1536);
1095 if (vid_conwidth.value != conwidth)
1096 Cvar_SetValue("vid_conwidth", conwidth);
1097 if (vid_conheight.value != conheight)
1098 Cvar_SetValue("vid_conheight", conheight);
1100 vid.conwidth = vid_conwidth.integer;
1101 vid.conheight = vid_conheight.integer;
1103 /* if (vid.realheight > 240)
1105 vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
1106 vid.conheight = bound(240, vid.conheight, vid.realheight);
1109 vid.conheight = 240;*/
1111 SCR_SetUpToDrawConsole();
1114 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1115 void CL_UpdateScreen(void)
1117 if (!scr_initialized || !con_initialized || vid_hidden)
1118 return; // not initialized yet
1122 if (cls.signon == SIGNONS)
1123 R_TimeReport("other");
1125 CL_SetupScreenSize();
1129 if (cls.signon == SIGNONS)
1130 R_TimeReport("setup");
1132 //FIXME: force menu if nothing else to look at?
1133 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1135 if (scr_drawloading)
1137 scr_drawloading = false;
1142 if (cls.signon == SIGNONS)
1147 if (!r_letterbox.value)
1150 SCR_CheckDrawCenterString();
1156 if (cls.signon == SIGNONS)
1160 R_TimeReport_Start();
1162 R_Shadow_EditLights_DrawSelectedLightProperties();
1169 void CL_Screen_NewMap(void)