5 cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100"};
6 cvar_t scr_fov = {CVAR_SAVE, "fov","90"}; // 10 - 170
7 cvar_t scr_conspeed = {CVAR_SAVE, "scr_conspeed","900"}; // LordHavoc: quake used 300
8 cvar_t scr_centertime = {0, "scr_centertime","2"};
9 cvar_t scr_showram = {CVAR_SAVE, "showram","1"};
10 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0"};
11 cvar_t scr_showpause = {CVAR_SAVE, "showpause","1"};
12 cvar_t scr_printspeed = {0, "scr_printspeed","8"};
13 cvar_t scr_2dresolution = {CVAR_SAVE, "scr_2dresolution", "1"};
14 cvar_t cl_avidemo = {0, "cl_avidemo", "0"};
16 qboolean scr_initialized; // ready to draw
18 float scr_con_current;
19 float scr_conlines; // lines of console to display
24 qboolean scr_drawloading = false;
26 static qbyte menuplyr_pixels[4096];
28 void DrawCrosshair(int num);
29 void V_CalcRefdef (void);
30 static void SCR_ScreenShot_f (void);
31 static void R_Envmap_f (void);
34 void R_ClearScreen(void);
37 ===============================================================================
41 ===============================================================================
44 char scr_centerstring[1024];
45 float scr_centertime_start; // for slow victory printing
46 float scr_centertime_off;
55 Called for important messages that should stay in the center of the screen
59 void SCR_CenterPrint (char *str)
61 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
62 scr_centertime_off = scr_centertime.value;
63 scr_centertime_start = cl.time;
65 // count the number of lines for centering
76 void SCR_DrawCenterString (void)
83 // the finale prints the characters one at a time
85 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
90 start = scr_centerstring;
92 if (scr_center_lines <= 4)
93 y = vid.conheight*0.35;
99 // scan the width of the line
100 for (l=0 ; l<40 ; l++)
101 if (start[l] == '\n' || !start[l])
103 x = (vid.conwidth - l*8)/2;
108 DrawQ_String(x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
116 while (*start && *start != '\n')
121 start++; // skip the \n
125 void SCR_CheckDrawCenterString (void)
127 if (scr_center_lines > scr_erase_lines)
128 scr_erase_lines = scr_center_lines;
130 scr_centertime_off -= host_frametime;
132 // don't draw if this is a normal stats-screen intermission,
133 // only if it is not an intermission, or a finale intermission
134 if (cl.intermission == 1)
136 if (scr_centertime_off <= 0 && !cl.intermission)
138 if (key_dest != key_game)
141 SCR_DrawCenterString ();
149 void SCR_DrawTurtle (void)
153 if (cls.state != ca_connected)
156 if (!scr_showturtle.integer)
159 if (host_frametime < 0.1)
169 DrawQ_Pic (0, 0, "turtle", 0, 0, 1, 1, 1, 1, 0);
177 void SCR_DrawNet (void)
179 if (cls.state != ca_connected)
181 if (realtime - cl.last_received_message < 0.3)
183 if (cls.demoplayback)
186 DrawQ_Pic (64, 0, "net", 0, 0, 1, 1, 1, 1, 0);
194 void SCR_DrawPause (void)
198 if (cls.state != ca_connected)
201 if (!scr_showpause.integer) // turn off for screenshots
207 pic = Draw_CachePic ("gfx/pause.lmp");
208 DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/pause.lmp", 0, 0, 1, 1, 1, 1, 0);
218 void SCR_DrawLoading (void)
222 pic = Draw_CachePic ("gfx/loading.lmp");
223 DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/loading.lmp", 0, 0, 1, 1, 1, 1, 0);
228 //=============================================================================
233 SCR_SetUpToDrawConsole
236 void SCR_SetUpToDrawConsole (void)
240 if (key_dest == key_game && cls.signon != SIGNONS)
241 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
243 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
245 // decide on the height of the console
246 if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
247 scr_conlines = vid.conheight; // full screen
248 else if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
249 scr_conlines = vid.conheight/2; // half screen
251 scr_conlines = 0; // none visible
253 if (scr_conspeed.value)
255 if (scr_conlines < scr_con_current)
257 scr_con_current -= scr_conspeed.value*host_realframetime;
258 if (scr_conlines > scr_con_current)
259 scr_con_current = scr_conlines;
262 else if (scr_conlines > scr_con_current)
264 scr_con_current += scr_conspeed.value*host_realframetime;
265 if (scr_conlines < scr_con_current)
266 scr_con_current = scr_conlines;
270 scr_con_current = scr_conlines;
278 void SCR_DrawConsole (void)
282 Con_DrawConsole (scr_con_current);
287 if (key_dest == key_game || key_dest == key_message)
288 Con_DrawNotify (); // only draw notify in game
294 SCR_BeginLoadingPlaque
298 void SCR_BeginLoadingPlaque (void)
303 S_StopAllSounds (true);
305 scr_drawloading = true;
307 scr_drawloading = true;
311 //=============================================================================
313 char r_speeds_string[1024];
314 int speedstringcount, r_timereport_active;
315 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
317 void R_TimeReport(char *desc)
323 if (!r_timereport_active)
326 r_timereport_temp = r_timereport_current;
327 r_timereport_current = Sys_DoubleTime();
328 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
330 sprintf(tempbuf, "%8i %s", t, desc);
331 length = strlen(tempbuf);
333 tempbuf[length++] = ' ';
335 if (speedstringcount + length > (vid.conwidth / 8))
337 strcat(r_speeds_string, "\n");
338 speedstringcount = 0;
340 // skip the space at the beginning if it's the first on the line
341 if (speedstringcount == 0)
343 strcat(r_speeds_string, tempbuf + 1);
344 speedstringcount = length - 1;
348 strcat(r_speeds_string, tempbuf);
349 speedstringcount += length;
353 extern int c_rt_lights, c_rt_clears, c_rt_scissored;
354 extern int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
355 extern int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
356 extern int r_shadow_lightingmode;
357 void R_TimeReport_Start(void)
359 r_timereport_active = r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected;
360 r_speeds_string[0] = 0;
361 if (r_timereport_active)
363 speedstringcount = 0;
364 AngleVectors (r_refdef.viewangles, vpn, NULL, NULL);
365 sprintf(r_speeds_string,
366 "org:'%+8.2f %+8.2f %+8.2f' ang:'%+4.0f %+4.0f %+4.0f' dir:'%+2.3f %+2.3f %+2.3f'\n"
367 "world:%6i faces%6i nodes%6i leafs%6i dlitwalls\n"
368 "%5i models%5i bmodels%5i sprites%6i particles%4i dlights\n"
369 "%6i modeltris%6i meshs%6i meshtris\n",
370 r_refdef.vieworg[0], r_refdef.vieworg[1], r_refdef.vieworg[2], r_refdef.viewangles[0], r_refdef.viewangles[1], r_refdef.viewangles[2], vpn[0], vpn[1], vpn[2],
371 c_faces, c_nodes, c_leafs, c_light_polys,
372 c_models, c_bmodels, c_sprites, c_particles, c_dlights,
373 c_alias_polys, c_meshs, c_meshelements / 3);
374 if (r_shadow_lightingmode)
376 sprintf(r_speeds_string + strlen(r_speeds_string),
377 "realtime lighting:%4i lights%4i clears%4i scissored\n"
378 "dynamic: %6i shadowmeshes%6i shadowtris%6i lightmeshes%6i lighttris\n"
379 "precomputed: %6i shadowmeshes%6i shadowtris\n",
380 c_rt_lights, c_rt_clears, c_rt_scissored,
381 c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris,
382 c_rtcached_shadowmeshes, c_rtcached_shadowtris);
397 r_timereport_start = Sys_DoubleTime();
401 void R_TimeReport_End(void)
403 r_timereport_current = r_timereport_start;
404 R_TimeReport("total");
406 if (r_timereport_active)
410 for (i = 0;r_speeds_string[i];i++)
411 if (r_speeds_string[i] == '\n')
413 y = vid.conheight - sb_lines - lines * 8;
415 DrawQ_Fill(0, y, vid.conwidth, lines * 8, 0, 0, 0, 0.5, 0);
416 while (r_speeds_string[i])
419 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
422 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
423 if (r_speeds_string[i] == '\n')
437 void SCR_SizeUp_f (void)
439 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
450 void SCR_SizeDown_f (void)
452 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
455 void CL_Screen_Init(void)
459 Cvar_RegisterVariable (&scr_fov);
460 Cvar_RegisterVariable (&scr_viewsize);
461 Cvar_RegisterVariable (&scr_conspeed);
462 Cvar_RegisterVariable (&scr_showram);
463 Cvar_RegisterVariable (&scr_showturtle);
464 Cvar_RegisterVariable (&scr_showpause);
465 Cvar_RegisterVariable (&scr_centertime);
466 Cvar_RegisterVariable (&scr_printspeed);
467 Cvar_RegisterVariable (&scr_2dresolution);
468 Cvar_RegisterVariable (&cl_avidemo);
470 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
471 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
472 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
473 Cmd_AddCommand ("envmap", R_Envmap_f);
475 scr_initialized = true;
478 // load the image data for the player image in the config menu
479 dat = (qpic_t *)COM_LoadFile ("gfx/menuplyr.lmp", false);
481 Sys_Error("unable to load gfx/menuplyr.lmp");
484 if (dat->width*dat->height <= 4096)
485 memcpy (menuplyr_pixels, dat->data, dat->width * dat->height);
487 Con_Printf("gfx/menuplyr.lmp larger than 4k buffer");
491 void DrawQ_Clear(void)
493 r_refdef.drawqueuesize = 0;
496 void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
500 if (alpha < (1.0f / 255.0f) || !picname || !picname[0])
502 size = sizeof(*dq) + ((strlen(picname) + 1 + 3) & ~3);
503 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
505 red = bound(0, red, 1);
506 green = bound(0, green, 1);
507 blue = bound(0, blue, 1);
508 alpha = bound(0, alpha, 1);
509 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
511 dq->command = DRAWQUEUE_PIC;
513 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));
516 // if these are not zero, they override the pic's size
519 strcpy((char *)(dq + 1), picname);
520 r_refdef.drawqueuesize += dq->size;
523 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)
528 if (alpha < (1.0f / 255.0f))
531 len = strlen(string);
533 for (len = 0;len < maxlen && string[len];len++);
534 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
535 for (;len > 0 && string[len - 1] == ' ';len--);
538 if (x >= vid.conwidth || y >= vid.conheight || x < (-scalex * maxlen) || y < (-scaley))
540 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
541 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
543 red = bound(0, red, 1);
544 green = bound(0, green, 1);
545 blue = bound(0, blue, 1);
546 alpha = bound(0, alpha, 1);
547 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
549 dq->command = DRAWQUEUE_STRING;
551 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));
556 out = (char *)(dq + 1);
557 memcpy(out, string, len);
559 r_refdef.drawqueuesize += dq->size;
562 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
566 if (alpha < (1.0f / 255.0f))
568 size = sizeof(*dq) + 4;
569 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
571 red = bound(0, red, 1);
572 green = bound(0, green, 1);
573 blue = bound(0, blue, 1);
574 alpha = bound(0, alpha, 1);
575 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
577 dq->command = DRAWQUEUE_PIC;
579 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));
585 *((char *)(dq + 1)) = 0;
586 r_refdef.drawqueuesize += dq->size;
589 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
596 size += sizeof(drawqueuemesh_t);
597 size += sizeof(int[3]) * mesh->numtriangles;
598 size += sizeof(float[4]) * mesh->numvertices;
599 size += sizeof(float[2]) * mesh->numvertices;
600 size += sizeof(float[4]) * mesh->numvertices;
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;(qbyte *)p += sizeof(drawqueuemesh_t);
614 m->numtriangles = mesh->numtriangles;
615 m->numvertices = mesh->numvertices;
616 m->texture = mesh->texture;
617 m->indices = p;memcpy(m->indices , mesh->indices , m->numtriangles * sizeof(int[3]));(qbyte *)p += m->numtriangles * sizeof(int[3]);
618 m->vertices = p;memcpy(m->vertices , mesh->vertices , m->numvertices * sizeof(float[4]));(qbyte *)p += m->numvertices * sizeof(float[4]);
619 m->texcoords = p;memcpy(m->texcoords, mesh->texcoords, m->numvertices * sizeof(float[4]));(qbyte *)p += m->numvertices * sizeof(float[4]);
620 m->colors = p;memcpy(m->colors , mesh->colors , m->numvertices * sizeof(float[4]));(qbyte *)p += m->numvertices * sizeof(float[4]);
621 r_refdef.drawqueuesize += dq->size;
629 float CalcFov (float fov_x, float width, float height)
631 // calculate vision size and alter by aspect, then convert back to angle
632 return atan (height / (width / tan(fov_x/360*M_PI))) * 360 / M_PI;
639 Must be called whenever vid changes
643 static void SCR_CalcRefdef (void)
648 //========================================
651 if (scr_viewsize.value < 30)
652 Cvar_Set ("viewsize","30");
653 if (scr_viewsize.value > 120)
654 Cvar_Set ("viewsize","120");
656 // bound field of view
657 if (scr_fov.value < 10)
658 Cvar_Set ("fov","10");
659 if (scr_fov.value > 170)
660 Cvar_Set ("fov","170");
662 // intermission is always full screen
670 if (scr_viewsize.value >= 120)
671 sb_lines = 0; // no status bar at all
672 else if (scr_viewsize.value >= 110)
673 sb_lines = 24; // no inventory
676 size = scr_viewsize.value * (1.0 / 100.0);
681 r_refdef.width = vid.realwidth;
682 r_refdef.height = vid.realheight;
688 r_refdef.width = vid.realwidth * size;
689 r_refdef.height = vid.realheight * size;
690 r_refdef.x = (vid.realwidth - r_refdef.width)/2;
691 r_refdef.y = (vid.realheight - r_refdef.height)/2;
694 r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
695 r_refdef.height = bound(0, r_refdef.height, vid.realheight);
696 r_refdef.x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width) + vid.realx;
697 r_refdef.y = bound(0, r_refdef.y, vid.realheight - r_refdef.height) + vid.realy;
699 // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
700 r_refdef.fov_x = scr_fov.value * cl.viewzoom;
701 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.width, r_refdef.height);
705 Mod_CheckLoaded(cl.worldmodel);
706 contents = Mod_PointContents(r_refdef.vieworg, cl.worldmodel);
707 if (contents != CONTENTS_EMPTY && contents != CONTENTS_SOLID)
709 r_refdef.fov_x *= (sin(cl.time * 4.7) * 0.015 + 0.985);
710 r_refdef.fov_y *= (sin(cl.time * 3.0) * 0.015 + 0.985);
720 void SCR_ScreenShot_f (void)
724 char checkname[MAX_OSPATH];
726 // find a file name to save it to
728 for (; i<=9999 ; i++)
730 sprintf (filename, "dp%04i.tga", i);
731 sprintf (checkname, "%s/%s", com_gamedir, filename);
732 if (Sys_FileTime(checkname) == -1)
733 break; // file doesn't exist
737 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
741 if (SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight))
742 Con_Printf ("Wrote %s\n", filename);
744 Con_Printf ("unable to write %s\n", filename);
747 static int cl_avidemo_frame = 0;
749 void SCR_CaptureAVIDemo(void)
752 sprintf(filename, "dpavi%06d.tga", cl_avidemo_frame);
753 if (SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight))
757 Cvar_SetValueQuick(&cl_avidemo, 0);
758 Con_Printf("avi saving failed on frame %i, out of disk space? stopping avi demo catpure.\n", cl_avidemo_frame);
759 cl_avidemo_frame = 0;
767 Grab six views for environment mapping tests
779 {{ 0, 180, 0}, "bk"},
780 {{ 0, 270, 0}, "lf"},
781 {{-90, 90, 0}, "up"},
785 static void R_Envmap_f (void)
788 char filename[256], basename[256];
792 Con_Printf ("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");
796 strcpy(basename, Cmd_Argv(1));
797 size = atoi(Cmd_Argv(2));
798 if (size != 128 && size != 256 && size != 512 && size != 1024)
800 Con_Printf("envmap: size must be one of 128, 256, 512, or 1024\n");
803 if (size > vid.realwidth || size > vid.realheight)
805 Con_Printf("envmap: your resolution is not big enough to render that size\n");
813 r_refdef.width = size;
814 r_refdef.height = size;
819 for (j = 0;j < 6;j++)
821 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
822 VectorCopy(envmapinfo[j].angles, r_refdef.viewangles);
825 SCR_ScreenShot(filename, vid.realx, vid.realy, size, size);
831 //=============================================================================
833 // LordHavoc: SHOWLMP stuff
834 #define SHOWLMP_MAXLABELS 256
835 typedef struct showlmp_s
845 showlmp_t showlmp[SHOWLMP_MAXLABELS];
847 void SHOWLMP_decodehide(void)
851 lmplabel = MSG_ReadString();
852 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
853 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
855 showlmp[i].isactive = false;
860 void SHOWLMP_decodeshow(void)
863 qbyte lmplabel[256], picname[256];
865 strcpy(lmplabel,MSG_ReadString());
866 strcpy(picname, MSG_ReadString());
867 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
878 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
879 if (showlmp[i].isactive)
881 if (strcmp(showlmp[i].label, lmplabel) == 0)
884 break; // drop out to replace it
887 else if (k < 0) // find first empty one to replace
890 return; // none found to replace
891 // change existing one
892 showlmp[k].isactive = true;
893 strcpy(showlmp[k].label, lmplabel);
894 strcpy(showlmp[k].pic, picname);
899 void SHOWLMP_drawall(void)
902 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
903 if (showlmp[i].isactive)
904 DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
907 void SHOWLMP_clear(void)
910 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
911 showlmp[i].isactive = false;
914 void CL_SetupScreenSize(void)
916 static float old2dresolution = -1;
918 VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
920 VID_UpdateGamma(false);
922 if (scr_2dresolution.value != old2dresolution)
924 Cvar_SetValue("scr_2dresolution", bound(0.0f, scr_2dresolution.value, 1.0f));
925 old2dresolution = scr_2dresolution.value;
928 if (vid.realwidth > 320)
930 vid.conwidth = (vid.realwidth - 320) * scr_2dresolution.value + 320;
931 vid.conwidth = bound(320, vid.conwidth, vid.realwidth);
936 if (vid.realheight > 240)
938 vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
939 vid.conheight = bound(240, vid.conheight, vid.realheight);
944 SCR_SetUpToDrawConsole();
946 // determine size of refresh window
950 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
951 void CL_UpdateScreen(void)
953 if (!scr_initialized || !con_initialized || vid_hidden)
954 return; // not initialized yet
956 if (cl_avidemo.integer)
957 SCR_CaptureAVIDemo();
959 cl_avidemo_frame = 0;
961 if (cls.signon == SIGNONS)
962 R_TimeReport("other");
964 CL_SetupScreenSize();
971 if (cls.signon == SIGNONS)
972 R_TimeReport("setup");
974 //FIXME: force menu if nothing else to look at?
975 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
979 scr_drawloading = false;
984 if (cls.signon == SIGNONS)
991 SCR_CheckDrawCenterString();
996 if (cls.signon == SIGNONS)
1000 R_TimeReport_Start();
1002 R_Shadow_EditLights_DrawSelectedLightProperties();
1009 void CL_Screen_NewMap(void)