4 cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100"};
5 cvar_t scr_fov = {CVAR_SAVE, "fov","90"}; // 10 - 170
6 cvar_t scr_conspeed = {CVAR_SAVE, "scr_conspeed","900"}; // LordHavoc: quake used 300
7 cvar_t scr_centertime = {0, "scr_centertime","2"};
8 cvar_t scr_showram = {CVAR_SAVE, "showram","1"};
9 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0"};
10 cvar_t scr_showpause = {CVAR_SAVE, "showpause","1"};
11 cvar_t scr_printspeed = {0, "scr_printspeed","8"};
12 cvar_t scr_2dresolution = {CVAR_SAVE, "scr_2dresolution", "1"};
14 qboolean scr_initialized; // ready to draw
16 float scr_con_current;
17 float scr_conlines; // lines of console to display
22 qboolean scr_disabled_for_loading;
23 //qboolean scr_drawloading;
24 //float scr_disabled_time;
26 static byte menuplyr_pixels[4096];
29 ===============================================================================
33 ===============================================================================
36 char scr_centerstring[1024];
37 float scr_centertime_start; // for slow victory printing
38 float scr_centertime_off;
47 Called for important messages that should stay in the center of the screen
51 void SCR_CenterPrint (char *str)
53 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
54 scr_centertime_off = scr_centertime.value;
55 scr_centertime_start = cl.time;
57 // count the number of lines for centering
68 void SCR_DrawCenterString (void)
75 // the finale prints the characters one at a time
77 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
82 start = scr_centerstring;
84 if (scr_center_lines <= 4)
85 y = vid.conheight*0.35;
91 // scan the width of the line
92 for (l=0 ; l<40 ; l++)
93 if (start[l] == '\n' || !start[l])
95 x = (vid.conwidth - l*8)/2;
100 DrawQ_String(x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
108 while (*start && *start != '\n')
113 start++; // skip the \n
117 void SCR_CheckDrawCenterString (void)
119 if (scr_center_lines > scr_erase_lines)
120 scr_erase_lines = scr_center_lines;
122 scr_centertime_off -= host_frametime;
124 if (scr_centertime_off <= 0 && !cl.intermission)
126 if (key_dest != key_game)
129 SCR_DrawCenterString ();
137 void SCR_DrawRam (void)
139 // if (!scr_showram.integer)
141 // DrawQ_Pic (32, 0, "ram", 0, 0, 1, 1, 1, 1, 0);
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);
219 void SCR_DrawLoading (void)
223 if (!scr_drawloading)
226 pic = Draw_CachePic ("gfx/loading.lmp");
227 DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/loading.lmp", 0, 0, 1, 1, 1, 1, 0);
233 //=============================================================================
238 SCR_SetUpToDrawConsole
241 void SCR_SetUpToDrawConsole (void)
245 // decide on the height of the console
246 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
250 scr_conlines = vid.conheight; // full screen
251 scr_con_current = scr_conlines;
253 else if (key_dest == key_console)
254 scr_conlines = vid.conheight/2; // half screen
256 scr_conlines = 0; // none visible
258 if (scr_conlines < scr_con_current)
260 scr_con_current -= scr_conspeed.value*host_realframetime;
261 if (scr_conlines > scr_con_current)
262 scr_con_current = scr_conlines;
265 else if (scr_conlines > scr_con_current)
267 scr_con_current += scr_conspeed.value*host_realframetime;
268 if (scr_conlines < scr_con_current)
269 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
299 void SCR_BeginLoadingPlaque (void)
301 S_StopAllSounds (true);
303 // if (cls.state != ca_connected)
305 // if (cls.signon != SIGNONS)
308 // redraw with no console and the loading plaque
309 // Con_ClearNotify ();
310 // scr_centertime_off = 0;
311 // scr_con_current = 0;
313 scr_drawloading = true;
316 // scr_disabled_for_loading = true;
317 // scr_disabled_time = realtime;
328 void SCR_EndLoadingPlaque (void)
330 // scr_disabled_for_loading = false;
331 scr_drawloading = false;
336 //=============================================================================
338 char *scr_notifystring;
340 void SCR_DrawNotifyString (void)
346 start = scr_notifystring;
348 y = vid.conheight*0.35;
352 // scan the width of the line
353 for (l=0 ; l<40 ; l++)
354 if (start[l] == '\n' || !start[l])
356 x = (vid.conwidth - l*8)/2;
357 DrawQ_String (x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
361 while (*start && *start != '\n')
366 start++; // skip the \n
371 void DrawCrosshair(int num);
373 char r_speeds_string[1024];
374 int speedstringcount, r_timereport_active;
375 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
377 void R_TimeReport(char *desc)
383 if (!r_timereport_active)
386 r_timereport_temp = r_timereport_current;
387 r_timereport_current = Sys_DoubleTime();
388 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
390 sprintf(tempbuf, "%8i %s", t, desc);
391 length = strlen(tempbuf);
393 tempbuf[length++] = ' ';
395 if (speedstringcount + length > (vid.conwidth / 8))
397 strcat(r_speeds_string, "\n");
398 speedstringcount = 0;
400 // skip the space at the beginning if it's the first on the line
401 if (speedstringcount == 0)
403 strcat(r_speeds_string, tempbuf + 1);
404 speedstringcount = length - 1;
408 strcat(r_speeds_string, tempbuf);
409 speedstringcount += length;
413 void R_TimeReport_Start(void)
415 r_timereport_active = r_speeds.integer && cl.worldmodel && cls.state == ca_connected;
416 r_speeds_string[0] = 0;
417 if (r_timereport_active)
419 speedstringcount = 0;
420 AngleVectors (r_refdef.viewangles, vpn, NULL, NULL);
421 //sprintf(r_speeds_string, "org:'%c%6.2f %c%6.2f %c%6.2f' ang:'%c%3.0f %c%3.0f %c%3.0f' dir:'%c%2.3f %c%2.3f %c%2.3f'\n%6i walls %6i dlitwalls %7i modeltris %7i meshtris\nBSP: %6i faces %6i nodes %6i leafs\n%4i models %4i bmodels %4i sprites %5i particles %3i dlights\n",
422 // r_refdef.vieworg[0] < 0 ? '-' : ' ', fabs(r_refdef.vieworg[0]), r_refdef.vieworg[1] < 0 ? '-' : ' ', fabs(r_refdef.vieworg[1]), r_refdef.vieworg[2] < 0 ? '-' : ' ', fabs(r_refdef.vieworg[2]),
423 // r_refdef.viewangles[0] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[0]), r_refdef.viewangles[1] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[1]), r_refdef.viewangles[2] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[2]),
424 // vpn[0] < 0 ? '-' : ' ', fabs(vpn[0]), vpn[1] < 0 ? '-' : ' ', fabs(vpn[1]), vpn[2] < 0 ? '-' : ' ', fabs(vpn[2]),
425 sprintf(r_speeds_string,
426 "org:'%+8.2f %+8.2f %+8.2f' ang:'%+4.0f %+4.0f %+4.0f' dir:'%+2.3f %+2.3f %+2.3f'\n"
427 "world:%6i faces%6i nodes%6i leafs%6i walls%6i dlitwalls\n"
428 "%5i models%5i bmodels%5i sprites%6i particles%4i dlights\n"
429 "%6i modeltris%6i transmeshs%6i transtris%6i meshs%6i meshtris\n",
430 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],
431 c_faces, c_nodes, c_leafs, c_brush_polys, c_light_polys,
432 c_models, c_bmodels, c_sprites, c_particles, c_dlights,
433 c_alias_polys, c_transmeshs, c_transtris, c_meshs, c_meshtris);
447 r_timereport_start = Sys_DoubleTime();
451 void R_TimeReport_End(void)
453 r_timereport_current = r_timereport_start;
454 R_TimeReport("total");
456 if (r_timereport_active)
460 for (i = 0;r_speeds_string[i];i++)
461 if (r_speeds_string[i] == '\n')
463 y = vid.conheight - sb_lines - lines * 8/* - 8*/;
465 DrawQ_Fill(0, y, vid.conwidth, lines * 8, 0, 0, 0, 0.5, 0);
466 while (r_speeds_string[i])
469 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
472 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
473 if (r_speeds_string[i] == '\n')
487 void SCR_SizeUp_f (void)
489 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
500 void SCR_SizeDown_f (void)
502 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
505 void CL_Screen_Init(void)
509 Cvar_RegisterVariable (&scr_fov);
510 Cvar_RegisterVariable (&scr_viewsize);
511 Cvar_RegisterVariable (&scr_conspeed);
512 Cvar_RegisterVariable (&scr_showram);
513 Cvar_RegisterVariable (&scr_showturtle);
514 Cvar_RegisterVariable (&scr_showpause);
515 Cvar_RegisterVariable (&scr_centertime);
516 Cvar_RegisterVariable (&scr_printspeed);
517 Cvar_RegisterVariable(&scr_2dresolution);
519 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
520 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
522 scr_initialized = true;
525 // load the image data for the player image in the config menu
526 dat = (qpic_t *)COM_LoadFile ("gfx/menuplyr.lmp", false);
528 Sys_Error("unable to load gfx/menuplyr.lmp");
531 if (dat->width*dat->height <= 4096)
532 memcpy (menuplyr_pixels, dat->data, dat->width * dat->height);
534 Con_Printf("gfx/menuplyr.lmp larger than 4k buffer");
538 void DrawQ_Clear(void)
540 r_refdef.drawqueuesize = 0;
543 void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
547 if (alpha < (1.0f / 255.0f))
549 size = sizeof(*dq) + ((strlen(picname) + 1 + 3) & ~3);
550 if (r_refdef.drawqueuesize + size > MAX_DRAWQUEUE)
552 red = bound(0, red, 1);
553 green = bound(0, green, 1);
554 blue = bound(0, blue, 1);
555 alpha = bound(0, alpha, 1);
556 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
558 dq->command = DRAWQUEUE_PIC;
560 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));
563 // if these are not zero, they override the pic's size
566 strcpy((char *)(dq + 1), picname);
567 r_refdef.drawqueuesize += dq->size;
570 void DrawQ_String(float x, float y, char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
575 if (alpha < (1.0f / 255.0f))
578 len = strlen(string);
580 for (len = 0;len < maxlen && string[len];len++);
581 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
582 for (;len > 0 && string[len - 1] == ' ';len--);
585 if (x >= vid.conwidth || y >= vid.conheight || x < (-scalex * maxlen) || y < (-scaley))
587 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
588 if (r_refdef.drawqueuesize + size > MAX_DRAWQUEUE)
590 red = bound(0, red, 1);
591 green = bound(0, green, 1);
592 blue = bound(0, blue, 1);
593 alpha = bound(0, alpha, 1);
594 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
596 dq->command = DRAWQUEUE_STRING;
598 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));
603 out = (char *)(dq + 1);
604 memcpy(out, string, len);
606 r_refdef.drawqueuesize += dq->size;
609 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
613 if (alpha < (1.0f / 255.0f))
615 size = sizeof(*dq) + 4;
616 if (r_refdef.drawqueuesize + size > MAX_DRAWQUEUE)
618 red = bound(0, red, 1);
619 green = bound(0, green, 1);
620 blue = bound(0, blue, 1);
621 alpha = bound(0, alpha, 1);
622 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
624 dq->command = DRAWQUEUE_PIC;
626 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));
632 *((char *)(dq + 1)) = 0;
633 r_refdef.drawqueuesize += dq->size;
636 //only used for the player color selection menu
637 void DrawQ_PicTranslate (int x, int y, char *picname, byte *translation)
640 unsigned int trans[4096];
643 pic = Draw_CachePic(picname);
647 c = pic->width * pic->height;
650 Con_Printf("DrawQ_PicTranslate: image larger than 4k buffer\n");
654 for (i = 0;i < c;i++)
655 trans[i] = d_8to24table[translation[menuplyr_pixels[i]]];
657 // FIXME: this is renderer stuff?
658 R_UpdateTexture (pic->tex, (byte *)trans);
660 DrawQ_Pic(x, y, picname, 0, 0, 1, 1, 1, 1, 0);
669 float CalcFov (float fov_x, float width, float height)
671 // calculate vision size and alter by aspect, then convert back to angle
672 return atan (height / (width / tan(fov_x/360*M_PI))) * 360 / M_PI;
679 Must be called whenever vid changes
683 static void SCR_CalcRefdef (void)
688 //========================================
691 if (scr_viewsize.value < 30)
692 Cvar_Set ("viewsize","30");
693 if (scr_viewsize.value > 120)
694 Cvar_Set ("viewsize","120");
696 // bound field of view
697 if (scr_fov.value < 10)
698 Cvar_Set ("fov","10");
699 if (scr_fov.value > 170)
700 Cvar_Set ("fov","170");
702 // intermission is always full screen
710 if (scr_viewsize.value >= 120)
711 sb_lines = 0; // no status bar at all
712 else if (scr_viewsize.value >= 110)
713 sb_lines = 24; // no inventory
716 size = scr_viewsize.value * (1.0 / 100.0);
721 r_refdef.width = vid.realwidth;
722 r_refdef.height = vid.realheight;
728 r_refdef.width = vid.realwidth * size;
729 r_refdef.height = vid.realheight * size;
730 r_refdef.x = (vid.realwidth - r_refdef.width)/2;
731 r_refdef.y = (vid.realheight - r_refdef.height)/2;
734 r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
735 r_refdef.height = bound(0, r_refdef.height, vid.realheight);
736 r_refdef.x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width) + vid.realx;
737 r_refdef.y = bound(0, r_refdef.y, vid.realheight - r_refdef.height) + vid.realy;
739 // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
740 r_refdef.fov_x = scr_fov.value * cl.viewzoom;
741 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.width, r_refdef.height);
745 Mod_CheckLoaded(cl.worldmodel);
746 contents = Mod_PointInLeaf(r_refdef.vieworg, cl.worldmodel)->contents;
747 if (contents != CONTENTS_EMPTY && contents != CONTENTS_SOLID)
749 r_refdef.fov_x *= (sin(cl.time * 4.7) * 0.015 + 0.985);
750 r_refdef.fov_y *= (sin(cl.time * 3.0) * 0.015 + 0.985);
756 void V_CalcRefdef (void);
758 //=============================================================================
760 // LordHavoc: SHOWLMP stuff
761 #define SHOWLMP_MAXLABELS 256
762 typedef struct showlmp_s
772 showlmp_t showlmp[SHOWLMP_MAXLABELS];
774 void SHOWLMP_decodehide(void)
778 lmplabel = MSG_ReadString();
779 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
780 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
782 showlmp[i].isactive = false;
787 void SHOWLMP_decodeshow(void)
790 byte lmplabel[256], picname[256];
792 strcpy(lmplabel,MSG_ReadString());
793 strcpy(picname, MSG_ReadString());
794 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
805 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
806 if (showlmp[i].isactive)
808 if (strcmp(showlmp[i].label, lmplabel) == 0)
811 break; // drop out to replace it
814 else if (k < 0) // find first empty one to replace
817 return; // none found to replace
818 // change existing one
819 showlmp[k].isactive = true;
820 strcpy(showlmp[k].label, lmplabel);
821 strcpy(showlmp[k].pic, picname);
826 void SHOWLMP_drawall(void)
830 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
831 if (showlmp[i].isactive)
832 DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
835 void SHOWLMP_clear(void)
838 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
839 showlmp[i].isactive = false;
842 void CL_UpdateScreen(void)
844 static float old2dresolution = -1;
846 if (scr_disabled_for_loading)
849 if (!scr_initialized || !con_initialized)
850 return; // not initialized yet
852 R_TimeReport("other");
854 VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
856 VID_UpdateGamma(false);
858 if (scr_2dresolution.value != old2dresolution)
860 Cvar_SetValue("scr_2dresolution", bound(0.0f, scr_2dresolution.value, 1.0f));
861 old2dresolution = scr_2dresolution.value;
864 if (vid.realwidth > 320)
866 vid.conwidth = (vid.realwidth - 320) * scr_2dresolution.value + 320;
867 vid.conwidth = bound(320, vid.conwidth, vid.realwidth);
872 if (vid.realheight > 240)
874 vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
875 vid.conheight = bound(240, vid.conheight, vid.realheight);
880 SCR_SetUpToDrawConsole();
882 // determine size of refresh window
890 R_TimeReport("setup");
896 SCR_CheckDrawCenterString();
906 // add r_speeds text to queue
909 // start a new timing run
910 R_TimeReport_Start();
912 // make menu fade everything else on the screen
918 void CL_Screen_NewMap(void)