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_showbrand = {0, "showbrand","0"};
18 cvar_t scr_printspeed = {0, "scr_printspeed","8"};
19 cvar_t vid_conwidth = {CVAR_SAVE, "vid_conwidth", "640"};
20 cvar_t vid_conheight = {CVAR_SAVE, "vid_conheight", "480"};
21 cvar_t vid_pixelheight = {CVAR_SAVE, "vid_pixelheight", "1"};
22 cvar_t scr_screenshot_jpeg = {CVAR_SAVE, "scr_screenshot_jpeg","1"};
23 cvar_t scr_screenshot_jpeg_quality = {CVAR_SAVE, "scr_screenshot_jpeg_quality","0.9"};
24 cvar_t scr_screenshot_gamma = {CVAR_SAVE, "scr_screenshot_gamma","2.2"};
25 // scr_screenshot_name is defined in fs.c
26 cvar_t cl_capturevideo = {0, "cl_capturevideo", "0"};
27 cvar_t cl_capturevideo_sound = {0, "cl_capturevideo_sound", "0"};
28 cvar_t cl_capturevideo_fps = {0, "cl_capturevideo_fps", "30"};
29 cvar_t cl_capturevideo_rawrgb = {0, "cl_capturevideo_rawrgb", "0"};
30 cvar_t cl_capturevideo_rawyv12 = {0, "cl_capturevideo_rawyv12", "0"};
31 cvar_t r_textshadow = {0, "r_textshadow", "0"};
32 cvar_t r_letterbox = {0, "r_letterbox", "0"};
34 int jpeg_supported = false;
36 qboolean scr_initialized; // ready to draw
38 float scr_con_current;
40 extern int con_vislines;
42 void DrawCrosshair(int num);
43 static void SCR_ScreenShot_f (void);
44 static void R_Envmap_f (void);
47 void R_ClearScreen(void);
50 static vec4_t string_colors[] =
53 // LordHavoc: why on earth is cyan before magenta in Quake3?
54 // LordHavoc: note: Doom3 uses white for [0] and [7]
55 {0.0, 0.0, 0.0, 1.0}, // black
56 {1.0, 0.0, 0.0, 1.0}, // red
57 {0.0, 1.0, 0.0, 1.0}, // green
58 {1.0, 1.0, 0.0, 1.0}, // yellow
59 {0.0, 0.0, 1.0, 1.0}, // blue
60 {0.0, 1.0, 1.0, 1.0}, // cyan
61 {1.0, 0.0, 1.0, 1.0}, // magenta
62 {1.0, 1.0, 1.0, 1.0}, // white
63 // [515]'s BX_COLOREDTEXT extension
64 {1.0, 1.0, 1.0, 0.5}, // half transparent
65 {0.5, 0.5, 0.5, 1.0} // half brightness
66 // Black's color table
67 //{1.0, 1.0, 1.0, 1.0},
68 //{1.0, 0.0, 0.0, 1.0},
69 //{0.0, 1.0, 0.0, 1.0},
70 //{0.0, 0.0, 1.0, 1.0},
71 //{1.0, 1.0, 0.0, 1.0},
72 //{0.0, 1.0, 1.0, 1.0},
73 //{1.0, 0.0, 1.0, 1.0},
74 //{0.1, 0.1, 0.1, 1.0}
77 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
79 // color is read and changed in the end
80 void DrawQ_ColoredString( float x, float y, const char *text, int maxlen, float scalex, float scaley, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor )
85 const char *start, *current;
87 if( !outcolor || *outcolor == -1 ) {
88 colorindex = STRING_COLOR_DEFAULT;
90 colorindex = *outcolor;
92 color = string_colors[colorindex];
95 len = (int)strlen( text );
97 len = min( maxlen, (int) strlen( text ) );
99 start = current = text;
101 // check for color control char
102 if( *current == STRING_COLOR_TAG ) {
109 // display the tag char?
110 if( *current == STRING_COLOR_TAG ) {
111 // only display one of the two
116 } else if( '0' <= *current && *current <= '9' ) {
119 colorindex = colorindex * 10 + (*current - '0');
120 // only read as long as it makes a valid index
121 if( colorindex >= (int)STRING_COLORS_COUNT ) {
122 // undo the last operation
128 } while( len > 0 && '0' <= *current && *current <= '9' );
130 color = string_colors[colorindex];
131 // we jump over the color tag
135 // go on and read normal text in until the next control char
136 while( len > 0 && *current != STRING_COLOR_TAG ) {
141 if( start != current ) {
143 DrawQ_String( x, y, start, current - start, scalex, scaley, basered * color[0], basegreen * color[1], baseblue * color[2], basealpha * color[3], flags );
144 // update x to be at the new start position
145 x += (current - start) * scalex;
146 // set start accordingly
151 // return the last colorindex
153 *outcolor = colorindex;
158 ===============================================================================
162 ===============================================================================
165 char scr_centerstring[MAX_INPUTLINE];
166 float scr_centertime_start; // for slow victory printing
167 float scr_centertime_off;
168 int scr_center_lines;
170 int scr_erase_center;
176 Called for important messages that should stay in the center of the screen
180 void SCR_CenterPrint(char *str)
182 strlcpy (scr_centerstring, str, sizeof (scr_centerstring));
183 scr_centertime_off = scr_centertime.value;
184 scr_centertime_start = cl.time;
186 // count the number of lines for centering
187 scr_center_lines = 1;
197 void SCR_DrawCenterString (void)
205 // the finale prints the characters one at a time
207 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
211 scr_erase_center = 0;
212 start = scr_centerstring;
217 if (scr_center_lines <= 4)
218 y = vid_conheight.integer*0.35;
225 // scan the width of the line
226 for (l=0 ; l<vid_conwidth.integer/8 ; l++)
227 if (start[l] == '\n' || !start[l])
229 x = (vid_conwidth.integer - l*8)/2;
234 DrawQ_ColoredString(x, y, start, l, 8, 8, 1, 1, 1, 1, 0, &color);
242 while (*start && *start != '\n')
247 start++; // skip the \n
251 void SCR_CheckDrawCenterString (void)
253 if (scr_center_lines > scr_erase_lines)
254 scr_erase_lines = scr_center_lines;
256 scr_centertime_off -= host_frametime;
258 // don't draw if this is a normal stats-screen intermission,
259 // only if it is not an intermission, or a finale intermission
260 if (cl.intermission == 1)
262 if (scr_centertime_off <= 0 && !cl.intermission)
264 if (key_dest != key_game)
267 SCR_DrawCenterString ();
275 void SCR_DrawTurtle (void)
279 if (cls.state != ca_connected)
282 if (!scr_showturtle.integer)
285 if (host_frametime < 0.1)
295 DrawQ_Pic (0, 0, "gfx/turtle", 0, 0, 1, 1, 1, 1, 0);
303 void SCR_DrawNet (void)
305 if (cls.state != ca_connected)
307 if (realtime - cl.last_received_message < 0.3)
309 if (cls.demoplayback)
312 DrawQ_Pic (64, 0, "gfx/net", 0, 0, 1, 1, 1, 1, 0);
320 void SCR_DrawPause (void)
324 if (cls.state != ca_connected)
327 if (!scr_showpause.integer) // turn off for screenshots
333 pic = Draw_CachePic ("gfx/pause", true);
334 DrawQ_Pic ((vid_conwidth.integer - pic->width)/2, (vid_conheight.integer - pic->height)/2, "gfx/pause", 0, 0, 1, 1, 1, 1, 0);
342 void SCR_DrawBrand (void)
347 if (!scr_showbrand.value)
350 pic = Draw_CachePic ("gfx/brand", true);
352 switch ((int)scr_showbrand.value)
354 case 1: // bottom left
356 y = vid_conheight.integer - pic->height;
358 case 2: // bottom centre
359 x = (vid_conwidth.integer - pic->width) / 2;
360 y = vid_conheight.integer - pic->height;
362 case 3: // bottom right
363 x = vid_conwidth.integer - pic->width;
364 y = vid_conheight.integer - pic->height;
366 case 4: // centre right
367 x = vid_conwidth.integer - pic->width;
368 y = (vid_conheight.integer - pic->height) / 2;
371 x = vid_conwidth.integer - pic->width;
374 case 6: // top centre
375 x = (vid_conwidth.integer - pic->width) / 2;
382 case 8: // centre left
384 y = (vid_conheight.integer - pic->height) / 2;
390 DrawQ_Pic (x, y, "gfx/brand", 0, 0, 1, 1, 1, 1, 0);
393 //=============================================================================
398 SCR_SetUpToDrawConsole
401 void SCR_SetUpToDrawConsole (void)
403 // lines of console to display
408 if (key_dest == key_game && cls.signon != SIGNONS && scr_conforcewhiledisconnected.integer)
409 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
411 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
413 // decide on the height of the console
414 if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
415 conlines = vid_conheight.integer/2; // half screen
417 conlines = 0; // none visible
419 if (scr_conspeed.value)
421 if (scr_con_current > conlines)
423 scr_con_current -= scr_conspeed.value*host_realframetime;
424 if (scr_con_current < conlines)
425 scr_con_current = conlines;
428 else if (scr_con_current < conlines)
430 scr_con_current += scr_conspeed.value*host_realframetime;
431 if (scr_con_current > conlines)
432 scr_con_current = conlines;
436 scr_con_current = conlines;
444 void SCR_DrawConsole (void)
446 if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
449 Con_DrawConsole (vid_conheight.integer);
451 else if (scr_con_current)
452 Con_DrawConsole (scr_con_current);
456 if (key_dest == key_game || key_dest == key_message)
457 Con_DrawNotify (); // only draw notify in game
463 SCR_BeginLoadingPlaque
467 void SCR_BeginLoadingPlaque (void)
471 SCR_UpdateLoadingScreen();
474 //=============================================================================
476 char r_speeds_string[1024];
477 int speedstringcount, r_timereport_active;
478 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
480 void R_TimeReport(char *desc)
486 if (!r_timereport_active || r_showtrispass)
490 r_timereport_temp = r_timereport_current;
491 r_timereport_current = Sys_DoubleTime();
492 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
494 dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %s", t, desc);
495 length = (int)strlen(tempbuf);
497 tempbuf[length++] = ' ';
499 if (speedstringcount + length > (vid_conwidth.integer / 8))
501 strlcat(r_speeds_string, "\n", sizeof(r_speeds_string));
502 speedstringcount = 0;
504 // skip the space at the beginning if it's the first on the line
505 if (speedstringcount == 0)
507 strlcat(r_speeds_string, tempbuf + 1, sizeof(r_speeds_string));
508 speedstringcount = length - 1;
512 strlcat(r_speeds_string, tempbuf, sizeof(r_speeds_string));
513 speedstringcount += length;
517 void R_TimeReport_Start(void)
519 r_timereport_active = r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected;
520 r_speeds_string[0] = 0;
521 if (r_timereport_active)
523 speedstringcount = 0;
524 sprintf(r_speeds_string + strlen(r_speeds_string), "org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n", r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], r_viewforward[0], r_viewforward[1], r_viewforward[2]);
525 sprintf(r_speeds_string + strlen(r_speeds_string), "%5i entities%6i surfaces%6i triangles%5i leafs%5i portals%6i particles\n", renderstats.entities, renderstats.entities_surfaces, renderstats.entities_triangles, renderstats.world_leafs, renderstats.world_portals, renderstats.particles);
526 sprintf(r_speeds_string + strlen(r_speeds_string), "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n", renderstats.lights, renderstats.lights_clears, renderstats.lights_scissored, renderstats.lights_lighttriangles, renderstats.lights_shadowtriangles, renderstats.lights_dynamicshadowtriangles);
527 if (renderstats.bloom)
528 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles bloompixels%8i copied%8i drawn\n", renderstats.meshes, renderstats.meshes_elements / 3, renderstats.bloom_copypixels, renderstats.bloom_drawpixels);
530 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", renderstats.meshes, renderstats.meshes_elements / 3);
532 r_timereport_start = Sys_DoubleTime();
535 memset(&renderstats, 0, sizeof(renderstats));
538 void R_TimeReport_End(void)
540 r_timereport_current = r_timereport_start;
541 R_TimeReport("total");
543 if (r_timereport_active)
547 for (i = 0;r_speeds_string[i];i++)
548 if (r_speeds_string[i] == '\n')
550 y = vid_conheight.integer - sb_lines - lines * 8;
552 DrawQ_Fill(0, y, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
553 while (r_speeds_string[i])
556 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
559 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
560 if (r_speeds_string[i] == '\n')
574 void SCR_SizeUp_f (void)
576 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
587 void SCR_SizeDown_f (void)
589 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
592 void CL_Screen_Init(void)
594 Cvar_RegisterVariable (&scr_fov);
595 Cvar_RegisterVariable (&scr_viewsize);
596 Cvar_RegisterVariable (&scr_conspeed);
597 Cvar_RegisterVariable (&scr_conalpha);
598 Cvar_RegisterVariable (&scr_conbrightness);
599 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
600 Cvar_RegisterVariable (&scr_showram);
601 Cvar_RegisterVariable (&scr_showturtle);
602 Cvar_RegisterVariable (&scr_showpause);
603 Cvar_RegisterVariable (&scr_showbrand);
604 Cvar_RegisterVariable (&scr_centertime);
605 Cvar_RegisterVariable (&scr_printspeed);
606 Cvar_RegisterVariable (&vid_conwidth);
607 Cvar_RegisterVariable (&vid_conheight);
608 Cvar_RegisterVariable (&vid_pixelheight);
609 Cvar_RegisterVariable (&scr_screenshot_jpeg);
610 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
611 Cvar_RegisterVariable (&scr_screenshot_gamma);
612 Cvar_RegisterVariable (&cl_capturevideo);
613 Cvar_RegisterVariable (&cl_capturevideo_sound);
614 Cvar_RegisterVariable (&cl_capturevideo_fps);
615 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
616 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
617 Cvar_RegisterVariable (&r_textshadow);
618 Cvar_RegisterVariable (&r_letterbox);
620 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
621 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
622 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
623 Cmd_AddCommand ("envmap", R_Envmap_f);
625 scr_initialized = true;
628 void DrawQ_Clear(void)
630 r_refdef.drawqueuesize = 0;
633 static int picelements[6] = {0, 1, 2, 0, 2, 3};
634 void DrawQ_Pic(float x, float y, const char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
636 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);
639 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)
644 if (alpha < (1.0f / 255.0f))
647 len = (int)strlen(string);
649 for (len = 0;len < maxlen && string[len];len++);
650 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
651 for (;len > 0 && string[len - 1] == ' ';len--);
654 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || x < (-scalex * len) || y < (-scaley))
656 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
657 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
659 red = bound(0, red, 1);
660 green = bound(0, green, 1);
661 blue = bound(0, blue, 1);
662 alpha = bound(0, alpha, 1);
663 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
665 dq->command = DRAWQUEUE_STRING;
667 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));
672 out = (char *)(dq + 1);
673 memcpy(out, string, len);
675 r_refdef.drawqueuesize += dq->size;
678 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)
680 if (r_textshadow.integer)
681 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
683 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
688 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
690 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);
693 void DrawQ_SuperPic(float x, float y, const 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)
697 drawqueuemesh_t mesh;
698 memset(&mesh, 0, sizeof(mesh));
699 if (picname && picname[0])
701 pic = Draw_CachePic(picname, false);
705 height = pic->height;
706 mesh.texture = pic->tex;
708 mesh.num_triangles = 2;
709 mesh.num_vertices = 4;
710 mesh.data_element3i = picelements;
711 mesh.data_vertex3f = floats;
712 mesh.data_texcoord2f = floats + 12;
713 mesh.data_color4f = floats + 20;
714 memset(floats, 0, sizeof(floats));
715 mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
716 mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
717 mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
718 mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
719 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;
720 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;
721 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;
722 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;
723 DrawQ_Mesh (&mesh, flags);
726 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
733 size += sizeof(drawqueuemesh_t);
734 size += sizeof(int[3]) * mesh->num_triangles;
735 size += sizeof(float[3]) * mesh->num_vertices;
736 size += sizeof(float[2]) * mesh->num_vertices;
737 size += sizeof(float[4]) * mesh->num_vertices;
738 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
740 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
742 dq->command = DRAWQUEUE_MESH;
749 p = (void *)(dq + 1);
750 m = (drawqueuemesh_t *)p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
751 m->num_triangles = mesh->num_triangles;
752 m->num_vertices = mesh->num_vertices;
753 m->texture = mesh->texture;
754 m->data_element3i = (int *)p;memcpy(m->data_element3i , mesh->data_element3i , m->num_triangles * sizeof(int[3]));p = (unsigned char*)p + m->num_triangles * sizeof(int[3]);
755 m->data_vertex3f = (float *)p;memcpy(m->data_vertex3f , mesh->data_vertex3f , m->num_vertices * sizeof(float[3]));p = (unsigned char*)p + m->num_vertices * sizeof(float[3]);
756 m->data_texcoord2f = (float *)p;memcpy(m->data_texcoord2f, mesh->data_texcoord2f, m->num_vertices * sizeof(float[2]));p = (unsigned char*)p + m->num_vertices * sizeof(float[2]);
757 m->data_color4f = (float *)p;memcpy(m->data_color4f , mesh->data_color4f , m->num_vertices * sizeof(float[4]));p = (unsigned char*)p + m->num_vertices * sizeof(float[4]);
758 r_refdef.drawqueuesize += dq->size;
761 void DrawQ_Lines (drawqueuemesh_t *mesh, int flags)
768 size += sizeof(drawqueuemesh_t);
769 size += sizeof(int[3]) * mesh->num_triangles;
770 size += sizeof(float[3]) * mesh->num_vertices;
771 size += sizeof(float[2]) * mesh->num_vertices;
772 size += sizeof(float[4]) * mesh->num_vertices;
773 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
775 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
777 dq->command = DRAWQUEUE_LINES;
784 p = (void *)(dq + 1);
785 m = p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
786 m->num_triangles = mesh->num_triangles;
787 m->num_vertices = mesh->num_vertices;
788 m->texture = mesh->texture;
789 m->data_element3i = p;memcpy(m->data_element3i , mesh->data_element3i , m->num_triangles * sizeof(int[3]));p = (unsigned char*)p + m->num_triangles * sizeof(int[3]);
790 m->data_vertex3f = p;memcpy(m->data_vertex3f , mesh->data_vertex3f , m->num_vertices * sizeof(float[3]));p = (unsigned char*)p + m->num_vertices * sizeof(float[3]);
791 m->data_texcoord2f = p;memcpy(m->data_texcoord2f, mesh->data_texcoord2f, m->num_vertices * sizeof(float[2]));p = (unsigned char*)p + m->num_vertices * sizeof(float[2]);
792 m->data_color4f = p;memcpy(m->data_color4f , mesh->data_color4f , m->num_vertices * sizeof(float[4]));p = (unsigned char*)p + m->num_vertices * sizeof(float[4]);
793 r_refdef.drawqueuesize += dq->size;
796 //LordHavoc: FIXME: this is nasty!
797 void DrawQ_LineWidth (float width)
800 static int linewidth = 1;
801 if(width == linewidth)
804 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
806 Con_DPrint("DrawQueue full !\n");
809 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
810 dq->size = sizeof(*dq);
811 dq->command = DRAWQUEUE_LINEWIDTH;
814 r_refdef.drawqueuesize += dq->size;
817 //[515]: this is old, delete
818 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
822 DrawQ_LineWidth(width);
823 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
825 Con_DPrint("DrawQueue full !\n");
828 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
829 dq->size = sizeof(*dq);
830 dq->command = DRAWQUEUE_LINES;
836 dq->color = ((unsigned int) (r * 255.0f) << 24) | ((unsigned int) (g * 255.0f) << 16) | ((unsigned int) (b * 255.0f) << 8) | ((unsigned int) (alpha * 255.0f));
838 r_refdef.drawqueuesize += dq->size;
841 void DrawQ_SetClipArea(float x, float y, float width, float height)
844 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
846 Con_DPrint("DrawQueue full !\n");
849 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
850 dq->size = sizeof(*dq);
851 dq->command = DRAWQUEUE_SETCLIP;
859 r_refdef.drawqueuesize += dq->size;
862 void DrawQ_ResetClipArea(void)
865 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
867 Con_DPrint("DrawQueue full !\n");
870 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
871 dq->size = sizeof(*dq);
872 dq->command = DRAWQUEUE_RESETCLIP;
880 r_refdef.drawqueuesize += dq->size;
888 void SCR_ScreenShot_f (void)
890 static int shotnumber;
891 static char oldname[MAX_QPATH];
892 char base[MAX_QPATH];
893 char filename[MAX_QPATH];
894 unsigned char *buffer1;
895 unsigned char *buffer2;
896 unsigned char *buffer3;
897 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
899 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
901 if (strcmp (oldname, scr_screenshot_name.string))
903 sprintf(oldname, "%s", scr_screenshot_name.string);
907 // find a file name to save it to
908 for (;shotnumber < 1000000;shotnumber++)
909 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
911 if (shotnumber >= 1000000)
913 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
917 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
919 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
920 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
921 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
923 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
924 Con_Printf("Wrote %s\n", filename);
926 Con_Printf("unable to write %s\n", filename);
935 typedef enum capturevideoformat_e
937 CAPTUREVIDEOFORMAT_TARGA,
938 CAPTUREVIDEOFORMAT_JPEG,
939 CAPTUREVIDEOFORMAT_RAWRGB,
940 CAPTUREVIDEOFORMAT_RAWYV12
942 capturevideoformat_t;
944 qboolean cl_capturevideo_active = false;
945 capturevideoformat_t cl_capturevideo_format;
946 static double cl_capturevideo_starttime = 0;
947 double cl_capturevideo_framerate = 0;
948 static int cl_capturevideo_soundrate = 0;
949 static int cl_capturevideo_frame = 0;
950 static unsigned char *cl_capturevideo_buffer = NULL;
951 static qfile_t *cl_capturevideo_videofile = NULL;
952 qfile_t *cl_capturevideo_soundfile = NULL;
953 static short cl_capturevideo_rgbtoyuvscaletable[3][3][256];
954 static unsigned char cl_capturevideo_yuvnormalizetable[3][256];
955 //static unsigned char cl_capturevideo_rgbgammatable[3][256];
957 void SCR_CaptureVideo_BeginVideo(void)
961 unsigned char out[44];
962 if (cl_capturevideo_active)
964 // soundrate is figured out on the first SoundFrame
965 cl_capturevideo_active = true;
966 cl_capturevideo_starttime = Sys_DoubleTime();
967 cl_capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
968 cl_capturevideo_soundrate = 0;
969 cl_capturevideo_frame = 0;
970 cl_capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
971 gamma = 1.0/scr_screenshot_gamma.value;
974 for (i = 0;i < 256;i++)
976 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
977 cl_capturevideo_rgbgammatable[0][i] = j;
978 cl_capturevideo_rgbgammatable[1][i] = j;
979 cl_capturevideo_rgbgammatable[2][i] = j;
983 R = Y + 1.4075 * (Cr - 128);
984 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
985 B = Y + 1.7790 * (Cb - 128);
986 Y = R * .299 + G * .587 + B * .114;
987 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
988 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
990 for (i = 0;i < 256;i++)
992 g = 255*pow(i/255.0, gamma);
993 // Y weights from RGB
994 cl_capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
995 cl_capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
996 cl_capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
997 // Cb weights from RGB
998 cl_capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
999 cl_capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
1000 cl_capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
1001 // Cr weights from RGB
1002 cl_capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
1003 cl_capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
1004 cl_capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
1005 // range reduction of YCbCr to valid signal range
1006 cl_capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
1007 cl_capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
1008 cl_capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
1011 if (cl_capturevideo_rawrgb.integer)
1013 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
1014 cl_capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
1016 else if (cl_capturevideo_rawyv12.integer)
1018 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
1019 cl_capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
1021 else if (scr_screenshot_jpeg.integer)
1023 cl_capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
1024 cl_capturevideo_videofile = NULL;
1028 cl_capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
1029 cl_capturevideo_videofile = NULL;
1032 if (cl_capturevideo_sound.integer)
1034 cl_capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
1035 // wave header will be filled out when video ends
1037 FS_Write (cl_capturevideo_soundfile, out, 44);
1040 cl_capturevideo_soundfile = NULL;
1043 void SCR_CaptureVideo_EndVideo(void)
1046 unsigned char out[44];
1047 if (!cl_capturevideo_active)
1049 cl_capturevideo_active = false;
1051 if (cl_capturevideo_videofile)
1053 FS_Close(cl_capturevideo_videofile);
1054 cl_capturevideo_videofile = NULL;
1057 // finish the wave file
1058 if (cl_capturevideo_soundfile)
1060 i = (int)FS_Tell (cl_capturevideo_soundfile);
1061 //"RIFF", (int) unknown (chunk size), "WAVE",
1062 //"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
1063 //"data", (int) unknown (chunk size)
1064 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
1065 // the length of the whole RIFF chunk
1067 out[4] = (n) & 0xFF;
1068 out[5] = (n >> 8) & 0xFF;
1069 out[6] = (n >> 16) & 0xFF;
1070 out[7] = (n >> 24) & 0xFF;
1072 n = cl_capturevideo_soundrate;
1073 out[24] = (n) & 0xFF;
1074 out[25] = (n >> 8) & 0xFF;
1075 out[26] = (n >> 16) & 0xFF;
1076 out[27] = (n >> 24) & 0xFF;
1077 // bytes per second (rate * channels * bytes per channel)
1078 n = cl_capturevideo_soundrate * 2 * 2;
1079 out[28] = (n) & 0xFF;
1080 out[29] = (n >> 8) & 0xFF;
1081 out[30] = (n >> 16) & 0xFF;
1082 out[31] = (n >> 24) & 0xFF;
1083 // the length of the data chunk
1085 out[40] = (n) & 0xFF;
1086 out[41] = (n >> 8) & 0xFF;
1087 out[42] = (n >> 16) & 0xFF;
1088 out[43] = (n >> 24) & 0xFF;
1089 FS_Seek (cl_capturevideo_soundfile, 0, SEEK_SET);
1090 FS_Write (cl_capturevideo_soundfile, out, 44);
1091 FS_Close (cl_capturevideo_soundfile);
1092 cl_capturevideo_soundfile = NULL;
1095 if (cl_capturevideo_buffer)
1097 Mem_Free (cl_capturevideo_buffer);
1098 cl_capturevideo_buffer = NULL;
1101 cl_capturevideo_starttime = 0;
1102 cl_capturevideo_framerate = 0;
1103 cl_capturevideo_frame = 0;
1106 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
1108 int x = 0, y = 0, width = vid.width, height = vid.height;
1109 unsigned char *b, *out;
1111 int outoffset = (width/2)*(height/2);
1112 //return SCR_ScreenShot(filename, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.width * vid.height * 3, cl_capturevideo_buffer + vid.width * vid.height * 6, 0, 0, vid.width, vid.height, false, false, false, jpeg, true);
1113 // speed is critical here, so do saving as directly as possible
1114 switch (cl_capturevideo_format)
1116 case CAPTUREVIDEOFORMAT_RAWYV12:
1117 // FIXME: width/height must be multiple of 2, enforce this?
1118 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1120 // process one line at a time, and CbCr every other line at 2 pixel intervals
1121 for (y = 0;y < height;y++)
1124 for (b = cl_capturevideo_buffer + (height-1-y)*width*3, out = cl_capturevideo_buffer + width*height*3 + y*width, x = 0;x < width;x++, b += 3, out++)
1125 *out = cl_capturevideo_yuvnormalizetable[0][cl_capturevideo_rgbtoyuvscaletable[0][0][b[0]] + cl_capturevideo_rgbtoyuvscaletable[0][1][b[1]] + cl_capturevideo_rgbtoyuvscaletable[0][2][b[2]]];
1128 // 2x2 Cb and Cr planes
1130 // low quality, no averaging
1131 for (b = cl_capturevideo_buffer + (height-2-y)*width*3, out = cl_capturevideo_buffer + width*height*3 + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
1134 out[0 ] = cl_capturevideo_yuvnormalizetable[2][cl_capturevideo_rgbtoyuvscaletable[2][0][b[0]] + cl_capturevideo_rgbtoyuvscaletable[2][1][b[1]] + cl_capturevideo_rgbtoyuvscaletable[2][2][b[2]] + 128];
1136 out[outoffset] = cl_capturevideo_yuvnormalizetable[1][cl_capturevideo_rgbtoyuvscaletable[1][0][b[0]] + cl_capturevideo_rgbtoyuvscaletable[1][1][b[1]] + cl_capturevideo_rgbtoyuvscaletable[1][2][b[2]] + 128];
1139 // high quality, averaging
1140 int inpitch = width*3;
1141 for (b = cl_capturevideo_buffer + (height-2-y)*width*3, out = cl_capturevideo_buffer + width*height*3 + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
1143 int blockr, blockg, blockb;
1144 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
1145 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
1146 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
1148 out[0 ] = cl_capturevideo_yuvnormalizetable[2][cl_capturevideo_rgbtoyuvscaletable[2][0][blockr] + cl_capturevideo_rgbtoyuvscaletable[2][1][blockg] + cl_capturevideo_rgbtoyuvscaletable[2][2][blockb] + 128];
1150 out[outoffset] = cl_capturevideo_yuvnormalizetable[1][cl_capturevideo_rgbtoyuvscaletable[1][0][blockr] + cl_capturevideo_rgbtoyuvscaletable[1][1][blockg] + cl_capturevideo_rgbtoyuvscaletable[1][2][blockb] + 128];
1155 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1156 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
1159 case CAPTUREVIDEOFORMAT_RAWRGB:
1160 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1162 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1163 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer, width*height*3))
1166 case CAPTUREVIDEOFORMAT_JPEG:
1167 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1169 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1171 sprintf(filename, "video/dp%06d.jpg", cl_capturevideo_frame);
1172 if (!JPEG_SaveImage_preflipped (filename, width, height, cl_capturevideo_buffer))
1176 case CAPTUREVIDEOFORMAT_TARGA:
1177 //return Image_WriteTGARGB_preflipped (filename, width, height, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.width * vid.height * 3, );
1178 memset (cl_capturevideo_buffer, 0, 18);
1179 cl_capturevideo_buffer[2] = 2; // uncompressed type
1180 cl_capturevideo_buffer[12] = (width >> 0) & 0xFF;
1181 cl_capturevideo_buffer[13] = (width >> 8) & 0xFF;
1182 cl_capturevideo_buffer[14] = (height >> 0) & 0xFF;
1183 cl_capturevideo_buffer[15] = (height >> 8) & 0xFF;
1184 cl_capturevideo_buffer[16] = 24; // pixel size
1185 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cl_capturevideo_buffer + 18);
1187 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1189 sprintf(filename, "video/dp%06d.tga", cl_capturevideo_frame);
1190 if (!FS_WriteFile (filename, cl_capturevideo_buffer, width*height*3 + 18))
1199 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
1201 if (!cl_capturevideo_soundfile)
1203 cl_capturevideo_soundrate = rate;
1204 if (FS_Write (cl_capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
1206 Cvar_SetValueQuick(&cl_capturevideo, 0);
1207 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1208 SCR_CaptureVideo_EndVideo();
1212 void SCR_CaptureVideo(void)
1215 if (cl_capturevideo.integer && r_render.integer)
1217 if (!cl_capturevideo_active)
1218 SCR_CaptureVideo_BeginVideo();
1219 if (cl_capturevideo_framerate != cl_capturevideo_fps.value)
1221 Con_Printf("You can not change the video framerate while recording a video.\n");
1222 Cvar_SetValueQuick(&cl_capturevideo_fps, cl_capturevideo_framerate);
1224 if (cl_capturevideo_soundfile)
1226 // preserve sound sync by duplicating frames when running slow
1227 newframenum = (Sys_DoubleTime() - cl_capturevideo_starttime) * cl_capturevideo_framerate;
1230 newframenum = cl_capturevideo_frame + 1;
1231 // if falling behind more than one second, stop
1232 if (newframenum - cl_capturevideo_frame > (int)ceil(cl_capturevideo_framerate))
1234 Cvar_SetValueQuick(&cl_capturevideo, 0);
1235 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cl_capturevideo_frame);
1236 SCR_CaptureVideo_EndVideo();
1240 if (!SCR_CaptureVideo_VideoFrame(newframenum))
1242 Cvar_SetValueQuick(&cl_capturevideo, 0);
1243 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1244 SCR_CaptureVideo_EndVideo();
1247 else if (cl_capturevideo_active)
1248 SCR_CaptureVideo_EndVideo();
1255 Grab six views for environment mapping tests
1262 qboolean flipx, flipy, flipdiagonaly;
1266 {{ 0, 0, 0}, "rt", false, false, false},
1267 {{ 0, 270, 0}, "ft", false, false, false},
1268 {{ 0, 180, 0}, "lf", false, false, false},
1269 {{ 0, 90, 0}, "bk", false, false, false},
1270 {{-90, 180, 0}, "up", true, true, false},
1271 {{ 90, 180, 0}, "dn", true, true, false},
1273 {{ 0, 0, 0}, "px", true, true, true},
1274 {{ 0, 90, 0}, "py", false, true, false},
1275 {{ 0, 180, 0}, "nx", false, false, true},
1276 {{ 0, 270, 0}, "ny", true, false, false},
1277 {{-90, 180, 0}, "pz", false, false, true},
1278 {{ 90, 180, 0}, "nz", false, false, true}
1281 static void R_Envmap_f (void)
1284 char filename[MAX_QPATH], basename[MAX_QPATH];
1285 unsigned char *buffer1;
1286 unsigned char *buffer2;
1287 unsigned char *buffer3;
1289 if (Cmd_Argc() != 3)
1291 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");
1295 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1296 size = atoi(Cmd_Argv(2));
1297 if (size != 128 && size != 256 && size != 512 && size != 1024)
1299 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1302 if (size > vid.width || size > vid.height)
1304 Con_Print("envmap: your resolution is not big enough to render that size\n");
1312 r_refdef.width = size;
1313 r_refdef.height = size;
1315 r_refdef.frustum_x = tan(90 * M_PI / 360.0);
1316 r_refdef.frustum_y = tan(90 * M_PI / 360.0);
1318 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1319 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1320 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1322 for (j = 0;j < 12;j++)
1324 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1325 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);
1330 SCR_ScreenShot(filename, buffer1, buffer2, buffer3, 0, vid.height - (r_refdef.y + r_refdef.height), size, size, envmapinfo[j].flipx, envmapinfo[j].flipy, envmapinfo[j].flipdiagonaly, false, false);
1340 //=============================================================================
1342 // LordHavoc: SHOWLMP stuff
1343 #define SHOWLMP_MAXLABELS 256
1344 typedef struct showlmp_s
1354 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1356 void SHOWLMP_decodehide(void)
1360 lmplabel = MSG_ReadString();
1361 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1362 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1364 showlmp[i].isactive = false;
1369 void SHOWLMP_decodeshow(void)
1372 char lmplabel[256], picname[256];
1374 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1375 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1376 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1383 x = MSG_ReadShort();
1384 y = MSG_ReadShort();
1387 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1388 if (showlmp[i].isactive)
1390 if (strcmp(showlmp[i].label, lmplabel) == 0)
1393 break; // drop out to replace it
1396 else if (k < 0) // find first empty one to replace
1399 return; // none found to replace
1400 // change existing one
1401 showlmp[k].isactive = true;
1402 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1403 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1408 void SHOWLMP_drawall(void)
1411 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1412 if (showlmp[i].isactive)
1413 DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
1416 void SHOWLMP_clear(void)
1419 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1420 showlmp[i].isactive = false;
1423 void CL_SetupScreenSize(void)
1425 float conwidth, conheight;
1427 VID_UpdateGamma(false);
1429 conwidth = bound(320, vid_conwidth.value, 2048);
1430 conheight = bound(200, vid_conheight.value, 1536);
1431 if (vid_conwidth.value != conwidth)
1432 Cvar_SetValue("vid_conwidth", conwidth);
1433 if (vid_conheight.value != conheight)
1434 Cvar_SetValue("vid_conheight", conheight);
1436 vid_conwidth.integer = vid_conwidth.integer;
1437 vid_conheight.integer = vid_conheight.integer;
1439 SCR_SetUpToDrawConsole();
1442 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1443 void CL_UpdateScreen(void)
1445 if (!scr_initialized || !con_initialized || vid_hidden)
1446 return; // not initialized yet
1448 // don't allow cheats in multiplayer
1449 if (!cl.islocalgame && cl.worldmodel)
1451 if (r_fullbright.integer != 0)
1452 Cvar_Set ("r_fullbright", "0");
1453 if (r_ambient.value != 0)
1454 Cvar_Set ("r_ambient", "0");
1458 if (scr_viewsize.value < 30)
1459 Cvar_Set ("viewsize","30");
1460 if (scr_viewsize.value > 120)
1461 Cvar_Set ("viewsize","120");
1463 // bound field of view
1464 if (scr_fov.value < 1)
1465 Cvar_Set ("fov","1");
1466 if (scr_fov.value > 170)
1467 Cvar_Set ("fov","170");
1469 // intermission is always full screen
1470 if (cl.intermission)
1474 if (scr_viewsize.value >= 120)
1475 sb_lines = 0; // no status bar at all
1476 else if (scr_viewsize.value >= 110)
1477 sb_lines = 24; // no inventory
1482 r_refdef.colormask[0] = 1;
1483 r_refdef.colormask[1] = 1;
1484 r_refdef.colormask[2] = 1;
1488 if (cls.signon == SIGNONS)
1489 R_TimeReport("other");
1491 CL_SetupScreenSize();
1495 if (cls.signon == SIGNONS)
1496 R_TimeReport("setup");
1498 //FIXME: force menu if nothing else to look at?
1499 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1501 if (cls.signon == SIGNONS)
1506 if (!r_letterbox.value)
1509 SCR_CheckDrawCenterString();
1515 if (cls.signon == SIGNONS)
1519 R_TimeReport_Start();
1521 R_Shadow_EditLights_DrawSelectedLightProperties();
1530 void CL_Screen_NewMap(void)