From 845bb231cad36975b872af6c366f5d0e184f972e Mon Sep 17 00:00:00 2001 From: Spoike Date: Thu, 28 Dec 2017 16:24:50 +0000 Subject: [PATCH] xonotic: fix 'sticky walls' issue when spectating. xonotic: fix jumppads not working while onground. attempt to parse meag's protocol changes, in case we get a .qwd from ezquake. does not report them to servers at this time. added cl_fullpitch cvar. only affects nq servers that lack serverinfo. support dds/ktx-based cubemaps, including for skyboxes. recognise multiple new compressed texture formats - bc1-7, etc1+2+eac,.astc. Addeded to supporting drivers/apis. software decoder for etc2,bc4+bc5 textures, so they can be considered universal (but with fallbacks). software decoder for bc1-bc3 textures, but disabled due to lingering patent paranoia. report heartbeats once, by default. r_viewmodel_fov support for vk+d3d9+d3d11 renderers. fix depth projection differences with various renderers (min dist is now consistent). added some code to announce when cl_delay_packets changes. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5188 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_ents.c | 38 +- engine/client/cl_main.c | 14 +- engine/client/cl_parse.c | 22 +- engine/client/cl_screen.c | 10 +- engine/client/cl_tent.c | 2 +- engine/client/client.h | 19 +- engine/client/image.c | 1443 ++- engine/client/m_options.c | 1 + engine/client/merged.h | 70 +- engine/client/net_master.c | 19 +- engine/client/r_2d.c | 9 +- engine/client/render.h | 1 + engine/client/renderer.c | 96 +- engine/client/textedit.c | 51 +- engine/common/bothdefs.h | 4 + engine/common/common.c | 6 + engine/common/common.h | 1 + engine/common/cvar.h | 2 +- engine/common/gl_q2bsp.c | 43 +- engine/common/mathlib.c | 36 +- engine/common/mathlib.h | 4 +- engine/common/net_wins.c | 16 +- engine/common/pmove.c | 8 + engine/common/pr_bgcmd.c | 4 +- engine/common/protocol.h | 5 + engine/d3d/d3d11_backend.c | 26 +- engine/d3d/d3d11_image.c | 79 +- engine/d3d/d3d8_image.c | 37 +- engine/d3d/d3d_backend.c | 72 +- engine/d3d/d3d_image.c | 60 +- engine/d3d/d3d_shader.c | 2 +- engine/d3d/vid_d3d.c | 67 +- engine/d3d/vid_d3d11.c | 67 +- engine/d3d/vid_d3d8.c | 10 +- engine/gl/gl_backend.c | 2 +- engine/gl/gl_draw.c | 116 +- engine/gl/gl_model.c | 4 +- engine/gl/gl_rlight.c | 1 + engine/gl/gl_rmain.c | 12 +- engine/gl/gl_rmisc.c | 3 - engine/gl/gl_shader.c | 36 +- engine/gl/gl_shadow.c | 2 +- engine/gl/gl_vidcommon.c | 83 +- engine/gl/gl_vidnt.c | 48 +- engine/gl/glsupp.h | 58 +- engine/gl/shader.h | 6 +- engine/server/pr_lua.c | 68 +- engine/server/sv_main.c | 5 +- engine/server/sv_phys.c | 40 +- engine/server/sv_user.c | 4 +- engine/sw/sw_rast.c | 2 +- engine/vk/vk_backend.c | 30 +- engine/vk/vk_init.c | 310 +- plugins/ezhud/ezquakeisms.c | 1136 +-- plugins/ezhud/hud_common.c | 16444 +++++++++++++++++----------------- 55 files changed, 11191 insertions(+), 9563 deletions(-) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 0dbece937..4c51a28dd 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -407,19 +407,34 @@ void CLQW_ParseDelta (entity_state_t *from, entity_state_t *to, int bits) to->effects = (to->effects&0xff00)|MSG_ReadByte(); if (bits & U_ORIGIN1) - to->origin[0] = MSG_ReadCoord (); + { + if (cls.ezprotocolextensions1 & EZPEXT1_FLOATENTCOORDS) + to->origin[0] = MSG_ReadCoordFloat (); + else + to->origin[0] = MSG_ReadCoord (); + } if (bits & U_ANGLE1) to->angles[0] = MSG_ReadAngle (); if (bits & U_ORIGIN2) - to->origin[1] = MSG_ReadCoord (); + { + if (cls.ezprotocolextensions1 & EZPEXT1_FLOATENTCOORDS) + to->origin[1] = MSG_ReadCoordFloat (); + else + to->origin[1] = MSG_ReadCoord (); + } if (bits & U_ANGLE2) to->angles[1] = MSG_ReadAngle (); if (bits & U_ORIGIN3) - to->origin[2] = MSG_ReadCoord (); + { + if (cls.ezprotocolextensions1 & EZPEXT1_FLOATENTCOORDS) + to->origin[1] = MSG_ReadCoordFloat (); + else + to->origin[2] = MSG_ReadCoord (); + } if (bits & U_ANGLE3) to->angles[2] = MSG_ReadAngle (); @@ -4420,7 +4435,7 @@ void CL_MVDUpdateSpectator(void) } -void CL_ParsePlayerinfo (void) +void CLQW_ParsePlayerinfo (void) { float msec; unsigned int flags; @@ -4571,9 +4586,18 @@ void CL_ParsePlayerinfo (void) state->flags = flags; state->messagenum = cl.parsecount; - org[0] = MSG_ReadCoord (); - org[1] = MSG_ReadCoord (); - org[2] = MSG_ReadCoord (); + if (cls.ezprotocolextensions1 & EZPEXT1_FLOATENTCOORDS) + { + org[0] = MSG_ReadCoordFloat (); + org[1] = MSG_ReadCoordFloat (); + org[2] = MSG_ReadCoordFloat (); + } + else + { + org[0] = MSG_ReadCoord (); + org[1] = MSG_ReadCoord (); + org[2] = MSG_ReadCoord (); + } VectorCopy(org, state->origin); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 817485940..ed85641a1 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -64,6 +64,7 @@ cvar_t cl_nopext = CVARF("cl_nopext", "0", CVAR_ARCHIVE); cvar_t cl_pext_mask = CVAR("cl_pext_mask", "0xffffffff"); cvar_t cl_nolerp = CVARD("cl_nolerp", "0", "Disables interpolation. If set, missiles/monsters will be show exactly what was last received, which will be jerky. Does not affect players. A value of 2 means 'interpolate only in single-player/coop'."); cvar_t cl_nolerp_netquake = CVARD("cl_nolerp_netquake", "0", "Disables interpolation when connected to an NQ server. Does affect players, even the local player. You probably don't want to set this."); +cvar_t cl_fullpitch_nq = CVARAFD("cl_fullpitch", "0", "pq_fullpitch", CVAR_SEMICHEAT, "When set, attempts to unlimit the default view pitch. Note that some servers will screw over your angles if you use this, resulting in terrible gameplay, while some may merely clamp your angle serverside. This is also considered a cheat in quakeworld, so this will not function there. For the equivelent in quakeworld, use serverinfo minpitch+maxpitch instead, which applies to all players fairly."); cvar_t *hud_tracking_show; cvar_t *hud_miniscores_show; extern cvar_t net_compress; @@ -417,6 +418,7 @@ void CL_ConnectToDarkPlaces(char *challenge, netadr_t *adr) char data[2048]; cls.fteprotocolextensions = 0; cls.fteprotocolextensions2 = 0; + cls.ezprotocolextensions1 = 0; cls.resendinfo = false; @@ -2157,10 +2159,10 @@ void CL_CheckServerInfo(void) // Initialize cl.maxpitch & cl.minpitch if (cls.protocol == CP_QUAKEWORLD || cls.protocol == CP_NETQUAKE) { - s = (cls.z_ext & Z_EXT_PITCHLIMITS) ? Info_ValueForKey (cl.serverinfo, "maxpitch") : ""; - cl.maxpitch = *s ? Q_atof(s) : 80.0f; - s = (cls.z_ext & Z_EXT_PITCHLIMITS) ? Info_ValueForKey (cl.serverinfo, "minpitch") : ""; - cl.minpitch = *s ? Q_atof(s) : -70.0f; + s = Info_ValueForKey (cl.serverinfo, "maxpitch"); + cl.maxpitch = *s ? Q_atof(s) : ((cl_fullpitch_nq.ival && !cl.haveserverinfo)?90.0f:80.0f); + s = Info_ValueForKey (cl.serverinfo, "minpitch"); + cl.minpitch = *s ? Q_atof(s) : ((cl_fullpitch_nq.ival && !cl.haveserverinfo)?-90.0f:-70.0f); if (cls.protocol == CP_NETQUAKE) { //proquake likes spamming us with fixangles @@ -3477,6 +3479,7 @@ void CLNQ_ConnectionlessPacket(void) cls.fteprotocolextensions = connectinfo.fteext1; cls.fteprotocolextensions2 = connectinfo.fteext2; + cls.ezprotocolextensions1 = 0; Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport); CL_ParseEstablished(); cls.netchan.isnqprotocol = true; @@ -4221,6 +4224,9 @@ void CL_Init (void) Cvar_Register (&cl_nolerp, "Item effects"); Cvar_Register (&cl_nolerp_netquake, "Item effects"); +#ifdef NQPROT + Cvar_Register (&cl_fullpitch_nq, "Cheats"); +#endif Cvar_Register (&r_drawflame, "Item effects"); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index c1731836c..00e2a1d34 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -3013,8 +3013,9 @@ static void CLQW_ParseServerData (void) // parse protocol version number // allow 2.2 and 2.29 demos to play #ifdef PROTOCOL_VERSION_FTE - cls.fteprotocolextensions=0; - cls.fteprotocolextensions2=0; + cls.fteprotocolextensions = 0; + cls.fteprotocolextensions2 = 0; + cls.ezprotocolextensions1 = 0; for(;;) { protover = MSG_ReadLong (); @@ -3028,6 +3029,11 @@ static void CLQW_ParseServerData (void) cls.fteprotocolextensions2 = MSG_ReadLong(); continue; } + if (protover == PROTOCOL_VERSION_EZQUAKE1) + { + cls.ezprotocolextensions1 = MSG_ReadLong(); + continue; + } if (protover == PROTOCOL_VERSION_VARLENGTH) { int ident; @@ -3059,9 +3065,11 @@ static void CLQW_ParseServerData (void) Host_EndGame ("Server returned version %i, not %i\n", protover, PROTOCOL_VERSION_QW); #endif - if (cls.fteprotocolextensions2||cls.fteprotocolextensions) - if (developer.ival || cl_shownet.ival) + if (developer.ival || cl_shownet.ival) + { + if (cls.fteprotocolextensions2||cls.fteprotocolextensions) Con_TPrintf ("Using FTE extensions 0x%x%08x\n", cls.fteprotocolextensions2, cls.fteprotocolextensions); + } if (cls.fteprotocolextensions & PEXT_FLOATCOORDS) { @@ -3313,6 +3321,7 @@ static void CLQ2_ParseServerData (void) cls.netchan.netprim.anglesize = 1; cls.fteprotocolextensions = 0; cls.fteprotocolextensions2 = 0; + cls.ezprotocolextensions1 = 0; cls.demohadkeyframe = true; //assume that it did, so this stuff all gets recorded. Con_DPrintf ("Serverdata packet %s.\n", cls.demoplayback?"read":"received"); @@ -3479,6 +3488,7 @@ static void CLNQ_ParseProtoVersion(void) cls.fteprotocolextensions = 0; cls.fteprotocolextensions2 = 0; + cls.ezprotocolextensions1 = 0; for(;;) { protover = MSG_ReadLong (); @@ -6713,6 +6723,8 @@ void CLQW_ParseServerMessage (void) else { inframe_t *inf = &cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK]; + if (cls.ezprotocolextensions1 & EZPEXT1_SETANGLEREASON) + MSG_ReadByte(); //0=unknown, 1=tele, 2=spawn for (i=0 ; i<3 ; i++) ang[i] = MSG_ReadAngle(); if (!CSQC_Parse_SetAngles(destsplit, ang, false)) @@ -6963,7 +6975,7 @@ void CLQW_ParseServerMessage (void) break; case svc_playerinfo: - CL_ParsePlayerinfo (); + CLQW_ParsePlayerinfo (); break; case svc_nails: diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 88af4c786..1ee16775f 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -2698,11 +2698,11 @@ static void SCR_ScreenShot_Mega_f(void) } if (!fbwidth) - fbwidth = sh_config.texture_maxsize; - fbwidth = bound(1, fbwidth, sh_config.texture_maxsize); + fbwidth = sh_config.texture2d_maxsize; + fbwidth = bound(1, fbwidth, sh_config.texture2d_maxsize); if (!fbheight) fbheight = (fbwidth * 3)/4; - fbheight = bound(1, fbheight, sh_config.texture_maxsize); + fbheight = bound(1, fbheight, sh_config.texture2d_maxsize); if (strstr (screenyname, "..") || strchr(screenyname, ':') || *screenyname == '.' || *screenyname == '/') screenyname = ""; @@ -2799,8 +2799,8 @@ static void SCR_ScreenShot_VR_f(void) if (width <= 2) width = 2048; - if (width > sh_config.texture_maxsize) - width = sh_config.texture_maxsize; + if (width > sh_config.texture2d_maxsize) + width = sh_config.texture2d_maxsize; height = width/2; if (step <= 0) step = 5; diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 0bcb565e2..640851065 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -278,7 +278,7 @@ sfx_t *cl_sfx_ric2; sfx_t *cl_sfx_ric3; sfx_t *cl_sfx_r_exp3; -cvar_t cl_expsprite = CVARFD("cl_expsprite", "0", CVAR_ARCHIVE, "Display a central sprite in explosion effects. QuakeWorld typically does so, NQ mods should not (which is problematic when played with the qw protocol)."); +cvar_t cl_expsprite = CVARFD("cl_expsprite", "1", CVAR_ARCHIVE, "Display a central sprite in explosion effects. QuakeWorld typically does so, NQ mods should not (which is problematic when played with the qw protocol)."); cvar_t r_explosionlight = CVARFC("r_explosionlight", "1", CVAR_ARCHIVE, Cvar_Limiter_ZeroToOne_Callback); cvar_t cl_truelightning = CVARF("cl_truelightning", "0", CVAR_SEMICHEAT); cvar_t cl_beam_trace = CVAR("cl_beam_trace", "0"); diff --git a/engine/client/client.h b/engine/client/client.h index 0437ad9a2..dc8ec31a0 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -442,6 +442,7 @@ typedef struct #ifdef PROTOCOLEXTENSIONS unsigned int fteprotocolextensions; unsigned int fteprotocolextensions2; + unsigned int ezprotocolextensions1; #endif unsigned int z_ext; @@ -953,10 +954,18 @@ extern unsigned int cl_enemybottomcolor; //FPD values //(commented out ones are ones that we don't support) -#define FPD_NO_FORCE_SKIN 256 -#define FPD_NO_FORCE_COLOR 512 -#define FPD_LIMIT_PITCH (1 << 14) //limit scripted pitch changes -#define FPD_LIMIT_YAW (1 << 15) //limit scripted yaw changes +//#define FPD_NO_SAY_MACROS (1 << 0) +//#define FPD_NO_TIMERS (1 << 1) +//#define FPD_NO_SOUNDTRIGGERS (1 << 2) +#define FPD_NO_FAKE_LAG (1 << 3) +#define FPD_ANOUNCE_FAKE_LAG (1 << 4) +//#define FPD_HIDE_ENEMY_VICINITY (1 << 5) +//#define FPD_NO_SPEC_CHAT (1 << 6) +//#define FPD_HIDE_X_Y_MACRO (1 << 7) +#define FPD_NO_FORCE_SKIN (1 << 8) +#define FPD_NO_FORCE_COLOR (1 << 9) +#define FPD_LIMIT_PITCH (1 << 14) //limit scripted pitch changes +#define FPD_LIMIT_YAW (1 << 15) //limit scripted yaw changes // // cvars @@ -1336,7 +1345,7 @@ void CLQW_ParsePacketEntities (qboolean delta); void CLFTE_ParseEntities (void); void CLFTE_ParseBaseline(entity_state_t *es, qboolean numberisimportant); void CL_SetSolidEntities (void); -void CL_ParsePlayerinfo (void); +void CLQW_ParsePlayerinfo (void); void CL_ParseClientPersist(void); //these last ones are needed for csqc handling of engine-bound ents. void CL_ClearEntityLists(void); diff --git a/engine/client/image.c b/engine/client/image.c index ef977b8fe..9b8381b0f 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -33,10 +33,14 @@ char *r_defaultimageextensions = #if defined(AVAIL_JPEGLIB) || defined(FTE_TARGET_WEB) " jpg" //q3 uses some jpegs, for some reason #endif +#if 0//def IMAGEFMT_PKM + " pkm" //compressed format, but lacks mipmaps which makes it terrible to use. +#endif #ifndef NOLEGACY " pcx" //pcxes are the original gamedata of q2. So we don't want them to override pngs. #endif ; +static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int flags, uploadfmt_t origfmt); static void QDECL R_ImageExtensions_Callback(struct cvar_s *var, char *oldvalue); cvar_t r_imageexensions = CVARCD("r_imageexensions", NULL, R_ImageExtensions_Callback, "The list of image file extensions which fte should attempt to load."); cvar_t r_image_downloadsizelimit = CVARFD("r_image_downloadsizelimit", "131072", CVAR_NOTFROMSERVER, "The maximum allowed file size of images loaded from a web-based url. 0 disables completely, while empty imposes no limit."); @@ -2621,7 +2625,7 @@ typedef struct unsigned int numberofmipmaplevels; unsigned int bytesofkeyvaluedata; } ktxheader_t; -static qboolean Image_ReadKTXFile(texid_t tex, unsigned int flags, char *fname, qbyte *filedata, size_t filesize) +static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fname, qbyte *filedata, size_t filesize) { static const char magic[12] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A}; ktxheader_t *header; @@ -2629,13 +2633,13 @@ static qboolean Image_ReadKTXFile(texid_t tex, unsigned int flags, char *fname, int mipnum; int face; int datasize; - unsigned int w, h, x, y; + unsigned int w, h; struct pendingtextureinfo *mips; int encoding; - qbyte *out, *in; + qbyte *in; if (memcmp(filedata, magic, sizeof(magic))) - return false; //not a ktx file + return NULL; //not a ktx file header = (ktxheader_t*)filedata; nummips = header->numberofmipmaplevels; @@ -2643,76 +2647,94 @@ static qboolean Image_ReadKTXFile(texid_t tex, unsigned int flags, char *fname, nummips = 1; if (header->numberofarrayelements != 0) - return false; //don't support array textures + return NULL; //don't support array textures if (header->numberoffaces == 1) ; //non-cubemap else if (header->numberoffaces == 6) { if (header->pixeldepth != 0) - return false; - if (header->numberofmipmaplevels != 1) - return false; //only allow cubemaps that have no mips + return NULL; +// if (header->numberofmipmaplevels != 1) +// return false; //only allow cubemaps that have no mips } else - return false; //don't allow weird cubemaps + return NULL; //don't allow weird cubemaps if (header->pixeldepth && header->pixelwidth != header->pixeldepth && header->pixelheight != header->pixeldepth) - return false; //we only support 3d textures where width+height+depth are the same. too lazy to change it now. + return NULL; //we only support 3d textures where width+height+depth are the same. too lazy to change it now. switch(header->glinternalformat) { - case 0x8D64/*GL_ETC1_RGB8_OES*/: - encoding = PTI_ETC1_RGB8; - break; - case 0x9274/*GL_COMPRESSED_RGB8_ETC2*/: - case 0x9275/*GL_COMPRESSED_SRGB8_ETC2*/: - encoding = PTI_ETC2_RGB8; - break; - case 0x9276/*GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2*/: - case 0x9277/*GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2*/: - encoding = PTI_ETC2_RGB8A1; - break; - case 0x9278/*GL_COMPRESSED_RGBA8_ETC2_EAC*/: - case 0x9279/*GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC*/: - encoding = PTI_ETC2_RGB8A8; - break; - case 0x83F0/*GL_COMPRESSED_RGB_S3TC_DXT1_EXT*/: - encoding = PTI_S3RGB1; - break; - case 0x83F1/*GL_COMPRESSED_RGBA_S3TC_DXT1_EXT*/: - encoding = PTI_S3RGBA1; - break; - case 0x83F2/*GL_COMPRESSED_RGBA_S3TC_DXT3_EXT*/: - encoding = PTI_S3RGBA3; - break; - case 0x83F3/*GL_COMPRESSED_RGBA_S3TC_DXT5_EXT*/: - encoding = PTI_S3RGBA5; - break; - case 0x80E1/*GL_BGRA_EXT*/: - encoding = PTI_BGRA8; - break; - case 0x1908/*GL_RGBA*/: - encoding = PTI_RGBA8; - break; - case 0x8C43/*GL_SRGB8_ALPHA8_EXT*/: - encoding = PTI_RGBA8_SRGB; - break; - case 0x8045/*GL_LUMINANCE8_ALPHA8*/: - encoding = PTI_RGBA8; - break; - case 0x8051/*GL_RGB8*/: - encoding = PTI_RGBX8; - break; + case 0x8D64/*GL_ETC1_RGB8_OES*/: encoding = PTI_ETC1_RGB8; break; + case 0x9274/*GL_COMPRESSED_RGB8_ETC2*/: encoding = PTI_ETC2_RGB8; break; + case 0x9275/*GL_COMPRESSED_SRGB8_ETC2*/: encoding = PTI_ETC2_RGB8_SRGB; break; + case 0x9276/*GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2*/: encoding = PTI_ETC2_RGB8A1; break; + case 0x9277/*GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2*/:encoding = PTI_ETC2_RGB8A1_SRGB; break; + case 0x9278/*GL_COMPRESSED_RGBA8_ETC2_EAC*/: encoding = PTI_ETC2_RGB8A8; break; + case 0x9279/*GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC*/: encoding = PTI_ETC2_RGB8A8_SRGB; break; + case 0x83F0/*GL_COMPRESSED_RGB_S3TC_DXT1_EXT*/: encoding = PTI_BC1_RGB; break; + case 0x8C4C/*GL_COMPRESSED_SRGB_S3TC_DXT1_EXT*/: encoding = PTI_BC1_RGB_SRGB; break; + case 0x83F1/*GL_COMPRESSED_RGBA_S3TC_DXT1_EXT*/: encoding = PTI_BC1_RGBA; break; + case 0x8C4D/*GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT*/: encoding = PTI_BC1_RGBA_SRGB; break; + case 0x83F2/*GL_COMPRESSED_RGBA_S3TC_DXT3_EXT*/: encoding = PTI_BC2_RGBA; break; + case 0x8C4E/*GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT*/: encoding = PTI_BC2_RGBA_SRGB; break; + case 0x83F3/*GL_COMPRESSED_RGBA_S3TC_DXT5_EXT*/: encoding = PTI_BC3_RGBA; break; + case 0x8C4F/*GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT*/: encoding = PTI_BC3_RGBA_SRGB; break; + case 0x8DBC/*GL_COMPRESSED_SIGNED_RED_RGTC1*/: encoding = PTI_BC4_R8_SIGNED; break; + case 0x8DBB/*GL_COMPRESSED_RED_RGTC1*/: encoding = PTI_BC4_R8; break; + case 0x8DBE/*GL_COMPRESSED_SIGNED_RG_RGTC2*/: encoding = PTI_BC5_RG8_SIGNED; break; + case 0x8DBD/*GL_COMPRESSED_RG_RGTC2*/: encoding = PTI_BC5_RG8; break; + case 0x8E8F/*GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB*/: encoding = PTI_BC6_RGBF; break; + case 0x8E8E/*GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB*/: encoding = PTI_BC6_RGBF_SIGNED; break; + case 0x8E8C/*GL_COMPRESSED_RGBA_BPTC_UNORM_ARB*/: encoding = PTI_BC7_RGBA; break; + case 0x8E8D/*GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB*/: encoding = PTI_BC7_RGBA_SRGB; break; + case 0x93B0/*GL_COMPRESSED_RGBA_ASTC_4x4_KHR*/: encoding = PTI_ASTC_4X4; break; + case 0x93B1/*GL_COMPRESSED_RGBA_ASTC_5x4_KHR*/: encoding = PTI_ASTC_5X4; break; + case 0x93B2/*GL_COMPRESSED_RGBA_ASTC_5x5_KHR*/: encoding = PTI_ASTC_5X5; break; + case 0x93B3/*GL_COMPRESSED_RGBA_ASTC_6x5_KHR*/: encoding = PTI_ASTC_6X5; break; + case 0x93B4/*GL_COMPRESSED_RGBA_ASTC_6x6_KHR*/: encoding = PTI_ASTC_6X6; break; + case 0x93B5/*GL_COMPRESSED_RGBA_ASTC_8x5_KHR*/: encoding = PTI_ASTC_8X5; break; + case 0x93B6/*GL_COMPRESSED_RGBA_ASTC_8x6_KHR*/: encoding = PTI_ASTC_8X6; break; + case 0x93B7/*GL_COMPRESSED_RGBA_ASTC_10x5_KHR*/: encoding = PTI_ASTC_10X5; break; + case 0x93B8/*GL_COMPRESSED_RGBA_ASTC_10x6_KHR*/: encoding = PTI_ASTC_10X6; break; + case 0x93B9/*GL_COMPRESSED_RGBA_ASTC_8x8_KHR*/: encoding = PTI_ASTC_8X8; break; + case 0x93BA/*GL_COMPRESSED_RGBA_ASTC_10x8_KHR*/: encoding = PTI_ASTC_10X8; break; + case 0x93BB/*GL_COMPRESSED_RGBA_ASTC_10x10_KHR*/: encoding = PTI_ASTC_10X10; break; + case 0x93BC/*GL_COMPRESSED_RGBA_ASTC_12x10_KHR*/: encoding = PTI_ASTC_12X10; break; + case 0x93BD/*GL_COMPRESSED_RGBA_ASTC_12x12_KHR*/: encoding = PTI_ASTC_12X12; break; + case 0x93D0/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR*/: encoding = PTI_ASTC_4X4_SRGB; break; + case 0x93D1/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR*/: encoding = PTI_ASTC_5X4_SRGB; break; + case 0x93D2/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR*/: encoding = PTI_ASTC_5X5_SRGB; break; + case 0x93D3/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR*/: encoding = PTI_ASTC_6X5_SRGB; break; + case 0x93D4/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR*/: encoding = PTI_ASTC_6X6_SRGB; break; + case 0x93D5/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR*/: encoding = PTI_ASTC_8X5_SRGB; break; + case 0x93D6/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR*/: encoding = PTI_ASTC_8X6_SRGB; break; + case 0x93D7/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR*/: encoding = PTI_ASTC_10X5_SRGB; break; + case 0x93D8/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR*/: encoding = PTI_ASTC_10X6_SRGB; break; + case 0x93D9/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR*/: encoding = PTI_ASTC_8X8_SRGB; break; + case 0x93DA/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR*/: encoding = PTI_ASTC_10X8_SRGB; break; + case 0x93DB/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR*/: encoding = PTI_ASTC_10X10_SRGB; break; + case 0x93DC/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR*/: encoding = PTI_ASTC_12X10_SRGB; break; + case 0x93DD/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR*/: encoding = PTI_ASTC_12X12_SRGB; break; + case 0x80E1/*GL_BGRA_EXT*/: encoding = PTI_BGRA8; break; + case 0x1908/*GL_RGBA*/: encoding = PTI_RGBA8; break; + case 0x8C43/*GL_SRGB8_ALPHA8_EXT*/: encoding = PTI_RGBA8_SRGB; break; + case 0x8045/*GL_LUMINANCE8_ALPHA8*/: encoding = PTI_LUMINANCE8_ALPHA8; break; + case 0x8051/*GL_RGB8*/: encoding = PTI_RGB8; break; +// case 0x????/*GL_BGR8_EXT*/: encoding = PTI_BGR8; break; + case GL_RGBA16F_ARB: encoding = PTI_RGBA16F; break; + case GL_RGBA32F_ARB: encoding = PTI_RGBA32F; break; + //note: this could be pretty much anything, including 24bit data. default: Con_Printf("Unsupported ktx internalformat %x in %s\n", header->glinternalformat, fname); - return false; + return NULL; } - if (!sh_config.texfmt[encoding]) - { - Con_Printf("KTX %s: encoding %x not supported on this system\n", fname, header->glinternalformat); - return false; - } +// if (!sh_config.texfmt[encoding]) +// { +// Con_Printf("KTX %s: encoding %x not supported on this system\n", fname, header->glinternalformat); +// return false; +// } mips = Z_Malloc(sizeof(*mips)); mips->mipcount = 0; @@ -2728,6 +2750,9 @@ static qboolean Image_ReadKTXFile(texid_t tex, unsigned int flags, char *fname, filedata += sizeof(*header); //skip the header... filedata += header->bytesofkeyvaluedata; //skip the keyvalue stuff + if (nummips * header->numberoffaces > countof(mips->mip)) + nummips = countof(mips->mip) / header->numberoffaces; + w = header->pixelwidth; h = header->pixelheight; for (mipnum = 0; mipnum < nummips; mipnum++) @@ -2742,38 +2767,6 @@ static qboolean Image_ReadKTXFile(texid_t tex, unsigned int flags, char *fname, mips->mip[mips->mipcount].datasize = datasize; mips->mip[mips->mipcount].width = w; mips->mip[mips->mipcount].height = h; - - //some formats are old and not really supported. we convert. - switch(header->glinternalformat) - { - case 0x8045/*GL_LUMINANCE8_ALPHA8*/: - mips->mip[mips->mipcount].needfree = true; - mips->mip[mips->mipcount].data = out = BZ_Malloc(datasize*2); - mips->mip[mips->mipcount].datasize = datasize * 2; - //fixme: input must be a multiple of 2... - for (y = 0; y < h; y++) - for (x = 0; x < w; x++, out+=4) - { - out[0] = out[1] = out[2] = *in++; - out[3] = *in++; - } - break; - case 0x8051/*GL_RGB8*/: -// case GL_BGR8_EXT: - mips->mip[mips->mipcount].needfree = true; - mips->mip[mips->mipcount].datasize = (datasize/3)*4; - mips->mip[mips->mipcount].data = out = BZ_Malloc((datasize/3)*4); - //fixme: input must be a multiple of 4... - for (y = 0; y < h; y++) - for (x = 0; x < w; x++, out+=4) - { - out[0] = *in++; - out[1] = *in++; - out[2] = *in++; - out[3] = 255; - } - break; - } mips->mipcount++; filedata += datasize; @@ -2784,11 +2777,96 @@ static qboolean Image_ReadKTXFile(texid_t tex, unsigned int flags, char *fname, h = (h+1)>>1; } - if (flags & IF_NOWORKER) - Image_LoadTextureMips(tex, mips, 0, 0); + return mips; +} +#endif + +#ifdef IMAGEFMT_PKM +static struct pendingtextureinfo *Image_ReadPKMFile(unsigned int flags, char *fname, qbyte *filedata, size_t filesize) +{ + struct pendingtextureinfo *mips; + unsigned int encoding, blockbytes; + unsigned short ver, dfmt; + unsigned short datawidth, dataheight; + unsigned short imgwidth, imgheight; + if (filedata[0] != 'P' || filedata[1] != 'K' || filedata[2] != 'M' || filedata[3] != ' ') + return NULL; + ver = (filedata[4]<<8) | filedata[5]; + dfmt = (filedata[6]<<8) | filedata[7]; + datawidth = (filedata[8]<<8) | filedata[9]; + dataheight = (filedata[10]<<8) | filedata[11]; + imgwidth = (filedata[12]<<8) | filedata[13]; + imgheight = (filedata[14]<<8) | filedata[15]; + if (((imgwidth+3)&~3)!=datawidth || ((imgheight+3)&~3)!=dataheight) + return NULL; //these are all 4*4 blocks. + if (ver == ((1<<8)|0) && ver == ((2<<8)|0)) + { + if (dfmt == 0) //should only be in v1 + encoding = PTI_ETC1_RGB8; + //following should only be in v2, but we don't care. + else if (dfmt == 1) + encoding = PTI_ETC2_RGB8; + else if (dfmt == 2) + return NULL; //'old' rgba8 format that's not supported. + else if (dfmt == 3) + encoding = PTI_ETC2_RGB8A8; + else if (dfmt == 4) + encoding = PTI_ETC2_RGB8A1; + else if (dfmt == 5) + encoding = PTI_EAC_R11; + else if (dfmt == 6) + encoding = PTI_EAC_RG11; + else if (dfmt == 7) + encoding = PTI_EAC_R11_SIGNED; + else if (dfmt == 8) + encoding = PTI_EAC_RG11_SIGNED; + else if (dfmt == 9) + encoding = PTI_ETC2_RGB8_SRGB; //srgb + else if (dfmt == 10) + encoding = PTI_ETC2_RGB8A8_SRGB; //srgb + else if (dfmt == 11) + encoding = PTI_ETC2_RGB8A1_SRGB; //srgb + else + return NULL; //unknown/unsupported + } else - COM_AddWork(WG_MAIN, Image_LoadTextureMips, tex, mips, 0, 0); - return true; + return NULL; + + switch(encoding) + { + case PTI_ETC1_RGB8: + case PTI_ETC2_RGB8: + case PTI_ETC2_RGB8_SRGB: + case PTI_ETC2_RGB8A1: + case PTI_ETC2_RGB8A1_SRGB: + case PTI_EAC_R11: + case PTI_EAC_R11_SIGNED: + blockbytes = 8; + break; + case PTI_ETC2_RGB8A8: + case PTI_ETC2_RGB8A8_SRGB: + case PTI_EAC_RG11: + case PTI_EAC_RG11_SIGNED: + blockbytes = 16; + break; + default: + return NULL; + } + + if (16+(datawidth/4)*(dataheight/4)*blockbytes != filesize) + return NULL; //err, not the right size! + + mips = Z_Malloc(sizeof(*mips)); + mips->mipcount = 1; //this format doesn't support mipmaps. so there's only one level. + mips->type = PTI_2D; + mips->extrafree = filedata; + mips->encoding = encoding; + mips->mip[0].data = filedata+16; + mips->mip[0].datasize = filesize-16; + mips->mip[0].width = imgwidth; + mips->mip[0].height = imgheight; + mips->mip[0].needfree = false; + return mips; } #endif @@ -2814,26 +2892,37 @@ typedef struct { unsigned int ddsCaps[4]; unsigned int dwReserved2; } ddsheader; +typedef struct { + unsigned int dxgiformat; + unsigned int resourcetype; //0=unknown, 1=buffer, 2=1d, 3=2d, 4=3d + unsigned int miscflag; //singular... yeah. 4=cubemap. + unsigned int arraysize; + unsigned int miscflags2; +} dds10header_t; - -static qboolean Image_ReadDDSFile(texid_t tex, unsigned int flags, char *fname, qbyte *filedata, size_t filesize) +static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, char *fname, qbyte *filedata, size_t filesize) { int nummips; int mipnum; int datasize; - int pad; +// int pad; unsigned int w, h; - int divsize, blocksize; + unsigned int blockwidth, blockheight, blockbytes; struct pendingtextureinfo *mips; int encoding; + int layers = 1, layer; ddsheader fmtheader; + dds10header_t fmt10header; + if (*(int*)filedata != (('D'<<0)|('D'<<8)|('S'<<16)|(' '<<24))) - return false; + return NULL; memcpy(&fmtheader, filedata+4, sizeof(fmtheader)); if (fmtheader.dwSize != sizeof(fmtheader)) - return false; //corrupt/different version + return NULL; //corrupt/different version + memset(&fmt10header, 0, sizeof(fmt10header)); + fmt10header.arraysize = 1; nummips = fmtheader.dwMipMapCount; if (nummips < 1) @@ -2841,58 +2930,130 @@ static qboolean Image_ReadDDSFile(texid_t tex, unsigned int flags, char *fname, if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24))) { - encoding = PTI_S3RGBA1; //alpha or not? Assume yes, and let the drivers decide. - pad = 8; - divsize = 4; - blocksize = 8; + encoding = PTI_BC1_RGBA; //alpha or not? Assume yes, and let the drivers decide. +// pad = 8; } else if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('2'<<24))) //dx3 with premultiplied alpha { // if (!(tex->flags & IF_PREMULTIPLYALPHA)) // return false; - encoding = PTI_S3RGBA3; - pad = 8; - divsize = 4; - blocksize = 16; + encoding = PTI_BC2_RGBA; +// pad = 8; } else if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('3'<<24))) { // if (tex->flags & IF_PREMULTIPLYALPHA) // return false; - encoding = PTI_S3RGBA3; - pad = 8; - divsize = 4; - blocksize = 16; + encoding = PTI_BC2_RGBA; +// pad = 8; } else if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('4'<<24))) //dx5 with premultiplied alpha { // if (!(tex->flags & IF_PREMULTIPLYALPHA)) // return false; - encoding = PTI_S3RGBA5; - pad = 8; - divsize = 4; - blocksize = 16; + encoding = PTI_BC3_RGBA; +// pad = 8; } else if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('5'<<24))) { // if (tex->flags & IF_PREMULTIPLYALPHA) // return false; - encoding = PTI_S3RGBA5; - pad = 8; - divsize = 4; - blocksize = 16; + encoding = PTI_BC3_RGBA; +// pad = 8; + } + else if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('E'<<0)|('T'<<8)|('C'<<16)|('2'<<24))) + { + encoding = PTI_ETC2_RGB8; +// pad = 8; + } + else if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('1'<<16)|('0'<<24))) + { + //this has some weird extra header with dxgi format types. + memcpy(&fmt10header, filedata+4+fmtheader.dwSize, sizeof(fmt10header)); + fmtheader.dwSize += sizeof(fmt10header); +// pad = 8; + switch(fmt10header.dxgiformat) + { + case 71/*DXGI_FORMAT_BC1_UNORM*/: + encoding = PTI_BC1_RGBA; + break; + case 72/*DXGI_FORMAT_BC1_UNORM_SRGB*/: + encoding = PTI_BC1_RGBA_SRGB; + break; + case 74/*DXGI_FORMAT_BC2_UNORM*/: + encoding = PTI_BC2_RGBA; + break; + case 75/*DXGI_FORMAT_BC2_UNORM_SRGB*/: + encoding = PTI_BC2_RGBA_SRGB; + break; + case 77/*DXGI_FORMAT_BC3_UNORM*/: + encoding = PTI_BC3_RGBA; + break; + case 78/*DXGI_FORMAT_BC3_UNORM_SRGB*/: + encoding = PTI_BC3_RGBA_SRGB; + break; + case 80/*DXGI_FORMAT_BC4_UNORM*/: + encoding = PTI_BC4_R8; + break; + case 81/*DXGI_FORMAT_BC4_SNORM*/: + encoding = PTI_BC4_R8_SIGNED; + break; + case 83/*DXGI_FORMAT_BC5_UNORM*/: + encoding = PTI_BC5_RG8; + break; + case 84/*DXGI_FORMAT_BC5_SNORM*/: + encoding = PTI_BC5_RG8_SIGNED; + break; + case 95/*DXGI_FORMAT_BC6H_UF16*/: + encoding = PTI_BC6_RGBF; + break; + case 96/*DXGI_FORMAT_BC6H_SF16*/: + encoding = PTI_BC6_RGBF_SIGNED; + break; + case 98/*DXGI_FORMAT_BC7_UNORM*/: + encoding = PTI_BC7_RGBA; + break; + case 99/*DXGI_FORMAT_BC7_UNORM_SRGB*/: + encoding = PTI_BC7_RGBA_SRGB; + break; + + default: + Con_Printf("Unsupported dds10 dxgi in %s - %u\n", fname, fmt10header.dxgiformat); + return NULL; + } } else { - Con_Printf("Unsupported dds fourcc in %s\n", fname); - return false; + Con_Printf("Unsupported dds fourcc in %s - \"%c%c%c%c\"\n", fname, + ((char*)&fmtheader.ddpfPixelFormat.dwFourCC)[0], + ((char*)&fmtheader.ddpfPixelFormat.dwFourCC)[1], + ((char*)&fmtheader.ddpfPixelFormat.dwFourCC)[2], + ((char*)&fmtheader.ddpfPixelFormat.dwFourCC)[3]); + return NULL; } + if ((fmtheader.ddsCaps[1] & 0x200) && (fmtheader.ddsCaps[1] & 0xfc00) != 0xfc00) + return NULL; //cubemap without all 6 faces defined. + if (fmtheader.ddsCaps[1] & 0x200000) + return NULL; //3d texture. fte internally interleaves layers on the x axis. I'll bet dds does not. + + Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight); + if (!blockbytes) + return NULL; //werid/unsupported + mips = Z_Malloc(sizeof(*mips)); mips->mipcount = 0; - mips->type = PTI_2D; + if (fmtheader.ddsCaps[1] & 0x200) + { + layers = 6; + mips->type = PTI_CUBEMAP; + } + else if (fmtheader.ddsCaps[1] & 0x200000) + mips->type = PTI_3D; + else + mips->type = PTI_2D; mips->extrafree = filedata; mips->encoding = encoding; @@ -2903,34 +3064,32 @@ static qboolean Image_ReadDDSFile(texid_t tex, unsigned int flags, char *fname, h = fmtheader.dwHeight; for (mipnum = 0; mipnum < nummips; mipnum++) { - if (nummips >= countof(mips->mip)) + if (mips->mipcount >= countof(mips->mip)) break; - if (datasize < pad) - datasize = pad; - datasize = ((w+divsize-1)/divsize) * ((h+divsize-1)/divsize) * blocksize; +// if (datasize < 8) +// datasize = pad; + datasize = ((w+blockwidth-1)/blockwidth) * ((h+blockheight-1)/blockheight) * blockbytes; - mips->mip[mipnum].data = filedata; - mips->mip[mipnum].datasize = datasize; - mips->mip[mipnum].width = w; - mips->mip[mipnum].height = h; - filedata += datasize; + for (layer = 0; layer < layers; layer++) + { + mips->mip[mips->mipcount].data = filedata; + mips->mip[mips->mipcount].datasize = datasize; + mips->mip[mips->mipcount].width = w; + mips->mip[mips->mipcount].height = h; + mips->mipcount++; + filedata += datasize; + } w = (w+1)>>1; h = (h+1)>>1; } - mips->mipcount = mipnum; - - if (flags & IF_NOWORKER) - Image_LoadTextureMips(tex, mips, 0, 0); - else - COM_AddWork(WG_MAIN, Image_LoadTextureMips, tex, mips, 0, 0); - return true; + return mips; } #endif #ifdef IMAGEFMT_BLP -static qboolean Image_ReadBLPFile(texid_t tex, unsigned int flags, char *fname, qbyte *filedata, size_t filesize) +static struct pendingtextureinfo *Image_ReadBLPFile(unsigned int flags, char *fname, qbyte *filedata, size_t filesize) { //FIXME: cba with endian. int miplevel; @@ -2958,7 +3117,7 @@ static qboolean Image_ReadBLPFile(texid_t tex, unsigned int flags, char *fname, blp = (void*)filedata; if (memcmp(blp->blp2, "BLP2", 4) || blp->type != 1) - return false; + return NULL; mips = Z_Malloc(sizeof(*mips)); mips->mipcount = 0; @@ -2975,15 +3134,15 @@ static qboolean Image_ReadBLPFile(texid_t tex, unsigned int flags, char *fname, default: case 0: //dxt1 if (blp->alphadepth) - mips->encoding = PTI_S3RGBA1; + mips->encoding = PTI_BC1_RGBA; else - mips->encoding = PTI_S3RGB1; + mips->encoding = PTI_BC1_RGB; break; case 1: //dxt2/3 - mips->encoding = PTI_S3RGBA3; + mips->encoding = PTI_BC2_RGBA; break; case 7: //dxt4/5 - mips->encoding = PTI_S3RGBA5; + mips->encoding = PTI_BC3_RGBA; break; } for (miplevel = 0; miplevel < 16; ) @@ -3092,15 +3251,7 @@ static qboolean Image_ReadBLPFile(texid_t tex, unsigned int flags, char *fname, BZ_Free(filedata); mips->mipcount = miplevel; } - - tex->width = w; - tex->height = h; - if (flags & IF_NOWORKER) - Image_LoadTextureMips(tex, mips, 0, 0); - else - COM_AddWork(WG_MAIN, Image_LoadTextureMips, tex, mips, 0, 0); - - return true; + return mips; } #endif @@ -3752,12 +3903,12 @@ static void Image_RoundDimensions(int *scaled_width, int *scaled_height, unsigne TRACE(("dbg: GL_RoundDimensions: %f\n", gl_max_size.value)); - if (sh_config.texture_maxsize) + if (sh_config.texture2d_maxsize) { - if (*scaled_width > sh_config.texture_maxsize) - *scaled_width = sh_config.texture_maxsize; - if (*scaled_height > sh_config.texture_maxsize) - *scaled_height = sh_config.texture_maxsize; + if (*scaled_width > sh_config.texture2d_maxsize) + *scaled_width = sh_config.texture2d_maxsize; + if (*scaled_height > sh_config.texture2d_maxsize) + *scaled_height = sh_config.texture2d_maxsize; } if (!(flags & (IF_UIPIC|IF_RENDERTARGET))) { @@ -3934,6 +4085,668 @@ static void Image_8_BGR_RGB_Swap(qbyte *data, unsigned int w, unsigned int h) } } +typedef union +{ + byte_vec4_t v; + unsigned int u; +} pixel32_t; +#ifdef DECOMPRESS_ETC2 +//FIXME: this is littleendian only... +static void Image_ETC2_Decode_Block_TH_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w, pixel32_t base1, pixel32_t base2, int d, qboolean tmode) +{ + pixel32_t painttable[4]; + int dtab[] = {3,6,11,16,23,32,41,64}; //writing that felt like giving out lottery numbers. +#define etc_addclamptopixel(r,p,d) r.v[0]=bound(0,p.v[0]+d, 255),r.v[1]=bound(0,p.v[1]+d, 255),r.v[2]=bound(0,p.v[2]+d, 255),r.v[3]=0xff + d = dtab[d]; + if (tmode) + { + painttable[0].u = base1.u; + etc_addclamptopixel(painttable[1], base2, d); + painttable[2].u = base2.u; + etc_addclamptopixel(painttable[3], base2, -d); + } + else + { + etc_addclamptopixel(painttable[0], base1, d); + etc_addclamptopixel(painttable[1], base1, -d); + etc_addclamptopixel(painttable[2], base2, d); + etc_addclamptopixel(painttable[3], base2, -d); + } +#undef etc_addclamptoint + //yay, we have our painttable. now use it. also, screw that msb/lsb split. + +#define etc2_th_pix(r,i) \ + if (in[5-(i/8)]&(1<<(i&7))) { \ + if (in[7-(i/8)]&(1<<(i&7))) r.u = painttable[3].u; \ + else r.u = painttable[2].u; \ + } else { \ + if (in[7-(i/8)]&(1<<(i&7))) r.u = painttable[1].u; \ + else r.u = painttable[0].u; \ + } + + etc2_th_pix(out[0], 0); + etc2_th_pix(out[1], 4); + etc2_th_pix(out[2], 8); + etc2_th_pix(out[3], 12); + out += w; + etc2_th_pix(out[0], 1); + etc2_th_pix(out[1], 5); + etc2_th_pix(out[2], 9); + etc2_th_pix(out[3], 13); + out += w; + etc2_th_pix(out[0], 2); + etc2_th_pix(out[1], 6); + etc2_th_pix(out[2], 10); + etc2_th_pix(out[3], 14); + out += w; + etc2_th_pix(out[0], 3); + etc2_th_pix(out[1], 7); + etc2_th_pix(out[2], 11); + etc2_th_pix(out[3], 15); +#undef etc2_th_pix +} +static void Image_ETC2_Decode_Block_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out0, int w, int alphamode) +{ + static const char tab[8][2] = + { + {2,8}, + {5,17}, + {9,29}, + {13,42}, + {18,60}, + {24,80}, + {33,106}, + {47,183} + }; + int tv; + pixel32_t base1, base2, base3; + const char *cw1, *cw2; + unsigned char R1,G1,B1; + pixel32_t *out1, *out2, *out3; + +#define etc_expandv(p,x,y,z) p.v[0]|=p.v[0]>>x,p.v[1]|=p.v[1]>>y,p.v[2]|=p.v[2]>>z + + qboolean opaque; + + if (alphamode) + opaque = in[3]&2; + else + opaque = 1; + + if (alphamode || (in[3]&2)) //diffbit, bit 33 + { + R1=(in[0]>>3)&31;//59+5 + G1=(in[1]>>3)&31;//51+5 + B1=(in[2]>>3)&31;//43+5 + VectorSet(base1.v, (R1<<3)+(R1>>2), (G1<<3)+(G1>>2), (B1<<3)+(B1>>2)); + R1 += (char)((in[0]&3)|((in[0]&4)*0x3f)); //56+3 + if (R1&~0x1f) //R2 overflow = T mode + { + Vector4Set(base1.v, ((in[0]&0x18)<<3) | ((in[0]&0x3)<<4), (in[1]&0xf0), ((in[1]&0x0f)<<4), 0xff); + Vector4Set(base2.v, (in[2]&0xf0), ((in[2]&0x0f)<<4), (in[3]&0xf0), 0xff); + tv = ((in[3]&0x0c)>>1)|(in[3]&0x01); + etc_expandv(base1,4,4,4); + etc_expandv(base2,4,4,4); + Image_ETC2_Decode_Block_TH_Internal(in, out0, w, base1, base2, tv, true); + return; + } + G1 += (char)((in[1]&3)|((in[1]&4)*0x3f)); //48+3 + if (G1&~0x1f) //G2 overflow = H mode + { + Vector4Set(base1.v, ((in[0]&0x78)<<1), ((in[0]&0x07)<<5)|((in[1]&0x10)<<0), ((in[1]&0x08)<<4)|((in[1]&0x03)<<5)|((in[2]&0x80)>>3), 0xff); + Vector4Set(base2.v, ((in[2]&0x78)<<1), ((in[2]&0x07)<<5)|((in[3]&0x80)>>3), ((in[3]&0x78)<<1), 0xff); + tv = ((in[3]&0x04)>>1)|(in[3]&0x01); + etc_expandv(base1,4,4,4); + etc_expandv(base2,4,4,4); + Image_ETC2_Decode_Block_TH_Internal(in, out0, w, base1, base2, tv, false); + return; + } + B1 += (char)((in[2]&3)|((in[2]&4)*0x3f)); //40+3 + if (B1&~0x1f) //B2 overflow = Planar mode + {//origin horizontal, vertical delas, interpolated across the 16 pixels + VectorSet(base1.v, ((in[0]&0x7f)<<1),((in[0]&0x01)<<7)|((in[1])&0x7e),(in[1]<<7)|((in[2]&0x18)<<2)|((in[2]&0x3)<<3)|((in[3]&0x80)>>5)); + VectorSet(base2.v, ((in[3]&0x7c)<<1)|((in[3]&0x01)<<2),(in[4]&0xfe),((in[4]&1)<<7)|((in[5]&0xf8)>>1)); + VectorSet(base3.v, ((in[5]&0x07)<<5)|((in[6]&0xe0)>>3),((in[6]&0x1f)<<3)|((in[7]&0xc0)>>5),(in[7]&0x3f)<<2); + etc_expandv(base1,6,7,6); + etc_expandv(base2,6,7,6); + etc_expandv(base3,6,7,6); +#define etc2_planar2(r,x,y) \ + r[x].v[0] = bound(0,(4*base1.v[0] + x*((short)base2.v[0]-base1.v[0]) + y*((short)base3.v[0]-base1.v[0]) + 2)>>2,0xff), \ + r[x].v[1] = bound(0,(4*base1.v[1] + x*((short)base2.v[1]-base1.v[1]) + y*((short)base3.v[1]-base1.v[1]) + 2)>>2,0xff), \ + r[x].v[2] = bound(0,(4*base1.v[2] + x*((short)base2.v[2]-base1.v[2]) + y*((short)base3.v[2]-base1.v[2]) + 2)>>2,0xff), \ + r[x].v[3] = 0xff +#define etc2_planar(r,y) \ + etc2_planar2(r,0,y); \ + etc2_planar2(r,1,y); \ + etc2_planar2(r,2,y); \ + etc2_planar2(r,3,y); + etc2_planar(out0,0);out0 += w; + etc2_planar(out0,1);out0 += w; + etc2_planar(out0,2);out0 += w; + etc2_planar(out0,3); + return; + } + //they should still be 5 bits. + VectorSet(base2.v, (R1<<3)+(R1>>2), (G1<<3)+(G1>>2), (B1<<3)+(B1>>2)); + } + else + { + VectorSet(base1.v, ((in[0]>>4)&15)*0x11, /*60+4*/ + ((in[1]>>4)&15)*0x11, /*52+4*/ + ((in[2]>>4)&15)*0x11); /*44+4*/ + VectorSet(base2.v, ((in[0]>>0)&15)*0x11, /*56+4*/ + ((in[1]>>0)&15)*0x11, /*48+4*/ + ((in[2]>>0)&15)*0x11); /*40+4*/ + } + + cw1 = tab[(in[3]>>5)&7]; //37+3 + cw2 = tab[(in[3]>>2)&7]; //34+3 + + out1 = out0+w*1; + out2 = out0+w*2; + out3 = out0+w*3; + +#define etc1_pix(r, base,cw,i) \ + if (in[7-(i/8)]&(1<<(i&7))) \ + tv = (in[5-(i/8)]&(1<<(i&7)))?-cw[1]:cw[1]; \ + else if (opaque) \ + tv = (in[5-(i/8)]&(1<<(i&7)))?-cw[0]:cw[0]; \ + else /*punchthrough alpha mode*/ \ + tv = (in[5-(i/8)]&(1<<(i&7)))?-255:0; \ + if (tv==-255) \ + r.u = 0; \ + else \ + r.v[0] = bound(0,base.v[0]+tv,0xff), \ + r.v[1] = bound(0,base.v[1]+tv,0xff), \ + r.v[2] = bound(0,base.v[2]+tv,0xff), \ + r.v[3] = 0xff + + etc1_pix(out0[0], base1,cw1,0); + etc1_pix(out0[1], base1,cw1,4); + etc1_pix(out1[0], base1,cw1,1); + etc1_pix(out1[1], base1,cw1,5); + + etc1_pix(out2[2], base2,cw2,10); + etc1_pix(out2[3], base2,cw2,14); + etc1_pix(out3[2], base2,cw2,11); + etc1_pix(out3[3], base2,cw2,15); + if (in[3]&1) //flipbit bit 32 - blocks are vertical + { + etc1_pix(out0[2], base1,cw1,8); + etc1_pix(out0[3], base1,cw1,12); + etc1_pix(out1[2], base1,cw1,9); + etc1_pix(out1[3], base1,cw1,13); + + etc1_pix(out2[0], base2,cw2,2); + etc1_pix(out2[1], base2,cw2,6); + etc1_pix(out3[0], base2,cw2,3); + etc1_pix(out3[1], base2,cw2,7); + } + else + { + etc1_pix(out0[2], base2,cw2,8); + etc1_pix(out0[3], base2,cw2,12); + etc1_pix(out1[2], base2,cw2,9); + etc1_pix(out1[3], base2,cw2,13); + + etc1_pix(out2[0], base1,cw1,2); + etc1_pix(out2[1], base1,cw1,6); + etc1_pix(out3[0], base1,cw1,3); + etc1_pix(out3[1], base1,cw1,7); + } +#undef etc1_pix +} +static void Image_EAC8U_Decode_Block_Internal(qbyte *fte_restrict in, qbyte *fte_restrict out, int stride, qboolean goestoeleven) +{ + static const char tabs[16][8] = + { + {-3,-6, -9,-15,2,5,8,14}, + {-3,-7,-10,-13,2,6,9,12}, + {-2,-5, -8,-13,1,4,7,12}, + {-2,-4, -6,-13,1,3,5,12}, + {-3,-6, -8,-12,2,5,7,11}, + {-3,-7, -9,-11,2,6,8,10}, + {-4,-7, -8,-11,3,6,7,10}, + {-3,-5, -8,-11,2,4,7,10}, + {-2,-6, -8,-10,1,5,7,9}, + {-3,-5, -8,-10,1,4,7,9}, + {-2,-4, -8,-10,1,3,7,9}, + {-2,-5, -7,-10,1,4,6,9}, + {-3,-4, -7,-10,2,3,6,9}, + {-1,-2, -3,-10,0,1,2,9}, + {-4,-6, -8, -9,3,5,7,8}, + {-3,-5, -7, -9,2,4,6,8}, + }; + + const qbyte base = in[0]; + const qbyte mul = in[1]>>4; + const char *tab = tabs[in[1]&0xf]; + const quint64_t bits = in[2] | (in[3]<<8) | (in[4]<<16) | (in[5]<<24) | ((quint64_t)in[6]<<32) | ((quint64_t)in[7]<<40); + +#define EAC_Pix(r,x,y) r = bound(0, base + tab[(bits>>((x*4+y)*3))&7] * mul, 255); +#define EAC_Row(y) EAC_Pix(out[0], 0,y);EAC_Pix(out[1], 1,y);EAC_Pix(out[2], 2,y);EAC_Pix(out[3], 3,y); + EAC_Row(0);out += stride;EAC_Row(1);out += stride;EAC_Row(2);out += stride;EAC_Row(3); +#undef EAC_Row +#undef EAC_Pix +} +static void Image_ETC2_RGB8_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + Image_ETC2_Decode_Block_Internal(in, out, w, false); +} +//punchthrough alpha works by removing interleaved mode releasing a bit that says whether a block can have alpha=0, . +static void Image_ETC2_RGB8A1_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + Image_ETC2_Decode_Block_Internal(in, out, w, true); +} +//ETC2 RGBA's alpha and R11(and RG11) work the same way as each other, but with varying extra blocks with either 8 or 11 bits of valid precision. +static void Image_ETC2_RGB8A8_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + Image_ETC2_Decode_Block_Internal(in+8, out, w, false); + Image_EAC8U_Decode_Block_Internal(in, out->v+3, w*4, false); +} +static void Image_EAC_R11U_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + pixel32_t r; + int i = 0; + Vector4Set(r.v, 0, 0, 0, 0xff); + for (i = 0; i < 4; i++) + out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; + Image_EAC8U_Decode_Block_Internal(in, out->v, w*4, false); +} +static void Image_EAC_RG11U_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + pixel32_t r; + int i = 0; + Vector4Set(r.v, 0, 0, 0, 0xff); + for (i = 0; i < 4; i++) + out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; + Image_EAC8U_Decode_Block_Internal(in, out->v+0, w*4, false); + Image_EAC8U_Decode_Block_Internal(in+8, out->v+1, w*4, false); +} +#endif + +#ifdef DECOMPRESS_S3TC +static void Image_S3TC_Decode_Block_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w, qbyte blackalpha) +{ + pixel32_t tab[4]; + unsigned int bits; + + Vector4Set(tab[0].v, (in[1]&0xf8), ((in[0]&0xe0)>>3)|((in[1]&7)<<5), (in[0]&0x1f)<<3, 0xff); + etc_expandv(tab[0],5,6,5); + Vector4Set(tab[1].v, (in[3]&0xf8), ((in[2]&0xe0)>>3)|((in[3]&7)<<5), (in[2]&0x1f)<<3, 0xff); + etc_expandv(tab[1],5,6,5); + +#define BC1_Lerp(a,as,b,bs,div,c) ((c)[0]=((a)[0]*(as)+(b)[0]*(bs))/(div),(c)[1]=((a)[1]*(as)+(b)[1]*(bs))/(div), (c)[2]=((a)[2]*(as)+(b)[2]*(bs))/(div), (c)[3] = 0xff) + if ((in[0]|(in[1]<<8)) > (in[2]|(in[3]<<8))) + { + BC1_Lerp(tab[0].v,2, tab[1].v,1, 3,tab[2].v); + BC1_Lerp(tab[0].v,1, tab[1].v,2, 3,tab[3].v); + } + else + { + BC1_Lerp(tab[0].v,1, tab[1].v,1, 2,tab[2].v); + Vector4Set(tab[3].v, 0, 0, 0, blackalpha); + } + + bits = in[4] | (in[5]<<8) | (in[6]<<16) | (in[7]<<24); + +#define BC1_Pix(r,i) r.u = tab[(bits>>(i*2))&3].u; + + BC1_Pix(out[0], 0); + BC1_Pix(out[1], 1); + BC1_Pix(out[2], 2); + BC1_Pix(out[3], 3); + out += w; + BC1_Pix(out[0], 4); + BC1_Pix(out[1], 5); + BC1_Pix(out[2], 6); + BC1_Pix(out[3], 7); + out += w; + BC1_Pix(out[0], 8); + BC1_Pix(out[1], 9); + BC1_Pix(out[2], 10); + BC1_Pix(out[3], 11); + out += w; + BC1_Pix(out[0], 12); + BC1_Pix(out[1], 13); + BC1_Pix(out[2], 14); + BC1_Pix(out[3], 15); +} +static void Image_BC1_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + Image_S3TC_Decode_Block_Internal(in, out, w, 0xff); +} +static void Image_BC1A_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + Image_S3TC_Decode_Block_Internal(in, out, w, 0); +} +static void Image_BC2_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + Image_S3TC_Decode_Block_Internal(in+8, out, w, 0xff); + + //BC2 has straight 4-bit alpha. +#define BC2_AlphaRow() \ + out[0].v[3] = in[0]&0x0f; out[0].v[3] |= out[0].v[3]<<4; \ + out[1].v[3] = in[0]&0xf0; out[1].v[3] |= out[1].v[3]>>4; \ + out[2].v[3] = in[1]&0x0f; out[2].v[3] |= out[2].v[3]<<4; \ + out[3].v[3] = in[1]&0xf0; out[3].v[3] |= out[3].v[3]>>4; + + BC2_AlphaRow(); + in += 2;out += w; + BC2_AlphaRow(); + in += 2;out += w; + BC2_AlphaRow(); + in += 2;out += w; + BC2_AlphaRow(); +#undef BC2_AlphaRow +} +#endif +#ifdef DECOMPRESS_RGTC +static void Image_RGTC_Decode_Block_Internal(qbyte *fte_restrict in, qbyte *fte_restrict out, int stride, qboolean issigned) +{ + quint64_t bits; + union + { + qbyte u; + char s; + } tab[8]; + tab[0].u = in[0]; + tab[1].u = in[1]; + if (issigned) + { + if (tab[0].s > tab[1].s) + { + tab[2].s = (tab[0].s*6 + tab[1].s*1)/7; + tab[3].s = (tab[0].s*5 + tab[1].s*2)/7; + tab[4].s = (tab[0].s*4 + tab[1].s*3)/7; + tab[5].s = (tab[0].s*3 + tab[1].s*4)/7; + tab[6].s = (tab[0].s*2 + tab[1].s*5)/7; + tab[7].s = (tab[0].s*1 + tab[1].s*6)/7; + } + else + { + tab[2].s = (tab[0].s*4 + tab[1].s*1)/5; + tab[3].s = (tab[0].s*3 + tab[1].s*2)/5; + tab[4].s = (tab[0].s*2 + tab[1].s*3)/5; + tab[5].s = (tab[0].s*1 + tab[1].s*4)/5; + tab[6].s = -128; + tab[7].s = 127; + } + } + else + { + if (tab[0].u > tab[1].u) + { + tab[2].u = (tab[0].u*6 + tab[1].u*1)/7; + tab[3].u = (tab[0].u*5 + tab[1].u*2)/7; + tab[4].u = (tab[0].u*4 + tab[1].u*3)/7; + tab[5].u = (tab[0].u*3 + tab[1].u*4)/7; + tab[6].u = (tab[0].u*2 + tab[1].u*5)/7; + tab[7].u = (tab[0].u*1 + tab[1].u*6)/7; + } + else + { + tab[2].u = (tab[0].u*4 + tab[1].u*1)/5; + tab[3].u = (tab[0].u*3 + tab[1].u*2)/5; + tab[4].u = (tab[0].u*2 + tab[1].u*3)/5; + tab[5].u = (tab[0].u*1 + tab[1].u*4)/5; + tab[6].u = 0; + tab[7].u = 0xff; + } + } + + bits = in[2] | (in[3]<<8) | (in[4]<<16) | (in[5]<<24) | ((quint64_t)in[6]<<32) | ((quint64_t)in[7]<<40); + +#define BC3AU_Pix(r,i) r = tab[(bits>>((i)*3))&7].u; +#define BC3AU_Row(i) BC3AU_Pix(out[0], i+0);BC3AU_Pix(out[4], i+1);BC3AU_Pix(out[8], i+2);BC3AU_Pix(out[12], i+3); + BC3AU_Row(0);out += stride;BC3AU_Row(4);out += stride;BC3AU_Row(8);out += stride;BC3AU_Row(12); +#undef BC3AU_Pix +} +#ifdef DECOMPRESS_S3TC +//s3tc rgb channel, with an rgtc alpha channel that depends upon both encodings (really the origin of rgtc, but mneh). +static void Image_BC3_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + Image_S3TC_Decode_Block_Internal(in+8, out, w, 0xff); + Image_RGTC_Decode_Block_Internal(in, out->v+3, w*4, false); +} +#endif +static void Image_BC4U_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ //BC4: BC3's alpha channel but used as red only. + pixel32_t r; + int i = 0; + Vector4Set(r.v, 0, 0, 0, 0xff); + for (i = 0; i < 4; i++) + out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; + Image_RGTC_Decode_Block_Internal(in, out->v+0, w*4, false); +} +static void Image_BC4S_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ //BC4: BC3's alpha channel but used as red only. + pixel32_t r; + int i = 0; + Vector4Set(r.v, 0, 0, 0, 0xff); + for (i = 0; i < 4; i++) + out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; + Image_RGTC_Decode_Block_Internal(in, out->v+0, w*4, true); +} +static void Image_BC5U_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ //BC5: two of BC3's alpha channels but used as red+green only. + pixel32_t r; + int i = 0; + Vector4Set(r.v, 0, 0, 0, 0xff); + for (i = 0; i < 4; i++) + out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; + Image_RGTC_Decode_Block_Internal(in+0, out->v+0, w*4, false); + Image_RGTC_Decode_Block_Internal(in+8, out->v+1, w*4, false); +} +static void Image_BC5S_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ //BC5: two of BC3's alpha channels but used as red+green only. + pixel32_t r; + int i = 0; + Vector4Set(r.v, 0, 0, 0, 0xff); + for (i = 0; i < 4; i++) + out[w*0+i] = out[w*1+i] = out[w*2+i] = out[w*3+i] = r; + Image_RGTC_Decode_Block_Internal(in+0, out->v+0, w*4, true); + Image_RGTC_Decode_Block_Internal(in+8, out->v+1, w*4, true); +} +#endif + +static void Image_RGB8_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + Vector4Set(out->v, in[0], in[1], in[2], 0xff); +} +static void Image_LUMA8_Decode_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) +{ + Vector4Set(out->v, in[0], in[0], in[0], 0xff); +} + +void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, unsigned int *blockwidth, unsigned int *blockheight) +{ + unsigned int b, w = 1, h = 1; + switch(encoding) + { + case PTI_RGB565: + case PTI_RGBA4444: + case PTI_ARGB4444: + case PTI_RGBA5551: + case PTI_ARGB1555: + b = 2; //16bit formats + break; + case PTI_RGBA8: + case PTI_RGBX8: + case PTI_BGRA8: + case PTI_BGRX8: + case PTI_RGBA8_SRGB: + case PTI_RGBX8_SRGB: + case PTI_BGRA8_SRGB: + case PTI_BGRX8_SRGB: + b = 4; + break; + + case PTI_RGBA16F: + b = 4*2; + break; + case PTI_RGBA32F: + b = 4*4; + break; + case PTI_R8: + case PTI_R8_SIGNED: + b = 1; + break; + case PTI_RG8: + case PTI_RG8_SIGNED: + b = 2; + break; + + case PTI_DEPTH16: + b = 2; + break; + case PTI_DEPTH24: + b = 3; + break; + case PTI_DEPTH32: + b = 4; + break; + case PTI_DEPTH24_8: + b = 4; + break; + + case PTI_RGB8: + b = 3; + break; + case PTI_LUMINANCE8_ALPHA8: + b = 2; + break; + + case PTI_BC1_RGB: + case PTI_BC1_RGB_SRGB: + case PTI_BC1_RGBA: + case PTI_BC1_RGBA_SRGB: + case PTI_BC4_R8: + case PTI_BC4_R8_SIGNED: + case PTI_ETC1_RGB8: + case PTI_ETC2_RGB8: + case PTI_ETC2_RGB8_SRGB: + case PTI_ETC2_RGB8A1: + case PTI_ETC2_RGB8A1_SRGB: + case PTI_EAC_R11: + case PTI_EAC_R11_SIGNED: + w = h = 4; + b = 8; + break; + case PTI_BC2_RGBA: + case PTI_BC2_RGBA_SRGB: + case PTI_BC3_RGBA: + case PTI_BC3_RGBA_SRGB: + case PTI_BC5_RG8: + case PTI_BC5_RG8_SIGNED: + case PTI_BC6_RGBF: + case PTI_BC6_RGBF_SIGNED: + case PTI_BC7_RGBA: + case PTI_BC7_RGBA_SRGB: + case PTI_ETC2_RGB8A8: + case PTI_ETC2_RGB8A8_SRGB: + case PTI_EAC_RG11: + case PTI_EAC_RG11_SIGNED: + w = h = 4; + b = 16; + break; + +// ASTC is crazy with its format subtypes... note that all are potentially rgba, selected on a per-block basis + case PTI_ASTC_4X4_SRGB: + case PTI_ASTC_4X4: w = 4; h = 4; b = 16; break; + case PTI_ASTC_5X4_SRGB: + case PTI_ASTC_5X4: w = 5; h = 4; b = 16; break; + case PTI_ASTC_5X5_SRGB: + case PTI_ASTC_5X5: w = 5; h = 5; b = 16; break; + case PTI_ASTC_6X5_SRGB: + case PTI_ASTC_6X5: w = 6; h = 5; b = 16; break; + case PTI_ASTC_6X6_SRGB: + case PTI_ASTC_6X6: w = 6; h = 6; b = 16; break; + case PTI_ASTC_8X5_SRGB: + case PTI_ASTC_8X5: w = 8; h = 5; b = 16; break; + case PTI_ASTC_8X6_SRGB: + case PTI_ASTC_8X6: w = 8; h = 6; b = 16; break; + case PTI_ASTC_10X5_SRGB: + case PTI_ASTC_10X5: w = 10; h = 5; b = 16; break; + case PTI_ASTC_10X6_SRGB: + case PTI_ASTC_10X6: w = 10; h = 6; b = 16; break; + case PTI_ASTC_8X8_SRGB: + case PTI_ASTC_8X8: w = 8; h = 8; b = 16; break; + case PTI_ASTC_10X8_SRGB: + case PTI_ASTC_10X8: w = 10; h = 8; b = 16; break; + case PTI_ASTC_10X10_SRGB: + case PTI_ASTC_10X10: w = 10; h = 10; b = 16; break; + case PTI_ASTC_12X10_SRGB: + case PTI_ASTC_12X10: w = 12; h = 10; b = 16; break; + case PTI_ASTC_12X12_SRGB: + case PTI_ASTC_12X12: w = 12; h = 12; b = 16; break; + + case PTI_WHOLEFILE: //UNKNOWN! + case PTI_MAX: + default: + w = h = 1; + b = 0; + break; + } + + *blockbytes = b; + *blockwidth = w; + *blockheight = h; +} + +static pixel32_t *Image_Block_Decode(qbyte *fte_restrict in, int w, int h, void(*decodeblock)(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w), int encoding) +{ +#define TMPBLOCKSIZE 16u + pixel32_t *ret, *out; + pixel32_t tmp[TMPBLOCKSIZE*TMPBLOCKSIZE]; + int x, y, i, j; + + unsigned int blockbytes, blockwidth, blockheight; + Image_BlockSizeForEncoding(encoding, &blockbytes, &blockwidth, &blockheight); + + if (blockwidth > TMPBLOCKSIZE || blockheight > TMPBLOCKSIZE) + Sys_Error("Image_Block_Decode only supports up to %u*%u blocks.\n", TMPBLOCKSIZE,TMPBLOCKSIZE); + + ret = out = BZ_Malloc(w*h*sizeof(*out)); + + for (y = 0; y < (h&~(blockheight-1)); y+=blockheight, out += w*(blockheight-1)) + { + for (x = 0; x < (w&~(blockwidth-1)); x+=blockwidth, in+=blockbytes, out+=blockwidth) + decodeblock(in, out, w); + if (w%blockwidth) + { + decodeblock(in, tmp, TMPBLOCKSIZE); + for (i = 0; x < w; x++, out++, i++) + { + for (j = 0; j < blockheight; j++) + out[w*j] = tmp[i+TMPBLOCKSIZE*j]; + } + in+=blockbytes; + } + } + + if (h%blockheight) + { + h %= blockheight; + for (x = 0; x < w; ) + { + decodeblock(in, tmp, TMPBLOCKSIZE); + i = 0; + do + { + if (x == w) + break; + for (y = 0; y < h; y++) + out[w*y] = tmp[i+TMPBLOCKSIZE*y]; + out++; + i++; + } while (++x % blockwidth); + in+=blockbytes; + } + } + return ret; +} + static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int flags, uploadfmt_t origfmt) { int mip; @@ -3952,7 +4765,7 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla unsigned char *out; unsigned char *in; void *needfree = NULL; - + in = mips->mip[mip].data; if (mips->mip[mip].needfree) out = in; @@ -3978,6 +4791,129 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla if (sh_config.texfmt[mips->encoding]) return; + { //various compressed formats might not be supported. + void *decodefunc = NULL; + int rcoding = mips->encoding; + //its easy enough to decompress these, if needed, its not so easy to compress them as something that's actually supported... + switch(mips->encoding) + { + default: + break; + case PTI_RGB8: + decodefunc = Image_RGB8_Decode_Block; + rcoding = PTI_RGBX8; + break; + case PTI_LUMINANCE8_ALPHA8: + decodefunc = Image_LUMA8_Decode_Block; + rcoding = PTI_RGBA8; + break; +#ifdef DECOMPRESS_ETC2 + case PTI_ETC1_RGB8: + case PTI_ETC2_RGB8: //backwards compatible, so we just treat them the same + case PTI_ETC2_RGB8_SRGB: + decodefunc = Image_ETC2_RGB8_Decode_Block; + rcoding = (mips->encoding==PTI_ETC2_RGB8_SRGB)?PTI_RGBX8_SRGB:PTI_RGBX8; + break; + case PTI_ETC2_RGB8A1: //weird hack mode + case PTI_ETC2_RGB8A1_SRGB: + decodefunc = Image_ETC2_RGB8A1_Decode_Block; + rcoding = (mips->encoding==PTI_ETC2_RGB8A1_SRGB)?PTI_RGBA8_SRGB:PTI_RGBA8; + break; + case PTI_ETC2_RGB8A8: + case PTI_ETC2_RGB8A8_SRGB: + decodefunc = Image_ETC2_RGB8A8_Decode_Block; + rcoding = (mips->encoding==PTI_ETC2_RGB8A8_SRGB)?PTI_RGBA8_SRGB:PTI_RGBA8; + break; +/* case PTI_EAC_R11_SIGNED: + decodefunc = Image_EAC_R11S_Decode_Block; + rcoding = PTI_RGBX8; + break; +*/ case PTI_EAC_R11_SIGNED: + decodefunc = Image_EAC_R11U_Decode_Block; + rcoding = PTI_RGBX8; + break; +/* case PTI_EAC_RG11_SIGNED: + decodefunc = Image_EAC_RG11S_Decode_Block; + rcoding = PTI_RGBX8; + break;*/ + case PTI_EAC_RG11: + decodefunc = Image_EAC_RG11U_Decode_Block; + rcoding = PTI_RGBX8; + break; +#endif + +#ifdef DECOMPRESS_S3TC + case PTI_BC1_RGB: + case PTI_BC1_RGB_SRGB: + decodefunc = Image_BC1_Decode_Block; + rcoding = (mips->encoding==PTI_BC1_RGB_SRGB)?PTI_RGBX8_SRGB:PTI_RGBX8; + break; + case PTI_BC1_RGBA: + case PTI_BC1_RGBA_SRGB: + decodefunc = Image_BC1A_Decode_Block; + rcoding = (mips->encoding==PTI_BC1_RGBA_SRGB)?PTI_RGBA8_SRGB:PTI_RGBA8; + break; + case PTI_BC2_RGBA: + case PTI_BC2_RGBA_SRGB: + decodefunc = Image_BC2_Decode_Block; + rcoding = (mips->encoding==PTI_BC2_RGBA_SRGB)?PTI_RGBA8_SRGB:PTI_RGBA8; + break; +#endif +#if defined(DECOMPRESS_RGTC) && defined(DECOMPRESS_S3TC) + case PTI_BC3_RGBA: + case PTI_BC3_RGBA_SRGB: + decodefunc = Image_BC3_Decode_Block; + rcoding = (mips->encoding==PTI_BC3_RGBA_SRGB)?PTI_RGBA8_SRGB:PTI_RGBA8; + break; +#endif +#ifdef DECOMPRESS_RGTC + case PTI_BC4_R8_SIGNED: + decodefunc = Image_BC4S_Decode_Block; + rcoding = PTI_RGBX8; + break; + case PTI_BC4_R8: + decodefunc = Image_BC4U_Decode_Block; + rcoding = PTI_RGBX8; + break; + case PTI_BC5_RG8_SIGNED: + decodefunc = Image_BC5S_Decode_Block; + rcoding = PTI_RGBX8; + break; + case PTI_BC5_RG8: + decodefunc = Image_BC5U_Decode_Block; + rcoding = PTI_RGBX8; + break; +#endif +#if 0//def DECOMPRESS_BPTC + case PTI_BC6_RGBFU: + case PTI_BC6_RGBFS: + case PTI_BC7_RGBA: + case PTI_BC7_RGBA_SRGB: + rcoding = PTI_ZOMGWTF; + break; +#endif + } + if (decodefunc) + { + for (mip = 0; mip < mips->mipcount; mip++) + { + pixel32_t *out = Image_Block_Decode(mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, decodefunc, mips->encoding); + if (mips->mip[mip].needfree) + BZ_Free(mips->mip[mip].data); + mips->mip[mip].data = out; + mips->mip[mip].needfree = true; + mips->mip[mip].datasize = mips->mip[mip].width*mips->mip[mip].height*sizeof(*out); + } + if (mips->extrafree) + BZ_Free(mips->extrafree); //might as well free this now, as nothing is poking it any more. + mips->extrafree = NULL; + mips->encoding = rcoding; + + if (sh_config.texfmt[mips->encoding]) + return; //its okay now + } + } + if (mips->encoding == PTI_R8) { if (sh_config.texfmt[PTI_BGRX8]) //bgra8 is typically faster when supported. @@ -4518,24 +5454,79 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case PTI_RGBA4444: case PTI_RGBA5551: break; //erk - case PTI_S3RGBA1: //mostly compatible, but I don't want to push it. - case PTI_S3RGBA3: - case PTI_S3RGBA5: - case PTI_ETC2_RGB8A1: - case PTI_ETC2_RGB8A8: + case PTI_BC1_RGBA: + mips->encoding = PTI_BC1_RGB; + break; + case PTI_BC1_RGBA_SRGB: + mips->encoding = PTI_BC1_RGB_SRGB; + break; + case PTI_BC2_RGBA: //could strip to PTI_BC1_RGB + case PTI_BC2_RGBA_SRGB: //could strip to PTI_BC1_RGB + case PTI_BC3_RGBA: //could strip to PTI_BC1_RGB + case PTI_BC3_RGBA_SRGB: //could strip to PTI_BC1_RGB + case PTI_BC7_RGBA: //much too messy... + case PTI_BC7_RGBA_SRGB: + case PTI_ETC2_RGB8A1: //would need to force the 'opaque' bit in each block and treat as PTI_ETC2_RGB8. + case PTI_ETC2_RGB8A1_SRGB: //would need to force the 'opaque' bit in each block and treat as PTI_ETC2_RGB8. + case PTI_ETC2_RGB8A8: //could strip to PTI_ETC2_RGB8 + case PTI_ETC2_RGB8A8_SRGB: //could strip to PTI_ETC2_SRGB8 + case PTI_ASTC_4X4: + case PTI_ASTC_4X4_SRGB: + case PTI_ASTC_5X4: + case PTI_ASTC_5X4_SRGB: + case PTI_ASTC_5X5: + case PTI_ASTC_5X5_SRGB: + case PTI_ASTC_6X5: + case PTI_ASTC_6X5_SRGB: + case PTI_ASTC_6X6: + case PTI_ASTC_6X6_SRGB: + case PTI_ASTC_8X5: + case PTI_ASTC_8X5_SRGB: + case PTI_ASTC_8X6: + case PTI_ASTC_8X6_SRGB: + case PTI_ASTC_10X5: + case PTI_ASTC_10X5_SRGB: + case PTI_ASTC_10X6: + case PTI_ASTC_10X6_SRGB: + case PTI_ASTC_8X8: + case PTI_ASTC_8X8_SRGB: + case PTI_ASTC_10X8: + case PTI_ASTC_10X8_SRGB: + case PTI_ASTC_10X10: + case PTI_ASTC_10X10_SRGB: + case PTI_ASTC_12X10: + case PTI_ASTC_12X10_SRGB: + case PTI_ASTC_12X12: + case PTI_ASTC_12X12_SRGB: case PTI_WHOLEFILE: + case PTI_LUMINANCE8_ALPHA8: //erk. meh. break; case PTI_R8: + case PTI_R8_SIGNED: case PTI_RG8: + case PTI_RG8_SIGNED: case PTI_RGB565: + case PTI_RGB8: case PTI_RGBX8: case PTI_BGRX8: case PTI_RGBX8_SRGB: case PTI_BGRX8_SRGB: - case PTI_S3RGB1: + case PTI_BC1_RGB: + case PTI_BC1_RGB_SRGB: + case PTI_BC4_R8: + case PTI_BC4_R8_SIGNED: + case PTI_BC5_RG8: + case PTI_BC5_RG8_SIGNED: + case PTI_BC6_RGBF: + case PTI_BC6_RGBF_SIGNED: case PTI_ETC1_RGB8: case PTI_ETC2_RGB8: + case PTI_ETC2_RGB8_SRGB: + case PTI_EAC_R11: + case PTI_EAC_R11_SIGNED: + case PTI_EAC_RG11: + case PTI_EAC_RG11_SIGNED: break; //already no alpha in these formats case PTI_DEPTH16: case PTI_DEPTH24: @@ -4553,10 +5544,21 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag int nf = PTI_MAX; switch(mips->encoding) { - case PTI_RGBA8: nf = PTI_RGBA8_SRGB; break; - case PTI_RGBX8: nf = PTI_RGBX8_SRGB; break; - case PTI_BGRA8: nf = PTI_BGRA8_SRGB; break; - case PTI_BGRX8: nf = PTI_BGRX8_SRGB; break; + case PTI_RGBA8: nf = PTI_RGBA8_SRGB; break; + case PTI_RGBX8: nf = PTI_RGBX8_SRGB; break; + case PTI_BGRA8: nf = PTI_BGRA8_SRGB; break; + case PTI_BGRX8: nf = PTI_BGRX8_SRGB; break; + case PTI_BC1_RGB: nf = PTI_BC1_RGB_SRGB; break; + case PTI_BC1_RGBA: nf = PTI_BC1_RGBA_SRGB; break; + case PTI_BC2_RGBA: nf = PTI_BC2_RGBA_SRGB; break; + case PTI_BC3_RGBA: nf = PTI_BC3_RGBA_SRGB; break; + case PTI_BC7_RGBA: nf = PTI_BC7_RGBA_SRGB; break; + case PTI_ETC1_RGB8: nf = PTI_ETC2_RGB8_SRGB; break; + case PTI_ETC2_RGB8: nf = PTI_ETC2_RGB8_SRGB; break; + case PTI_ETC2_RGB8A1: nf = PTI_ETC2_RGB8A1_SRGB; break; + case PTI_ETC2_RGB8A8: nf = PTI_ETC2_RGB8A8_SRGB; break; + //case PTI_ASTC_4X4: nf = PTI_ASTC_4X4_SRGB; break; + //ASTC fixme: more blocksize formats default: if (freedata) BZ_Free(rgbadata); @@ -4567,6 +5569,14 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag else { //srgb->linear int m = mips->mip[0].width*mips->mip[0].height*4; + if (nf >= PTI_BC1_RGB) + { //these formats are weird. we can't just fiddle with the rgbdata + //FIXME: bc1/2/3 has two leading 16bit values per block. + //FIXME: etc2 has all sorts of weird encoding tables... + if (freedata) + BZ_Free(rgbadata); + return false; + } if (mips->type == PTI_3D) m *= mips->mip[0].height; for (i = 0; i < m; i+=4) @@ -4641,7 +5651,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag { //works for rgba or bgra int i; - unsigned char *fte_restrict premul = (unsigned char*)mips->mip[0].data; + qbyte *fte_restrict premul = (qbyte*)mips->mip[0].data; for (i = 0; i < mips->mip[0].width*mips->mip[0].height; i++, premul+=4) { premul[0] = (premul[0] * premul[3])>>8; @@ -4705,23 +5715,39 @@ qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, int imgwidth, imgheight; + struct pendingtextureinfo *mips = NULL; + //these formats have special handling, because they cannot be implemented via Read32BitImageFile - they don't result in rgba images. #ifdef IMAGEFMT_KTX - if (Image_ReadKTXFile(tex, flags, fname, filedata, filesize)) - return true; + if (!mips) + mips = Image_ReadKTXFile(flags, fname, filedata, filesize); +#endif +#ifdef IMAGEFMT_PKM + if (!mips) + mips = Image_ReadPKMFile(flags, fname, filedata, filesize); #endif #ifdef IMAGEFMT_DDS - if (Image_ReadDDSFile(tex, flags, fname, filedata, filesize)) - return true; + if (!mips) + mips = Image_ReadDDSFile(flags, fname, filedata, filesize); #endif #ifdef IMAGEFMT_BLP - if (filedata[0] == 'B' && filedata[1] == 'L' && filedata[2] == 'P' && filedata[3] == '2') - { - if (Image_ReadBLPFile(tex, flags, fname, filedata, filesize)) - return true; - } + if (!mips && filedata[0] == 'B' && filedata[1] == 'L' && filedata[2] == 'P' && filedata[3] == '2') + mips = Image_ReadBLPFile(flags, fname, filedata, filesize); #endif + if (mips) + { + tex->width = mips->mip[0].width; + tex->height = mips->mip[0].height; + Image_ChangeFormat(mips, flags, TF_INVALID); + + if (flags & IF_NOWORKER) + Image_LoadTextureMips(tex, mips, 0, 0); + else + COM_AddWork(WG_MAIN, Image_LoadTextureMips, tex, mips, 0, 0); + return true; + } + hasalpha = false; if ((rgbadata = Read32BitImageFile(filedata, filesize, &imgwidth, &imgheight, &hasalpha, fname))) { @@ -5144,6 +6170,7 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t { image_t *tex = ctx; char fname[MAX_QPATH]; + char fname2[MAX_QPATH]; char *altname; char *nextalt; @@ -5154,6 +6181,7 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t size_t fsize; char *buf; + int i, j; int imgwidth; int imgheight; qboolean alphaed; @@ -5165,7 +6193,8 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t //the exception is single-file dds cubemaps, but we don't support those. for(altname = tex->ident;altname;altname = nextalt) { - struct pendingtextureinfo *mips; + struct pendingtextureinfo *mips = NULL; + static const char *cubeexts[] = {"", ".ktx", ".dds"}; nextalt = strchr(altname, ':'); if (nextalt) @@ -5178,7 +6207,57 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t altname = fname; } - mips = Image_LoadCubemapTextureData(altname, tex->subpath, tex->flags); + for (i = 0; i < countof(tex_path) && !mips; i++) + { + if (!tex_path[i].enabled) + continue; + buf = NULL; + if (tex_path[i].args == 3 && tex->subpath) + { + char subpath[MAX_QPATH]; + char *n = tex->subpath, *e; + while (*n) + { + e = strchr(n, ':'); + if (!e) + e = n+strlen(n); + Q_strncpyz(subpath, n, min(sizeof(subpath), (e-n)+1)); + n = e; + while(*n == ':') + n++; + for (j = 0; !buf && j < countof(cubeexts); j++) + { + Q_snprintfz(fname2, sizeof(fname2), tex_path[i].path, subpath, altname, cubeexts[j]); + buf = FS_LoadMallocFile(fname2, &fsize); + } + } + } + else if (tex_path[i].args == 2) + { + for (j = 0; !buf && j < countof(cubeexts); j++) + { + Q_snprintfz(fname2, sizeof(fname2), tex_path[i].path, altname, cubeexts[j]); + buf = FS_LoadMallocFile(fname2, &fsize); + } + } + if (buf) + { +#ifdef IMAGEFMT_KTX + if (!mips) + mips = Image_ReadKTXFile(tex->flags, altname, buf, fsize); +#endif +#ifdef IMAGEFMT_DDS + if (!mips) + mips = Image_ReadDDSFile(tex->flags, altname, buf, fsize); +#endif + if (!mips) + BZ_Free(buf); + } + } + + if (!mips) //try to load multiple images + mips = Image_LoadCubemapTextureData(altname, tex->subpath, tex->flags); + if (mips) { tex->width = mips->mip[0].width; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 8e91ef9db..50ed1d771 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -736,6 +736,7 @@ const char *presetexec[] = "seta r_part_classic_square 0;" "seta r_part_classic_expgrav 10;" "seta r_part_classic_opaque 0;" + "seta cl_expsprite 1;" "seta r_stains 0;" "seta r_drawflat 1;" "seta r_lightmap 0;" diff --git a/engine/client/merged.h b/engine/client/merged.h index 375a11ab2..6912e428e 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -303,22 +303,74 @@ struct pendingtextureinfo PTI_ARGB4444, //16bit format (d3d) PTI_RGBA5551, //16bit alpha format (gl). PTI_ARGB1555, //16bit alpha format (d3d). + PTI_RGB8, //24bit packed format. generally not supported + PTI_LUMINANCE8_ALPHA8, //16bit format. //floating point formats PTI_RGBA16F, PTI_RGBA32F, //small formats. PTI_R8, - PTI_RG8, - //(desktop) compressed formats - PTI_S3RGB1, - PTI_S3RGBA1, - PTI_S3RGBA3, - PTI_S3RGBA5, - //(mobile) compressed formats + PTI_RG8, //might be useful for normalmaps + PTI_R8_SIGNED, + PTI_RG8_SIGNED, //might be useful for normalmaps + //(desktop/tegra) compressed formats + PTI_BC1_RGB, + PTI_BC1_RGB_SRGB, + PTI_BC1_RGBA, + PTI_BC1_RGBA_SRGB, + PTI_BC2_RGBA, + PTI_BC2_RGBA_SRGB, + PTI_BC3_RGBA, //maybe add a bc3 normalmapswizzle type for d3d9? + PTI_BC3_RGBA_SRGB, + PTI_BC4_R8, + PTI_BC4_R8_SIGNED, + PTI_BC5_RG8, //useful for normalmaps + PTI_BC5_RG8_SIGNED, //useful for normalmaps + PTI_BC6_RGBF, //unsigned (half) floats! + PTI_BC6_RGBF_SIGNED, //signed (half) floats! + PTI_BC7_RGBA, //multimode compression, using as many bits as bc2/bc3 + PTI_BC7_RGBA_SRGB, + //(mobile/intel) compressed formats PTI_ETC1_RGB8, //limited form PTI_ETC2_RGB8, //extended form PTI_ETC2_RGB8A1, PTI_ETC2_RGB8A8, + PTI_ETC2_RGB8_SRGB, + PTI_ETC2_RGB8A1_SRGB, + PTI_ETC2_RGB8A8_SRGB, + PTI_EAC_R11, //no idea what this might be used for, whatever + PTI_EAC_R11_SIGNED, //no idea what this might be used for, whatever + PTI_EAC_RG11, //useful for normalmaps (calculate blue) + PTI_EAC_RG11_SIGNED, //useful for normalmaps (calculate blue) + //astc... zomg + PTI_ASTC_4X4, + PTI_ASTC_4X4_SRGB, + PTI_ASTC_5X4, + PTI_ASTC_5X4_SRGB, + PTI_ASTC_5X5, + PTI_ASTC_5X5_SRGB, + PTI_ASTC_6X5, + PTI_ASTC_6X5_SRGB, + PTI_ASTC_6X6, + PTI_ASTC_6X6_SRGB, + PTI_ASTC_8X5, + PTI_ASTC_8X5_SRGB, + PTI_ASTC_8X6, + PTI_ASTC_8X6_SRGB, + PTI_ASTC_10X5, + PTI_ASTC_10X5_SRGB, + PTI_ASTC_10X6, + PTI_ASTC_10X6_SRGB, + PTI_ASTC_8X8, + PTI_ASTC_8X8_SRGB, + PTI_ASTC_10X8, + PTI_ASTC_10X8_SRGB, + PTI_ASTC_10X10, + PTI_ASTC_10X10_SRGB, + PTI_ASTC_12X10, + PTI_ASTC_12X10_SRGB, + PTI_ASTC_12X12, + PTI_ASTC_12X12_SRGB, //weird specialcase mess to take advantage of webgl so we don't need redundant bloat where we're already strugging with potential heap limits PTI_WHOLEFILE, //depth formats @@ -328,6 +380,7 @@ struct pendingtextureinfo PTI_DEPTH24_8, PTI_MAX, } encoding; //0 + void *extrafree; int mipcount; struct { @@ -336,8 +389,7 @@ struct pendingtextureinfo int width; int height; qboolean needfree; - } mip[32]; - void *extrafree; + } mip[72]; //enough for a 4096 cubemap. or a really smegging big 2d texture... }; //small context for easy vbo creation. diff --git a/engine/client/net_master.c b/engine/client/net_master.c index ee765591d..ef1fa875e 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -76,6 +76,7 @@ typedef struct { cvar_t cv; char *comment; + qboolean announced; //when set, hide when sv_reportheartbeats 2 qboolean needsresolve; //set any time the cvar is modified qboolean resolving; //set any time the cvar is modified netadr_t adr[MAX_MASTER_ADDRESSES]; @@ -245,7 +246,11 @@ void SV_Master_SingleHeartbeat(net_masterlist_t *master) } if (sv_reportheartbeats.value) - Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string); + { + if (sv_reportheartbeats.ival != 2 || !master->announced) + Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string); + master->announced = true; + } NET_SendPacket (NS_SERVER, strlen(string), string, na); } @@ -255,7 +260,11 @@ void SV_Master_SingleHeartbeat(net_masterlist_t *master) if (svs.gametype == GT_QUAKE2 && sv_listen_qw.value) //set listen to 1 to allow qw connections, 2 to allow nq connections too. { if (sv_reportheartbeats.value) - Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string); + { + if (sv_reportheartbeats.ival != 2 || !master->announced) + Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string); + master->announced = true; + } { char *str = "\377\377\377\377heartbeat\n%s"; @@ -269,7 +278,11 @@ void SV_Master_SingleHeartbeat(net_masterlist_t *master) if (sv_listen_dp.value || sv_listen_nq.value) //set listen to 1 to allow qw connections, 2 to allow nq connections too. { if (sv_reportheartbeats.value) - Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string); + { + if (sv_reportheartbeats.ival != 2 || !master->announced) + Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string); + master->announced = true; + } { //darkplaces here refers to the master server protocol, rather than the game protocol diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index bc7b15850..fc88c4590 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -395,7 +395,7 @@ void R2D_Init(void) atlas.shader = NULL; atlas.data = NULL; atlas.dirty = false; - Mod_LightmapAllocInit(&atlas.allocation, false, min(512, sh_config.texture_maxsize), min(512, sh_config.texture_maxsize), 0); + Mod_LightmapAllocInit(&atlas.allocation, false, min(512, sh_config.texture2d_maxsize), min(512, sh_config.texture2d_maxsize), 0); } mpic_t *R2D_SafeCachePic (const char *path) @@ -1161,7 +1161,12 @@ void R2D_Console_Resize(void) } if (!cwidth && !cheight) - cheight = 480; + { + if (vid.dpi_y) + cheight = (480 * 96) / vid.dpi_y; + else + cheight = 480; + } if (cheight && !cwidth && vid.rotpixelheight) cwidth = (cheight*vid.rotpixelwidth)/vid.rotpixelheight; if (cwidth && !cheight && vid.rotpixelwidth) diff --git a/engine/client/render.h b/engine/client/render.h index 8ca16516e..4b5ec7811 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -448,6 +448,7 @@ void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, in void Image_Purge(void); //purge any textures which are not needed any more (releases memory, but doesn't give null pointers). void Image_Init(void); void Image_Shutdown(void); +void Image_BlockSizeForEncoding(unsigned int encoding, unsigned int *blockbytes, unsigned int *blockwidth, unsigned int *blockheight); image_t *Image_LoadTexture (const char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 278e6a694..a9b865e81 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -224,7 +224,7 @@ cvar_t scr_conspeed = CVAR ("scr_conspeed", "2000"); // 10 - 170 cvar_t scr_fov = CVARFCD("fov", "90", CVAR_ARCHIVE, SCR_Fov_Callback, "field of vision, 1-170 degrees, standard fov is 90, nquake defaults to 108."); -cvar_t scr_fov_viewmodel = CVARFCD("r_viewmodel_fov", "", CVAR_ARCHIVE, SCR_Fov_Callback, +cvar_t scr_fov_viewmodel = CVARFD("r_viewmodel_fov", "", CVAR_ARCHIVE, "field of vision, 1-170 degrees, standard fov is 90, nquake defaults to 108."); cvar_t scr_printspeed = CVAR ("scr_printspeed", "16"); cvar_t scr_showpause = CVAR ("showpause", "1"); @@ -377,7 +377,6 @@ cvar_t gl_overbright_all = CVARF ("gl_overbright_all", "0", cvar_t gl_picmip = CVARFD ("gl_picmip", "0", CVAR_ARCHIVE, "Reduce world/model texture sizes by some exponential factor."); cvar_t gl_picmip2d = CVARFD ("gl_picmip2d", "0", CVAR_ARCHIVE, "Reduce hud/menu texture sizes by some exponential factor."); cvar_t gl_nohwblend = CVARD ("gl_nohwblend","1", "If 1, don't use hardware gamma ramps for transient effects that change each frame (does not affect long-term effects like holding quad or underwater tints)."); -cvar_t gl_savecompressedtex = CVARD ("gl_savecompressedtex", "0", "Write out a copy of textures in a compressed format. The driver will do the compression on the fly, thus this setting is likely inferior to software which does not care so much about compression times."); //cvar_t gl_schematics = CVARD ("gl_schematics", "0", "Gimmick rendering mode that draws the length of various world edges."); cvar_t gl_skyboxdist = CVARD ("gl_skyboxdist", "0", "The distance of the skybox. If 0, the engine will determine it based upon the far clip plane distance."); //0 = guess. cvar_t gl_smoothcrosshair = CVAR ("gl_smoothcrosshair", "1"); @@ -518,7 +517,6 @@ void GLRenderer_Init(void) Cvar_Register (&gl_picmip2d, GLRENDEREROPTIONS); Cvar_Register (&r_shaderblobs, GLRENDEREROPTIONS); - Cvar_Register (&gl_savecompressedtex, GLRENDEREROPTIONS); Cvar_Register (&gl_compress, GLRENDEREROPTIONS); // Cvar_Register (&gl_detail, GRAPHICALNICETIES); // Cvar_Register (&gl_detailscale, GRAPHICALNICETIES); @@ -1370,8 +1368,8 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr) pmove.numphysent = 0; pmove.physents[0].model = NULL; - vid.dpi_x = 0; - vid.dpi_y = 0; + vid.dpi_x = 96; + vid.dpi_y = 96; #ifndef CLIENTONLY sv.world.lastcheckpvs = NULL; @@ -2693,56 +2691,60 @@ void R_SetFrustum (float projmat[16], float viewmat[16]) float scale; int i; float mvp[16]; + mplane_t *p; if (r_novis.ival & 4) return; Matrix4_Multiply(projmat, viewmat, mvp); + r_refdef.frustum_numplanes = 0; + for (i = 0; i < 4; i++) { + //each of the four side planes + p = &r_refdef.frustum[r_refdef.frustum_numplanes++]; if (i & 1) { - r_refdef.frustum[i].normal[0] = mvp[3] + mvp[0+i/2]; - r_refdef.frustum[i].normal[1] = mvp[7] + mvp[4+i/2]; - r_refdef.frustum[i].normal[2] = mvp[11] + mvp[8+i/2]; - r_refdef.frustum[i].dist = mvp[15] + mvp[12+i/2]; + p->normal[0] = mvp[3] + mvp[0+i/2]; + p->normal[1] = mvp[7] + mvp[4+i/2]; + p->normal[2] = mvp[11] + mvp[8+i/2]; + p->dist = mvp[15] + mvp[12+i/2]; } else { - r_refdef.frustum[i].normal[0] = mvp[3] - mvp[0+i/2]; - r_refdef.frustum[i].normal[1] = mvp[7] - mvp[4+i/2]; - r_refdef.frustum[i].normal[2] = mvp[11] - mvp[8+i/2]; - r_refdef.frustum[i].dist = mvp[15] - mvp[12+i/2]; + p->normal[0] = mvp[3] - mvp[0+i/2]; + p->normal[1] = mvp[7] - mvp[4+i/2]; + p->normal[2] = mvp[11] - mvp[8+i/2]; + p->dist = mvp[15] - mvp[12+i/2]; } - scale = 1/sqrt(DotProduct(r_refdef.frustum[i].normal, r_refdef.frustum[i].normal)); - r_refdef.frustum[i].normal[0] *= scale; - r_refdef.frustum[i].normal[1] *= scale; - r_refdef.frustum[i].normal[2] *= scale; - r_refdef.frustum[i].dist *= -scale; + scale = 1/sqrt(DotProduct(p->normal, p->normal)); + p->normal[0] *= scale; + p->normal[1] *= scale; + p->normal[2] *= scale; + p->dist *= -scale; - r_refdef.frustum[i].type = PLANE_ANYZ; - r_refdef.frustum[i].signbits = SignbitsForPlane (&r_refdef.frustum[i]); + p->type = PLANE_ANYZ; + p->signbits = SignbitsForPlane (p); } - r_refdef.frustum_numplanes = 4; + //the near clip plane. + p = &r_refdef.frustum[r_refdef.frustum_numplanes++]; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] = mvp[3] - mvp[2]; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] = mvp[7] - mvp[6]; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] = mvp[11] - mvp[10]; - r_refdef.frustum[r_refdef.frustum_numplanes].dist = mvp[15] - mvp[14]; + p->normal[0] = mvp[3] - mvp[2]; + p->normal[1] = mvp[7] - mvp[6]; + p->normal[2] = mvp[11] - mvp[10]; + p->dist = mvp[15] - mvp[14]; - scale = 1/sqrt(DotProduct(r_refdef.frustum[r_refdef.frustum_numplanes].normal, r_refdef.frustum[r_refdef.frustum_numplanes].normal)); - r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] *= scale; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] *= scale; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] *= scale; - r_refdef.frustum[r_refdef.frustum_numplanes].dist *= -scale; + scale = 1/sqrt(DotProduct(p->normal, p->normal)); + p->normal[0] *= scale; + p->normal[1] *= scale; + p->normal[2] *= scale; + p->dist *= -scale; - r_refdef.frustum[r_refdef.frustum_numplanes].type = PLANE_ANYZ; - r_refdef.frustum[r_refdef.frustum_numplanes].signbits = SignbitsForPlane (&r_refdef.frustum[4]); - - r_refdef.frustum_numplanes++; + p->type = PLANE_ANYZ; + p->signbits = SignbitsForPlane (p); r_refdef.frustum_numworldplanes = r_refdef.frustum_numplanes; @@ -2773,21 +2775,21 @@ void R_SetFrustum (float projmat[16], float viewmat[16]) culldist = culldist / (-r_refdef.globalfog.density); //anything drawn beyond this point is fully obscured by fog - r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] = mvp[3] - mvp[2]; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] = mvp[7] - mvp[6]; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] = mvp[11] - mvp[10]; - r_refdef.frustum[r_refdef.frustum_numplanes].dist = mvp[15] - mvp[14]; + p = &r_refdef.frustum[r_refdef.frustum_numplanes++]; + p->normal[0] = mvp[3] - mvp[2]; + p->normal[1] = mvp[7] - mvp[6]; + p->normal[2] = mvp[11] - mvp[10]; + p->dist = mvp[15] - mvp[14]; - scale = 1/sqrt(DotProduct(r_refdef.frustum[r_refdef.frustum_numplanes].normal, r_refdef.frustum[r_refdef.frustum_numplanes].normal)); - r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] *= -scale; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] *= -scale; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] *= -scale; -// r_refdef.frustum[r_refdef.frustum_numplanes].dist *= scale; - r_refdef.frustum[r_refdef.frustum_numplanes].dist = DotProduct(r_origin, r_refdef.frustum[r_refdef.frustum_numplanes].normal)-culldist; + scale = 1/sqrt(DotProduct(p->normal, p->normal)); + p->normal[0] *= -scale; + p->normal[1] *= -scale; + p->normal[2] *= -scale; +// p->dist *= scale; + p->dist = DotProduct(r_origin, p->normal)-culldist; - r_refdef.frustum[r_refdef.frustum_numplanes].type = PLANE_ANYZ; - r_refdef.frustum[r_refdef.frustum_numplanes].signbits = SignbitsForPlane (&r_refdef.frustum[r_refdef.frustum_numplanes]); - r_refdef.frustum_numplanes++; + p->type = PLANE_ANYZ; + p->signbits = SignbitsForPlane (p); } } #else diff --git a/engine/client/textedit.c b/engine/client/textedit.c index 86c59cf08..bc62e3efa 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -872,6 +872,20 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st { char newname[MAX_QPATH]; console_t *edit; + + if (!strncmp(filename, "./", 2)) + filename+=2; + + stepasm = !line || *line < 0; + + //we can cope with no line info by displaying asm + if (editormodal || (stepasm && !statement)) + { + if (fatal) + return DEBUG_TRACE_ABORT; + return DEBUG_TRACE_OFF; //whoops + } + if (!pr_debugger.ival) { Con_Printf("Set %s to trace\n", pr_debugger.name); @@ -880,26 +894,20 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st return DEBUG_TRACE_OFF; //get lost } - if (!strncmp(filename, "./", 2)) - filename+=2; - - //we can cope with no line info by displaying asm - if (editormodal || !statement - || !line || *line == -1 //FIXME - ) - { - if (fatal) - return DEBUG_TRACE_ABORT; - return DEBUG_TRACE_OFF; //whoops - } - - if (qrenderer == QR_NONE) + if (qrenderer == QR_NONE || stepasm) { //just dump the line of code that's being execed onto the console. int i; char buffer[8192]; char *r; vfsfile_t *f; + if (stepasm) + { + prfncs->GenerateStatementString(prfncs, *statement, buffer, sizeof(buffer)); + Con_Printf("%s", buffer); + return DEBUG_TRACE_INTO; + } + if (!line) { //please don't crash if (fatal) @@ -924,10 +932,9 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st return DEBUG_TRACE_OUT; //only display the line itself. } - stepasm = !line; editprogfuncs = prfncs; - if (!COM_FCheckExists(filename)) + if (!stepasm && *filename && !COM_FCheckExists(filename)) { //people generally run their qcc from $mod/src/ or so, so paths are usually relative to that instead of the mod directory. //this means we now need to try and guess what the user used. @@ -963,19 +970,19 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st } if (filename != newname) { + stepasm = true; if (fatal) - { Con_Printf(CON_ERROR "Unable to find file \"%s\"\n", filename); - return DEBUG_TRACE_ABORT; - } - Con_Printf(CON_WARNING "Unable to find file \"%s\"\n", filename); - return DEBUG_TRACE_OFF; //whoops + else + Con_Printf(CON_WARNING "Unable to find file \"%s\"\n", filename); } } if (stepasm) { - return DEBUG_TRACE_OFF; + if (fatal) + return DEBUG_TRACE_ABORT; + return DEBUG_TRACE_OFF; //whoops } else { diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index a0e31b90f..b5b814d71 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -293,8 +293,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define R_XFLIP //allow view to be flipped horizontally #define TEXTEDITOR #define IMAGEFMT_KTX //Khronos TeXture. common on gles3 devices for etc2 compression + #define IMAGEFMT_PKM //file format generally written by etcpack or android's etc1tool #define IMAGEFMT_DDS //a sort of image file format. #define IMAGEFMT_BLP //a sort of image file format. + #define DECOMPRESS_ETC2 //decompress etc2(core in gles3/gl4.3) if the graphics driver doesn't support it (eg d3d or crappy gpus with vulkan). +// #define DECOMPRESS_S3TC //allows bc1-3 to work even when drivers don't support it. This is probably only an issue on mobile chips. WARNING: not entirely sure if all patents expired yet... + #define DECOMPRESS_RGTC //bc4+bc5 #ifndef RTLIGHTS #define RTLIGHTS //realtime lighting #endif diff --git a/engine/common/common.c b/engine/common/common.c index 14cf0d369..fe1059211 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -1711,6 +1711,12 @@ float MSG_ReadCoord24 (void) MSG_ReadData(&c, 3); return MSG_FromCoord(c, 3); } +float MSG_ReadCoordFloat (void) +{ + coorddata c = {{0}}; + MSG_ReadData(&c, 4); + return MSG_FromCoord(c, 4); +} void MSG_ReadPos (vec3_t pos) { diff --git a/engine/common/common.h b/engine/common/common.h index 9aa370cbe..6ada721a2 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -290,6 +290,7 @@ char *MSG_ReadString (void); char *MSG_ReadStringLine (void); float MSG_ReadCoord (void); +float MSG_ReadCoordFloat (void); void MSG_ReadPos (float *pos); float MSG_ReadAngle (void); float MSG_ReadAngle16 (void); diff --git a/engine/common/cvar.h b/engine/common/cvar.h index ca9ae7594..9b91dd956 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -127,7 +127,7 @@ typedef struct cvar_group_s #define CVAR_NOTFROMSERVER (1<<7) //cvar cannot be set by gamecode. the console will ignore changes to cvars if set at from the server or any gamecode. This is to protect against security flaws - like qterm #define CVAR_USERCREATED (1<<8) //write a 'set' or 'seta' in front of the var name. #define CVAR_CHEAT (1<<9) //latch to the default, unless cheats are enabled. -#define CVAR_SEMICHEAT (1<<10) //if strict ruleset, force to 0/blank. +#define CVAR_SEMICHEAT (1<<10) //if strict ruleset, force to blank (aka 0). #define CVAR_RENDERERLATCH (1<<11) //requires a vid_restart to reapply. #define CVAR_SERVEROVERRIDE (1<<12) //the server has overridden out local value - should probably be called SERVERLATCH #define CVAR_RENDERERCALLBACK (1<<13) //force callback for cvars on renderer change diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index af420b850..95b09e0c4 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -3511,7 +3511,7 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l) maps /= 2; { - int limit = min(sh_config.texture_maxsize / loadmodel->lightmaps.height, 16);//mod_mergeq3lightmaps.ival); + int limit = min(sh_config.texture2d_maxsize / loadmodel->lightmaps.height, 16);//mod_mergeq3lightmaps.ival); loadmodel->lightmaps.merge = 1; while (loadmodel->lightmaps.merge*2 <= limit && loadmodel->lightmaps.merge < maps) loadmodel->lightmaps.merge *= 2; @@ -5881,6 +5881,19 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, VectorCopy (mins, trace_mins); VectorCopy (maxs, trace_maxs); + if (1) + { + VectorAdd(trace_maxs, trace_mins, point); + VectorScale(point, 0.5, point); + + VectorAdd(trace_start, point, trace_start); + VectorAdd(trace_end, point, trace_end); + VectorSubtract(trace_mins, point, trace_mins); + VectorSubtract(trace_maxs, point, trace_maxs); + } + + + // build a bounding box of the entire move (for patches) ClearBounds (trace_absmins, trace_absmaxs); @@ -5890,8 +5903,8 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, trace_shape = shape_ispoint; VectorSet (trace_extents, 1/32.0, 1/32.0, 1/32.0); //acedemic - AddPointToBounds (start, trace_absmins, trace_absmaxs); - AddPointToBounds (end, trace_absmins, trace_absmaxs); + AddPointToBounds (trace_start, trace_absmins, trace_absmaxs); + AddPointToBounds (trace_end, trace_absmins, trace_absmaxs); } else if (capsule) { @@ -5909,24 +5922,24 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, trace_extents[2] = ext+1; //determine the total range - VectorSubtract (start, trace_extents, point); + VectorSubtract (trace_start, trace_extents, point); AddPointToBounds (point, trace_absmins, trace_absmaxs); - VectorAdd (start, trace_extents, point); + VectorAdd (trace_start, trace_extents, point); AddPointToBounds (point, trace_absmins, trace_absmaxs); - VectorSubtract (end, trace_extents, point); + VectorSubtract (trace_end, trace_extents, point); AddPointToBounds (point, trace_absmins, trace_absmaxs); - VectorAdd (end, trace_extents, point); + VectorAdd (trace_end, trace_extents, point); AddPointToBounds (point, trace_absmins, trace_absmaxs); } else { - VectorAdd (start, trace_mins, point); + VectorAdd (trace_start, trace_mins, point); AddPointToBounds (point, trace_absmins, trace_absmaxs); - VectorAdd (start, trace_maxs, point); + VectorAdd (trace_start, trace_maxs, point); AddPointToBounds (point, trace_absmins, trace_absmaxs); - VectorAdd (end, trace_mins, point); + VectorAdd (trace_end, trace_mins, point); AddPointToBounds (point, trace_absmins, trace_absmaxs); - VectorAdd (end, trace_maxs, point); + VectorAdd (trace_end, trace_maxs, point); AddPointToBounds (point, trace_absmins, trace_absmaxs); trace_shape = shape_isbox; @@ -5969,8 +5982,8 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, vec3_t c1, c2; int topnode; - VectorAdd (start, mins, c1); - VectorAdd (start, maxs, c2); + VectorAdd (trace_start, mins, c1); + VectorAdd (trace_start, maxs, c2); for (i=0 ; i<3 ; i++) { c1[i] -= 1; @@ -5998,7 +6011,7 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, if (trace_nearfraction == 1) { trace_trace.fraction = 1; - VectorCopy (trace_end, trace_trace.endpos); + VectorCopy (end, trace_trace.endpos); } else { @@ -6006,7 +6019,7 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, trace_nearfraction=0; trace_trace.fraction = trace_nearfraction; for (i=0 ; i<3 ; i++) - trace_trace.endpos[i] = trace_start[i] + trace_trace.fraction * (trace_end[i] - trace_start[i]); + trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]); } return trace_trace; } diff --git a/engine/common/mathlib.c b/engine/common/mathlib.c index fc84652d2..996b0c56b 100644 --- a/engine/common/mathlib.c +++ b/engine/common/mathlib.c @@ -1321,9 +1321,10 @@ void Matrix4x4_Identity(float *outm) outm[15] = 1; } -void Matrix4x4_CM_Projection_Far(float *proj, float fovx, float fovy, float neard, float fard) +void Matrix4x4_CM_Projection_Far(float *proj, float fovx, float fovy, float neard, float fard, qboolean d3d) { double xmin, xmax, ymin, ymax; + double dn = (d3d?0:-1), df = 1; //proj ymax = neard * tan( fovy * M_PI / 360.0 ); @@ -1352,8 +1353,8 @@ void Matrix4x4_CM_Projection_Far(float *proj, float fovx, float fovy, float near proj[2] = 0; proj[6] = 0; - proj[10] = (fard+neard)/(neard-fard); - proj[14] = (2*fard*neard)/(neard-fard); + proj[10] = (fard*df-neard*dn)/(neard-fard); + proj[14] = ((df-dn)*fard*neard)/(neard-fard); proj[3] = 0; proj[7] = 0; @@ -1361,10 +1362,10 @@ void Matrix4x4_CM_Projection_Far(float *proj, float fovx, float fovy, float near proj[15] = 0; } -void Matrix4x4_CM_Projection_Inf(float *proj, float fovx, float fovy, float neard) +void Matrix4x4_CM_Projection_Inf(float *proj, float fovx, float fovy, float neard, qboolean d3d) { float xmin, xmax, ymin, ymax; - float nudge = 1; + double dn = (d3d?0:-1), df = 1; //proj ymax = neard * tan( fovy * M_PI / 360.0 ); @@ -1391,10 +1392,29 @@ void Matrix4x4_CM_Projection_Inf(float *proj, float fovx, float fovy, float near proj[9] = (ymax + ymin) / (ymax - ymin); proj[13] = 0; +#if 1 + { + const double epsilon = 1.0/(1<<22); + proj[2] = 0; + proj[6] = 0; + proj[10] = epsilon-1; + proj[14] = (epsilon-(df-dn))*neard; + } +#elif 1 + { //mathematical target + const float fard = (1<<22); + proj[2] = 0; + proj[6] = 0; + proj[10] = (fard*df-neard*dn)/(neard-fard); + proj[14] = ((df-dn)*fard*neard)/(neard-fard); + } +#else + //old logic proj[2] = 0; proj[6] = 0; proj[10] = -1 * ((float)(1<<21)/(1<<22)); - proj[14] = -2*neard * nudge; + proj[14] = -2*neard; +#endif proj[3] = 0; proj[7] = 0; @@ -1793,7 +1813,7 @@ void Matrix4x4_CM_UnProject(const vec3_t in, vec3_t out, const vec3_t viewangles float tempm[16]; Matrix4x4_CM_ModelViewMatrix(modelview, viewangles, vieworg); - Matrix4x4_CM_Projection_Inf(proj, fovx, fovy, 4); + Matrix4x4_CM_Projection_Inf(proj, fovx, fovy, 4, true); Matrix4_Multiply(proj, modelview, tempm); Matrix4_Invert(tempm, proj); @@ -1828,7 +1848,7 @@ qboolean Matrix4x4_CM_Project (const vec3_t in, vec3_t out, const vec3_t viewang float proj[16]; Matrix4x4_CM_ModelViewMatrix(modelview, viewangles, vieworg); - Matrix4x4_CM_Projection_Inf(proj, fovx, fovy, 4); + Matrix4x4_CM_Projection_Inf(proj, fovx, fovy, 4, true); { float v[4], tempv[4]; diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index ae0d427cc..f0f206541 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -184,9 +184,9 @@ void QuaternionSlerp(const vec4_t p, vec4_t q, float t, vec4_t qt); //projection matricies of different types... gesh void Matrix4x4_CM_Orthographic (float *proj, float xmin, float xmax, float ymax, float ymin, float znear, float zfar); void Matrix4x4_CM_OrthographicD3D(float *proj, float xmin, float xmax, float ymax, float ymin, float znear, float zfar); -void Matrix4x4_CM_Projection_Far(float *proj, float fovx, float fovy, float neard, float fard); +void Matrix4x4_CM_Projection_Far(float *proj, float fovx, float fovy, float neard, float fard, qboolean d3d); void Matrix4x4_CM_Projection2 (float *proj, float fovx, float fovy, float neard); -void Matrix4x4_CM_Projection_Inf(float *proj, float fovx, float fovy, float neard); +void Matrix4x4_CM_Projection_Inf(float *proj, float fovx, float fovy, float neard, qboolean d3d); fixed16_t Mul16_30 (fixed16_t multiplier, fixed16_t multiplicand); int Q_log2 (int val); diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index da78ad01c..a8858c0da 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -102,7 +102,15 @@ cvar_t net_enable_http = CVARD("net_enable_http", "1", "If enabled, tcp port cvar_t net_enable_websockets = CVARD("net_enable_websockets", "1", "If enabled, tcp ports will accept websocket game clients."); cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "1", "If 1, tcp ports will accept websocket connections from clients trying to broker direct webrtc connections. This should be low traffic, but might involve a lot of mostly-idle connections."); #endif -cvar_t cl_delay_packets = CVARD("cl_delay_packets", "0", "Extra latency, in milliseconds."); + +#ifndef SERVERONLY +static void cl_delay_packets_Announce(cvar_t *var, char *oldval) +{ + if (cls.state >= ca_connected && cl.fpd & FPD_ANOUNCE_FAKE_LAG) + Cbuf_AddText(va("say Fake lag now %ims\n", var->ival), RESTRICT_LOCAL); +} +static cvar_t cl_delay_packets = CVARCD("cl_delay_packets", "0", cl_delay_packets_Announce, "Extra latency, in milliseconds."); +#endif extern cvar_t sv_public, sv_listen_qw, sv_listen_nq, sv_listen_dp; #ifdef QWOVERQ3 @@ -6570,13 +6578,13 @@ neterr_t NET_SendPacket (netsrc_t netsrc, int length, const void *data, netadr_t #else collection = cls.sockets; - if (cl_delay_packets.value >= 1) + if (cl_delay_packets.ival >= 1 && !(cl.fpd & FPD_NO_FAKE_LAG)) { struct ftenet_delayed_packet_s *p, **l; if (!collection) return NETERR_NOROUTE; //erk... p = BZ_Malloc(sizeof(*p) - sizeof(p->data) + length); - p->sendtime = Sys_Milliseconds() + (int)cl_delay_packets.value; + p->sendtime = Sys_Milliseconds() + cl_delay_packets.ival; p->next = NULL; p->cursize = length; p->dest = *to; @@ -7313,12 +7321,12 @@ void NET_Init (void) Cvar_Register(&net_hybriddualstack, "networking"); Cvar_Register(&net_fakeloss, "networking"); - Cvar_Register(&cl_delay_packets, "networking"); #ifndef CLIENTONLY Cmd_AddCommand("sv_addport", SVNET_AddPort_f); #endif #ifndef SERVERONLY + Cvar_Register(&cl_delay_packets, "networking"); Cmd_AddCommand("cl_addport", NET_ClientPort_f); #endif diff --git a/engine/common/pmove.c b/engine/common/pmove.c index 649a8e0fc..acfdb9561 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -773,6 +773,14 @@ void PM_AirMove (void) vec3_t wishdir; float wishspeed; + if (pmove.gravitydir[2] == -1 && (pmove.angles[0] == 90 || pmove.angles[0] == -90)) + { //HACK: attempt to avoid a stupid numerical precision issue. + //You know its a hack because I'm comparing exact angles. + vec3_t tmp; + VectorSet(tmp, pmove.angles[0]*0.99, pmove.angles[1], pmove.angles[2]); + AngleVectors (tmp, forward, right, up); + } + fmove = pmove.cmd.forwardmove; smove = pmove.cmd.sidemove; VectorMA(forward, -DotProduct(forward, pmove.gravitydir), pmove.gravitydir, forward); //z=0 diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 50620805e..8c3e36e85 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -53,7 +53,7 @@ void PF_Common_RegisterCvars(void) _mm_setcsr(mxcsr & ~(0x8040)); } else - Con_Printf(CON_WARNING "WARNING: denormalised floats are disabled. Use -nodaz to re-enable if mods malfunction\n"); + Con_Printf(CON_WARNING "denormalised floats are disabled. Use -nodaz to re-enable if mods malfunction\n"); } #else volatile union @@ -64,7 +64,7 @@ void PF_Common_RegisterCvars(void) a.i = 1; b.i = 1; if (!(a.f && b.f)) - Con_Printf(CON_WARNING "WARNING: denormalised floats are disabled. Some mods might may malfunction\n"); + Con_Printf(CON_WARNING "denormalised floats are disabled. Some mods might may malfunction\n"); #endif #endif diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 0f9a1ffe5..5055df47e 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -78,6 +78,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PEXT2_PREDINFO 0x00000020 //movevar stats, NQ input sequences+acks. #define PEXT2_NEWSIZEENCODING 0x00000040 //richer size encoding. +//EzQuake/Mvdsv extensions +#define EZPEXT1_FLOATENTCOORDS 0x00000001 //quirky - doesn't apply to broadcasts, just players+ents. this gives more precision, but will bug out if you try using it to increase map bounds in ways that may not be immediately apparent. iiuc this was added instead of fixing some inconsistent rounding... +#define EZPEXT1_SETANGLEREASON 0x00000002 //specifies the reason for an svc_setangles call. the mvdsv implementation will fuck over any mods that writebyte them. we'd need to modify our preparse stuff to work around the issue. + //ZQuake transparent protocol extensions. #define Z_EXT_PM_TYPE (1<<0) // basic PM_TYPE functionality (reliable jump_held) #define Z_EXT_PM_TYPE_NEW (1<<1) // adds PM_FLY, PM_SPECTATOR @@ -102,6 +106,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PROTOCOL_VERSION_FTE (('F'<<0) + ('T'<<8) + ('E'<<16) + ('X' << 24)) //fte extensions. #define PROTOCOL_VERSION_FTE2 (('F'<<0) + ('T'<<8) + ('E'<<16) + ('2' << 24)) //fte extensions. +#define PROTOCOL_VERSION_EZQUAKE1 (('M'<<0) + ('V'<<8) + ('D'<<16) + ('1' << 24)) //ezquake/mvdsv extensions #define PROTOCOL_VERSION_HUFFMAN (('H'<<0) + ('U'<<8) + ('F'<<16) + ('F' << 24)) //packet compression #define PROTOCOL_VERSION_FRAGMENT (('F'<<0) + ('R'<<8) + ('A'<<16) + ('G' << 24)) //supports fragmentation/packets larger than 1450 #ifdef HAVE_DTLS diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index a253a06fb..0183d7f20 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -2748,21 +2748,21 @@ batch_t *D3D11BE_GetTempBatch(void) return &shaderstate.wbatches[shaderstate.wbatch++]; } -float projd3dtogl[16] = +/*static float projd3dtogl[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, -1.0, 1.0 -}; -float projgltod3d[16] = +};*/ +static float projgltod3d[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5, 1.0 }; -void D3D11BE_SetupViewCBuffer(void) +static void D3D11BE_SetupViewCBuffer(void) { cbuf_view_t *cbv; D3D11_MAPPED_SUBRESOURCE msr; @@ -2778,7 +2778,7 @@ void D3D11BE_SetupViewCBuffer(void) //d3d uses 0 to 1 depth. //so we scale the projection matrix by a bias #if 1 - Matrix4_Multiply(projgltod3d, r_refdef.m_projection_std, cbv->m_projection); + Matrix4_Multiply(projgltod3d, (shaderstate.depthrange<1)?r_refdef.m_projection_view:r_refdef.m_projection_std, cbv->m_projection); #else memcpy(cbv->m_projection, r_refdef.m_projection_std, sizeof(cbv->m_projection)); cbv->m_projection[10] = r_refdef.m_projection_std[10] * 0.5; @@ -2789,6 +2789,20 @@ void D3D11BE_SetupViewCBuffer(void) ID3D11DeviceContext_Unmap(d3ddevctx, (ID3D11Resource*)shaderstate.vcbuffer, 0); } +void D3D11BE_Set2D(void) +{ + D3D11_VIEWPORT vport; + vport.TopLeftX = 0; + vport.TopLeftY = 0; + vport.Width = vid.pixelwidth; + vport.Height = vid.pixelheight; + vport.MinDepth = 0; + vport.MaxDepth = shaderstate.depthrange = 1; + + ID3D11DeviceContext_RSSetViewports(d3ddevctx, 1, &vport); + D3D11BE_SetupViewCBuffer(); + D3D11BE_Scissor(NULL); +} void D3D11BE_SetupLightCBuffer(dlight_t *l, vec3_t colour) { extern cvar_t gl_specular; @@ -3096,6 +3110,8 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) vport.MinDepth = 0; vport.MaxDepth = shaderstate.depthrange; ID3D11DeviceContext_RSSetViewports(d3ddevctx, 1, &vport); + + D3D11BE_SetupViewCBuffer(); } } diff --git a/engine/d3d/d3d11_image.c b/engine/d3d/d3d11_image.c index 77e4fb271..42b277cd3 100644 --- a/engine/d3d/d3d11_image.c +++ b/engine/d3d/d3d11_image.c @@ -111,8 +111,7 @@ static void Upload_Texture_32(ID3D11Texture2D *tex, unsigned int *data, int data qboolean D3D11_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mips) { - int bytesperpixel = 4; - int bcbytes = 0; + unsigned int blockbytes, blockwidth, blockheight; HRESULT hr; D3D11_TEXTURE2D_DESC tdesc = {0}; D3D11_SUBRESOURCE_DATA subresdesc[sizeof(mips->mip) / sizeof(mips->mip[0])]; @@ -159,92 +158,108 @@ qboolean D3D11_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mi case PTI_DEPTH16: tdesc.Format = DXGI_FORMAT_D16_UNORM; tdesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - bytesperpixel = 2; break; case PTI_DEPTH24: tdesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; tdesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - bytesperpixel = 3; break; case PTI_DEPTH32: tdesc.Format = DXGI_FORMAT_D32_FLOAT; tdesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - bytesperpixel = 4; break; case PTI_DEPTH24_8: tdesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; tdesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - bytesperpixel = 4; break; case PTI_RGB565: tdesc.Format = DXGI_FORMAT_B5G6R5_UNORM; - bytesperpixel = 2; break; // case PTI_RGBA5551: // tdesc.Format = DXGI_FORMAT_A1B5G5R5_UNORM; -// bytesperpixel = 2; // break; case PTI_ARGB1555: tdesc.Format = DXGI_FORMAT_B5G5R5A1_UNORM; - bytesperpixel = 2; break; case PTI_RGBA4444: tdesc.Format = DXGI_FORMAT_B4G4R4A4_UNORM; - bytesperpixel = 2; break; // case PTI_ARGB4444: // tdesc.Format = DXGI_FORMAT_A4B4G4R4_UNORM; -// bytesperpixel = 2; // break; case PTI_RGBA8: tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - bytesperpixel = 4; break; case PTI_RGBX8: //d3d11 has no alphaless format. be sure to proprly disable alpha in the shader. tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - bytesperpixel = 4; break; case PTI_BGRA8: tdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - bytesperpixel = 4; break; case PTI_BGRX8: tdesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; - bytesperpixel = 4; break; case PTI_RGBA8_SRGB: tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - bytesperpixel = 4; break; case PTI_RGBX8_SRGB: //d3d11 has no alphaless format. be sure to proprly disable alpha in the shader. tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - bytesperpixel = 4; break; case PTI_BGRA8_SRGB: tdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; - bytesperpixel = 4; break; case PTI_BGRX8_SRGB: tdesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; - bytesperpixel = 4; break; - case PTI_S3RGB1: //d3d11 provides no way to disable alpha with dxt1. be sure to proprly disable alpha in the shader. - case PTI_S3RGBA1: + case PTI_BC1_RGB: //d3d11 provides no way to disable alpha with dxt1. be sure to proprly disable alpha in the shader. + case PTI_BC1_RGBA: tdesc.Format = DXGI_FORMAT_BC1_UNORM; - bcbytes = 8; break; - case PTI_S3RGBA3: + case PTI_BC2_RGBA: tdesc.Format = DXGI_FORMAT_BC2_UNORM; - bcbytes = 16; break; - case PTI_S3RGBA5: + case PTI_BC3_RGBA: tdesc.Format = DXGI_FORMAT_BC3_UNORM; - bcbytes = 16; + break; + case PTI_BC1_RGB_SRGB: //d3d11 provides no way to disable alpha with dxt1. be sure to proprly disable alpha in the shader. + case PTI_BC1_RGBA_SRGB: + tdesc.Format = DXGI_FORMAT_BC1_UNORM_SRGB; + break; + case PTI_BC2_RGBA_SRGB: + tdesc.Format = DXGI_FORMAT_BC2_UNORM_SRGB; + break; + case PTI_BC3_RGBA_SRGB: + tdesc.Format = DXGI_FORMAT_BC3_UNORM_SRGB; + break; + case PTI_BC4_R8: + tdesc.Format = DXGI_FORMAT_BC4_UNORM; + break; + case PTI_BC4_R8_SIGNED: + tdesc.Format = DXGI_FORMAT_BC4_SNORM; + break; + case PTI_BC5_RG8: + tdesc.Format = DXGI_FORMAT_BC5_UNORM; + break; + case PTI_BC5_RG8_SIGNED: + tdesc.Format = DXGI_FORMAT_BC5_SNORM; + break; + case PTI_BC6_RGBF: + tdesc.Format = DXGI_FORMAT_BC6H_UF16; + break; + case PTI_BC6_RGBF_SIGNED: + tdesc.Format = DXGI_FORMAT_BC6H_SF16; + break; + case PTI_BC7_RGBA: + tdesc.Format = DXGI_FORMAT_BC7_UNORM; + break; + case PTI_BC7_RGBA_SRGB: + tdesc.Format = DXGI_FORMAT_BC7_UNORM_SRGB; break; } + Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight); + if (!mips->mip[0].data) { subresdesc[0].pSysMem = NULL; @@ -256,16 +271,8 @@ qboolean D3D11_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mi for (i = 0; i < mips->mipcount; i++) { subresdesc[i].pSysMem = mips->mip[i].data; - if (bcbytes) - { - subresdesc[i].SysMemPitch = ((mips->mip[i].width+3)/4) * bcbytes; - subresdesc[i].SysMemSlicePitch = mips->mip[i].datasize; - } - else - { - subresdesc[i].SysMemPitch = mips->mip[i].width*bytesperpixel; - subresdesc[i].SysMemSlicePitch = mips->mip[i].datasize;//mips->mip[i].width*mips->mip[i].height*bytesperpixel; - } + subresdesc[i].SysMemPitch = ((mips->mip[i].width+blockwidth-1)/blockwidth) * blockbytes; + subresdesc[i].SysMemSlicePitch = mips->mip[i].datasize; } tdesc.MipLevels = i/tdesc.ArraySize; } diff --git a/engine/d3d/d3d8_image.c b/engine/d3d/d3d8_image.c index 52f48205d..99411fa15 100644 --- a/engine/d3d/d3d8_image.c +++ b/engine/d3d/d3d8_image.c @@ -34,29 +34,25 @@ qboolean D3D8_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip D3DSURFACE_DESC desc; IDirect3DTexture8 *dt; qboolean swap = false; - unsigned int pixelsize = 4; - unsigned int blocksize = 0; + unsigned int blockwidth, blockheight, blockbytes = 1; switch(mips->encoding) { case PTI_RGB565: - pixelsize = 2; fmt = D3DFMT_R5G6B5; break; case PTI_RGBA4444://not supported on d3d9 return false; case PTI_ARGB4444: - pixelsize = 2; fmt = D3DFMT_A4R4G4B4; break; case PTI_RGBA5551://not supported on d3d9 return false; case PTI_ARGB1555: - pixelsize = 2; fmt = D3DFMT_A1R5G5B5; break; case PTI_RGBA8: -// fmt = D3DFMT_A8B8G8R8; /*how do we check +// fmt = D3DFMT_A8B8G8R8; //how do we check fmt = D3DFMT_A8R8G8B8; swap = true; break; @@ -73,24 +69,23 @@ qboolean D3D8_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip break; //too lazy to support these for now - case PTI_S3RGB1: - case PTI_S3RGBA1: //d3d doesn't distinguish between these + case PTI_BC1_RGB: + case PTI_BC1_RGBA: //d3d doesn't distinguish between these fmt = D3DFMT_DXT1; - blocksize = 8; break; - case PTI_S3RGBA3: + case PTI_BC2_RGBA: fmt = D3DFMT_DXT3; - blocksize = 16; break; - case PTI_S3RGBA5: + case PTI_BC3_RGBA: fmt = D3DFMT_DXT5; - blocksize = 16; break; default: //no idea return false; } + Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight); + if (!pD3DDev8) return false; //can happen on errors if (FAILED(IDirect3DDevice8_CreateTexture(pD3DDev8, mips->mip[0].width, mips->mip[0].height, mips->mipcount, 0, fmt, D3DPOOL_MANAGED, &dt))) @@ -110,17 +105,12 @@ qboolean D3D8_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip //can't do it in one go. pitch might contain padding or be upside down. if (!mips->mip[i].data) ; - else if (blocksize) - { - if (lock.Pitch == ((mips->mip[i].width+3)/4)*blocksize) - //for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*pixelsize) - memcpy(lock.pBits, mips->mip[i].data, mips->mip[i].datasize); - } else if (swap) { - for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*4) + size_t rowbytes = ((mips->mip[i].width+blockwidth-1)/blockwidth)*blockbytes; + for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += rowbytes) { - for (x = 0; x < mips->mip[i].width*4; x+=4) + for (x = 0; x < rowbytes; x+=4) { out[x+0] = in[x+2]; out[x+1] = in[x+1]; @@ -131,8 +121,9 @@ qboolean D3D8_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip } else { - for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*pixelsize) - memcpy(out, in, mips->mip[i].width*pixelsize); + size_t rowbytes = ((mips->mip[i].width+blockwidth-1)/blockwidth)*blockbytes; + for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y+blockheight, out += lock.Pitch, in += rowbytes) + memcpy(out, in, rowbytes); } IDirect3DTexture8_UnlockRect(dt, i); } diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index a075f96d4..8b74a30d2 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -54,9 +54,10 @@ extern LPDIRECT3DDEVICE9 pD3DDev9; #define MAX_TC_TMUS 4 extern texid_t r_whiteimage; -extern float d3d_trueprojection[16]; +extern float d3d_trueprojection_std[16]; +extern float d3d_trueprojection_view[16]; -static void BE_RotateForEntity (const entity_t *e, const model_t *mod); +static void D3D9BE_RotateForEntity (const entity_t *e, const model_t *mod); /*========================================== tables for deforms =====================================*/ #define frand() (rand()*(1.0/RAND_MAX)) @@ -158,6 +159,9 @@ typedef struct backendmode_t mode; unsigned int flags; + D3DVIEWPORT9 vport; + float *curprojection; + float curtime; const entity_t *curentity; const dlight_t *curdlight; @@ -671,6 +675,7 @@ void D3D9BE_Init(void) be_maxpasses = MAX_TMUS; memset(&shaderstate, 0, sizeof(shaderstate)); shaderstate.curvertdecl = -1; + shaderstate.curentity = &r_worldentity; FTable_Init(); @@ -693,6 +698,20 @@ void D3D9BE_Set2D(void) shaderstate.curtime = r_refdef.time; } +void D3D9BE_SetViewport(int x, int w, int y, int h) +{ + shaderstate.vport.X = x; + shaderstate.vport.Y = y; + shaderstate.vport.Width = w; + shaderstate.vport.Height = h; + shaderstate.vport.MinZ = 0; + shaderstate.vport.MaxZ = 1; + IDirect3DDevice9_SetViewport(pD3DDev9, &shaderstate.vport); + + shaderstate.curprojection = d3d_trueprojection_std; + IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)shaderstate.curprojection); +} + static void allocvertexbuffer(IDirect3DVertexBuffer9 *buff, unsigned int bmaxsize, unsigned int *offset, void **data, unsigned int bytes) { unsigned int boff; @@ -1677,14 +1696,7 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds for (j = 0; j < 3; j++) rot_centre[j] = (quad[0][j] + quad[1][j] + quad[2][j] + quad[3][j]) * 0.25; - if (shaderstate.curentity) - { - VectorAdd(shaderstate.curentity->origin, rot_centre, tv); - } - else - { - VectorCopy(rot_centre, tv); - } + VectorAdd(shaderstate.curentity->origin, rot_centre, tv); VectorSubtract(r_origin, tv, tv); // filter any longest-axis-parts off the camera-direction @@ -1863,7 +1875,7 @@ static void BE_ApplyUniforms(program_t *prog, int permu) switch (pp->type) { case SP_M_PROJECTION: - IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, h, d3d_trueprojection, 4); + IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, h, shaderstate.curprojection, 4); break; case SP_M_VIEW: IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, h, r_refdef.m_view, 4); @@ -1898,7 +1910,7 @@ static void BE_ApplyUniforms(program_t *prog, int permu) { float mv[16], mvp[16]; Matrix4_Multiply(r_refdef.m_view, shaderstate.m_model, mv); - Matrix4_Multiply(d3d_trueprojection, mv, mvp); + Matrix4_Multiply(shaderstate.curprojection, mv, mvp); IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, h, mvp, 4); } break; @@ -2048,7 +2060,7 @@ static void BE_RenderMeshProgram(shader_t *s, unsigned int vertbase, unsigned in // if (p->permu[perm|PERMUTATION_DELUXE].h.loaded && TEXVALID(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe) // perm |= PERMUTATION_DELUXE; #if MAXRLIGHTMAPS > 1 - if (shaderstate.curbatch->lightmap[1] >= 0 && p->permu[perm|PERMUTATION_LIGHTSTYLES].h.loaded) + if (shaderstate.curbatch && shaderstate.curbatch->lightmap[1] >= 0 && p->permu[perm|PERMUTATION_LIGHTSTYLES].h.loaded) perm |= PERMUTATION_LIGHTSTYLES; #endif @@ -2544,7 +2556,7 @@ qboolean D3D9BE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsign void D3D9BE_SelectEntity(entity_t *ent) { shaderstate.curentity = ent; - BE_RotateForEntity(ent, ent->model); + D3D9BE_RotateForEntity(ent, ent->model); } #if 1 @@ -2983,10 +2995,11 @@ batch_t *D3D9BE_GetTempBatch(void) return &shaderstate.wbatches[shaderstate.wbatch++]; } -static void BE_RotateForEntity (const entity_t *e, const model_t *mod) +static void D3D9BE_RotateForEntity (const entity_t *e, const model_t *mod) { // float mv[16]; float *m = shaderstate.m_model; + float maxz; shaderstate.curentity = e; @@ -3147,11 +3160,22 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_WORLD, (D3DMATRIX*)m); + if (e->flags & RF_DEPTHHACK) + maxz = 0.333; + else + maxz = 1; + + if (shaderstate.vport.MaxZ != maxz) { - D3DVIEWPORT9 vport; - IDirect3DDevice9_GetViewport(pD3DDev9, &vport); - vport.MaxZ = (e->flags & RF_DEPTHHACK)?0.333:1; - IDirect3DDevice9_SetViewport(pD3DDev9, &vport); + shaderstate.vport.MaxZ = maxz; + + if (maxz < 1) + shaderstate.curprojection = d3d_trueprojection_view; + else + shaderstate.curprojection = d3d_trueprojection_std; + + IDirect3DDevice9_SetViewport(pD3DDev9, &shaderstate.vport); + IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)shaderstate.curprojection); } } @@ -3163,7 +3187,7 @@ void D3D9BE_SubmitBatch(batch_t *batch) return; if (shaderstate.curentity != batch->ent) { - BE_RotateForEntity(batch->ent, batch->ent->model); + D3D9BE_RotateForEntity(batch->ent, batch->ent->model); shaderstate.curtime = r_refdef.time - shaderstate.curentity->shaderTime; } shaderstate.batchvbo = batch->vbo; @@ -3379,7 +3403,7 @@ static void TransformDir(vec3_t in, vec3_t planea[3], vec3_t viewa[3], vec3_t re } static void R_RenderScene(void) { - IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)d3d_trueprojection); +// IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)d3d_trueprojection); IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)r_refdef.m_view); R_SetFrustum (r_refdef.m_projection_std, r_refdef.m_view); Surf_DrawWorld(); @@ -3491,7 +3515,7 @@ static void R_DrawPortal(batch_t *batch, batch_t **blist) AngleVectors (r_refdef.viewangles, vpn, vright, vup); VectorCopy (r_refdef.vieworg, r_origin); - IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)d3d_trueprojection); +// IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)d3d_trueprojection); IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)r_refdef.m_view); R_SetFrustum (r_refdef.m_projection_std, r_refdef.m_view); } @@ -3603,7 +3627,7 @@ void D3D9BE_DrawWorld (batch_t **worldbatches) batch_t *batches[SHADER_SORT_COUNT]; RSpeedLocals(); - shaderstate.curentity = NULL; + shaderstate.curentity = &r_worldentity; if (!r_refdef.recurse) { @@ -3677,7 +3701,7 @@ void D3D9BE_DrawWorld (batch_t **worldbatches) R_RenderDlights (); - BE_RotateForEntity(&r_worldentity, NULL); + D3D9BE_RotateForEntity(&r_worldentity, NULL); } void D3D9BE_VBO_Begin(vbobctx_t *ctx, size_t maxsize) { diff --git a/engine/d3d/d3d_image.c b/engine/d3d/d3d_image.c index 2cc56914a..45afa3b40 100644 --- a/engine/d3d/d3d_image.c +++ b/engine/d3d/d3d_image.c @@ -27,25 +27,21 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip D3DSURFACE_DESC desc; IDirect3DBaseTexture9 *dbt; qboolean swap = false; - unsigned int pixelsize = 4; - unsigned int blocksize = 0; + unsigned int blockwidth, blockheight, blockbytes; switch(mips->encoding) { case PTI_RGB565: - pixelsize = 2; fmt = D3DFMT_R5G6B5; break; case PTI_RGBA4444://not supported on d3d9 return false; case PTI_ARGB4444: - pixelsize = 2; fmt = D3DFMT_A4R4G4B4; break; case PTI_RGBA5551://not supported on d3d9 return false; case PTI_ARGB1555: - pixelsize = 2; fmt = D3DFMT_A1R5G5B5; break; case PTI_RGBA8_SRGB: @@ -70,24 +66,30 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip break; //too lazy to support these for now - case PTI_S3RGB1: - case PTI_S3RGBA1: //d3d doesn't distinguish between these + case PTI_BC1_RGB_SRGB: + case PTI_BC1_RGBA_SRGB: //d3d doesn't distinguish between these + case PTI_BC1_RGB: + case PTI_BC1_RGBA: //d3d doesn't distinguish between these fmt = D3DFMT_DXT1; - blocksize = 8; break; - case PTI_S3RGBA3: + case PTI_BC2_RGBA_SRGB: + case PTI_BC2_RGBA: fmt = D3DFMT_DXT3; - blocksize = 16; break; - case PTI_S3RGBA5: + case PTI_BC3_RGBA_SRGB: + case PTI_BC3_RGBA: fmt = D3DFMT_DXT5; - blocksize = 16; break; + //bc4-7 not supported on d3d9. + //etc2 have no chance. + default: //no idea return false; } + Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight); + if (!pD3DDev9) return false; //can happen on errors if (mips->type == PTI_CUBEMAP) @@ -111,17 +113,12 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip //can't do it in one go. pitch might contain padding or be upside down. if (!mips->mip[i].data) ; - else if (blocksize) - { - if (lock.Pitch == ((mips->mip[i].width+3)/4)*blocksize) - //for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*pixelsize) - memcpy(lock.pBits, mips->mip[i].data, mips->mip[i].datasize); - } else if (swap) - { - for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*4) + { //only works for blockbytes=4 + size_t rowbytes = ((mips->mip[i].width+blockwidth-1)/blockwidth)*blockbytes; + for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y+=blockheight, out += lock.Pitch, in += rowbytes) { - for (x = 0; x < mips->mip[i].width*4; x+=4) + for (x = 0; x < rowbytes; x+=4) { out[x+0] = in[x+2]; out[x+1] = in[x+1]; @@ -132,8 +129,9 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip } else { - for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*pixelsize) - memcpy(out, in, mips->mip[i].width*pixelsize); + size_t rowbytes = ((mips->mip[i].width+blockwidth-1)/blockwidth)*blockbytes; + for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y+=blockheight, out += lock.Pitch, in += rowbytes) + memcpy(out, in, rowbytes); } IDirect3DCubeTexture9_UnlockRect(dt, i%6, i/6); } @@ -159,17 +157,12 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip //can't do it in one go. pitch might contain padding or be upside down. if (!mips->mip[i].data) ; - else if (blocksize) - { - if (lock.Pitch == ((mips->mip[i].width+3)/4)*blocksize) - //for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*pixelsize) - memcpy(lock.pBits, mips->mip[i].data, mips->mip[i].datasize); - } else if (swap) { - for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*4) + size_t rowbytes = ((mips->mip[i].width+blockwidth-1)/blockwidth)*blockbytes; + for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y+=blockheight, out += lock.Pitch, in += rowbytes) { - for (x = 0; x < mips->mip[i].width*4; x+=4) + for (x = 0; x < rowbytes; x+=4) { out[x+0] = in[x+2]; out[x+1] = in[x+1]; @@ -180,8 +173,9 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip } else { - for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*pixelsize) - memcpy(out, in, mips->mip[i].width*pixelsize); + size_t rowbytes = ((mips->mip[i].width+blockwidth-1)/blockwidth)*blockbytes; + for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y+=blockheight, out += lock.Pitch, in += rowbytes) + memcpy(out, in, rowbytes); } IDirect3DTexture9_UnlockRect(dt, i); } diff --git a/engine/d3d/d3d_shader.c b/engine/d3d/d3d_shader.c index c5beb789d..9562aafe0 100644 --- a/engine/d3d/d3d_shader.c +++ b/engine/d3d/d3d_shader.c @@ -605,7 +605,7 @@ void D3D9Shader_Init(void) sh_config.texture_non_power_of_two = true; } - sh_config.texture_maxsize = min(caps.MaxTextureWidth, caps.MaxTextureHeight); + sh_config.texturecube_maxsize = sh_config.texture2d_maxsize = min(caps.MaxTextureWidth, caps.MaxTextureHeight); } #endif diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 3ab178f58..3d5096b2e 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -59,7 +59,8 @@ static void resetD3D9(void); static LPDIRECT3D9 pD3D; LPDIRECT3DDEVICE9 pD3DDev9; static D3DPRESENT_PARAMETERS d3dpp; -float d3d_trueprojection[16]; +float d3d_trueprojection_std[16]; +float d3d_trueprojection_view[16]; qboolean vid_initializing; @@ -613,14 +614,23 @@ static qboolean initD3D9Device(HWND hWnd, rendererstate_t *info, unsigned int de unsigned int usage; } fmts[] = { - {PTI_BGRX8, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER}, - {PTI_BGRA8, D3DFMT_A8R8G8B8, D3DUSAGE_QUERY_FILTER}, - {PTI_RGB565, D3DFMT_R5G6B5, D3DUSAGE_QUERY_FILTER}, - {PTI_ARGB1555, D3DFMT_A1R5G5B5, D3DUSAGE_QUERY_FILTER}, - {PTI_ARGB4444, D3DFMT_A4R4G4B4, D3DUSAGE_QUERY_FILTER}, + {PTI_BGRX8, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER}, + {PTI_BGRA8, D3DFMT_A8R8G8B8, D3DUSAGE_QUERY_FILTER}, + {PTI_RGB565, D3DFMT_R5G6B5, D3DUSAGE_QUERY_FILTER}, + {PTI_ARGB1555, D3DFMT_A1R5G5B5, D3DUSAGE_QUERY_FILTER}, + {PTI_ARGB4444, D3DFMT_A4R4G4B4, D3DUSAGE_QUERY_FILTER}, - {PTI_BGRX8_SRGB, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBREAD}, - {PTI_BGRA8_SRGB, D3DFMT_A8R8G8B8, D3DUSAGE_QUERY_SRGBREAD}, + {PTI_BGRX8_SRGB, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER|D3DUSAGE_QUERY_SRGBREAD}, + {PTI_BGRA8_SRGB, D3DFMT_A8R8G8B8, D3DUSAGE_QUERY_FILTER|D3DUSAGE_QUERY_SRGBREAD}, + + {PTI_BC1_RGB, D3DFMT_DXT1, D3DUSAGE_QUERY_FILTER}, + {PTI_BC1_RGBA, D3DFMT_DXT1, D3DUSAGE_QUERY_FILTER}, + {PTI_BC2_RGBA, D3DFMT_DXT3, D3DUSAGE_QUERY_FILTER}, + {PTI_BC3_RGBA, D3DFMT_DXT5, D3DUSAGE_QUERY_FILTER}, + {PTI_BC1_RGB_SRGB, D3DFMT_DXT1, D3DUSAGE_QUERY_FILTER|D3DUSAGE_QUERY_SRGBREAD}, + {PTI_BC1_RGBA_SRGB, D3DFMT_DXT1, D3DUSAGE_QUERY_FILTER|D3DUSAGE_QUERY_SRGBREAD}, + {PTI_BC2_RGBA_SRGB, D3DFMT_DXT3, D3DUSAGE_QUERY_FILTER|D3DUSAGE_QUERY_SRGBREAD}, + {PTI_BC3_RGBA_SRGB, D3DFMT_DXT5, D3DUSAGE_QUERY_FILTER|D3DUSAGE_QUERY_SRGBREAD}, }; for (i = 0; i < countof(fmts); i++) if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(pD3D, devno, devtype, d3dpp.BackBufferFormat, fmts[i].usage, D3DRTYPE_TEXTURE, fmts[i].d3d9))) @@ -919,11 +929,9 @@ static void (D3D9_VID_SetWindowCaption) (const char *msg) void D3D9_Set2D (void) { float m[16]; - D3DVIEWPORT9 vport; // IDirect3DDevice9_EndScene(pD3DDev9); - Matrix4x4_CM_OrthographicD3D(m, 0 + (0.5*vid.width/vid.pixelwidth), vid.width + (0.5*vid.width/vid.pixelwidth), 0 + (0.5*vid.height/vid.pixelheight), vid.height + (0.5*vid.height/vid.pixelheight), 0, 100); - IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)m); + Matrix4x4_CM_OrthographicD3D(d3d_trueprojection_std, 0 + (0.5*vid.width/vid.pixelwidth), vid.width + (0.5*vid.width/vid.pixelwidth), 0 + (0.5*vid.height/vid.pixelheight), vid.height + (0.5*vid.height/vid.pixelheight), 0, 100); Matrix4x4_Identity(m); IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_WORLD, (D3DMATRIX*)m); @@ -931,15 +939,6 @@ void D3D9_Set2D (void) Matrix4x4_Identity(m); IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)m); - vport.X = 0; - vport.Y = 0; - vport.Width = vid.pixelwidth; - vport.Height = vid.pixelheight; - vport.MinZ = 0; - vport.MaxZ = 1; - IDirect3DDevice9_SetViewport(pD3DDev9, &vport); - - vid.fbvwidth = vid.width; vid.fbvheight = vid.height; vid.fbpwidth = vid.pixelwidth; @@ -951,6 +950,7 @@ void D3D9_Set2D (void) r_refdef.pxrect.height = vid.fbpheight; D3D9BE_Set2D(); + D3D9BE_SetViewport(0, vid.fbpwidth, 0, vid.fbpheight); } static int d3d9error(int i) @@ -1196,8 +1196,7 @@ static void D3D9_SetupViewPortProjection(void) int x, x2, y2, y, w, h; float fov_x, fov_y; - - D3DVIEWPORT9 vport; + float fovv_x, fovv_y; AngleVectors (r_refdef.viewangles, vpn, vright, vup); VectorCopy (r_refdef.vieworg, r_origin); @@ -1223,21 +1222,17 @@ static void D3D9_SetupViewPortProjection(void) w = x2 - x; h = y2 - y; - vport.X = x; - vport.Y = y; - vport.Width = w; - vport.Height = h; - vport.MinZ = 0; - vport.MaxZ = 1; - IDirect3DDevice9_SetViewport(pD3DDev9, &vport); - fov_x = r_refdef.fov_x;//+sin(cl.time)*5; fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5; + fovv_x = r_refdef.fovv_x; + fovv_y = r_refdef.fovv_y; if ((r_refdef.flags & RDF_UNDERWATER) && !(r_refdef.flags & RDF_WATERWARP)) { fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); fov_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); + fovv_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); + fovv_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); } /*view matrix*/ @@ -1247,19 +1242,21 @@ static void D3D9_SetupViewPortProjection(void) if (r_refdef.maxdist) { /*d3d projection matricies scale depth to 0 to 1*/ - Matrix4x4_CM_Projection_Far(d3d_trueprojection, fov_x, fov_y, r_refdef.mindist/2, r_refdef.maxdist); + Matrix4x4_CM_Projection_Far(d3d_trueprojection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist, true); + Matrix4x4_CM_Projection_Far(d3d_trueprojection_view, fovv_x, fovv_y, r_refdef.mindist, r_refdef.maxdist, true); /*ogl projection matricies scale depth to -1 to 1, and I would rather my code used consistant culling*/ - Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist); + Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist, false); } else { /*d3d projection matricies scale depth to 0 to 1*/ - Matrix4x4_CM_Projection_Inf(d3d_trueprojection, fov_x, fov_y, r_refdef.mindist/2); + Matrix4x4_CM_Projection_Inf(d3d_trueprojection_std, fov_x, fov_y, r_refdef.mindist, true); + Matrix4x4_CM_Projection_Inf(d3d_trueprojection_view, fovv_x, fovv_y, r_refdef.mindist, true); /*ogl projection matricies scale depth to -1 to 1, and I would rather my code used consistant culling*/ - Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist); + Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, false); } - d3d9error(IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)d3d_trueprojection)); + D3D9BE_SetViewport(x, w, y, h); } static void (D3D9_R_RenderView) (void) diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index f9fda45d9..68bd0b77c 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -839,13 +839,18 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA sh_config.texture_non_power_of_two_pic = true; //always supported in d3d11, supposedly, even with d3d9 devices. sh_config.npot_rounddown = false; if (flevel>=D3D_FEATURE_LEVEL_11_0) - sh_config.texture_maxsize = 16384; + sh_config.texture2d_maxsize = 16384; else if (flevel>=D3D_FEATURE_LEVEL_10_0) - sh_config.texture_maxsize = 8192; + sh_config.texture2d_maxsize = 8192; else if (flevel>=D3D_FEATURE_LEVEL_9_3) - sh_config.texture_maxsize = 4096; + sh_config.texture2d_maxsize = 4096; else - sh_config.texture_maxsize = 2048; + sh_config.texture2d_maxsize = 2048; + + if (flevel>=D3D_FEATURE_LEVEL_9_3) + sh_config.texture2d_maxsize = 4096; + else + sh_config.texture2d_maxsize = 512; //11.1 formats #define DXGI_FORMAT_B4G4R4A4_UNORM 115 @@ -860,13 +865,26 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, &support); sh_config.texfmt[PTI_RGBA8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, &support); sh_config.texfmt[PTI_BGRA8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, &support); sh_config.texfmt[PTI_BGRX8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC1_UNORM, &support); sh_config.texfmt[PTI_S3RGBA1] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC2_UNORM, &support); sh_config.texfmt[PTI_S3RGBA3] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); - ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC3_UNORM, &support); sh_config.texfmt[PTI_S3RGBA5] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC1_UNORM, &support); sh_config.texfmt[PTI_BC1_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC2_UNORM, &support); sh_config.texfmt[PTI_BC2_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC3_UNORM, &support); sh_config.texfmt[PTI_BC3_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC1_UNORM_SRGB, &support); sh_config.texfmt[PTI_BC1_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC2_UNORM_SRGB, &support); sh_config.texfmt[PTI_BC2_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC3_UNORM_SRGB, &support); sh_config.texfmt[PTI_BC3_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC4_UNORM, &support); sh_config.texfmt[PTI_BC4_R8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC4_SNORM, &support); sh_config.texfmt[PTI_BC4_R8_SIGNED] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC5_UNORM, &support); sh_config.texfmt[PTI_BC5_RG8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC5_SNORM, &support); sh_config.texfmt[PTI_BC5_RG8_SIGNED] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC6H_UF16, &support); sh_config.texfmt[PTI_BC6_RGBF] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC6H_SF16, &support); sh_config.texfmt[PTI_BC6_RGBF_SIGNED] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC7_UNORM, &support); sh_config.texfmt[PTI_BC7_RGBA] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC7_UNORM_SRGB, &support); sh_config.texfmt[PTI_BC7_RGBA_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); //these formats are not officially supported as specified, but noone cares sh_config.texfmt[PTI_RGBX8] = sh_config.texfmt[PTI_RGBA8]; - sh_config.texfmt[PTI_S3RGB1] = sh_config.texfmt[PTI_S3RGBA1]; + sh_config.texfmt[PTI_RGBX8_SRGB] = sh_config.texfmt[PTI_RGBA8_SRGB]; + sh_config.texfmt[PTI_BC1_RGB] = sh_config.texfmt[PTI_BC1_RGBA]; + sh_config.texfmt[PTI_BC1_RGB_SRGB] = sh_config.texfmt[PTI_BC1_RGBA_SRGB]; vid.srgb = info->srgb>1; @@ -1184,34 +1202,22 @@ static void (D3D11_VID_SetWindowCaption) (const char *msg) void D3D11_Set2D (void) { - D3D11_VIEWPORT vport; - // Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0 + (0.5*vid.width/vid.pixelwidth), vid.width + (0.5*vid.width/vid.pixelwidth), 0 + (0.5*vid.height/vid.pixelheight), vid.height + (0.5*vid.height/vid.pixelheight), 0, 100); Matrix4x4_CM_Orthographic(r_refdef.m_projection_std, 0, vid.width, vid.height, 0, 0, 99999); Matrix4x4_Identity(r_refdef.m_view); - vport.TopLeftX = 0; - vport.TopLeftY = 0; - vport.Width = vid.pixelwidth; - vport.Height = vid.pixelheight; - vport.MinDepth = 0; - vport.MaxDepth = 1; - - ID3D11DeviceContext_RSSetViewports(d3ddevctx, 1, &vport); - D3D11BE_SetupViewCBuffer(); - vid.fbvwidth = vid.width; vid.fbvheight = vid.height; vid.fbpwidth = vid.pixelwidth; vid.fbpheight = vid.pixelheight; - D3D11BE_Scissor(NULL); - r_refdef.pxrect.x = 0; r_refdef.pxrect.y = 0; r_refdef.pxrect.width = vid.fbpwidth; r_refdef.pxrect.height = vid.fbpheight; + + D3D11BE_Set2D(); } static qboolean (D3D11_SCR_UpdateScreen) (void) @@ -1407,8 +1413,7 @@ static void D3D11_SetupViewPort(void) int x, x2, y2, y; float fov_x, fov_y; - -// D3DVIEWPORT9 vport; + float fovv_x, fovv_y; AngleVectors (r_refdef.viewangles, vpn, vright, vup); VectorCopy (r_refdef.vieworg, r_origin); @@ -1433,19 +1438,29 @@ static void D3D11_SetupViewPort(void) fov_x = r_refdef.fov_x;//+sin(cl.time)*5; fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5; + fovv_x = r_refdef.fovv_x; + fovv_y = r_refdef.fovv_y; if ((r_refdef.flags & RDF_UNDERWATER) && !(r_refdef.flags & RDF_WATERWARP)) { fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); fov_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); + fovv_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); + fovv_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); } /*view matrix*/ Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_refdef.vieworg); if (r_refdef.maxdist) - Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist); + { + Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist, false); + Matrix4x4_CM_Projection_Far(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, r_refdef.maxdist, false); + } else - Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist); + { + Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, false); + Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, false); + } } static void (D3D11_R_RenderView) (void) diff --git a/engine/d3d/vid_d3d8.c b/engine/d3d/vid_d3d8.c index 5bad28af7..5310fd8ef 100644 --- a/engine/d3d/vid_d3d8.c +++ b/engine/d3d/vid_d3d8.c @@ -515,7 +515,7 @@ void D3D8Shader_Init(void) sh_config.texture_non_power_of_two = true; } - sh_config.texture_maxsize = min(caps.MaxTextureWidth, caps.MaxTextureHeight); + sh_config.texture2d_maxsize = min(caps.MaxTextureWidth, caps.MaxTextureHeight); } #if (WINVER < 0x500) && !defined(__GNUC__) @@ -1292,16 +1292,16 @@ static void D3D8_SetupViewPortProjection(void) if (r_refdef.maxdist) { /*d3d projection matricies scale depth to 0 to 1*/ - Matrix4x4_CM_Projection_Far(d3d_trueprojection, fov_x, fov_y, r_refdef.mindist/2, r_refdef.maxdist); + Matrix4x4_CM_Projection_Far(d3d_trueprojection, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist, true); /*ogl projection matricies scale depth to -1 to 1, and I would rather my code used consistant culling*/ - Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist); + Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist, false); } else { /*d3d projection matricies scale depth to 0 to 1*/ - Matrix4x4_CM_Projection_Inf(d3d_trueprojection, fov_x, fov_y, r_refdef.mindist/2); + Matrix4x4_CM_Projection_Inf(d3d_trueprojection, fov_x, fov_y, r_refdef.mindist, true); /*ogl projection matricies scale depth to -1 to 1, and I would rather my code used consistant culling*/ - Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist); + Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, false); } d3d8error(IDirect3DDevice8_SetTransform(pD3DDev8, D3DTS_PROJECTION, (D3DMATRIX*)d3d_trueprojection)); diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 1a1db53fd..89073d8ae 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -3923,7 +3923,7 @@ qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned float view[16]; float proj[16]; extern cvar_t r_shadow_shadowmapping_nearclip; - Matrix4x4_CM_Projection_Far(proj, dl->fov, dl->fov, r_shadow_shadowmapping_nearclip.value, dl->radius); + Matrix4x4_CM_Projection_Far(proj, dl->fov, dl->fov, r_shadow_shadowmapping_nearclip.value, dl->radius, false); Matrix4x4_CM_ModelViewMatrixFromAxis(view, axis[0], axis[1], axis[2], dl->origin); Matrix4_Multiply(proj, view, shaderstate.lightprojmatrix); } diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 49a3dae17..fe1ce1116 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -442,8 +442,8 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) if (tex->flags & IF_TEXTYPE) { - targface = cubeface[i]; - j = 0; + targface = cubeface[i%countof(cubeface)]; + j = i/countof(cubeface); } else { @@ -452,12 +452,13 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) } switch(encoding) { -#ifdef FTE_TARGET_WEB case PTI_WHOLEFILE: + case PTI_MAX: +#ifdef FTE_TARGET_WEB if (!i) emscriptenfte_gl_loadtexturefile(tex->num, &tex->width, &tex->height, mips->mip[i].data, mips->mip[i].datasize); - break; #endif + break; case PTI_DEPTH16: qglTexImage2D(targface, j, gl_config.gles?GL_DEPTH_COMPONENT:GL_DEPTH_COMPONENT16_ARB, mips->mip[i].width, mips->mip[i].height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, mips->mip[i].data); break; @@ -480,7 +481,6 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) case PTI_BGRX8: qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGB_ARB:GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); break; - default: case PTI_BGRA8: qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); break; @@ -519,19 +519,65 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) case PTI_RGB565: qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, mips->mip[i].data); break; - //(desktop) compressed formats - case PTI_S3RGB1: + + //legacy formats + case PTI_RGB8: + qglTexImage2D(targface, j, GL_RGB8, mips->mip[i].width, mips->mip[i].height, 0, GL_RGB, GL_UNSIGNED_BYTE, mips->mip[i].data); + break; + case PTI_LUMINANCE8_ALPHA8: + qglTexImage2D(targface, j, GL_LUMINANCE8_ALPHA8, mips->mip[i].width, mips->mip[i].height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, mips->mip[i].data); + break; + //s3tc (desktop) compressed formats + case PTI_BC1_RGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_S3RGBA1: + case PTI_BC1_RGBA: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_S3RGBA3: + case PTI_BC2_RGBA: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; - case PTI_S3RGBA5: + case PTI_BC3_RGBA: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_BC1_RGB_SRGB: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_BC1_RGBA_SRGB: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_BC2_RGBA_SRGB: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_BC3_RGBA_SRGB: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + //atin/rgtc (desktop) compressed formats (derived from bc3's alpha channel) + case PTI_BC4_R8: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RED_RGTC1, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_BC4_R8_SIGNED: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SIGNED_RED_RGTC1, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_BC5_RG8: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RG_RGTC2, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_BC5_RG8_SIGNED: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SIGNED_RG_RGTC2, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + //bptc desktop formats + case PTI_BC6_RGBF: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_BC6_RGBF_SIGNED: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_BC7_RGBA: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_BC7_RGBA_SRGB: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; //(mobile) compressed formats case PTI_ETC1_RGB8: case PTI_ETC2_RGB8: @@ -547,6 +593,56 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) case PTI_ETC2_RGB8A8: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA8_ETC2_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ETC2_RGB8_SRGB: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ETC2, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_ETC2_RGB8A1_SRGB: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_ETC2_RGB8A8_SRGB: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_EAC_R11: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_R11_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_EAC_R11_SIGNED: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SIGNED_R11_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_EAC_RG11: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RG11_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + case PTI_EAC_RG11_SIGNED: + qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SIGNED_RG11_EAC, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); + break; + //astc variations... + case PTI_ASTC_4X4: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_4X4_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_5X4: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_5X4_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_5X5: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_5X5_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_6X5: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_6X5_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_6X6: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_6X6_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_8X5: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_8X5_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_8X6: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_8X6_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_10X5: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_10X5_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_10X6: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_10X6_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_8X8: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_8X8_SRGB: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_10X8: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_10X8_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_10X10: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_10X10_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_12X10: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_12X10_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_12X12: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; + case PTI_ASTC_12X12_SRGB: qglCompressedTexImage2DARB(targface, j,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; } } } diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 33068c0a5..804b613fd 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -2937,8 +2937,8 @@ static void Mod_Batches_AllocLightmaps(model_t *mod) mod->lightmaps.width = 1<lightmaps.height; i++); mod->lightmaps.height = 1<lightmaps.width = bound(64, mod->lightmaps.width, sh_config.texture_maxsize); - mod->lightmaps.height = bound(64, mod->lightmaps.height, sh_config.texture_maxsize); + mod->lightmaps.width = bound(64, mod->lightmaps.width, sh_config.texture2d_maxsize); + mod->lightmaps.height = bound(64, mod->lightmaps.height, sh_config.texture2d_maxsize); Mod_LightmapAllocInit(&lmallocator, mod->deluxdata != NULL, mod->lightmaps.width, mod->lightmaps.height, 0x50); diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 132aa1c9b..b9732d923 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -602,6 +602,7 @@ void R_GenDlightBatches(batch_t *batches[]) if (!r_lightprepass) return; + modes = 0; if (r_shadow_realtime_dlight.ival) modes |= LFLAG_NORMALMODE; if (r_shadow_realtime_world.ival) diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index f0974beb6..f2b6a9b88 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -576,13 +576,13 @@ void R_SetupGL (float stereooffset, int i) // yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*(scr_fov.value*2)/M_PI; // MYgluPerspective (yfov, screenaspect, 4, 4096); - Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist); - Matrix4x4_CM_Projection_Far(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, r_refdef.maxdist); + Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist, false); + Matrix4x4_CM_Projection_Far(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, r_refdef.maxdist, false); } else { - Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist); - Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist); + Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, false); + Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, false); } } else @@ -2002,8 +2002,8 @@ void GLR_RenderView (void) } //well... err... meh. - vid.fbpwidth = bound(1, vid.fbpwidth, sh_config.texture_maxsize); - vid.fbpheight = bound(1, vid.fbpheight, sh_config.texture_maxsize); + vid.fbpwidth = bound(1, vid.fbpwidth, sh_config.texture2d_maxsize); + vid.fbpheight = bound(1, vid.fbpheight, sh_config.texture2d_maxsize); vid.fbvwidth = vid.fbpwidth; vid.fbvheight = vid.fbpheight; diff --git a/engine/gl/gl_rmisc.c b/engine/gl/gl_rmisc.c index fe9100d61..506cad942 100644 --- a/engine/gl/gl_rmisc.c +++ b/engine/gl/gl_rmisc.c @@ -445,9 +445,6 @@ void GLR_DeInit (void) // Cmd_RemoveCommand ("makewad"); - Cvar_Unhook(&vid_conautoscale); - Cvar_Unhook(&vid_conheight); - Cvar_Unhook(&vid_conwidth); // Cvar_Unhook(&v_gamma); // Cvar_Unhook(&v_contrast); // Cvar_Unhook(&v_brightness); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 30dc767f8..3f7ac3f82 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -356,6 +356,24 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr) lhs = false; else if (!Q_stricmp(token, "loweroverlay")) lhs = false; + + //these are for compat/documentation purposes with qfusion/warsow + else if (!Q_stricmp(token, "maxTextureSize")) + lhs = sh_config.texture2d_maxsize; + else if (!Q_stricmp(token, "maxTextureCubemapSize")) + lhs = sh_config.texturecube_maxsize; + else if (!Q_stricmp(token, "maxTextureUnits")) + lhs = 0; + else if (!Q_stricmp(token, "textureCubeMap")) + lhs = sh_config.havecubemaps; +// else if (!Q_stricmp(token, "GLSL")) +// lhs = 1; + else if (!Q_stricmp(token, "deluxeMaps") || !Q_stricmp(token, "deluxe")) + lhs = r_deluxmapping; + else if (!Q_stricmp(token, "portalMaps")) + lhs = false; + //end qfusion + else { cv = Cvar_Get(token, "", 0, "Shader Conditions"); @@ -3531,7 +3549,7 @@ static void Shaderpass_CubeMap(shader_t *shader, shaderpass_t *pass, char **ptr) { char *token = Shader_ParseString(ptr); - if (pass->tcgen == TC_GEN_BASE) + if (pass->tcgen == TC_GEN_UNSPECIFIED) pass->tcgen = TC_GEN_SKYBOX; pass->texgen = T_GEN_CUBEMAP; pass->anim_frames[0] = Shader_FindImage(token, IF_CUBEMAP); @@ -3593,14 +3611,14 @@ static shaderkey_t shaderpasskeys[] = //qfusion/warsow compat {"material", Shaderpass_QF_Material, "qf"}, {"animclampmap",Shaderpass_QF_AnimClampMap, "qf"}, -// {"cubemap", Shaderpass_CubeMap, "qf"}, -// {"shadecubemap",Shaderpass_ShadeCubeMap, "qf"}, -// {"surroundmap", Shaderpass_SurroundMap, "qf"}, -// {"distortion", Shaderpass_Distortion, "qf"}, -// {"celshade", Shaderpass_Celshade, "qf"}, -// {"grayscale", Shaderpass_Greyscale, "qf"}, -// {"greyscale", Shaderpass_Greyscale, "qf"}, -// {"skip", Shaderpass_Skip, "qf"}, +// {"cubemap", Shaderpass_QF_CubeMap, "qf"}, +// {"shadecubemap",Shaderpass_QF_ShadeCubeMap, "qf"}, + {"surroundmap", Shaderpass_CubeMap, "qf"}, +// {"distortion", Shaderpass_QF_Distortion, "qf"}, +// {"celshade", Shaderpass_QF_Celshade, "qf"}, +// {"grayscale", Shaderpass_QF_Greyscale, "qf"}, +// {"greyscale", Shaderpass_QF_Greyscale, "qf"}, +// {"skip", Shaderpass_QF_Skip, "qf"}, {NULL, NULL} }; diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index daac2f02c..1fc20ee12 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -2406,7 +2406,7 @@ qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize) oprect = r_refdef.pxrect; smesh = SHM_BuildShadowMesh(l, lvis, SMT_SHADOWMAP); - Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, l->fov?l->fov:90, l->fov?l->fov:90, r_shadow_shadowmapping_nearclip.value, l->radius); + Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, l->fov?l->fov:90, l->fov?l->fov:90, r_shadow_shadowmapping_nearclip.value, l->radius, false); switch(qrenderer) { diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 3fe2bdbec..db497def2 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -2884,25 +2884,35 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) qglGetError(); /*suck up the invalid operation error for non-debug contexts*/ #endif - sh_config.texture_maxsize = 256; //early minidrivers might not implement this, but anything else should. - qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &sh_config.texture_maxsize); + sh_config.texture2d_maxsize = 256; //early minidrivers might not implement this, but anything else should. + qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &sh_config.texture2d_maxsize); //always supported sh_config.texfmt[PTI_RGBA8] = true; if (GL_CheckExtension("GL_EXT_texture_compression_s3tc")) { - sh_config.texfmt[PTI_S3RGB1] = true; - sh_config.texfmt[PTI_S3RGBA1] = true; - sh_config.texfmt[PTI_S3RGBA3] = true; - sh_config.texfmt[PTI_S3RGBA5] = true; + sh_config.texfmt[PTI_BC1_RGB] = true; + sh_config.texfmt[PTI_BC1_RGBA] = true; + sh_config.texfmt[PTI_BC2_RGBA] = true; + sh_config.texfmt[PTI_BC3_RGBA] = true; } else if (gl_config.gles) { - sh_config.texfmt[PTI_S3RGB1] = - sh_config.texfmt[PTI_S3RGBA1] = GL_CheckExtension("GL_EXT_texture_compression_dxt1"); - sh_config.texfmt[PTI_S3RGBA3] = GL_CheckExtension("GL_ANGLE_texture_compression_dxt3"); - sh_config.texfmt[PTI_S3RGBA5] = GL_CheckExtension("GL_ANGLE_texture_compression_dxt5"); + sh_config.texfmt[PTI_BC1_RGB] = + sh_config.texfmt[PTI_BC1_RGBA] = GL_CheckExtension("GL_EXT_texture_compression_dxt1"); + sh_config.texfmt[PTI_BC2_RGBA] = GL_CheckExtension("GL_ANGLE_texture_compression_dxt3"); + sh_config.texfmt[PTI_BC3_RGBA] = GL_CheckExtension("GL_ANGLE_texture_compression_dxt5"); } + if (GL_CheckExtension("GL_ARB_texture_compression_rgtc") || GL_CheckExtension("GL_EXT_texture_compression_rgtc")) + { + sh_config.texfmt[PTI_BC4_R8] = true; + sh_config.texfmt[PTI_BC4_R8_SIGNED] = true; + sh_config.texfmt[PTI_BC5_RG8] = true; + sh_config.texfmt[PTI_BC5_RG8_SIGNED] = true; + } + if ((!gl_config.gles && gl_config.glversion >= 4.2) || GL_CheckExtension("GL_ARB_texture_compression_bptc")) + sh_config.texfmt[PTI_BC6_RGBF] = sh_config.texfmt[PTI_BC6_RGBF_SIGNED] = + sh_config.texfmt[PTI_BC7_RGBA] = sh_config.texfmt[PTI_BC7_RGBA_SRGB] = true; #ifdef FTE_TARGET_WEB if (GL_CheckExtension("WEBGL_compressed_texture_etc")) @@ -2913,17 +2923,45 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) //webgl tries to cater to d3d, so doesn't support this gles3 feature, because browser writers are lazy. //warning: while support is mandatory, it may just be a driver trick with the hardware using uncompressed data. sh_config.texfmt[PTI_ETC1_RGB8] = true; - sh_config.texfmt[PTI_ETC2_RGB8] = true; - sh_config.texfmt[PTI_ETC2_RGB8A1] = true; - sh_config.texfmt[PTI_ETC2_RGB8A8] = true; + + sh_config.texfmt[PTI_ETC2_RGB8] = true; + sh_config.texfmt[PTI_ETC2_RGB8A1] = true; + sh_config.texfmt[PTI_ETC2_RGB8A8] = true; + sh_config.texfmt[PTI_EAC_R11] = true; + sh_config.texfmt[PTI_EAC_R11_SIGNED] = true; + sh_config.texfmt[PTI_EAC_RG11] = true; + sh_config.texfmt[PTI_EAC_RG11_SIGNED] = true; } else { - sh_config.texfmt[PTI_ETC2_RGB8] = GL_CheckExtension("GL_OES_compressed_ETC2_RGB8_texture"); - sh_config.texfmt[PTI_ETC2_RGB8A1] = GL_CheckExtension("GL_OES_compressed_ETC2_punchthroughA_RGBA8_texture"); - sh_config.texfmt[PTI_ETC2_RGB8] = GL_CheckExtension("GL_OES_compressed_ETC2_RGBA8_texture"); - sh_config.texfmt[PTI_ETC1_RGB8] = sh_config.texfmt[PTI_ETC2_RGB8] || GL_CheckExtension("GL_OES_compressed_ETC1_RGB8_texture"); + sh_config.texfmt[PTI_ETC1_RGB8] = GL_CheckExtension("GL_OES_compressed_ETC1_RGB8_texture"); + + sh_config.texfmt[PTI_ETC2_RGB8] = GL_CheckExtension("GL_OES_compressed_ETC2_RGB8_texture"); //or OES_compressed_ETC2_sRGB8_texture... + sh_config.texfmt[PTI_ETC2_RGB8A1] = GL_CheckExtension("GL_OES_compressed_ETC2_punchthroughA_RGBA8_texture"); //or OES_compressed_ETC2_punchthroughA_sRGB8_alpha_texture... + sh_config.texfmt[PTI_ETC2_RGB8A8] = GL_CheckExtension("GL_OES_compressed_ETC2_RGBA8_texture"); //or OES_compressed_ETC2_sRGB8_alpha8_texture + sh_config.texfmt[PTI_EAC_R11] = GL_CheckExtension("GL_OES_compressed_EAC_R11_unsigned_texture"); + sh_config.texfmt[PTI_EAC_R11_SIGNED] = GL_CheckExtension("GL_OES_compressed_EAC_R11_signed_texture"); + sh_config.texfmt[PTI_EAC_RG11] = GL_CheckExtension("GL_OES_compressed_EAC_RG11_unsigned_texture"); + sh_config.texfmt[PTI_EAC_RG11_SIGNED] = GL_CheckExtension("GL_OES_compressed_EAC_RG11_signed_texture"); } + sh_config.texfmt[PTI_ETC1_RGB8] |= sh_config.texfmt[PTI_ETC2_RGB8]; + + if (GL_CheckExtension("GL_KHR_texture_compression_astc_ldr")) + { //24 different formats... + //hdr profile adds 3d slices, and support for the hdr subblocks (ldr-only will decode them as fixed-colour errors) + //full profile adds 3d blocks + //we don't do 3d astc textures, so the api doesn't change. either the gpu supports the data or parts get decoded as fixed colours, which is still better than our crappy fallback texture. + int gah; + for (gah = PTI_ASTC_4X4; gah <= PTI_ASTC_12X12_SRGB; gah++) + sh_config.texfmt[gah] = true; + } + + /*note regarding GL_COMPRESSED_TEXTURE_FORMATS: + nvidia lists bc1-3, oes paletted, etc2, astc, astc_srgb. + so the only listed formats that the hardware actually supports are bc1-3. + and bc4-7 are NOT listed, despite eg vulkan supporting them. + or in other words, this info is utterly useless (its deprecated somewhere, so this shouldn't be a huge surprise). + */ if (gl_config.gles) { @@ -3023,8 +3061,19 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) sh_config.texfmt[PTI_RGBA8_SRGB] = sh_config.texfmt[PTI_RGBA8] && srgb; sh_config.texfmt[PTI_BGRX8_SRGB] = sh_config.texfmt[PTI_BGRX8] && srgb; sh_config.texfmt[PTI_BGRA8_SRGB] = sh_config.texfmt[PTI_BGRA8] && srgb; + sh_config.texfmt[PTI_BC1_RGB_SRGB] = sh_config.texfmt[PTI_BC1_RGB] && srgb; + sh_config.texfmt[PTI_BC1_RGBA_SRGB] = sh_config.texfmt[PTI_BC1_RGBA] && srgb; + sh_config.texfmt[PTI_BC2_RGBA_SRGB] = sh_config.texfmt[PTI_BC2_RGBA] && srgb; + sh_config.texfmt[PTI_BC3_RGBA_SRGB] = sh_config.texfmt[PTI_BC3_RGBA] && srgb; + sh_config.texfmt[PTI_ETC2_RGB8_SRGB] = sh_config.texfmt[PTI_ETC2_RGB8] && srgb; + sh_config.texfmt[PTI_ETC2_RGB8A1_SRGB] = sh_config.texfmt[PTI_ETC2_RGB8A1] && srgb; + sh_config.texfmt[PTI_ETC2_RGB8A8_SRGB] = sh_config.texfmt[PTI_ETC2_RGB8A8] && srgb; } + sh_config.texturecube_maxsize = 0; + if (sh_config.havecubemaps) + qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &sh_config.texturecube_maxsize); + sh_config.progs_supported = gl_config.arb_shader_objects; sh_config.progs_required = gl_config_nofixedfunc; diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 940fdfcd2..8eceac857 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -981,14 +981,10 @@ static qboolean VID_SetWindowedMode (rendererstate_t *info) Con_Printf("Can't run GL in non-RGB mode\n"); return false; } + vid.dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); + vid.dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); ReleaseDC(NULL, hdc); - WindowRect.top = WindowRect.left = 0; - - WindowRect.right = info->width; - WindowRect.bottom = info->height; - - #ifndef FTE_SDL if (sys_parentwindow) { @@ -1001,8 +997,8 @@ static qboolean VID_SetWindowedMode (rendererstate_t *info) pwidth = sys_parentwidth; pheight = sys_parentheight; - WindowRect.right = sys_parentwidth; - WindowRect.bottom = sys_parentheight; + wwidth = sys_parentwidth; + wheight = sys_parentheight; } else #endif @@ -1018,21 +1014,27 @@ static qboolean VID_SetWindowedMode (rendererstate_t *info) pwidth = GetSystemMetrics(SM_CXSCREEN); pheight = GetSystemMetrics(SM_CYSCREEN); - /*Assume dual monitors, and chop the width to try to put it on only one screen*/ - if (pwidth >= pheight*2) - pwidth /= 2; + /*Assume dual monitors, and chop the width to try to put it on only one screen + "Because of app compatibility reasons these system metrics return the size of the primary monitor" + so we shouldn't need this... + */ +// if (pwidth >= pheight*2) +// pwidth /= 2; + + wwidth = info->width; + wheight = info->height; + /*win8 code: + HMONITOR mod = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST); + if (mon != INVALID_HANDLE_VALUE) + GetDpiForMonitor(mon, 0, &vid.dpi_x, &vid.dpi_y); + */ + wwidth = (wwidth*vid.dpi_x)/96; + wheight = (wheight*vid.dpi_y)/96; } - DIBWidth = WindowRect.right - WindowRect.left; - DIBHeight = WindowRect.bottom - WindowRect.top; - - rect = WindowRect; - AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); - - wwidth = rect.right - rect.left; - wheight = rect.bottom - rect.top; - WindowRect = centerrect(pleft, ptop, pwidth, pheight, wwidth, wheight); + if (!sys_parentwindow) + AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); // Create the DIB window if (WinNT) @@ -1072,6 +1074,12 @@ static qboolean VID_SetWindowedMode (rendererstate_t *info) return false; } + GetClientRect(dibwindow, &WindowRect); + WindowRect.right -= WindowRect.left; + WindowRect.bottom -= WindowRect.top; + DIBWidth = WindowRect.right; + DIBHeight = WindowRect.bottom; + SendMessage (dibwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); SendMessage (dibwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); diff --git a/engine/gl/glsupp.h b/engine/gl/glsupp.h index c7569d861..1a4fdb631 100644 --- a/engine/gl/glsupp.h +++ b/engine/gl/glsupp.h @@ -617,10 +617,22 @@ typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei #ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT -#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 -#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif +#ifndef GL_COMPRESSED_RED_RGTC1 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#endif +#ifndef GL_COMPRESSED_RGBA_BPTC_UNORM_ARB +#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F #endif #ifndef GL_EXT_texture_sRGB @@ -647,10 +659,10 @@ typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei #define GL_ETC1_RGB8_OES 0x8D64 //4*4 blocks of 8 bytes #endif #ifndef GL_COMPRESSED_RGB8_ETC2 -//#define GL_COMPRESSED_R11_EAC 0x9270 -//#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 -//#define GL_COMPRESSED_RG11_EAC 0x9272 -//#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 #define GL_COMPRESSED_RGB8_ETC2 0x9274 //4*4 blocks of 8 bytes. also accepts valid etc1 images #define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 // @@ -658,6 +670,36 @@ typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 //4*4 blocks of 8+8 bytes. #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 #endif +#ifndef GL_COMPRESSED_RGBA_ASTC_4x4_KHR +#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#endif #ifndef GL_ARB_pixel_buffer_object #define GL_PIXEL_PACK_BUFFER_ARB 0x88EB diff --git a/engine/gl/shader.h b/engine/gl/shader.h index e7b4808fe..419d867d0 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -741,7 +741,8 @@ typedef struct unsigned int max_gpu_bones; //max number of bones supported by uniforms. qboolean texfmt[PTI_MAX]; //which texture formats are supported (renderable not implied) - unsigned int texture_maxsize; //max size of a 2d texture + unsigned int texture2d_maxsize; //max size of a 2d texture + unsigned int texturecube_maxsize; qboolean texture_non_power_of_two; //full support for npot qboolean texture_non_power_of_two_pic; //npot only works with clamp-to-edge mipless images. qboolean npot_rounddown; //memory limited systems can say that they want to use less ram. @@ -859,6 +860,7 @@ void D3D9BE_Scissor(srect_t *rect); void D3D9Shader_Init(void); void D3D9BE_Reset(qboolean before); void D3D9BE_Set2D(void); +void D3D9BE_SetViewport(int x, int y, int w, int h); #endif #ifdef D3D11QUAKE void D3D11BE_Init(void); @@ -878,7 +880,7 @@ qboolean D3D11BE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsig qboolean D3D11Shader_Init(unsigned int featurelevel); void D3D11BE_Reset(qboolean before); -void D3D11BE_SetupViewCBuffer(void); +void D3D11BE_Set2D(void); void D3D11_UploadLightmap(lightmapinfo_t *lm); void D3D11BE_VBO_Begin(vbobctx_t *ctx, size_t maxsize); void D3D11BE_VBO_Data(vbobctx_t *ctx, void *data, size_t size, vboarray_t *varray); diff --git a/engine/server/pr_lua.c b/engine/server/pr_lua.c index ea00e1a5c..16df2402f 100644 --- a/engine/server/pr_lua.c +++ b/engine/server/pr_lua.c @@ -56,7 +56,8 @@ //any globals or functions that the server might want access to need to be known also. #define luaextragloballist \ globalstring (true, startspot) \ - globalstring (true, ClientReEnter) + globalstring (true, ClientReEnter) \ + globalfloat (false, dimension_default) typedef struct { @@ -107,7 +108,7 @@ static struct luafld_t entflds[1024]; //fld->offset+type qboolean triedlib; - dllhandle_t lib; + dllhandle_t *lib; lua_State * (QDECL *newstate) (lua_Alloc f, void *ud); lua_CFunction (QDECL *atpanic) (lua_State *L, lua_CFunction panicf); @@ -431,7 +432,7 @@ static int my_lua_entity_set(lua_State *L) //__newindex lua.getfield(L, 1, "entnum"); entnum = lua.tointegerx(L, -1, NULL); lua.pop(L, 1); - if (entnum < lua.maxedicts && lua.edicttable[entnum] && !lua.edicttable[entnum]->isfree) + if (entnum < lua.maxedicts && lua.edicttable[entnum] && !ED_ISFREE(lua.edicttable[entnum])) { eval = (eval_t*)((char*)lua.edicttable[entnum]->v + fld->offset); switch(fld->type) @@ -450,7 +451,7 @@ static int my_lua_entity_set(lua_State *L) //__newindex eval->function = 0; //so the engine can distinguish between nil and not. else eval->function = fld->offset | ((entnum+1)<<10); - lua.pushlightuserdata(L, (void *)fld->offset); //execute only knows a function id, so we need to translate the store to match. + lua.pushlightuserdata(L, (void *)(qintptr_t)fld->offset); //execute only knows a function id, so we need to translate the store to match. lua.replace(L, 2); lua.rawset(L, 1); return 0; @@ -459,7 +460,7 @@ static int my_lua_entity_set(lua_State *L) //__newindex eval->string = 0; //so the engine can distinguish between nil and not. else eval->string = fld->offset | ((entnum+1)<<10); - lua.pushlightuserdata(L, (void *)fld->offset); //execute only knows a string id, so we need to translate the store to match. + lua.pushlightuserdata(L, (void *)(qintptr_t)fld->offset); //execute only knows a string id, so we need to translate the store to match. lua.replace(L, 2); lua.rawset(L, 1); return 0; @@ -517,7 +518,7 @@ static int my_lua_entity_get(lua_State *L) //__index return 1; case ev_function: case ev_string: - lua.pushlightuserdata(L, (void *)(eval->function & 1023)); //execute only knows a function id, so we need to translate the store to match. + lua.pushlightuserdata(L, (void *)(qintptr_t)(eval->function & 1023)); //execute only knows a function id, so we need to translate the store to match. lua.replace(L, 2); lua.rawget(L, 1); return 1; @@ -619,7 +620,7 @@ static int my_lua_global_get(lua_State *L) //__index lua.pushnumber(L, eval->_float); return 1; case ev_function: - lua.pushlightuserdata(L, (void *)eval->function); //execute only knows a function id, so we need to translate the store to match. + lua.pushlightuserdata(L, (void *)(qintptr_t)eval->function); //execute only knows a function id, so we need to translate the store to match. lua.replace(L, 2); lua.rawget(L, 1); return 1; @@ -667,7 +668,7 @@ static int bi_lua_lightstyle(lua_State *L) } static int bi_lua_spawn(lua_State *L) { - edict_t *e = lua.progfuncs.EntAlloc(&lua.progfuncs); + edict_t *e = lua.progfuncs.EntAlloc(&lua.progfuncs, false, 0); if (e) { lua.pushlightuserdata(L, e); @@ -811,7 +812,7 @@ static int bi_lua_sound(lua_State *L) //note: channel & 256 == reliable - SVQ1_StartSound (NULL, (wedict_t*)EDICT_NUM((&lua.progfuncs), entnum), channel, samp, volume*255, attenuation, 0); + SVQ1_StartSound (NULL, (wedict_t*)EDICT_NUM((&lua.progfuncs), entnum), channel, samp, volume*255, attenuation, 0, 0, 0); return 0; } @@ -850,7 +851,7 @@ static int bi_lua_droptofloor(lua_State *L) vec3_t start; trace_t trace; const float *gravitydir; - extern const vec3_t standardgravity; + static const vec3_t standardgravity = {0,0,-1}; pubprogfuncs_t *prinst = &lua.progfuncs; world_t *world = prinst->parms->user; @@ -887,9 +888,10 @@ static int bi_lua_checkbottom(lua_State *L) { qboolean okay; int entnum; + vec3_t up = {0,0,1}; lua.getfield(L, 1, "entnum"); entnum = lua.tointegerx(L, -1, NULL); - okay = World_CheckBottom(&sv.world, (wedict_t*)EDICT_NUM((&lua.progfuncs), entnum)); + okay = World_CheckBottom(&sv.world, (wedict_t*)EDICT_NUM((&lua.progfuncs), entnum), up); lua.pushboolean(L, okay); return 1; } @@ -946,11 +948,11 @@ static void set_trace_globals(trace_t *trace) pr_global_struct->trace_fraction = trace->fraction; pr_global_struct->trace_inwater = trace->inwater; pr_global_struct->trace_inopen = trace->inopen; - pr_global_struct->trace_surfaceflags = trace->surface?trace->surface->flags:0; + pr_global_struct->trace_surfaceflagsf = trace->surface?trace->surface->flags:0; pr_global_struct->trace_surfaceflagsi = trace->surface?trace->surface->flags:0; - if (pr_global_struct->trace_surfacename) - prinst->SetStringField(prinst, NULL, &pr_global_struct->trace_surfacename, tr->surface?tr->surface->name:"", true); - pr_global_struct->trace_endcontents = trace->contents; +// if (pr_global_struct->trace_surfacename) +// prinst->SetStringField(prinst, NULL, &pr_global_struct->trace_surfacename, tr->surface?tr->surface->name:"", true); + pr_global_struct->trace_endcontentsf = trace->contents; pr_global_struct->trace_endcontentsi = trace->contents; // if (trace.fraction != 1) // VectorMA (trace->endpos, 4, trace->plane.normal, P_VEC(trace_endpos)); @@ -1011,7 +1013,7 @@ static int bi_lua_walkmove(lua_State *L) float yaw, dist; vec3_t move; int oldself; - vec3_t axis; + vec3_t axis[3]; ent = PROG_TO_WEDICT(prinst, *world->g.self); yaw = lua.tonumberx(L, 1, NULL); @@ -1070,7 +1072,7 @@ static int bi_lua_nextent(lua_State *L) break; } ent = WEDICT_NUM(world->progs, i); - if (!ent->isfree) + if (!ED_ISFREE(ent)) { break; } @@ -1098,7 +1100,7 @@ static int bi_lua_nextclient(lua_State *L) break; } ent = WEDICT_NUM(world->progs, i); - if (!ent->isfree) + if (!ED_ISFREE(ent)) { break; } @@ -1145,7 +1147,7 @@ static int bi_lua_vectoangles(lua_State *L) lua_readvector(L, 1, up); uv = up; } - VectorAngles(forward, up, ret); + VectorAngles(forward, uv, ret, true); lua.createtable(L, 0, 0); //FIXME: should provide a metatable with a __tostring @@ -1203,7 +1205,7 @@ static int bi_lua_findradiuschain(lua_State *L) for (i=1 ; inum_edicts ; i++) { ent = EDICT_NUM(world->progs, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (ent->v->solid == SOLID_NOT && (progstype != PROG_QW || !((int)ent->v->flags & FL_FINDABLE_NONSOLID)) && !sv_gameplayfix_blowupfallenzombies.value) continue; @@ -1242,7 +1244,7 @@ static int bi_lua_findradiustable(lua_State *L) for (i=1 ; inum_edicts ; i++) { ent = EDICT_NUM(world->progs, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (ent->v->solid == SOLID_NOT && (progstype != PROG_QW || !((int)ent->v->flags & FL_FINDABLE_NONSOLID)) && !sv_gameplayfix_blowupfallenzombies.value) continue; @@ -1408,7 +1410,7 @@ typedef struct lua_State *L; int idx; } luafsenum_t; -static int QDECL lua_file_enumerate(const char *fname, qofs_t fsize, void *param, searchpathfuncs_t *spath) +static int QDECL lua_file_enumerate(const char *fname, qofs_t fsize, time_t mtime, void *param, searchpathfuncs_t *spath) { luafsenum_t *e = param; lua.pushinteger(e->L, e->idx++); @@ -1651,7 +1653,7 @@ void Lua_EntClear (pubprogfuncs_t *pf, edict_t *e) { int num = e->entnum; memset (e->v, 0, sv.world.edict_size); - e->isfree = false; + e->ereftype = ER_ENTITY; e->entnum = num; } edict_t *Lua_CreateEdict(unsigned int num) @@ -1671,7 +1673,7 @@ static void QDECL Lua_EntRemove(pubprogfuncs_t *pf, edict_t *e) if (!ED_CanFree(e)) return; - e->isfree = true; + e->ereftype = ER_FREE; e->freetime = sv.time; //clear out the lua version of the entity, so that it can be garbage collected. @@ -1713,7 +1715,7 @@ static edict_t *Lua_DoRespawn(pubprogfuncs_t *pf, edict_t *e, int num) lua.settable(L, LUA_REGISTRYINDEX); return e; } -static edict_t *QDECL Lua_EntAlloc(pubprogfuncs_t *pf) +static edict_t *QDECL Lua_EntAlloc(pubprogfuncs_t *pf, pbool isobject, size_t extrasize) { int i; edict_t *e; @@ -1722,7 +1724,7 @@ static edict_t *QDECL Lua_EntAlloc(pubprogfuncs_t *pf) e = (edict_t*)EDICT_NUM(pf, i); // the first couple seconds of server time can involve a lot of // freeing and allocating, so relax the replacement policy - if (!e || (e->isfree && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )) + if (!e || (ED_ISFREE(e) && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )) { e = Lua_DoRespawn(pf, e, i); return (struct edict_s *)e; @@ -1736,7 +1738,7 @@ static edict_t *QDECL Lua_EntAlloc(pubprogfuncs_t *pf) e = (edict_t*)EDICT_NUM(pf, i); // the first couple seconds of server time can involve a lot of // freeing and allocating, so relax the replacement policy - if (!e || (e->isfree)) + if (!e || ED_ISFREE(e)) { e = Lua_DoRespawn(pf, e, i); return (struct edict_s *)e; @@ -1757,7 +1759,7 @@ static edict_t *QDECL Lua_EntAlloc(pubprogfuncs_t *pf) return (struct edict_s *)e; } -static int QDECL Lua_LoadEnts(pubprogfuncs_t *pf, char *mapstring, float spawnflags) +static int QDECL Lua_LoadEnts(pubprogfuncs_t *pf, const char *mapstring, void *ctx, void (PDECL *callback) (pubprogfuncs_t *progfuncs, struct edict_s *ed, void *ctx, const char *entstart, const char *entend)) { lua_State *L = lua.ctx; int i = 0; @@ -1769,7 +1771,7 @@ static int QDECL Lua_LoadEnts(pubprogfuncs_t *pf, char *mapstring, float spawnfl lua.pushstring(L, com_token); lua.settable(L, -3); } - lua.pushinteger(L, spawnflags); +// lua.pushinteger(L, spawnflags); if (lua.pcall(L, 2, 0, 0) != 0) { @@ -1871,7 +1873,7 @@ static void QDECL Lua_SetStringField(pubprogfuncs_t *prinst, edict_t *ed, string *fld = base | val; //set the engine's value //set the stuff so that lua can read it properly. - lua.pushlightuserdata(L, (void *)val); + lua.pushlightuserdata(L, (void *)(qintptr_t)val); lua.pushfstring(L, "%s", str); lua.rawset(L, -3); @@ -1902,7 +1904,7 @@ static const char *ASMCALL QDECL Lua_StringToNative(pubprogfuncs_t *prinst, stri } //read the function from the table - lua.pushlightuserdata(lua.ctx, (void *)str); + lua.pushlightuserdata(lua.ctx, (void *)(qintptr_t)str); lua.rawget(lua.ctx, -2); ret = lua.tolstring(lua.ctx, -1, NULL); lua.pop(lua.ctx, 2); //pop the table+string. @@ -2044,7 +2046,7 @@ void QDECL Lua_ExecuteProgram(pubprogfuncs_t *funcs, func_t func) } //read the function from the table - lua.pushlightuserdata(lua.ctx, (void *)func); + lua.pushlightuserdata(lua.ctx, (void *)(qintptr_t)func); lua.rawget(lua.ctx, -2); //and now invoke it. @@ -2131,7 +2133,7 @@ qboolean PR_LoadLua(void) my_lua_registerbuiltins(lua.ctx); //spawn the world, woo. - world->edicts = (wedict_t*)pf->EntAlloc(pf); + world->edicts = (wedict_t*)pf->EntAlloc(pf,false,0); //load the gamecode now. it should be safe for it to call various builtins. if (0 != lua.load(lua.ctx, my_lua_Reader, sourcefile, "progs.lua", "bt")) //load the file, embed it within a function and push it diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 9f6ecfba9..98401366e 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -127,7 +127,7 @@ cvar_t sv_listen_q3 = CVAR("sv_listen_q3", "0"); #ifdef HAVE_DTLS cvar_t sv_listen_dtls = CVARCD("net_enable_dtls", "", SV_Listen_Dtls_Changed, "Controls serverside dtls support.\n0: dtls blocked, not advertised.\n1: available in desired.\n2: used where possible (recommended setting).\n3: disallow non-dtls clients (sv_port_tcp should be eg tls://[::]:27500 to also disallow unencrypted tcp connections)."); #endif -cvar_t sv_reportheartbeats = CVAR("sv_reportheartbeats", "1"); +cvar_t sv_reportheartbeats = CVARD("sv_reportheartbeats", "2", "Print a notice each time a heartbeat is sent to a master server. When set to 2, the message will be displayed once."); cvar_t sv_highchars = CVAR("sv_highchars", "1"); cvar_t sv_maxrate = CVAR("sv_maxrate", "30000"); cvar_t sv_maxdrate = CVARAF("sv_maxdrate", "500000", @@ -541,6 +541,9 @@ void SV_DropClient (client_t *drop) { case GT_MAX: break; +#ifdef VM_LUA + case GT_LUA: +#endif case GT_Q1QVM: case GT_PROGS: if (svprogfuncs) diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 4ef933835..7feca5593 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -56,6 +56,7 @@ cvar_t sv_waterfriction = CVAR( "sv_waterfriction", "4"); cvar_t sv_gameplayfix_noairborncorpse = CVAR( "sv_gameplayfix_noairborncorpse", "0"); cvar_t sv_gameplayfix_multiplethinks = CVARD( "sv_gameplayfix_multiplethinks", "1", "Enables multiple thinks per entity per frame so small nextthink times are accurate. QuakeWorld mods expect a value of 1."); cvar_t sv_gameplayfix_stepdown = CVARD( "sv_gameplayfix_stepdown", "0", "Attempt to step down steps, instead of only up them. Affects non-predicted movetype_walk."); +cvar_t sv_gameplayfix_bouncedownslopes = CVARD( "sv_gameplayfix_grenadebouncedownslopes", "0", "MOVETYPE_BOUNCE speeds are calculated relative to the impacted surface, instead of the vertical, reducing the chance of grenades just sitting there on slopes."); #if !defined(CLIENTONLY) && defined(NQPROT) && !defined(NOLEGACY) cvar_t sv_gameplayfix_spawnbeforethinks = CVARD( "sv_gameplayfix_spawnbeforethinks", "0", "Fixes an issue where player thinks (including Pre+Post) can be called before PutClientInServer. Unfortunately at least one mod depends upon PreThink being called first in order to correctly determine spawn positions."); #endif @@ -92,6 +93,7 @@ void WPhys_Init(void) Cvar_Register (&sv_gameplayfix_noairborncorpse, cvargroup_serverphysics); Cvar_Register (&sv_gameplayfix_multiplethinks, cvargroup_serverphysics); Cvar_Register (&sv_gameplayfix_stepdown, cvargroup_serverphysics); + Cvar_Register (&sv_gameplayfix_bouncedownslopes, cvargroup_serverphysics); #if !defined(CLIENTONLY) && defined(NQPROT) && !defined(NOLEGACY) Cvar_Register (&sv_gameplayfix_spawnbeforethinks, cvargroup_serverphysics); @@ -1383,12 +1385,19 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) VectorCopy(trace.endpos, move); if (ent->v->movetype == MOVETYPE_BOUNCE) - backoff = 1.5; + { + if (ent->xv->bouncefactor) + backoff = 1 + ent->xv->bouncefactor; + else + backoff = 1.5; + } else if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE) { -// if (progstype == PROG_H2 && ent->v->solid == SOLID_PHASEH2 && ((int)((wedict_t*)trace.ent)->v->flags & (FL_MONSTER|FL_CLIENT))) + if (ent->xv->bouncefactor) + backoff = 1 + ent->xv->bouncefactor; +// else if (progstype == PROG_H2 && ent->v->solid == SOLID_PHASEH2 && ((int)((wedict_t*)trace.ent)->v->flags & (FL_MONSTER|FL_CLIENT))) // backoff = 0; -// else + else backoff = 2; } else @@ -1401,7 +1410,15 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) // stop if on ground if ((-DotProduct(gravitydir, trace.plane.normal) > 0.7) && (ent->v->movetype != MOVETYPE_BOUNCEMISSILE)) { - if (-DotProduct(gravitydir, ent->v->velocity) < 60 || ent->v->movetype != MOVETYPE_BOUNCE ) + float bouncespeed; + float bouncestop = ent->xv->bouncestop; + if (!bouncestop) + bouncestop = 60; + if (sv_gameplayfix_bouncedownslopes.ival) + bouncespeed = DotProduct(trace.plane.normal, ent->v->velocity); + else + bouncespeed = -DotProduct(gravitydir, ent->v->velocity); + if (bouncespeed < bouncestop || ent->v->movetype != MOVETYPE_BOUNCE ) { ent->v->flags = (int)ent->v->flags | FL_ONGROUND; ent->v->groundentity = EDICT_TO_PROG(w->progs, trace.ent); @@ -1926,7 +1943,7 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir) if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125) return; - if (ent->v->movetype != MOVETYPE_FLY) + if (ent->v->movetype != MOVETYPE_FLY && ent->v->movetype != MOVETYPE_FLY_WORLDONLY) { // return if gibbed by a trigger if (ent->v->movetype != MOVETYPE_WALK) @@ -2173,6 +2190,19 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) break; case MOVETYPE_FLY_WORLDONLY: case MOVETYPE_FLY: + if (svent) + { //NQ players with movetype_fly are not like non-players. + if (!WPhys_RunThink (w, ent)) + return; + if (ent->xv->gravitydir[2] || ent->xv->gravitydir[1] || ent->xv->gravitydir[0]) + gravitydir = ent->xv->gravitydir; + else + gravitydir = w->g.defaultgravitydir; + WPhys_CheckStuck (w, ent); + WPhys_WalkMove (w, ent, gravitydir); + break; + } + //fallthrough case MOVETYPE_H2SWIM: case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 8d5ebf415..2f2897d94 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -103,8 +103,8 @@ extern cvar_t pm_flyfriction; cvar_t sv_pushplayers = CVAR("sv_pushplayers", "0"); //yes, realip cvars need to be fully initialised or realip will be disabled -cvar_t sv_getrealip = CVARD("sv_getrealip", "0", "Attempt to obtain a more reliable IP for clients, rather than just their proxy."); -cvar_t sv_realip_kick = CVAR("sv_realip_kick", "0"); +cvar_t sv_getrealip = CVARD("sv_getrealip", "0", "Attempt to obtain a more reliable IP for clients, rather than just their proxy.\n0: Don't attempt.\n1: Unreliable checks.\n2: Validate if possible.\n3: Mandatory validation."); +cvar_t sv_realip_kick = CVARD("sv_realip_kick", "0", "Kicks clients if their realip could not be validated to the level specified by sv_getrealip."); cvar_t sv_realiphostname_ipv4 = CVARD("sv_realiphostname_ipv4", "", "This is the server's public ip:port. This is needed for realip to work when the autodetected/local ip is not globally routable"); cvar_t sv_realiphostname_ipv6 = CVARD("sv_realiphostname_ipv6", "", "This is the server's public ip:port. This is needed for realip to work when the autodetected/local ip is not globally routable"); cvar_t sv_realip_timeout = CVAR("sv_realip_timeout", "10"); diff --git a/engine/sw/sw_rast.c b/engine/sw/sw_rast.c index d0ccb0c48..0c2e90c74 100644 --- a/engine/sw/sw_rast.c +++ b/engine/sw/sw_rast.c @@ -930,7 +930,7 @@ void SW_R_RenderView(void) AngleVectors (r_refdef.viewangles, vpn, vright, vup); VectorCopy (r_refdef.vieworg, r_origin); if (r_refdef.useperspective) - Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, r_refdef.fov_x, r_refdef.fov_y, r_refdef.mindist); + Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, r_refdef.fov_x, r_refdef.fov_y, r_refdef.mindist, false); else Matrix4x4_CM_Orthographic(r_refdef.m_projection_std, -r_refdef.fov_x/2, r_refdef.fov_x/2, -r_refdef.fov_y/2, r_refdef.fov_y/2, r_refdef.mindist, r_refdef.maxdist>=1?r_refdef.maxdist:9999); VectorCopy(r_refdef.viewangles, newa); diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 3354d1c12..57ae55f5b 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -3587,10 +3587,22 @@ static void BE_DrawMeshChain_Internal(void) if (p->prog) { - vertexbuffers[VK_BUFF_TC] = shaderstate.batchvbo->texcoord.vk.buff; - vertexoffsets[VK_BUFF_TC] = shaderstate.batchvbo->texcoord.vk.offs; - vertexbuffers[VK_BUFF_LMTC] = shaderstate.batchvbo->lmcoord[0].vk.buff; - vertexoffsets[VK_BUFF_LMTC] = shaderstate.batchvbo->lmcoord[0].vk.offs; + if (shaderstate.batchvbo) + { + vertexbuffers[VK_BUFF_TC] = shaderstate.batchvbo->texcoord.vk.buff; + vertexoffsets[VK_BUFF_TC] = shaderstate.batchvbo->texcoord.vk.offs; + vertexbuffers[VK_BUFF_LMTC] = shaderstate.batchvbo->lmcoord[0].vk.buff; + vertexoffsets[VK_BUFF_LMTC] = shaderstate.batchvbo->lmcoord[0].vk.offs; + } + else + { + float *map; + map = VKBE_AllocateBufferSpace(DB_VBO, vertcount * sizeof(vec2_t), &vertexbuffers[VK_BUFF_TC], &vertexoffsets[VK_BUFF_TC]); + BE_GenerateTCMods(p, map); + + vertexbuffers[VK_BUFF_LMTC] = vertexbuffers[VK_BUFF_TC]; + vertexoffsets[VK_BUFF_LMTC] = vertexoffsets[VK_BUFF_TC]; + } BE_GenerateColourMods(vertcount, p, &vertexbuffers[VK_BUFF_COL], &vertexoffsets[VK_BUFF_COL]); @@ -4191,7 +4203,7 @@ void VKBE_SetupLightCBuffer(dlight_t *l, vec3_t colour) float view[16]; float proj[16]; extern cvar_t r_shadow_shadowmapping_nearclip; - Matrix4x4_CM_Projection_Far(proj, l->fov, l->fov, r_shadow_shadowmapping_nearclip.value, l->radius); + Matrix4x4_CM_Projection_Far(proj, l->fov, l->fov, r_shadow_shadowmapping_nearclip.value, l->radius, false); Matrix4x4_CM_ModelViewMatrixFromAxis(view, l->axis[0], l->axis[1], l->axis[2], l->origin); Matrix4_Multiply(proj, view, cbl->l_cubematrix); } @@ -4229,14 +4241,16 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) shaderstate.curentity = e; + if (e->flags & RF_DEPTHHACK) + proj = r_refdef.m_projection_view; + else + proj = r_refdef.m_projection_std; if ((e->flags & RF_WEAPONMODEL) && r_refdef.playerview->viewentity > 0) { float em[16]; float vm[16]; - proj = r_refdef.m_projection_view; - if (e->flags & RF_WEAPONMODELNOBOB) { vm[0] = vpn[0]; @@ -4306,8 +4320,6 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) } else { - proj = r_refdef.m_projection_std; - m[0] = e->axis[0][0]; m[1] = e->axis[0][1]; m[2] = e->axis[0][2]; diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index a2f29b851..f056c8e76 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -451,7 +451,8 @@ static qboolean VK_CreateSwapChain(void) } if (!vk.vsync && swapinfo.presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR) - Con_Printf("Warning: vulkan graphics driver does not support VK_PRESENT_MODE_IMMEDIATE_KHR.\n"); + if (!vk.swapchain) //only warn on vid_restart, otherwise its annoying when resizing. + Con_Printf("Warning: vulkan graphics driver does not support VK_PRESENT_MODE_IMMEDIATE_KHR.\n"); vk.srgbcapable = false; swapinfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; @@ -887,62 +888,99 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay ret.layout = staging?VK_IMAGE_LAYOUT_PREINITIALIZED:VK_IMAGE_LAYOUT_UNDEFINED; //16bit formats. - if (encoding == PTI_RGB565) - format = VK_FORMAT_R5G6B5_UNORM_PACK16; - else if (encoding == PTI_RGBA4444) - format = VK_FORMAT_R4G4B4A4_UNORM_PACK16; - else if (encoding == PTI_ARGB4444) - format = VK_FORMAT_B4G4R4A4_UNORM_PACK16; //fixme: this seems wrong. - else if (encoding == PTI_RGBA5551) - format = VK_FORMAT_R5G5B5A1_UNORM_PACK16; - else if (encoding == PTI_ARGB1555) - format = VK_FORMAT_A1R5G5B5_UNORM_PACK16; + switch(encoding) + { + case PTI_RGB565: format = VK_FORMAT_R5G6B5_UNORM_PACK16; break; + case PTI_RGBA4444: format = VK_FORMAT_R4G4B4A4_UNORM_PACK16; break; + case PTI_ARGB4444: format = VK_FORMAT_B4G4R4A4_UNORM_PACK16; break; //fixme: this seems wrong... + case PTI_RGBA5551: format = VK_FORMAT_R5G5B5A1_UNORM_PACK16; break; + case PTI_ARGB1555: format = VK_FORMAT_A1R5G5B5_UNORM_PACK16; break; //float formats - else if (encoding == PTI_RGBA16F) - format = VK_FORMAT_R16G16B16A16_SFLOAT; - else if (encoding == PTI_RGBA32F) - format = VK_FORMAT_R32G32B32A32_SFLOAT; + case PTI_RGBA16F: format = VK_FORMAT_R16G16B16A16_SFLOAT; break; + case PTI_RGBA32F: format = VK_FORMAT_R32G32B32A32_SFLOAT; break; //weird formats - else if (encoding == PTI_R8) - format = VK_FORMAT_R8_UNORM; - else if (encoding == PTI_RG8) - format = VK_FORMAT_R8G8_UNORM; + case PTI_R8: format = VK_FORMAT_R8_UNORM; break; + case PTI_RG8: format = VK_FORMAT_R8G8_UNORM; break; + case PTI_R8_SIGNED: format = VK_FORMAT_R8_SNORM; break; + case PTI_RG8_SIGNED: format = VK_FORMAT_R8G8_SNORM; break; //compressed formats - else if (encoding == PTI_S3RGB1) - format = VK_FORMAT_BC1_RGB_UNORM_BLOCK; - else if (encoding == PTI_S3RGBA1) - format = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; - else if (encoding == PTI_S3RGBA3) - format = VK_FORMAT_BC2_UNORM_BLOCK; - else if (encoding == PTI_S3RGBA5) - format = VK_FORMAT_BC3_UNORM_BLOCK; - else if (encoding == PTI_ETC1_RGB8) //vulkan doesn't support etc1, but etc2 is a superset so its all okay. - format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; - else if (encoding == PTI_ETC2_RGB8) - format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; - else if (encoding == PTI_ETC2_RGB8A1) - format = VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; - else if (encoding == PTI_ETC2_RGB8A8) - format = VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + case PTI_BC1_RGB: format = VK_FORMAT_BC1_RGB_UNORM_BLOCK; break; + case PTI_BC1_RGB_SRGB: format = VK_FORMAT_BC1_RGB_SRGB_BLOCK; break; + case PTI_BC1_RGBA: format = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; break; + case PTI_BC1_RGBA_SRGB: format = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; break; + case PTI_BC2_RGBA: format = VK_FORMAT_BC2_UNORM_BLOCK; break; + case PTI_BC2_RGBA_SRGB: format = VK_FORMAT_BC2_SRGB_BLOCK; break; + case PTI_BC3_RGBA: format = VK_FORMAT_BC3_UNORM_BLOCK; break; + case PTI_BC3_RGBA_SRGB: format = VK_FORMAT_BC3_SRGB_BLOCK; break; + case PTI_BC4_R8: format = VK_FORMAT_BC4_UNORM_BLOCK; break; + case PTI_BC4_R8_SIGNED: format = VK_FORMAT_BC4_SNORM_BLOCK; break; + case PTI_BC5_RG8: format = VK_FORMAT_BC5_UNORM_BLOCK; break; + case PTI_BC5_RG8_SIGNED: format = VK_FORMAT_BC5_SNORM_BLOCK; break; + case PTI_BC6_RGBF: format = VK_FORMAT_BC6H_UFLOAT_BLOCK; break; + case PTI_BC6_RGBF_SIGNED: format = VK_FORMAT_BC6H_SFLOAT_BLOCK; break; + case PTI_BC7_RGBA: format = VK_FORMAT_BC7_UNORM_BLOCK; break; + case PTI_BC7_RGBA_SRGB: format = VK_FORMAT_BC7_SRGB_BLOCK; break; + case PTI_ETC1_RGB8: format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; break; //vulkan doesn't support etc1, but etc2 is a superset so its all okay. + case PTI_ETC2_RGB8: format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; break; + case PTI_ETC2_RGB8_SRGB: format = VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK; break; + case PTI_ETC2_RGB8A1: format = VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; break; + case PTI_ETC2_RGB8A1_SRGB: format = VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK; break; + case PTI_ETC2_RGB8A8: format = VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; break; + case PTI_ETC2_RGB8A8_SRGB: format = VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK; break; + case PTI_EAC_R11: format = VK_FORMAT_EAC_R11_UNORM_BLOCK; break; + case PTI_EAC_R11_SIGNED: format = VK_FORMAT_EAC_R11_SNORM_BLOCK; break; + case PTI_EAC_RG11: format = VK_FORMAT_EAC_R11G11_UNORM_BLOCK; break; + case PTI_EAC_RG11_SIGNED: format = VK_FORMAT_EAC_R11G11_SNORM_BLOCK; break; + + case PTI_ASTC_4X4: format = VK_FORMAT_ASTC_4x4_UNORM_BLOCK; break; + case PTI_ASTC_4X4_SRGB: format = VK_FORMAT_ASTC_4x4_SRGB_BLOCK; break; + case PTI_ASTC_5X4: format = VK_FORMAT_ASTC_5x4_UNORM_BLOCK; break; + case PTI_ASTC_5X4_SRGB: format = VK_FORMAT_ASTC_5x4_SRGB_BLOCK; break; + case PTI_ASTC_5X5: format = VK_FORMAT_ASTC_5x5_UNORM_BLOCK; break; + case PTI_ASTC_5X5_SRGB: format = VK_FORMAT_ASTC_5x5_SRGB_BLOCK; break; + case PTI_ASTC_6X5: format = VK_FORMAT_ASTC_6x5_UNORM_BLOCK; break; + case PTI_ASTC_6X5_SRGB: format = VK_FORMAT_ASTC_6x5_SRGB_BLOCK; break; + case PTI_ASTC_6X6: format = VK_FORMAT_ASTC_6x6_UNORM_BLOCK; break; + case PTI_ASTC_6X6_SRGB: format = VK_FORMAT_ASTC_6x6_SRGB_BLOCK; break; + case PTI_ASTC_8X5: format = VK_FORMAT_ASTC_8x5_UNORM_BLOCK; break; + case PTI_ASTC_8X5_SRGB: format = VK_FORMAT_ASTC_8x5_SRGB_BLOCK; break; + case PTI_ASTC_8X6: format = VK_FORMAT_ASTC_8x6_UNORM_BLOCK; break; + case PTI_ASTC_8X6_SRGB: format = VK_FORMAT_ASTC_8x6_SRGB_BLOCK; break; + case PTI_ASTC_8X8: format = VK_FORMAT_ASTC_8x8_UNORM_BLOCK; break; + case PTI_ASTC_8X8_SRGB: format = VK_FORMAT_ASTC_8x8_SRGB_BLOCK; break; + case PTI_ASTC_10X5: format = VK_FORMAT_ASTC_10x5_UNORM_BLOCK; break; + case PTI_ASTC_10X5_SRGB: format = VK_FORMAT_ASTC_10x5_SRGB_BLOCK; break; + case PTI_ASTC_10X6: format = VK_FORMAT_ASTC_10x6_UNORM_BLOCK; break; + case PTI_ASTC_10X6_SRGB: format = VK_FORMAT_ASTC_10x6_SRGB_BLOCK; break; + case PTI_ASTC_10X8: format = VK_FORMAT_ASTC_10x8_UNORM_BLOCK; break; + case PTI_ASTC_10X8_SRGB: format = VK_FORMAT_ASTC_10x8_SRGB_BLOCK; break; + case PTI_ASTC_10X10: format = VK_FORMAT_ASTC_10x10_UNORM_BLOCK; break; + case PTI_ASTC_10X10_SRGB: format = VK_FORMAT_ASTC_10x10_SRGB_BLOCK; break; + case PTI_ASTC_12X10: format = VK_FORMAT_ASTC_12x10_UNORM_BLOCK; break; + case PTI_ASTC_12X10_SRGB: format = VK_FORMAT_ASTC_12x10_SRGB_BLOCK; break; + case PTI_ASTC_12X12: format = VK_FORMAT_ASTC_12x12_UNORM_BLOCK; break; + case PTI_ASTC_12X12_SRGB: format = VK_FORMAT_ASTC_12x12_SRGB_BLOCK; break; + //depth formats - else if (encoding == PTI_DEPTH16) - format = VK_FORMAT_D16_UNORM; - else if (encoding == PTI_DEPTH24) - format = VK_FORMAT_X8_D24_UNORM_PACK32; - else if (encoding == PTI_DEPTH32) - format = VK_FORMAT_D32_SFLOAT; - else if (encoding == PTI_DEPTH24_8) - format = VK_FORMAT_D24_UNORM_S8_UINT; + case PTI_DEPTH16: format = VK_FORMAT_D16_UNORM; break; + case PTI_DEPTH24: format = VK_FORMAT_X8_D24_UNORM_PACK32; break; + case PTI_DEPTH32: format = VK_FORMAT_D32_SFLOAT; break; + case PTI_DEPTH24_8: format = VK_FORMAT_D24_UNORM_S8_UINT; break; //srgb formats - else if (encoding == PTI_BGRA8_SRGB || encoding == PTI_BGRX8_SRGB) - format = VK_FORMAT_B8G8R8A8_SRGB; - else if (encoding == PTI_RGBA8_SRGB || encoding == PTI_RGBX8_SRGB) - format = VK_FORMAT_R8G8B8A8_SRGB; + case PTI_BGRA8_SRGB: + case PTI_BGRX8_SRGB: format = VK_FORMAT_B8G8R8A8_SRGB; break; + case PTI_RGBA8_SRGB: + case PTI_RGBX8_SRGB: format = VK_FORMAT_R8G8B8A8_SRGB; break; //standard formats - else if (encoding == PTI_BGRA8 || encoding == PTI_BGRX8) - format = VK_FORMAT_B8G8R8A8_UNORM; - else //if (encoding == PTI_RGBA8 || encoding == PTI_RGBX8) - format = VK_FORMAT_R8G8B8A8_UNORM; + case PTI_BGRA8: + case PTI_BGRX8: format = VK_FORMAT_B8G8R8A8_UNORM; break; + case PTI_RGBA8: + case PTI_RGBX8: format = VK_FORMAT_R8G8B8A8_UNORM; break; + default: + Sys_Error("VK_CreateTexture2DArray: Unrecognised image encoding: %u\n", encoding); + format = VK_FORMAT_UNDEFINED; + break; + } ici.flags = (ret.type==PTI_CUBEMAP)?VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT:0; ici.imageType = VK_IMAGE_TYPE_2D; ici.format = format; @@ -1188,7 +1226,7 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips) VkCommandBuffer vkloadcmd; vk_image_t target; uint32_t i; - uint32_t blocksize; + uint32_t blockwidth, blockheight; uint32_t blockbytes; uint32_t layers; uint32_t mipcount = mips->mipcount; @@ -1213,57 +1251,7 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips) } } - switch(mips->encoding) - { - case PTI_RGB565: - case PTI_RGBA4444: - case PTI_ARGB4444: - case PTI_RGBA5551: - case PTI_ARGB1555: - blocksize = 1; - blockbytes = 2; //16bit formats - break; - case PTI_RGBA8: - case PTI_RGBX8: - case PTI_BGRA8: - case PTI_BGRX8: - case PTI_RGBA8_SRGB: - case PTI_RGBX8_SRGB: - case PTI_BGRA8_SRGB: - case PTI_BGRX8_SRGB: - blocksize = 1; //in texels - blockbytes = 4; - break; - case PTI_S3RGB1: - case PTI_S3RGBA1: - blocksize = 4; - blockbytes = 8; - break; - case PTI_S3RGBA3: - case PTI_S3RGBA5: - blocksize = 4; - blockbytes = 16; - break; - case PTI_RGBA16F: - blocksize = 1; - blockbytes = 4*2; - break; - case PTI_RGBA32F: - blocksize = 1; - blockbytes = 4*4; - break; - case PTI_R8: - blocksize = 1; - blockbytes = 1; - break; - case PTI_RG8: - blocksize = 1; - blockbytes = 2; - break; - - default: - return false; - } + Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight); fence = VK_FencedBegin(VK_TextureLoaded, sizeof(*fence)); fence->mips = mipcount; @@ -1346,10 +1334,10 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips) bci.size = 0; for (i = 0; i < mipcount; i++) { - uint32_t blockwidth = (mips->mip[i].width+blocksize-1) / blocksize; - uint32_t blockheight = (mips->mip[i].height+blocksize-1) / blocksize; + uint32_t blockswidth = (mips->mip[i].width+blockwidth-1) / blockwidth; + uint32_t blocksheight = (mips->mip[i].height+blockheight-1) / blockheight; - bci.size += blockwidth*blockheight*blockbytes; + bci.size += blockswidth*blocksheight*blockbytes; } bci.flags = 0; bci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; @@ -1378,18 +1366,18 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips) //figure out the number of 'blocks' in the image. //for non-compressed formats this is just the width directly. //for compressed formats (ie: s3tc/dxt) we need to round up to deal with npot. - uint32_t blockwidth = (mips->mip[i].width+blocksize-1) / blocksize; - uint32_t blockheight = (mips->mip[i].height+blocksize-1) / blocksize; + uint32_t blockswidth = (mips->mip[i].width+blockwidth-1) / blockwidth; + uint32_t blocksheight = (mips->mip[i].height+blockheight-1) / blockheight; if (mips->mip[i].data) - memcpy((char*)mapdata + bci.size, (char*)mips->mip[i].data, blockwidth*blockbytes*blockheight); + memcpy((char*)mapdata + bci.size, (char*)mips->mip[i].data, blockswidth*blockbytes*blocksheight); else - memset((char*)mapdata + bci.size, 0, blockwidth*blockbytes*blockheight); + memset((char*)mapdata + bci.size, 0, blockswidth*blockbytes*blocksheight); //queue up a buffer->image copy for this mip region.bufferOffset = bci.size; - region.bufferRowLength = blockwidth*blocksize;//*blockbytes; - region.bufferImageHeight = blockheight*blocksize; + region.bufferRowLength = blockswidth*blockwidth; + region.bufferImageHeight = blocksheight*blockheight; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.mipLevel = i%(mipcount/layers); region.imageSubresource.baseArrayLayer = i/(mipcount/layers); @@ -1397,13 +1385,13 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips) region.imageOffset.x = 0; region.imageOffset.y = 0; region.imageOffset.z = 0; - region.imageExtent.width = mips->mip[i].width;//blockwidth*blocksize; - region.imageExtent.height = mips->mip[i].height;//blockheight*blocksize; + region.imageExtent.width = mips->mip[i].width;//blockswidth*blockwidth; + region.imageExtent.height = mips->mip[i].height;//blocksheight*blockheight; region.imageExtent.depth = 1; vkCmdCopyBufferToImage(vkloadcmd, fence->stagingbuffer, target.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - bci.size += blockwidth*blockheight*blockbytes; + bci.size += blockswidth*blocksheight*blockbytes; } vkUnmapMemory(vk.device, fence->stagingmemory); #else @@ -1416,8 +1404,8 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips) //figure out the number of 'blocks' in the image. //for non-compressed formats this is just the width directly. //for compressed formats (ie: s3tc/dxt) we need to round up to deal with npot. - uint32_t blockwidth = (mips->mip[i].width+blocksize-1) / blocksize; - uint32_t blockheight = (mips->mip[i].height+blocksize-1) / blocksize; + uint32_t blockswidth = (mips->mip[i].width+blockwidth-1) / blockwidth; + uint32_t blocksheight = (mips->mip[i].height+blockheight-1) / blockheight; fence->staging[i] = VK_CreateTexture2DArray(mips->mip[i].width, mips->mip[i].height, 0, 1, mips->encoding, PTI_2D); subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -1428,7 +1416,7 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips) if (mapdata) { for (y = 0; y < blockheight; y++) - memcpy((char*)mapdata + layout.offset + y*layout.rowPitch, (char*)mips->mip[i].data + y*blockwidth*blockbytes, blockwidth*blockbytes); + memcpy((char*)mapdata + layout.offset + y*layout.rowPitch, (char*)mips->mip[i].data + y*blockswidth*blockbytes, blockswidth*blockbytes); } else Sys_Error("Unable to map staging image\n"); @@ -1527,17 +1515,22 @@ void VK_R_DeInit (void) void VK_SetupViewPortProjection(qboolean flipy) { float fov_x, fov_y; + float fovv_x, fovv_y; AngleVectors (r_refdef.viewangles, vpn, vright, vup); VectorCopy (r_refdef.vieworg, r_origin); fov_x = r_refdef.fov_x;//+sin(cl.time)*5; fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5; + fovv_x = r_refdef.fovv_x; + fovv_y = r_refdef.fovv_y; if ((r_refdef.flags & RDF_UNDERWATER) && !(r_refdef.flags & RDF_WATERWARP)) { fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); fov_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); + fovv_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); + fovv_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); } // screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height; @@ -1557,9 +1550,15 @@ void VK_SetupViewPortProjection(qboolean flipy) r_refdef.flipcull = 0; } if (r_refdef.maxdist) - Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist); + { + Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist, false); + Matrix4x4_CM_Projection_Far(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, r_refdef.maxdist, false); + } else - Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist); + { + Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, false); + Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, false); + } } void VK_Set2D(void) @@ -3373,21 +3372,69 @@ void VK_CheckTextureFormats(void) {PTI_RGBA32F, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT}, {PTI_R8, VK_FORMAT_R8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, {PTI_RG8, VK_FORMAT_R8G8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_R8_SIGNED, VK_FORMAT_R8_SNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_RG8_SIGNED, VK_FORMAT_R8G8_SNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, {PTI_DEPTH16, VK_FORMAT_D16_UNORM, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, {PTI_DEPTH24, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, {PTI_DEPTH32, VK_FORMAT_D32_SFLOAT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, {PTI_DEPTH24_8, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, - {PTI_S3RGB1, VK_FORMAT_BC1_RGB_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_S3RGBA1, VK_FORMAT_BC1_RGBA_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_S3RGBA3, VK_FORMAT_BC2_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_S3RGBA5, VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - - {PTI_ETC1_RGB8, VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, //vulkan doesn't support etc1. - {PTI_ETC2_RGB8, VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_ETC2_RGB8A1, VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, - {PTI_ETC2_RGB8A8, VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC1_RGB, VK_FORMAT_BC1_RGB_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC1_RGBA, VK_FORMAT_BC1_RGBA_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC2_RGBA, VK_FORMAT_BC2_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC3_RGBA, VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC1_RGB_SRGB, VK_FORMAT_BC1_RGB_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC1_RGBA_SRGB, VK_FORMAT_BC1_RGBA_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC2_RGBA_SRGB, VK_FORMAT_BC2_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC3_RGBA_SRGB, VK_FORMAT_BC3_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC4_R8, VK_FORMAT_BC4_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC4_R8_SIGNED, VK_FORMAT_BC4_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC5_RG8, VK_FORMAT_BC5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC5_RG8_SIGNED, VK_FORMAT_BC5_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC6_RGBF, VK_FORMAT_BC6H_UFLOAT_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC6_RGBF_SIGNED, VK_FORMAT_BC6H_SFLOAT_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC7_RGBA, VK_FORMAT_BC7_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_BC7_RGBA_SRGB, VK_FORMAT_BC7_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ETC1_RGB8, VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, //vulkan doesn't support etc1 (but that's okay, because etc2 is a superset). + {PTI_ETC2_RGB8, VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ETC2_RGB8A1, VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ETC2_RGB8A8, VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ETC2_RGB8_SRGB, VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ETC2_RGB8A1_SRGB, VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ETC2_RGB8A8_SRGB, VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_EAC_R11, VK_FORMAT_EAC_R11_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_EAC_R11_SIGNED, VK_FORMAT_EAC_R11_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_EAC_RG11, VK_FORMAT_EAC_R11G11_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_EAC_RG11_SIGNED, VK_FORMAT_EAC_R11G11_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_4X4, VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_4X4_SRGB, VK_FORMAT_ASTC_4x4_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_5X4, VK_FORMAT_ASTC_5x4_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_5X4_SRGB, VK_FORMAT_ASTC_5x4_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_5X5, VK_FORMAT_ASTC_5x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_5X5_SRGB, VK_FORMAT_ASTC_5x5_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_6X5, VK_FORMAT_ASTC_6x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_6X5_SRGB, VK_FORMAT_ASTC_6x5_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_6X6, VK_FORMAT_ASTC_6x6_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_6X6_SRGB, VK_FORMAT_ASTC_6x6_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_8X5, VK_FORMAT_ASTC_8x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_8X5_SRGB, VK_FORMAT_ASTC_8x5_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_8X6, VK_FORMAT_ASTC_8x6_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_8X6_SRGB, VK_FORMAT_ASTC_8x6_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_8X8, VK_FORMAT_ASTC_8x8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_8X8_SRGB, VK_FORMAT_ASTC_8x8_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_10X5, VK_FORMAT_ASTC_10x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_10X5_SRGB, VK_FORMAT_ASTC_10x5_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_10X6, VK_FORMAT_ASTC_10x6_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_10X6_SRGB, VK_FORMAT_ASTC_10x6_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_10X8, VK_FORMAT_ASTC_10x8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_10X8_SRGB, VK_FORMAT_ASTC_10x8_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_10X10, VK_FORMAT_ASTC_10x10_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_10X10_SRGB, VK_FORMAT_ASTC_10x10_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_12X10, VK_FORMAT_ASTC_12x10_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_12X10_SRGB, VK_FORMAT_ASTC_12x10_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_12X12, VK_FORMAT_ASTC_12x12_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, + {PTI_ASTC_12X12_SRGB, VK_FORMAT_ASTC_12x12_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT}, }; unsigned int i; VkPhysicalDeviceProperties props; @@ -3395,7 +3442,8 @@ void VK_CheckTextureFormats(void) vkGetPhysicalDeviceProperties(vk.gpu, &props); vk.limits = props.limits; - sh_config.texture_maxsize = props.limits.maxImageDimension2D; + sh_config.texture2d_maxsize = props.limits.maxImageDimension2D; + sh_config.texturecube_maxsize = props.limits.maxImageDimensionCube; for (i = 0; i < countof(texfmt); i++) { @@ -3803,6 +3851,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre //try to enable whatever we can use, if we can. features.robustBufferAccess = avail.robustBufferAccess; features.textureCompressionBC = avail.textureCompressionBC; + features.textureCompressionETC2 = avail.textureCompressionETC2; features.samplerAnisotropy = avail.samplerAnisotropy; features.geometryShader = avail.geometryShader; features.tessellationShader = avail.tessellationShader; @@ -3923,7 +3972,6 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre sh_config.minver = -1; sh_config.maxver = -1; - sh_config.texture_maxsize = 4096; //must be at least 4096, FIXME: query this properly sh_config.texture_non_power_of_two = true; //is this always true? sh_config.texture_non_power_of_two_pic = true; //probably true... sh_config.npot_rounddown = false; diff --git a/plugins/ezhud/ezquakeisms.c b/plugins/ezhud/ezquakeisms.c index 3a53abc4c..d234ae68e 100644 --- a/plugins/ezhud/ezquakeisms.c +++ b/plugins/ezhud/ezquakeisms.c @@ -1,50 +1,50 @@ -#include "../plugin.h" -#include "ezquakeisms.h" -#include "hud.h" -#include "hud_editor.h" - -int sb_lines; -float scr_con_current; -int sb_showteamscores; -int sb_showscores; -int host_screenupdatecount; -float alphamul; - -cvar_t *scr_newHud; - -char *Cmd_Argv(int arg) -{ - static char buf[4][128]; - if (arg >= 4) - return ""; - pCmd_Argv(arg, buf[arg], sizeof(buf[arg])); - return buf[arg]; -} - -float infofloat(char *info, char *findkey, float def); - -void Draw_SetOverallAlpha(float a) -{ - alphamul = a; -} -void Draw_AlphaFillRGB(float x, float y, float w, float h, qbyte r, qbyte g, qbyte b, qbyte a) -{ - pDraw_Colour4f(r/255.0, g/255.0, b/255.0, a/255.0 * alphamul); - pDraw_Fill(x, y, w, h); - pDraw_Colour4f(1, 1, 1, 1); -} -void Draw_Fill(float x, float y, float w, float h, qbyte pal) -{ - pDraw_Colourpa(pal, alphamul); - pDraw_Fill(x, y, w, h); - pDraw_Colour4f(1, 1, 1, 1); -} -const char *ColorNameToRGBString (const char *newval) -{ - return newval; -} -byte *StringToRGB(const char *str) -{ +#include "../plugin.h" +#include "ezquakeisms.h" +#include "hud.h" +#include "hud_editor.h" + +int sb_lines; +float scr_con_current; +int sb_showteamscores; +int sb_showscores; +int host_screenupdatecount; +float alphamul; + +cvar_t *scr_newHud; + +char *Cmd_Argv(int arg) +{ + static char buf[4][128]; + if (arg >= 4) + return ""; + pCmd_Argv(arg, buf[arg], sizeof(buf[arg])); + return buf[arg]; +} + +float infofloat(char *info, char *findkey, float def); + +void Draw_SetOverallAlpha(float a) +{ + alphamul = a; +} +void Draw_AlphaFillRGB(float x, float y, float w, float h, qbyte r, qbyte g, qbyte b, qbyte a) +{ + pDraw_Colour4f(r/255.0, g/255.0, b/255.0, a/255.0 * alphamul); + pDraw_Fill(x, y, w, h); + pDraw_Colour4f(1, 1, 1, 1); +} +void Draw_Fill(float x, float y, float w, float h, qbyte pal) +{ + pDraw_Colourpa(pal, alphamul); + pDraw_Fill(x, y, w, h); + pDraw_Colour4f(1, 1, 1, 1); +} +const char *ColorNameToRGBString (const char *newval) +{ + return newval; +} +byte *StringToRGB(const char *str) +{ static byte rgba[4]; int i; for (i = 0; i < 4; i++) @@ -55,97 +55,97 @@ byte *StringToRGB(const char *str) rgba[i] = 255; else rgba[i] = strtoul(str, (char**)&str, 0); - } - return rgba; -} -void Draw_TextBox (int x, int y, int width, int lines) -{ -} - -char *TP_LocationName (vec3_t location) -{ - static char locname[256]; - pGetLocationName(location, locname, sizeof(locname)); - return locname; -} - - -void Draw_SPic(float x, float y, mpic_t *pic, float scale) -{ - qhandle_t image = (intptr_t)pic; - float w, h; - pDraw_ImageSize(image, &w, &h); - pDraw_Image(x, y, w*scale, h*scale, 0, 0, 1, 1, image); -} -void Draw_SSubPic(float x, float y, mpic_t *pic, float s1, float t1, float s2, float t2, float scale) -{ - qhandle_t image = (intptr_t)pic; - float w, h; - pDraw_ImageSize(image, &w, &h); - pDraw_Image(x, y, (s2-s1)*scale, (t2-t1)*scale, s1/w, t1/h, s2/w, t2/h, image); -} -void Draw_EZString(float x, float y, char *str, float scale, qboolean red) -{ - unsigned int flags = 0; - if (red) - flags |= 1; - pDraw_StringH(x, y, scale, flags, str); -} - -#define Draw_STransPic Draw_SPic -void Draw_Character(float x, float y, unsigned int ch) -{ - pDraw_Character(x, y, 0xe000|ch); -} -void Draw_SCharacter(float x, float y, unsigned int ch, float scale) -{ - pDraw_CharacterH(x, y, 8*scale, 0, 0xe000|ch); -} - -void SCR_DrawWadString(float x, float y, float scale, char *str) -{ - pDraw_String(x, y, str); //FIXME -} - -void Draw_SAlphaSubPic2(float x, float y, mpic_t *pic, float s1, float t1, float s2, float t2, float sw, float sh, float alpha) -{ - qhandle_t image = (intptr_t)pic; - float w, h; - pDraw_ImageSize(image, &w, &h); - pDraw_Colour4f(1, 1, 1, alpha * alphamul); - pDraw_Image(x, y, (s2-s1)*sw, (t2-t1)*sh, s1/w, t1/h, s2/w, t2/h, image); - pDraw_Colour4f(1, 1, 1, 1); -} - -void Draw_AlphaFill(float x, float y, float w, float h, unsigned int pal, float alpha) -{ - if (pal >= 256) - pDraw_Colour4f(((pal>>16)&0xff)/255.0, ((pal>>8)&0xff)/255.0, ((pal>>0)&0xff)/255.0, alpha * alphamul); - else - pDraw_Colourpa(pal, alpha * alphamul); - pDraw_Fill(x, y, w, h); - pDraw_Colour4f(1, 1, 1, 1); -} -void Draw_AlphaPic(float x, float y, mpic_t *pic, float alpha) -{ - qhandle_t image = (intptr_t)pic; - float w, h; - pDraw_ImageSize(image, &w, &h); - pDraw_Colour4f(1, 1, 1, alpha * alphamul); - pDraw_Image(x, y, w, h, 0, 0, 1, 1, image); - pDraw_Colour4f(1, 1, 1, 1); -} -void Draw_AlphaSubPic(float x, float y, mpic_t *pic, float s1, float t1, float s2, float t2, float alpha) -{ - qhandle_t image = (intptr_t)pic; - float w, h; - pDraw_ImageSize(image, &w, &h); - pDraw_Colour4f(1, 1, 1, alpha * alphamul); - pDraw_Image(x, y, s2-s1, t2-t1, s1/w, t1/h, s2/w, t2/h, image); - pDraw_Colour4f(1, 1, 1, 1); -} -void SCR_HUD_DrawBar(int direction, int value, float max_value, float *rgba, int x, int y, int width, int height) -{ + } + return rgba; +} +void Draw_TextBox (int x, int y, int width, int lines) +{ +} + +char *TP_LocationName (vec3_t location) +{ + static char locname[256]; + pGetLocationName(location, locname, sizeof(locname)); + return locname; +} + + +void Draw_SPic(float x, float y, mpic_t *pic, float scale) +{ + qhandle_t image = (intptr_t)pic; + float w, h; + pDraw_ImageSize(image, &w, &h); + pDraw_Image(x, y, w*scale, h*scale, 0, 0, 1, 1, image); +} +void Draw_SSubPic(float x, float y, mpic_t *pic, float s1, float t1, float s2, float t2, float scale) +{ + qhandle_t image = (intptr_t)pic; + float w, h; + pDraw_ImageSize(image, &w, &h); + pDraw_Image(x, y, (s2-s1)*scale, (t2-t1)*scale, s1/w, t1/h, s2/w, t2/h, image); +} +void Draw_EZString(float x, float y, char *str, float scale, qboolean red) +{ + unsigned int flags = 0; + if (red) + flags |= 1; + pDraw_StringH(x, y, scale, flags, str); +} + +#define Draw_STransPic Draw_SPic +void Draw_Character(float x, float y, unsigned int ch) +{ + pDraw_Character(x, y, 0xe000|ch); +} +void Draw_SCharacter(float x, float y, unsigned int ch, float scale) +{ + pDraw_CharacterH(x, y, 8*scale, 0, 0xe000|ch); +} + +void SCR_DrawWadString(float x, float y, float scale, char *str) +{ + pDraw_String(x, y, str); //FIXME +} + +void Draw_SAlphaSubPic2(float x, float y, mpic_t *pic, float s1, float t1, float s2, float t2, float sw, float sh, float alpha) +{ + qhandle_t image = (intptr_t)pic; + float w, h; + pDraw_ImageSize(image, &w, &h); + pDraw_Colour4f(1, 1, 1, alpha * alphamul); + pDraw_Image(x, y, (s2-s1)*sw, (t2-t1)*sh, s1/w, t1/h, s2/w, t2/h, image); + pDraw_Colour4f(1, 1, 1, 1); +} + +void Draw_AlphaFill(float x, float y, float w, float h, unsigned int pal, float alpha) +{ + if (pal >= 256) + pDraw_Colour4f(((pal>>16)&0xff)/255.0, ((pal>>8)&0xff)/255.0, ((pal>>0)&0xff)/255.0, alpha * alphamul); + else + pDraw_Colourpa(pal, alpha * alphamul); + pDraw_Fill(x, y, w, h); + pDraw_Colour4f(1, 1, 1, 1); +} +void Draw_AlphaPic(float x, float y, mpic_t *pic, float alpha) +{ + qhandle_t image = (intptr_t)pic; + float w, h; + pDraw_ImageSize(image, &w, &h); + pDraw_Colour4f(1, 1, 1, alpha * alphamul); + pDraw_Image(x, y, w, h, 0, 0, 1, 1, image); + pDraw_Colour4f(1, 1, 1, 1); +} +void Draw_AlphaSubPic(float x, float y, mpic_t *pic, float s1, float t1, float s2, float t2, float alpha) +{ + qhandle_t image = (intptr_t)pic; + float w, h; + pDraw_ImageSize(image, &w, &h); + pDraw_Colour4f(1, 1, 1, alpha * alphamul); + pDraw_Image(x, y, s2-s1, t2-t1, s1/w, t1/h, s2/w, t2/h, image); + pDraw_Colour4f(1, 1, 1, 1); +} +void SCR_HUD_DrawBar(int direction, int value, float max_value, float *rgba, int x, int y, int width, int height) +{ int amount; if(direction >= 2) @@ -166,61 +166,61 @@ void SCR_HUD_DrawBar(int direction, int value, float max_value, float *rgba, int pDraw_Fill(x, y + height - amount, width, amount); else // up -> down - pDraw_Fill(x, y, width, amount); - pDraw_Colour4f(1, 1, 1, 1); -} - -void Draw_Polygon(int x, int y, vec3_t *vertices, int num_vertices, qbool fill, byte r, byte g, byte b, byte a) -{ - pDraw_Colour4f(r/255.0, g/255.0, b/255.0, a/255.0 * alphamul); -// pDraw_Line(x1, y1, x2, y1); - pDraw_Colour4f(1, 1, 1, 1); -} -void Draw_ColoredString3(float x, float y, const char *str, clrinfo_t *clr, int huh, int wut) -{ - pDraw_Colour4f(clr->c[0]/255.0, clr->c[1]/255.0, clr->c[2]/255.0, clr->c[3]/255.0 * alphamul); - pDraw_String(x, y, str); - pDraw_Colour4f(1, 1, 1, 1); -} -void UI_PrintTextBlock() -{ -} -void Draw_AlphaRectangleRGB(int x, int y, int w, int h, int foo, int bar, byte r, byte g, byte b, byte a) -{ - float x1 = x; - float x2 = x+w; - float y1 = y; - float y2 = y+h; - pDraw_Colour4f(r/255.0, g/255.0, b/255.0, a/255.0 * alphamul); - pDraw_Line(x1, y1, x2, y1); - pDraw_Line(x2, y1, x2, y2); - pDraw_Line(x1, y2, x2, y2); - pDraw_Line(x1, y1, x1, y2); - pDraw_Colour4f(1, 1, 1, 1); -} -void Draw_AlphaLineRGB(float x1, float y1, float x2, float y2, float width, byte r, byte g, byte b, byte a) -{ - pDraw_Colour4f(r/255.0, g/255.0, b/255.0, a/255.0 * alphamul); - pDraw_Line(x1, y1, x2, y2); - pDraw_Colour4f(1, 1, 1, 1); -} - -mpic_t *Draw_CachePicSafe(const char *name, qbool crash, qbool ignorewad) -{ - if (!*name) - return NULL; - return (mpic_t*)(qintptr_t)pDraw_LoadImage(name, false); -} -mpic_t *Draw_CacheWadPic(const char *name) -{ - return (mpic_t*)(qintptr_t)pDraw_LoadImage(name, true); -} - -mpic_t *SCR_LoadCursorImage(char *cursorimage) -{ - return Draw_CachePicSafe(cursorimage, false, true); -} - + pDraw_Fill(x, y, width, amount); + pDraw_Colour4f(1, 1, 1, 1); +} + +void Draw_Polygon(int x, int y, vec3_t *vertices, int num_vertices, qbool fill, byte r, byte g, byte b, byte a) +{ + pDraw_Colour4f(r/255.0, g/255.0, b/255.0, a/255.0 * alphamul); +// pDraw_Line(x1, y1, x2, y1); + pDraw_Colour4f(1, 1, 1, 1); +} +void Draw_ColoredString3(float x, float y, const char *str, clrinfo_t *clr, int huh, int wut) +{ + pDraw_Colour4f(clr->c[0]/255.0, clr->c[1]/255.0, clr->c[2]/255.0, clr->c[3]/255.0 * alphamul); + pDraw_String(x, y, str); + pDraw_Colour4f(1, 1, 1, 1); +} +void UI_PrintTextBlock() +{ +} +void Draw_AlphaRectangleRGB(int x, int y, int w, int h, int foo, int bar, byte r, byte g, byte b, byte a) +{ + float x1 = x; + float x2 = x+w; + float y1 = y; + float y2 = y+h; + pDraw_Colour4f(r/255.0, g/255.0, b/255.0, a/255.0 * alphamul); + pDraw_Line(x1, y1, x2, y1); + pDraw_Line(x2, y1, x2, y2); + pDraw_Line(x1, y2, x2, y2); + pDraw_Line(x1, y1, x1, y2); + pDraw_Colour4f(1, 1, 1, 1); +} +void Draw_AlphaLineRGB(float x1, float y1, float x2, float y2, float width, byte r, byte g, byte b, byte a) +{ + pDraw_Colour4f(r/255.0, g/255.0, b/255.0, a/255.0 * alphamul); + pDraw_Line(x1, y1, x2, y2); + pDraw_Colour4f(1, 1, 1, 1); +} + +mpic_t *Draw_CachePicSafe(const char *name, qbool crash, qbool ignorewad) +{ + if (!*name) + return NULL; + return (mpic_t*)(qintptr_t)pDraw_LoadImage(name, false); +} +mpic_t *Draw_CacheWadPic(const char *name) +{ + return (mpic_t*)(qintptr_t)pDraw_LoadImage(name, true); +} + +mpic_t *SCR_LoadCursorImage(char *cursorimage) +{ + return Draw_CachePicSafe(cursorimage, false, true); +} + unsigned int Sbar_ColorForMap (unsigned int m) { if (m >= 16) @@ -228,39 +228,39 @@ unsigned int Sbar_ColorForMap (unsigned int m) m = (m < 0) ? 0 : ((m > 13) ? 13 : m); m *= 16; return m < 128 ? m + 8 : m + 8; -} -int Sbar_TopColor(player_info_t *pi) -{ - return Sbar_ColorForMap(pi->topcolour); -} -int Sbar_BottomColor(player_info_t *pi) -{ - return Sbar_ColorForMap(pi->bottomcolour); -} -int dehex(char nib) -{ - if (nib >= '0' && nib <= '9') - return nib - '0'; - if (nib >= 'a' && nib <= 'f') - return nib - 'a' + 10; - if (nib >= 'A' && nib <= 'F') - return nib - 'A' + 10; - return 0; -} -char *TP_ParseFunChars(char *str, qbool chat) -{ - static char resultbuf[1024]; - char *out = resultbuf, *end = resultbuf+sizeof(resultbuf)-1; - - while (out < end) - { - if (str[0] == '$' && str[1] == 'x' && str[2] && str[3]) - { - *out++ = (dehex(str[2]) << 4) | dehex(str[3]); - str+=4; - } - else if (str[0] == '$') - { +} +int Sbar_TopColor(player_info_t *pi) +{ + return Sbar_ColorForMap(pi->topcolour); +} +int Sbar_BottomColor(player_info_t *pi) +{ + return Sbar_ColorForMap(pi->bottomcolour); +} +int dehex(char nib) +{ + if (nib >= '0' && nib <= '9') + return nib - '0'; + if (nib >= 'a' && nib <= 'f') + return nib - 'a' + 10; + if (nib >= 'A' && nib <= 'F') + return nib - 'A' + 10; + return 0; +} +char *TP_ParseFunChars(char *str, qbool chat) +{ + static char resultbuf[1024]; + char *out = resultbuf, *end = resultbuf+sizeof(resultbuf)-1; + + while (out < end) + { + if (str[0] == '$' && str[1] == 'x' && str[2] && str[3]) + { + *out++ = (dehex(str[2]) << 4) | dehex(str[3]); + str+=4; + } + else if (str[0] == '$') + { int c = 0; switch (str[1]) { @@ -294,83 +294,83 @@ char *TP_ParseFunChars(char *str, qbool chat) str++; } str++; - } - else if (*str) - *out++ = *str++; - else - break; - } - *out = 0; - return resultbuf; -} -char *TP_ItemName(unsigned int itbit) -{ - return "Dunno"; -} - -void Replace_In_String(char *src, size_t strsize, char leadchar, int patterns, ...) -{ - char orig[1024]; - char *out, *outstop; - va_list ap; - int i; - - strlcpy(orig, src, sizeof(orig)); - out = src; - outstop = out + strsize-1; - src = orig; - - while(*src) - { - if (out == outstop) - break; - if (*src != leadchar) - *out++ = *src++; - else if (*++src == leadchar) - *out++ = leadchar; - else - { - va_start(ap, patterns); - for (i = 0; i < patterns; i++) - { - const char *arg = va_arg(ap, const char *); - const char *val = va_arg(ap, const char *); - size_t alen = strlen(arg); - if (!strncmp(src, arg, strlen(arg))) - { - strlcpy(out, val, (outstop-out)+1); - out += strlen(out); - src += alen; - break; - } - } - if (i == patterns) - { - strlcpy(out, "unknown", (outstop-out)+1); - out += strlen(out); - } - va_end(ap); - } - } - *out = 0; -} - -int SCR_GetClockStringWidth(const char *s, qbool big, float scale) -{ - int w = 0; - if (big) - { - while(*s) - w += ((*s++==':')?16:24); - } - else - w = strlen(s) * 8; - return w * scale; -} -int SCR_GetClockStringHeight(qbool big, float scale) -{ - return (big?24:8)*scale; -} + } + else if (*str) + *out++ = *str++; + else + break; + } + *out = 0; + return resultbuf; +} +char *TP_ItemName(unsigned int itbit) +{ + return "Dunno"; +} + +void Replace_In_String(char *src, size_t strsize, char leadchar, int patterns, ...) +{ + char orig[1024]; + char *out, *outstop; + va_list ap; + int i; + + strlcpy(orig, src, sizeof(orig)); + out = src; + outstop = out + strsize-1; + src = orig; + + while(*src) + { + if (out == outstop) + break; + if (*src != leadchar) + *out++ = *src++; + else if (*++src == leadchar) + *out++ = leadchar; + else + { + va_start(ap, patterns); + for (i = 0; i < patterns; i++) + { + const char *arg = va_arg(ap, const char *); + const char *val = va_arg(ap, const char *); + size_t alen = strlen(arg); + if (!strncmp(src, arg, strlen(arg))) + { + strlcpy(out, val, (outstop-out)+1); + out += strlen(out); + src += alen; + break; + } + } + if (i == patterns) + { + strlcpy(out, "unknown", (outstop-out)+1); + out += strlen(out); + } + va_end(ap); + } + } + *out = 0; +} + +int SCR_GetClockStringWidth(const char *s, qbool big, float scale) +{ + int w = 0; + if (big) + { + while(*s) + w += ((*s++==':')?16:24); + } + else + w = strlen(s) * 8; + return w * scale; +} +int SCR_GetClockStringHeight(qbool big, float scale) +{ + return (big?24:8)*scale; +} char *SecondsToMinutesString(int print_time, char *buffer, size_t buffersize) { int tens_minutes, minutes, tens_seconds, seconds; @@ -380,7 +380,7 @@ char *SecondsToMinutesString(int print_time, char *buffer, size_t buffersize) { seconds = fmod (print_time, 10); snprintf (buffer, buffersize, "%i%i:%i%i", tens_minutes, minutes, tens_seconds, seconds); return buffer; -} +} char *SCR_GetGameTime(int t, char *buffer, size_t buffersize) { float timelimit; @@ -393,12 +393,12 @@ char *SCR_GetGameTime(int t, char *buffer, size_t buffersize) SecondsToMinutesString((int) abs(timelimit - (cl.time - cl.matchstart)), buffer, buffersize); return buffer; } - -const char* SCR_GetTimeString(int timetype, const char *format) -{ - static char buffer[256]; - switch(timetype) - { + +const char* SCR_GetTimeString(int timetype, const char *format) +{ + static char buffer[256]; + switch(timetype) + { case TIMETYPE_CLOCK: { time_t t; @@ -407,21 +407,21 @@ const char* SCR_GetTimeString(int timetype, const char *format) ptm = localtime (&t); if (!ptm) return "-:-"; if (!strftime(buffer, sizeof(buffer)-1, format, ptm)) return "-:-"; - return buffer; - } - case TIMETYPE_GAMECLOCK: - case TIMETYPE_GAMECLOCKINV: - return SCR_GetGameTime(timetype, buffer, sizeof(buffer)); - - case TIMETYPE_DEMOCLOCK: - return SecondsToMinutesString(infofloat(cl.serverinfo, "demotime", 0), buffer, sizeof(buffer)); - - default: - return "01234"; - } -} -void SCR_DrawBigClock(int x, int y, int style, int blink, float scale, const char *t) -{ + return buffer; + } + case TIMETYPE_GAMECLOCK: + case TIMETYPE_GAMECLOCKINV: + return SCR_GetGameTime(timetype, buffer, sizeof(buffer)); + + case TIMETYPE_DEMOCLOCK: + return SecondsToMinutesString(infofloat(cl.serverinfo, "demotime", 0), buffer, sizeof(buffer)); + + default: + return "01234"; + } +} +void SCR_DrawBigClock(int x, int y, int style, int blink, float scale, const char *t) +{ extern mpic_t *sb_nums[2][11]; extern mpic_t *sb_colon/*, *sb_slash*/; qbool lblink = (int)(cls.realtime*2) & 1; @@ -449,10 +449,10 @@ void SCR_DrawBigClock(int x, int y, int style, int blink, float scale, const cha x += 24*scale; } t++; - } -} -void SCR_DrawSmallClock(int x, int y, int style, int blink, float scale, const char *t) -{ + } +} +void SCR_DrawSmallClock(int x, int y, int style, int blink, float scale, const char *t) +{ qbool lblink = (int)(cls.realtime*2) & 1; int c; @@ -481,248 +481,248 @@ void SCR_DrawSmallClock(int x, int y, int style, int blink, float scale, const c Draw_SCharacter(x, y, c, scale); x+= 8*scale; t++; - } -} - -#include "builtin_huds.h" -void EZHud_UseNquake_f(void) -{ - const char *hudstr = builtin_hud_nquake; - pCmd_AddText(hudstr, true); -} - -struct -{ - xcommand_t cmd; - const char *name; -} concmds[128]; -int numconcmds; -qboolean Cmd_AddCommand (const char *funcname, xcommand_t function) -{ - if (numconcmds < sizeof(concmds)/sizeof(concmds[0])) - { - concmds[numconcmds].cmd = function; - concmds[numconcmds].name = funcname; - numconcmds++; - pCmd_AddCommand(funcname); - return true; - } - Con_Printf("ezhud: too many console commands\n"); - return false; -}; -qintptr_t EZHud_ExecuteCommand(qintptr_t *args) -{ - char buffer[128]; - int i; - pCmd_Argv(0, buffer, sizeof(buffer)); - for (i = 0; i < numconcmds; i++) - { - if (!strcmp(buffer, concmds[i].name)) - { - concmds[i].cmd(); - return 1; - } - } - return 0; -} - -int IN_BestWeapon(void) -{ - return 0; -} - -qbool VID_VSyncIsOn(void){return false;} -double vid_vsync_lag; - - -vrect_t scr_vrect; - -qintptr_t EZHud_Tick(qintptr_t *args) -{ - static float lasttime, lasttime_min = 99999; - static int framecount; - - //realtime(ms), realtime(secs), servertime - float oldtime = cls.realtime; - cls.realtime = *(float*)&args[1]; - cls.frametime = cls.realtime - oldtime; - - cl.time = *(float*)&args[2]; - - if (cls.realtime - lasttime > 1) - { - cls.fps = framecount/(cls.realtime - lasttime); - lasttime = cls.realtime; - framecount = 0; - - if (cls.realtime - lasttime_min > 30) - { - cls.min_fps = cls.fps; - lasttime_min = cls.realtime; - } - else if (cls.min_fps > cls.fps) - cls.min_fps = cls.fps; - } - framecount++; - - return 1; -} -char *findinfo(char *info, char *findkey) -{ - int kl = strlen(findkey); - char *key, *value; - while(*info) - { - key = strchr(info, '\\'); - if (!key) - break; - key++; - value = strchr(key, '\\'); - if (!value) - break; - info = value+1; - if (!strncmp(key, findkey, kl) && key[kl] == '\\') - return info; - } - return NULL; -} -char *infostring(char *info, char *findkey, char *buffer, size_t bufsize) -{ - char *value = findinfo(info, findkey); - char *end; - if (value) - { - end = strchr(value, '\\'); - if (!end) - end = value + strlen(value); - bufsize--; - if (bufsize > (end - value)) - bufsize = (end - value); - memcpy(buffer, value, bufsize); - buffer[bufsize] = 0; - return buffer; - } - *buffer = 0; - return buffer; -} -float infofloat(char *info, char *findkey, float def) -{ - char *value = findinfo(info, findkey); - if (value) - return atof(value); - return def; -} -qintptr_t EZHud_Draw(qintptr_t *args) -{ - char serverinfo[4096]; - char val[64]; - int i; - cl.splitscreenview = args[0]; - scr_vrect.x = args[1]; - scr_vrect.y = args[2]; - scr_vrect.width = args[3]; - scr_vrect.height = args[4]; - sb_showscores = args[5] & 1; - sb_showteamscores = args[5] & 2; - - pCL_GetStats(0, cl.stats, sizeof(cl.stats)/sizeof(cl.stats[0])); - for (i = 0; i < 32; i++) - pGetPlayerInfo(i, &cl.players[i]); - - pGetLocalPlayerNumbers(cl.splitscreenview, 1, &cl.playernum, &cl.tracknum); - pGetServerInfo(cl.serverinfo, sizeof(serverinfo)); - cl.deathmatch = infofloat(cl.serverinfo, "deathmatch", 0); - cl.teamplay = infofloat(cl.serverinfo, "teamplay", 0); - cl.intermission = infofloat(cl.serverinfo, "intermission", 0); - cl.spectator = (cl.playernum>=32)||cl.players[cl.playernum].spectator; - infostring(cl.serverinfo, "status", val, sizeof(val)); - cl.standby = !strcmp(val, "standby"); - cl.countdown = !strcmp(val, "countdown"); - cl.matchstart = infofloat(cl.serverinfo, "matchstart", 0); - cls.state = ca_active; - vid.width = pvid.width; - vid.height = pvid.height; - - infostring(cl.serverinfo, "demotype", val, sizeof(val)); - cls.mvdplayback = !strcmp(val, "mvd"); - cls.demoplayback = strcmp(val, ""); - - - { - static cvar_t *pscr_viewsize = NULL; - int size; - if (!pscr_viewsize) - pscr_viewsize = pCvar_GetNVFDG("viewsize", "100", 0, NULL, NULL); + } +} + +#include "builtin_huds.h" +void EZHud_UseNquake_f(void) +{ + const char *hudstr = builtin_hud_nquake; + pCmd_AddText(hudstr, true); +} + +struct +{ + xcommand_t cmd; + const char *name; +} concmds[128]; +int numconcmds; +qboolean Cmd_AddCommand (const char *funcname, xcommand_t function) +{ + if (numconcmds < sizeof(concmds)/sizeof(concmds[0])) + { + concmds[numconcmds].cmd = function; + concmds[numconcmds].name = funcname; + numconcmds++; + pCmd_AddCommand(funcname); + return true; + } + Con_Printf("ezhud: too many console commands\n"); + return false; +}; +qintptr_t EZHud_ExecuteCommand(qintptr_t *args) +{ + char buffer[128]; + int i; + pCmd_Argv(0, buffer, sizeof(buffer)); + for (i = 0; i < numconcmds; i++) + { + if (!strcmp(buffer, concmds[i].name)) + { + concmds[i].cmd(); + return 1; + } + } + return 0; +} + +int IN_BestWeapon(void) +{ + return 0; +} + +qbool VID_VSyncIsOn(void){return false;} +double vid_vsync_lag; + + +vrect_t scr_vrect; + +qintptr_t EZHud_Tick(qintptr_t *args) +{ + static float lasttime, lasttime_min = 99999; + static int framecount; + + //realtime(ms), realtime(secs), servertime + float oldtime = cls.realtime; + cls.realtime = *(float*)&args[1]; + cls.frametime = cls.realtime - oldtime; + + cl.time = *(float*)&args[2]; + + if (cls.realtime - lasttime > 1) + { + cls.fps = framecount/(cls.realtime - lasttime); + lasttime = cls.realtime; + framecount = 0; + + if (cls.realtime - lasttime_min > 30) + { + cls.min_fps = cls.fps; + lasttime_min = cls.realtime; + } + else if (cls.min_fps > cls.fps) + cls.min_fps = cls.fps; + } + framecount++; + + return 1; +} +char *findinfo(char *info, char *findkey) +{ + int kl = strlen(findkey); + char *key, *value; + while(*info) + { + key = strchr(info, '\\'); + if (!key) + break; + key++; + value = strchr(key, '\\'); + if (!value) + break; + info = value+1; + if (!strncmp(key, findkey, kl) && key[kl] == '\\') + return info; + } + return NULL; +} +char *infostring(char *info, char *findkey, char *buffer, size_t bufsize) +{ + char *value = findinfo(info, findkey); + char *end; + if (value) + { + end = strchr(value, '\\'); + if (!end) + end = value + strlen(value); + bufsize--; + if (bufsize > (end - value)) + bufsize = (end - value); + memcpy(buffer, value, bufsize); + buffer[bufsize] = 0; + return buffer; + } + *buffer = 0; + return buffer; +} +float infofloat(char *info, char *findkey, float def) +{ + char *value = findinfo(info, findkey); + if (value) + return atof(value); + return def; +} +qintptr_t EZHud_Draw(qintptr_t *args) +{ + char serverinfo[4096]; + char val[64]; + int i; + cl.splitscreenview = args[0]; + scr_vrect.x = args[1]; + scr_vrect.y = args[2]; + scr_vrect.width = args[3]; + scr_vrect.height = args[4]; + sb_showscores = args[5] & 1; + sb_showteamscores = args[5] & 2; + + pCL_GetStats(0, cl.stats, sizeof(cl.stats)/sizeof(cl.stats[0])); + for (i = 0; i < 32; i++) + pGetPlayerInfo(i, &cl.players[i]); + + pGetLocalPlayerNumbers(cl.splitscreenview, 1, &cl.playernum, &cl.tracknum); + pGetServerInfo(cl.serverinfo, sizeof(serverinfo)); + cl.deathmatch = infofloat(cl.serverinfo, "deathmatch", 0); + cl.teamplay = infofloat(cl.serverinfo, "teamplay", 0); + cl.intermission = infofloat(cl.serverinfo, "intermission", 0); + cl.spectator = (cl.playernum>=32)||cl.players[cl.playernum].spectator; + infostring(cl.serverinfo, "status", val, sizeof(val)); + cl.standby = !strcmp(val, "standby"); + cl.countdown = !strcmp(val, "countdown"); + cl.matchstart = infofloat(cl.serverinfo, "matchstart", 0); + cls.state = ca_active; + vid.width = pvid.width; + vid.height = pvid.height; + + infostring(cl.serverinfo, "demotype", val, sizeof(val)); + cls.mvdplayback = !strcmp(val, "mvd"); + cls.demoplayback = strcmp(val, ""); + + + { + static cvar_t *pscr_viewsize = NULL; + int size; + if (!pscr_viewsize) + pscr_viewsize = pCvar_GetNVFDG("viewsize", "100", 0, NULL, NULL); size = cl.intermission ? 120 : pscr_viewsize->value; if (size >= 120) sb_lines = 0; // no status bar at all else if (size >= 110) sb_lines = 24; // no inventory else - sb_lines = 24 + 16 + 8; - } - - - //cl.faceanimtime - //cl.simvel - //cl.item_gettime - - //cls.state; - //cls.min_fps; - //cls.fps; - ////cls.realtime; - ////cls.trueframetime; - //cls.mvdplayback; - //cls.demoplayback; - - host_screenupdatecount++; - HUD_Draw(); - return true; -} - -int keydown[K_MAX]; -float cursor_x; -float cursor_y; -float mouse_x; -float mouse_y; -mpic_t *scr_cursor_icon = NULL; -qintptr_t EZHud_MenuEvent(qintptr_t *args) -{ - int eventtype = args[0]; - int param = args[1]; - mouse_x += args[2] - cursor_x; //FIXME: the hud editor should NOT need this sort of thing - mouse_y += args[3] - cursor_y; - cursor_x = args[2]; - cursor_y = args[3]; - - HUD_Editor_MouseEvent(cursor_x, cursor_y); - - switch(eventtype) - { - case 0: //draw - host_screenupdatecount++; - HUD_Draw(); - HUD_Editor_Draw(); - - mouse_x = 0; - mouse_y = 0; - break; - case 1: - if (param < K_MAX) - keydown[param] = true; - HUD_Editor_Key(param, 0, true); - break; - case 2: - if (param < K_MAX) - keydown[param] = false; - HUD_Editor_Key(param, 0, false); - break; - } - return 1; -} - -qintptr_t Plug_Init(qintptr_t *args) -{ + sb_lines = 24 + 16 + 8; + } + + + //cl.faceanimtime + //cl.simvel + //cl.item_gettime + + //cls.state; + //cls.min_fps; + //cls.fps; + ////cls.realtime; + ////cls.trueframetime; + //cls.mvdplayback; + //cls.demoplayback; + + host_screenupdatecount++; + HUD_Draw(); + return true; +} + +int keydown[K_MAX]; +float cursor_x; +float cursor_y; +float mouse_x; +float mouse_y; +mpic_t *scr_cursor_icon = NULL; +qintptr_t EZHud_MenuEvent(qintptr_t *args) +{ + int eventtype = args[0]; + int param = args[1]; + mouse_x += args[2] - cursor_x; //FIXME: the hud editor should NOT need this sort of thing + mouse_y += args[3] - cursor_y; + cursor_x = args[2]; + cursor_y = args[3]; + + HUD_Editor_MouseEvent(cursor_x, cursor_y); + + switch(eventtype) + { + case 0: //draw + host_screenupdatecount++; + HUD_Draw(); + HUD_Editor_Draw(); + + mouse_x = 0; + mouse_y = 0; + break; + case 1: + if (param < K_MAX) + keydown[param] = true; + HUD_Editor_Key(param, 0, true); + break; + case 2: + if (param < K_MAX) + keydown[param] = false; + HUD_Editor_Key(param, 0, false); + break; + } + return 1; +} + +qintptr_t Plug_Init(qintptr_t *args) +{ if (BUILTINISVALID(Cvar_GetNVFDG) && BUILTINISVALID(Draw_ImageSize) && BUILTINISVALID(GetTeamInfo) && @@ -735,6 +735,6 @@ qintptr_t Plug_Init(qintptr_t *args) HUD_Init(); HUD_Editor_Init(); return 1; - } - return false; -} + } + return false; +} diff --git a/plugins/ezhud/hud_common.c b/plugins/ezhud/hud_common.c index d9a476d36..1bf34c836 100644 --- a/plugins/ezhud/hud_common.c +++ b/plugins/ezhud/hud_common.c @@ -1,74 +1,74 @@ -/* -Copyright (C) 2011 azazello and ezQuake team - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -// -// common HUD elements -// like clock etc.. -// - -#include "../plugin.h" -/* -#include "common_draw.h" -#include "mp3_player.h" -#include -#include "image.h" -#include "stats_grid.h" -#include "vx_stuff.h" -#include "gl_model.h" -#include "gl_local.h" -#include "tr_types.h" -#include "rulesets.h" -#include "utils.h" -#include "sbar.h" -#include "Ctrl.h" -#include "console.h" -#include "teamplay.h" -#include "mvd_utils.h" -*/ -#include "ezquakeisms.h" -#include "hud.h" - -//#define WITH_PNG - -#define draw_disc draw_disc2 - -static mpic_t *sb_ammo[4]; -static mpic_t *sb_faces[7][2]; -static mpic_t *sb_face_invis; -static mpic_t *sb_face_quad; -static mpic_t *sb_face_invuln; -static mpic_t *sb_face_invis_invuln; -static mpic_t *sb_weapons[7][8]; -static mpic_t *sb_items[6]; -static mpic_t *sb_sigil[4]; - mpic_t *sb_nums[2][11]; -static mpic_t *sb_ibar; -static mpic_t *sb_armor[3]; - mpic_t *sb_colon; -static mpic_t *sb_slash; -static mpic_t *sb_disc; -static mpic_t *sb_net; - -void HUD_InitSbarImages(void) -{ - int i; - sb_disc = Draw_CacheWadPic("disc"); - sb_net = Draw_CacheWadPic("net"); - +/* +Copyright (C) 2011 azazello and ezQuake team + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +// +// common HUD elements +// like clock etc.. +// + +#include "../plugin.h" +/* +#include "common_draw.h" +#include "mp3_player.h" +#include +#include "image.h" +#include "stats_grid.h" +#include "vx_stuff.h" +#include "gl_model.h" +#include "gl_local.h" +#include "tr_types.h" +#include "rulesets.h" +#include "utils.h" +#include "sbar.h" +#include "Ctrl.h" +#include "console.h" +#include "teamplay.h" +#include "mvd_utils.h" +*/ +#include "ezquakeisms.h" +#include "hud.h" + +//#define WITH_PNG + +#define draw_disc draw_disc2 + +static mpic_t *sb_ammo[4]; +static mpic_t *sb_faces[7][2]; +static mpic_t *sb_face_invis; +static mpic_t *sb_face_quad; +static mpic_t *sb_face_invuln; +static mpic_t *sb_face_invis_invuln; +static mpic_t *sb_weapons[7][8]; +static mpic_t *sb_items[6]; +static mpic_t *sb_sigil[4]; + mpic_t *sb_nums[2][11]; +static mpic_t *sb_ibar; +static mpic_t *sb_armor[3]; + mpic_t *sb_colon; +static mpic_t *sb_slash; +static mpic_t *sb_disc; +static mpic_t *sb_net; + +void HUD_InitSbarImages(void) +{ + int i; + sb_disc = Draw_CacheWadPic("disc"); + sb_net = Draw_CacheWadPic("net"); + for (i = 0; i < 10; i++) { sb_nums[0][i] = Draw_CacheWadPic (va("num_%i",i)); sb_nums[1][i] = Draw_CacheWadPic (va("anum_%i",i)); @@ -78,8 +78,8 @@ void HUD_InitSbarImages(void) sb_nums[1][10] = Draw_CacheWadPic ("anum_minus"); sb_colon = Draw_CacheWadPic ("num_colon"); - sb_slash = Draw_CacheWadPic ("num_slash"); - + sb_slash = Draw_CacheWadPic ("num_slash"); + sb_weapons[0][0] = Draw_CacheWadPic ("inv_shotgun"); sb_weapons[0][1] = Draw_CacheWadPic ("inv_sshotgun"); sb_weapons[0][2] = Draw_CacheWadPic ("inv_nailgun"); @@ -105,8 +105,8 @@ void HUD_InitSbarImages(void) sb_weapons[2 + i][4] = Draw_CacheWadPic (va("inva%i_rlaunch", i + 1)); sb_weapons[2 + i][5] = Draw_CacheWadPic (va("inva%i_srlaunch", i + 1)); sb_weapons[2 + i][6] = Draw_CacheWadPic (va("inva%i_lightng", i + 1)); - } - + } + sb_ammo[0] = Draw_CacheWadPic ("sb_shells"); sb_ammo[1] = Draw_CacheWadPic ("sb_nails"); sb_ammo[2] = Draw_CacheWadPic ("sb_rocket"); @@ -121,13 +121,13 @@ void HUD_InitSbarImages(void) sb_items[2] = Draw_CacheWadPic ("sb_invis"); sb_items[3] = Draw_CacheWadPic ("sb_invuln"); sb_items[4] = Draw_CacheWadPic ("sb_suit"); - sb_items[5] = Draw_CacheWadPic ("sb_quad"); - + sb_items[5] = Draw_CacheWadPic ("sb_quad"); + sb_sigil[0] = Draw_CacheWadPic ("sb_sigil1"); sb_sigil[1] = Draw_CacheWadPic ("sb_sigil2"); sb_sigil[2] = Draw_CacheWadPic ("sb_sigil3"); - sb_sigil[3] = Draw_CacheWadPic ("sb_sigil4"); - + sb_sigil[3] = Draw_CacheWadPic ("sb_sigil4"); + sb_faces[4][0] = Draw_CacheWadPic ("face1"); sb_faces[4][1] = Draw_CacheWadPic ("face_p1"); sb_faces[3][0] = Draw_CacheWadPic ("face2"); @@ -142,790 +142,790 @@ void HUD_InitSbarImages(void) sb_face_invis = Draw_CacheWadPic ("face_invis"); sb_face_invuln = Draw_CacheWadPic ("face_invul2"); sb_face_invis_invuln = Draw_CacheWadPic ("face_inv2"); - sb_face_quad = Draw_CacheWadPic ("face_quad"); - - sb_ibar = Draw_CacheWadPic("ibar"); -} - -vmnetinfo_t *GetNetworkInfo(void) -{ - static vmnetinfo_t ni; - static int uc; - if (uc != host_screenupdatecount && BUILTINISVALID(GetNetworkInfo)) - { - uc = host_screenupdatecount; - pGetNetworkInfo(&ni, sizeof(ni)); - } - return ∋ -} - - -#ifndef STAT_MINUS -#define STAT_MINUS 10 -#endif - -hud_t *hud_netgraph = NULL; - -// ---------------- -// HUD planning -// - -struct -{ - // this is temporary storage place for some of user's settings - // hud_* values will be dumped into config file - int old_multiview; - int old_fov; - int old_newhud; - - qbool active; -} autohud; - -void OnAutoHudChange(cvar_t *var, char *value, qbool *cancel); -qbool autohud_loaded = false; -cvar_t *hud_planmode; -cvar_t *mvd_autohud; -cvar_t *hud_digits_trim; -cvar_t *cl_multiview; - -int hud_stats[MAX_CL_STATS]; - -cvar_t *cl_weaponpreselect; -extern int IN_BestWeapon(void); -extern void DumpHUD(char *); -extern char *Macro_MatchType(void); - -int HUD_Stats(int stat_num) -{ - if (hud_planmode->value) - return hud_stats[stat_num]; - else - return cl.stats[stat_num]; -} - -// ---------------- -// HUD low levels -// - -cvar_t *hud_tp_need; - -/* tp need levels -int TP_IsHealthLow(void); -int TP_IsArmorLow(void); -int TP_IsAmmoLow(int weapon); */ -cvar_t *tp_need_health, *tp_need_ra, *tp_need_ya, *tp_need_ga, - *tp_weapon_order, *tp_need_weapon, *tp_need_shells, - *tp_need_nails, *tp_need_rockets, *tp_need_cells; - -int State_AmmoNumForWeapon(int weapon) -{ // returns ammo number (shells = 1, nails = 2, rox = 3, cells = 4) for given weapon - switch (weapon) { - case 2: case 3: return 1; - case 4: case 5: return 2; - case 6: case 7: return 3; - case 8: return 4; - default: return 0; - } -} - -int State_AmmoForWeapon(int weapon) -{ // returns ammo amount for given weapon - int ammon = State_AmmoNumForWeapon(weapon); - - if (ammon) - return cl.stats[STAT_SHELLS + ammon - 1]; - else - return 0; -} - -int TP_IsHealthLow(void) -{ - return cl.stats[STAT_HEALTH] <= tp_need_health->value; -} - -int TP_IsArmorLow(void) -{ - if ((cl.stats[STAT_ARMOR] > 0) && (cl.stats[STAT_ITEMS] & IT_ARMOR3)) - return cl.stats[STAT_ARMOR] <= tp_need_ra->value; - if ((cl.stats[STAT_ARMOR] > 0) && (cl.stats[STAT_ITEMS] & IT_ARMOR2)) - return cl.stats[STAT_ARMOR] <= tp_need_ya->value; - if ((cl.stats[STAT_ARMOR] > 0) && (cl.stats[STAT_ITEMS] & IT_ARMOR1)) - return cl.stats[STAT_ARMOR] <= tp_need_ga->value; - return 1; -} - -int TP_IsWeaponLow(void) -{ - char *s = tp_weapon_order->string; - while (*s && *s != tp_need_weapon->string[0]) - { - if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN << (*s-'0'-2))) - return false; - s++; - } - return true; -} - -int TP_IsAmmoLow(int weapon) -{ - int ammo = State_AmmoForWeapon(weapon); - switch (weapon) - { - case 2: - case 3: return ammo <= tp_need_shells->value; - case 4: - case 5: return ammo <= tp_need_nails->value; - case 6: - case 7: return ammo <= tp_need_rockets->value; - case 8: return ammo <= tp_need_cells->value; - default: return 0; - } -} - -int TP_TeamFortressEngineerSpanner(void) -{ -#ifdef HAXX - char *player_skin=Info_ValueForKey(cl.players[cl.playernum].userinfo,"skin"); - char *model_name=cl.model_precache[cl.viewent.current.modelindex]->name; - if (cl.teamfortress && player_skin - && (strcasecmp(player_skin, "tf_eng") == 0) - && model_name - && (strcasecmp(model_name, "progs/v_span.mdl") == 0)) - { - return 1; - } - else -#endif - { - return 0; - } -} - -qbool HUD_HealthLow(void) -{ - if (hud_tp_need->value) - return TP_IsHealthLow(); - else - return HUD_Stats(STAT_HEALTH) <= 25; -} - -qbool HUD_ArmorLow(void) -{ - if (hud_tp_need->value) - return (TP_IsArmorLow()); - else - return (HUD_Stats(STAT_ARMOR) <= 25); -} - -qbool HUD_AmmoLow(void) -{ - if (hud_tp_need->value) - { - if (HUD_Stats(STAT_ITEMS) & IT_SHELLS) - return TP_IsAmmoLow(2); - else if (HUD_Stats(STAT_ITEMS) & IT_NAILS) - return TP_IsAmmoLow(4); - else if (HUD_Stats(STAT_ITEMS) & IT_ROCKETS) - return TP_IsAmmoLow(6); - else if (HUD_Stats(STAT_ITEMS) & IT_CELLS) - return TP_IsAmmoLow(8); - return false; - } - else - return (HUD_Stats(STAT_AMMO) <= 10); -} - -int HUD_AmmoLowByWeapon(int weapon) -{ - if (hud_tp_need->value) - return TP_IsAmmoLow(weapon); - else - { - int a; - switch (weapon) - { - case 2: - case 3: - a = STAT_SHELLS; break; - case 4: - case 5: - a = STAT_NAILS; break; - case 6: - case 7: - a = STAT_ROCKETS; break; - case 8: - a = STAT_CELLS; break; - default: - return false; - } - return (HUD_Stats(a) <= 10); - } -} - -// ---------------- -// DrawFPS -void SCR_HUD_DrawFPS(hud_t *hud) -{ - int x, y; - char st[128]; - - static cvar_t - *hud_fps_show_min = NULL, - *hud_fps_style, - *hud_fps_title, - *hud_fps_drop; - - if (hud_fps_show_min == NULL) // first time called - { - hud_fps_show_min = HUD_FindVar(hud, "show_min"); - hud_fps_style = HUD_FindVar(hud, "style"); - hud_fps_title = HUD_FindVar(hud, "title"); - hud_fps_drop = HUD_FindVar(hud, "drop"); - } - - if (hud_fps_show_min->value) - snprintf (st, sizeof (st), "%3d^Ue00f%3d", (int)(cls.min_fps + 0.25), (int) (cls.fps + 0.25)); - else - snprintf (st, sizeof (st), "%3d", (int)(cls.fps + 0.25)); - - if (hud_fps_title->value) - strlcat (st, " fps", sizeof (st)); - - if (HUD_PrepareDraw(hud, strlen(st)*8, 8, &x, &y)) - { - vmnetinfo_t *netinfo = GetNetworkInfo(); - if (netinfo->capturing == 2) //don't show fps if its locked to something anyway. - return; - - if ((hud_fps_style->value) == 1) - Draw_Alt_String(x, y, st); - else if ((hud_fps_style->value) == 2) { - if ((hud_fps_drop->value) >= cls.fps) // if fps is less than a user-set value, then show it - Draw_String(x, y, st); - } - else if ((hud_fps_style->value) == 3) { - if ((hud_fps_drop->value) >= cls.fps) // if fps is less than a user-set value, then show it - Draw_Alt_String(x, y, st); - } - else // hud_fps_style is anything other than 1,2,3 - Draw_String(x, y, st); - } -} - -void SCR_HUD_DrawVidLag(hud_t *hud) -{ - int x, y; - char st[128]; - static cvar_t *hud_vidlag_style = NULL; - - vmnetinfo_t *netinfo = GetNetworkInfo(); - static double old_lag; - - if (netinfo->vlatency) - { - // take the average of last two values, otherwise it - // changes very fast and is hard to read - double current, avg; - current = netinfo->vlatency; - avg = (current + old_lag) * 0.5; - old_lag = current; - snprintf (st, sizeof (st), "%2.1f", avg * 1000); - } - else - strcpy(st, "?"); - - if (hud_vidlag_style == NULL) // first time called - { - hud_vidlag_style = HUD_FindVar(hud, "style"); - } - - strlcat (st, " ms", sizeof (st)); - - if (HUD_PrepareDraw(hud, strlen(st)*8, 8, &x, &y)) - { - if (hud_vidlag_style->value) - { - Draw_Alt_String(x, y, st); - } - else - { - Draw_String(x, y, st); - } - } -} - -void SCR_HUD_DrawMouserate(hud_t *hud) -{ - int x, y; - static int lastresult = 0; - int newresult; - char st[80]; // string buffer - double t; // current time - static double lastframetime; // last refresh - vmnetinfo_t *netinfo = GetNetworkInfo(); - - static cvar_t *hud_mouserate_title = NULL, - *hud_mouserate_interval, - *hud_mouserate_style; - - if (hud_mouserate_title == NULL) // first time called - { - hud_mouserate_style = HUD_FindVar(hud, "style"); - hud_mouserate_title = HUD_FindVar(hud, "title"); - hud_mouserate_interval = HUD_FindVar(hud, "interval"); - } - - t = cls.realtime; - if ((t - lastframetime) >= hud_mouserate_interval->value) { - newresult = netinfo->mrate; - lastframetime = t; - } else - newresult = 0; - - if (newresult > 0) { - snprintf(st, sizeof(st), "%4d", newresult); - lastresult = newresult; - } else if (!newresult) - snprintf(st, sizeof(st), "%4d", lastresult); - else - snprintf(st, sizeof(st), "n/a"); - - if (hud_mouserate_title->value) - strlcat(st, " Hz", sizeof (st)); - - if (HUD_PrepareDraw(hud, strlen(st)*8, 8, &x, &y)) - { - if (hud_mouserate_style->value) - { - Draw_Alt_String(x, y, st); - } - else - { - Draw_String(x, y, st); - } - } -} - -#define MAX_TRACKING_STRING 512 - -void SCR_HUD_DrawTracking(hud_t *hud) -{ -#ifdef HAXX - static char tracked_strings[MV_VIEWS][MAX_TRACKING_STRING]; - static int tracked[MV_VIEWS] = {-1, -1, -1, -1}; - int view = 0; -#endif - int views = 1; - int x = 0, y = 0, width = 0, height = 0; - char track_string[MAX_TRACKING_STRING]; - - static cvar_t *hud_tracking_format = NULL, - *hud_tracking_scale; - - if (!hud_tracking_format) { - hud_tracking_format = HUD_FindVar(hud, "format"); - hud_tracking_scale = HUD_FindVar(hud, "scale"); - } - - strlcpy(track_string, hud_tracking_format->string, sizeof(track_string)); - -#ifdef HAXX - if(cls.mvdplayback && cl_multiview->value && CURRVIEW > 0) - { - // - // Multiview. - // - - views = cl_multiview->value; - - // Save the currently tracked player for the slot being drawn - // (this will be done for all views and we'll get a complete - // list over who we're tracking). - tracked[CURRVIEW - 1] = spec_track; - - for(view = 0; view < MV_VIEWS; view++) - { - int new_width = 0; - - // We haven't found who we're tracking in this view. - if(tracked[view] < 0) - { - continue; - } - - strlcpy(tracked_strings[view], hud_tracking_format->string, sizeof(tracked_strings[view])); - - Replace_In_String(tracked_strings[view], sizeof(tracked_strings[view]), '%', 3, - "v", cl_multiview->value ? va("%d", view+1) : "", // Replace %v with the current view (in multiview) - "n", cl.players[tracked[view]].name, // Replace %n with player name. - "t", cl.teamplay ? cl.players[tracked[view]].team : ""); // Replace %t with player team if teamplay is on. - - // Set the width. - new_width = 8 * strlen_color(tracked_strings[view]); - width = (new_width > width) ? new_width : width; - } - } - else -#endif - { - // Normal. - Replace_In_String(track_string, sizeof(track_string), '%', 2, - "n", cl.players[spec_track].name, // Replace %n with player name. - "t", cl.teamplay ? cl.players[spec_track].team : ""); // Replace %t with player team if teamplay is on. - width = 8 * strlen_color(track_string); - } - - height = 8 * views; - height *= hud_tracking_scale->value; - width *= hud_tracking_scale->value; - - if (!(cl.spectator && autocam == CAM_TRACK)) - height = 0; - - if(!HUD_PrepareDraw(hud, width, height, &x, &y)) - { - return; - } - - if (height == 0) - return; - -#ifdef HAXX - if (cls.mvdplayback && cl_multiview->value && autocam == CAM_TRACK) - { - // Multiview - for(view = 0; view < MV_VIEWS; view++) - { - if(tracked[view] < 0 || CURRVIEW <= 0) - { - continue; - } - Draw_SString(x, y + view*8, tracked_strings[view], hud_tracking_scale->value); - } - } - else -#endif - if (cl.spectator && autocam == CAM_TRACK && !cl_multiview->value) - { - // Normal - Draw_SString(x, y, track_string, hud_tracking_scale->value); - } -} - -#ifdef HAXX -void R_MQW_NetGraph(int outgoing_sequence, int incoming_sequence, int *packet_latency, - int lost, int minping, int avgping, int maxping, int devping, - int posx, int posy, int width, int height, int revx, int revy); -// ---------------- -// Netgraph -static void SCR_HUD_Netgraph(hud_t *hud) -{ - static cvar_t - *par_width = NULL, *par_height, - *par_swap_x, *par_swap_y, - *par_ploss; - - if (par_width == NULL) // first time - { - par_width = HUD_FindVar(hud, "width"); - par_height = HUD_FindVar(hud, "height"); - par_swap_x = HUD_FindVar(hud, "swap_x"); - par_swap_y = HUD_FindVar(hud, "swap_y"); - par_ploss = HUD_FindVar(hud, "ploss"); - } - - R_MQW_NetGraph(cls.netchan.outgoing_sequence, cls.netchan.incoming_sequence, - packet_latency, par_ploss->value ? CL_CalcNet() : -1, -1, -1, -1, -1, -1, - -1, (int)par_width->value, (int)par_height->value, - (int)par_swap_x->value, (int)par_swap_y->value); -} -#endif - -//--------------------- -// -// draw HUD ping -// -static void SCR_HUD_DrawPing(hud_t *hud) -{ - double t; - static double last_calculated; - static int ping_avg, pl, ping_min, ping_max; - static float ping_dev; - - int width, height; - int x, y; - char buf[512]; - vmnetinfo_t *netinfo = GetNetworkInfo(); - - static cvar_t - *hud_ping_period = NULL, - *hud_ping_show_pl, - *hud_ping_show_dev, - *hud_ping_show_min, - *hud_ping_show_max, - *hud_ping_style, - *hud_ping_blink; - - if (hud_ping_period == NULL) // first time - { - hud_ping_period = HUD_FindVar(hud, "period"); - hud_ping_show_pl = HUD_FindVar(hud, "show_pl"); - hud_ping_show_dev = HUD_FindVar(hud, "show_dev"); - hud_ping_show_min = HUD_FindVar(hud, "show_min"); - hud_ping_show_max = HUD_FindVar(hud, "show_max"); - hud_ping_style = HUD_FindVar(hud, "style"); - hud_ping_blink = HUD_FindVar(hud, "blink"); - } - - t = cls.realtime; - if (t - last_calculated > hud_ping_period->value) - { -// float period; - - last_calculated = t; - -// period = max(hud_ping_period->value, 0); - - ping_avg = (int)(netinfo->ping.s_avg*1000 + 0.5); - ping_min = (int)(netinfo->ping.s_mn*1000 + 0.5); - ping_max = (int)(netinfo->ping.s_mx*1000 + 0.5); - ping_dev = netinfo->ping.ms_stddev; - pl = netinfo->loss.dropped*100; - - clamp(ping_avg, 0, 999); - clamp(ping_min, 0, 999); - clamp(ping_max, 0, 999); - clamp(ping_dev, 0, 99.9); - clamp(pl, 0, 100); - } - - buf[0] = 0; - - // blink - if (hud_ping_blink->value) // add dot - strlcat (buf, (last_calculated + hud_ping_period->value/2 > cls.realtime) ? "^Ue08f" : " ", sizeof (buf)); - - // min ping - if (hud_ping_show_min->value) - strlcat (buf, va("%d^Ue00f", ping_min), sizeof (buf)); - - // ping - strlcat (buf, va("%d", ping_avg), sizeof (buf)); - - // max ping - if (hud_ping_show_max->value) - strlcat (buf, va("^Ue00f%d", ping_max), sizeof (buf)); - - // unit - strlcat (buf, " ms", sizeof (buf)); - - // standard deviation - if (hud_ping_show_dev->value) - strlcat (buf, va(" (%.1f)", ping_dev), sizeof (buf)); - - // pl - if (hud_ping_show_pl->value) - strlcat (buf, va(" ^Ue08f %d%%", pl), sizeof (buf)); - - // display that on screen - width = strlen(buf) * 8; - height = 8; - - if (HUD_PrepareDraw(hud, width, height, &x, &y)) - { - if (hud_ping_style->value) - { - Draw_Alt_String(x, y, buf); - } - else - { - Draw_String(x, y, buf); - } - } -} - -static const char *SCR_HUD_ClockFormat(int format) -{ - switch (format) { - case 1: return "%I:%M %p"; - case 2: return "%I:%M:%S %p"; - case 3: return "%H:%M"; - default: case 0: return "%H:%M:%S"; - } -} - -//--------------------- -// -// draw HUD clock -// -void SCR_HUD_DrawClock(hud_t *hud) -{ - int width, height; - int x, y; - const char *t; - - static cvar_t - *hud_clock_big = NULL, - *hud_clock_style, - *hud_clock_blink, - *hud_clock_scale, - *hud_clock_format; - - if (hud_clock_big == NULL) // first time - { - hud_clock_big = HUD_FindVar(hud, "big"); - hud_clock_style = HUD_FindVar(hud, "style"); - hud_clock_blink = HUD_FindVar(hud, "blink"); - hud_clock_scale = HUD_FindVar(hud, "scale"); - hud_clock_format= HUD_FindVar(hud, "format"); - } - - t = SCR_GetTimeString(TIMETYPE_CLOCK, SCR_HUD_ClockFormat(hud_clock_format->ival)); - width = SCR_GetClockStringWidth(t, hud_clock_big->ival, hud_clock_scale->value); - height = SCR_GetClockStringHeight(hud_clock_big->ival, hud_clock_scale->value); - - if (HUD_PrepareDraw(hud, width, height, &x, &y)) - { - if (hud_clock_big->value) - SCR_DrawBigClock(x, y, hud_clock_style->value, hud_clock_blink->value, hud_clock_scale->value, t); - else - SCR_DrawSmallClock(x, y, hud_clock_style->value, hud_clock_blink->value, hud_clock_scale->value, t); - } -} - -//--------------------- -// -// draw HUD notify -// - -static void SCR_HUD_DrawNotify(hud_t* hud) -{ - static cvar_t* hud_notify_rows = NULL; - static cvar_t* hud_notify_scale; - static cvar_t* hud_notify_time; - static cvar_t* hud_notify_cols; - - int x; - int y; - int width; - int height; - - if (hud_notify_rows == NULL) // First time. - { - hud_notify_rows = HUD_FindVar(hud, "rows"); - hud_notify_cols = HUD_FindVar(hud, "cols"); - hud_notify_scale = HUD_FindVar(hud, "scale"); - hud_notify_time = HUD_FindVar(hud, "time"); - } - - height = hud_notify_rows->ival * 8 * hud_notify_scale->value; - width = 8 * hud_notify_cols->ival * hud_notify_scale->value; - - if (HUD_PrepareDraw(hud, width, height, &x, &y)) - { - pCvar_SetFloat("con_notify_x", (float)x / vid.width); - pCvar_SetFloat("con_notify_y", (float)y / vid.height); - pCvar_SetFloat("con_notify_w", (float)width / vid.width); - pCvar_SetFloat("con_numnotifylines",(int)(height/(8*hud_notify_scale->value) + 0.01)); - pCvar_SetFloat("con_notifytime", (float)hud_notify_time->ival); - pCvar_SetFloat("con_textsize", 8.0 * hud_notify_scale->value); -// SCR_DrawNotify(x, y, hud_notify_scale->value, hud_notify_time->ival, hud_notify_rows->ival, hud_notify_cols->ival); - } -} - -//--------------------- -// -// draw HUD gameclock -// -void SCR_HUD_DrawGameClock(hud_t *hud) -{ - int width, height; - int x, y; - int timetype; - const char *t; - - static cvar_t - *hud_gameclock_big = NULL, - *hud_gameclock_style, - *hud_gameclock_blink, - *hud_gameclock_countdown, - *hud_gameclock_scale -// *hud_gameclock_offset - ; - - if (hud_gameclock_big == NULL) // first time - { - hud_gameclock_big = HUD_FindVar(hud, "big"); - hud_gameclock_style = HUD_FindVar(hud, "style"); - hud_gameclock_blink = HUD_FindVar(hud, "blink"); - hud_gameclock_countdown = HUD_FindVar(hud, "countdown"); - hud_gameclock_scale = HUD_FindVar(hud, "scale"); -// hud_gameclock_offset = HUD_FindVar(hud, "offset"); -// gameclockoffset = &hud_gameclock_offset->ival; - } - - timetype = (hud_gameclock_countdown->value) ? TIMETYPE_GAMECLOCKINV : TIMETYPE_GAMECLOCK; - t = SCR_GetTimeString(timetype, NULL); - width = SCR_GetClockStringWidth(t, hud_gameclock_big->ival, hud_gameclock_scale->value); - height = SCR_GetClockStringHeight(hud_gameclock_big->ival, hud_gameclock_scale->value); - - if (HUD_PrepareDraw(hud, width, height, &x, &y)) - { - if (hud_gameclock_big->value) - SCR_DrawBigClock(x, y, hud_gameclock_style->value, hud_gameclock_blink->value, hud_gameclock_scale->value, t); - else - SCR_DrawSmallClock(x, y, hud_gameclock_style->value, hud_gameclock_blink->value, hud_gameclock_scale->value, t); - } -} - -//--------------------- -// -// draw HUD democlock -// -void SCR_HUD_DrawDemoClock(hud_t *hud) -{ - int width = 0; - int height = 0; - int x = 0; - int y = 0; - const char *t; - static cvar_t - *hud_democlock_big = NULL, - *hud_democlock_style, - *hud_democlock_blink, - *hud_democlock_scale; - - if (!cls.demoplayback || cls.mvdplayback == 2) - { - HUD_PrepareDraw(hud, width, height, &x, &y); - return; - } - - if (hud_democlock_big == NULL) // first time - { - hud_democlock_big = HUD_FindVar(hud, "big"); - hud_democlock_style = HUD_FindVar(hud, "style"); - hud_democlock_blink = HUD_FindVar(hud, "blink"); - hud_democlock_scale = HUD_FindVar(hud, "scale"); - } - - t = SCR_GetTimeString(TIMETYPE_DEMOCLOCK, NULL); - width = SCR_GetClockStringWidth(t, hud_democlock_big->ival, hud_democlock_scale->value); - height = SCR_GetClockStringHeight(hud_democlock_big->ival, hud_democlock_scale->value); - - if (HUD_PrepareDraw(hud, width, height, &x, &y)) - { - if (hud_democlock_big->value) - SCR_DrawBigClock(x, y, hud_democlock_style->value, hud_democlock_blink->value, hud_democlock_scale->value, t); - else - SCR_DrawSmallClock(x, y, hud_democlock_style->value, hud_democlock_blink->value, hud_democlock_scale->value, t); - } -} - -//--------------------- -// -// network statistics -// + sb_face_quad = Draw_CacheWadPic ("face_quad"); + + sb_ibar = Draw_CacheWadPic("ibar"); +} + +vmnetinfo_t *GetNetworkInfo(void) +{ + static vmnetinfo_t ni; + static int uc; + if (uc != host_screenupdatecount && BUILTINISVALID(GetNetworkInfo)) + { + uc = host_screenupdatecount; + pGetNetworkInfo(&ni, sizeof(ni)); + } + return ∋ +} + + +#ifndef STAT_MINUS +#define STAT_MINUS 10 +#endif + +hud_t *hud_netgraph = NULL; + +// ---------------- +// HUD planning +// + +struct +{ + // this is temporary storage place for some of user's settings + // hud_* values will be dumped into config file + int old_multiview; + int old_fov; + int old_newhud; + + qbool active; +} autohud; + +void OnAutoHudChange(cvar_t *var, char *value, qbool *cancel); +qbool autohud_loaded = false; +cvar_t *hud_planmode; +cvar_t *mvd_autohud; +cvar_t *hud_digits_trim; +cvar_t *cl_multiview; + +int hud_stats[MAX_CL_STATS]; + +cvar_t *cl_weaponpreselect; +extern int IN_BestWeapon(void); +extern void DumpHUD(char *); +extern char *Macro_MatchType(void); + +int HUD_Stats(int stat_num) +{ + if (hud_planmode->value) + return hud_stats[stat_num]; + else + return cl.stats[stat_num]; +} + +// ---------------- +// HUD low levels +// + +cvar_t *hud_tp_need; + +/* tp need levels +int TP_IsHealthLow(void); +int TP_IsArmorLow(void); +int TP_IsAmmoLow(int weapon); */ +cvar_t *tp_need_health, *tp_need_ra, *tp_need_ya, *tp_need_ga, + *tp_weapon_order, *tp_need_weapon, *tp_need_shells, + *tp_need_nails, *tp_need_rockets, *tp_need_cells; + +int State_AmmoNumForWeapon(int weapon) +{ // returns ammo number (shells = 1, nails = 2, rox = 3, cells = 4) for given weapon + switch (weapon) { + case 2: case 3: return 1; + case 4: case 5: return 2; + case 6: case 7: return 3; + case 8: return 4; + default: return 0; + } +} + +int State_AmmoForWeapon(int weapon) +{ // returns ammo amount for given weapon + int ammon = State_AmmoNumForWeapon(weapon); + + if (ammon) + return cl.stats[STAT_SHELLS + ammon - 1]; + else + return 0; +} + +int TP_IsHealthLow(void) +{ + return cl.stats[STAT_HEALTH] <= tp_need_health->value; +} + +int TP_IsArmorLow(void) +{ + if ((cl.stats[STAT_ARMOR] > 0) && (cl.stats[STAT_ITEMS] & IT_ARMOR3)) + return cl.stats[STAT_ARMOR] <= tp_need_ra->value; + if ((cl.stats[STAT_ARMOR] > 0) && (cl.stats[STAT_ITEMS] & IT_ARMOR2)) + return cl.stats[STAT_ARMOR] <= tp_need_ya->value; + if ((cl.stats[STAT_ARMOR] > 0) && (cl.stats[STAT_ITEMS] & IT_ARMOR1)) + return cl.stats[STAT_ARMOR] <= tp_need_ga->value; + return 1; +} + +int TP_IsWeaponLow(void) +{ + char *s = tp_weapon_order->string; + while (*s && *s != tp_need_weapon->string[0]) + { + if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN << (*s-'0'-2))) + return false; + s++; + } + return true; +} + +int TP_IsAmmoLow(int weapon) +{ + int ammo = State_AmmoForWeapon(weapon); + switch (weapon) + { + case 2: + case 3: return ammo <= tp_need_shells->value; + case 4: + case 5: return ammo <= tp_need_nails->value; + case 6: + case 7: return ammo <= tp_need_rockets->value; + case 8: return ammo <= tp_need_cells->value; + default: return 0; + } +} + +int TP_TeamFortressEngineerSpanner(void) +{ +#ifdef HAXX + char *player_skin=Info_ValueForKey(cl.players[cl.playernum].userinfo,"skin"); + char *model_name=cl.model_precache[cl.viewent.current.modelindex]->name; + if (cl.teamfortress && player_skin + && (strcasecmp(player_skin, "tf_eng") == 0) + && model_name + && (strcasecmp(model_name, "progs/v_span.mdl") == 0)) + { + return 1; + } + else +#endif + { + return 0; + } +} + +qbool HUD_HealthLow(void) +{ + if (hud_tp_need->value) + return TP_IsHealthLow(); + else + return HUD_Stats(STAT_HEALTH) <= 25; +} + +qbool HUD_ArmorLow(void) +{ + if (hud_tp_need->value) + return (TP_IsArmorLow()); + else + return (HUD_Stats(STAT_ARMOR) <= 25); +} + +qbool HUD_AmmoLow(void) +{ + if (hud_tp_need->value) + { + if (HUD_Stats(STAT_ITEMS) & IT_SHELLS) + return TP_IsAmmoLow(2); + else if (HUD_Stats(STAT_ITEMS) & IT_NAILS) + return TP_IsAmmoLow(4); + else if (HUD_Stats(STAT_ITEMS) & IT_ROCKETS) + return TP_IsAmmoLow(6); + else if (HUD_Stats(STAT_ITEMS) & IT_CELLS) + return TP_IsAmmoLow(8); + return false; + } + else + return (HUD_Stats(STAT_AMMO) <= 10); +} + +int HUD_AmmoLowByWeapon(int weapon) +{ + if (hud_tp_need->value) + return TP_IsAmmoLow(weapon); + else + { + int a; + switch (weapon) + { + case 2: + case 3: + a = STAT_SHELLS; break; + case 4: + case 5: + a = STAT_NAILS; break; + case 6: + case 7: + a = STAT_ROCKETS; break; + case 8: + a = STAT_CELLS; break; + default: + return false; + } + return (HUD_Stats(a) <= 10); + } +} + +// ---------------- +// DrawFPS +void SCR_HUD_DrawFPS(hud_t *hud) +{ + int x, y; + char st[128]; + + static cvar_t + *hud_fps_show_min = NULL, + *hud_fps_style, + *hud_fps_title, + *hud_fps_drop; + + if (hud_fps_show_min == NULL) // first time called + { + hud_fps_show_min = HUD_FindVar(hud, "show_min"); + hud_fps_style = HUD_FindVar(hud, "style"); + hud_fps_title = HUD_FindVar(hud, "title"); + hud_fps_drop = HUD_FindVar(hud, "drop"); + } + + if (hud_fps_show_min->value) + snprintf (st, sizeof (st), "%3d^Ue00f%3d", (int)(cls.min_fps + 0.25), (int) (cls.fps + 0.25)); + else + snprintf (st, sizeof (st), "%3d", (int)(cls.fps + 0.25)); + + if (hud_fps_title->value) + strlcat (st, " fps", sizeof (st)); + + if (HUD_PrepareDraw(hud, strlen(st)*8, 8, &x, &y)) + { + vmnetinfo_t *netinfo = GetNetworkInfo(); + if (netinfo->capturing == 2) //don't show fps if its locked to something anyway. + return; + + if ((hud_fps_style->value) == 1) + Draw_Alt_String(x, y, st); + else if ((hud_fps_style->value) == 2) { + if ((hud_fps_drop->value) >= cls.fps) // if fps is less than a user-set value, then show it + Draw_String(x, y, st); + } + else if ((hud_fps_style->value) == 3) { + if ((hud_fps_drop->value) >= cls.fps) // if fps is less than a user-set value, then show it + Draw_Alt_String(x, y, st); + } + else // hud_fps_style is anything other than 1,2,3 + Draw_String(x, y, st); + } +} + +void SCR_HUD_DrawVidLag(hud_t *hud) +{ + int x, y; + char st[128]; + static cvar_t *hud_vidlag_style = NULL; + + vmnetinfo_t *netinfo = GetNetworkInfo(); + static double old_lag; + + if (netinfo->vlatency) + { + // take the average of last two values, otherwise it + // changes very fast and is hard to read + double current, avg; + current = netinfo->vlatency; + avg = (current + old_lag) * 0.5; + old_lag = current; + snprintf (st, sizeof (st), "%2.1f", avg * 1000); + } + else + strcpy(st, "?"); + + if (hud_vidlag_style == NULL) // first time called + { + hud_vidlag_style = HUD_FindVar(hud, "style"); + } + + strlcat (st, " ms", sizeof (st)); + + if (HUD_PrepareDraw(hud, strlen(st)*8, 8, &x, &y)) + { + if (hud_vidlag_style->value) + { + Draw_Alt_String(x, y, st); + } + else + { + Draw_String(x, y, st); + } + } +} + +void SCR_HUD_DrawMouserate(hud_t *hud) +{ + int x, y; + static int lastresult = 0; + int newresult; + char st[80]; // string buffer + double t; // current time + static double lastframetime; // last refresh + vmnetinfo_t *netinfo = GetNetworkInfo(); + + static cvar_t *hud_mouserate_title = NULL, + *hud_mouserate_interval, + *hud_mouserate_style; + + if (hud_mouserate_title == NULL) // first time called + { + hud_mouserate_style = HUD_FindVar(hud, "style"); + hud_mouserate_title = HUD_FindVar(hud, "title"); + hud_mouserate_interval = HUD_FindVar(hud, "interval"); + } + + t = cls.realtime; + if ((t - lastframetime) >= hud_mouserate_interval->value) { + newresult = netinfo->mrate; + lastframetime = t; + } else + newresult = 0; + + if (newresult > 0) { + snprintf(st, sizeof(st), "%4d", newresult); + lastresult = newresult; + } else if (!newresult) + snprintf(st, sizeof(st), "%4d", lastresult); + else + snprintf(st, sizeof(st), "n/a"); + + if (hud_mouserate_title->value) + strlcat(st, " Hz", sizeof (st)); + + if (HUD_PrepareDraw(hud, strlen(st)*8, 8, &x, &y)) + { + if (hud_mouserate_style->value) + { + Draw_Alt_String(x, y, st); + } + else + { + Draw_String(x, y, st); + } + } +} + +#define MAX_TRACKING_STRING 512 + +void SCR_HUD_DrawTracking(hud_t *hud) +{ +#ifdef HAXX + static char tracked_strings[MV_VIEWS][MAX_TRACKING_STRING]; + static int tracked[MV_VIEWS] = {-1, -1, -1, -1}; + int view = 0; +#endif + int views = 1; + int x = 0, y = 0, width = 0, height = 0; + char track_string[MAX_TRACKING_STRING]; + + static cvar_t *hud_tracking_format = NULL, + *hud_tracking_scale; + + if (!hud_tracking_format) { + hud_tracking_format = HUD_FindVar(hud, "format"); + hud_tracking_scale = HUD_FindVar(hud, "scale"); + } + + strlcpy(track_string, hud_tracking_format->string, sizeof(track_string)); + +#ifdef HAXX + if(cls.mvdplayback && cl_multiview->value && CURRVIEW > 0) + { + // + // Multiview. + // + + views = cl_multiview->value; + + // Save the currently tracked player for the slot being drawn + // (this will be done for all views and we'll get a complete + // list over who we're tracking). + tracked[CURRVIEW - 1] = spec_track; + + for(view = 0; view < MV_VIEWS; view++) + { + int new_width = 0; + + // We haven't found who we're tracking in this view. + if(tracked[view] < 0) + { + continue; + } + + strlcpy(tracked_strings[view], hud_tracking_format->string, sizeof(tracked_strings[view])); + + Replace_In_String(tracked_strings[view], sizeof(tracked_strings[view]), '%', 3, + "v", cl_multiview->value ? va("%d", view+1) : "", // Replace %v with the current view (in multiview) + "n", cl.players[tracked[view]].name, // Replace %n with player name. + "t", cl.teamplay ? cl.players[tracked[view]].team : ""); // Replace %t with player team if teamplay is on. + + // Set the width. + new_width = 8 * strlen_color(tracked_strings[view]); + width = (new_width > width) ? new_width : width; + } + } + else +#endif + { + // Normal. + Replace_In_String(track_string, sizeof(track_string), '%', 2, + "n", cl.players[spec_track].name, // Replace %n with player name. + "t", cl.teamplay ? cl.players[spec_track].team : ""); // Replace %t with player team if teamplay is on. + width = 8 * strlen_color(track_string); + } + + height = 8 * views; + height *= hud_tracking_scale->value; + width *= hud_tracking_scale->value; + + if (!(cl.spectator && autocam == CAM_TRACK)) + height = 0; + + if(!HUD_PrepareDraw(hud, width, height, &x, &y)) + { + return; + } + + if (height == 0) + return; + +#ifdef HAXX + if (cls.mvdplayback && cl_multiview->value && autocam == CAM_TRACK) + { + // Multiview + for(view = 0; view < MV_VIEWS; view++) + { + if(tracked[view] < 0 || CURRVIEW <= 0) + { + continue; + } + Draw_SString(x, y + view*8, tracked_strings[view], hud_tracking_scale->value); + } + } + else +#endif + if (cl.spectator && autocam == CAM_TRACK && !cl_multiview->value) + { + // Normal + Draw_SString(x, y, track_string, hud_tracking_scale->value); + } +} + +#ifdef HAXX +void R_MQW_NetGraph(int outgoing_sequence, int incoming_sequence, int *packet_latency, + int lost, int minping, int avgping, int maxping, int devping, + int posx, int posy, int width, int height, int revx, int revy); +// ---------------- +// Netgraph +static void SCR_HUD_Netgraph(hud_t *hud) +{ + static cvar_t + *par_width = NULL, *par_height, + *par_swap_x, *par_swap_y, + *par_ploss; + + if (par_width == NULL) // first time + { + par_width = HUD_FindVar(hud, "width"); + par_height = HUD_FindVar(hud, "height"); + par_swap_x = HUD_FindVar(hud, "swap_x"); + par_swap_y = HUD_FindVar(hud, "swap_y"); + par_ploss = HUD_FindVar(hud, "ploss"); + } + + R_MQW_NetGraph(cls.netchan.outgoing_sequence, cls.netchan.incoming_sequence, + packet_latency, par_ploss->value ? CL_CalcNet() : -1, -1, -1, -1, -1, -1, + -1, (int)par_width->value, (int)par_height->value, + (int)par_swap_x->value, (int)par_swap_y->value); +} +#endif + +//--------------------- +// +// draw HUD ping +// +static void SCR_HUD_DrawPing(hud_t *hud) +{ + double t; + static double last_calculated; + static int ping_avg, pl, ping_min, ping_max; + static float ping_dev; + + int width, height; + int x, y; + char buf[512]; + vmnetinfo_t *netinfo = GetNetworkInfo(); + + static cvar_t + *hud_ping_period = NULL, + *hud_ping_show_pl, + *hud_ping_show_dev, + *hud_ping_show_min, + *hud_ping_show_max, + *hud_ping_style, + *hud_ping_blink; + + if (hud_ping_period == NULL) // first time + { + hud_ping_period = HUD_FindVar(hud, "period"); + hud_ping_show_pl = HUD_FindVar(hud, "show_pl"); + hud_ping_show_dev = HUD_FindVar(hud, "show_dev"); + hud_ping_show_min = HUD_FindVar(hud, "show_min"); + hud_ping_show_max = HUD_FindVar(hud, "show_max"); + hud_ping_style = HUD_FindVar(hud, "style"); + hud_ping_blink = HUD_FindVar(hud, "blink"); + } + + t = cls.realtime; + if (t - last_calculated > hud_ping_period->value) + { +// float period; + + last_calculated = t; + +// period = max(hud_ping_period->value, 0); + + ping_avg = (int)(netinfo->ping.s_avg*1000 + 0.5); + ping_min = (int)(netinfo->ping.s_mn*1000 + 0.5); + ping_max = (int)(netinfo->ping.s_mx*1000 + 0.5); + ping_dev = netinfo->ping.ms_stddev; + pl = netinfo->loss.dropped*100; + + clamp(ping_avg, 0, 999); + clamp(ping_min, 0, 999); + clamp(ping_max, 0, 999); + clamp(ping_dev, 0, 99.9); + clamp(pl, 0, 100); + } + + buf[0] = 0; + + // blink + if (hud_ping_blink->value) // add dot + strlcat (buf, (last_calculated + hud_ping_period->value/2 > cls.realtime) ? "^Ue08f" : " ", sizeof (buf)); + + // min ping + if (hud_ping_show_min->value) + strlcat (buf, va("%d^Ue00f", ping_min), sizeof (buf)); + + // ping + strlcat (buf, va("%d", ping_avg), sizeof (buf)); + + // max ping + if (hud_ping_show_max->value) + strlcat (buf, va("^Ue00f%d", ping_max), sizeof (buf)); + + // unit + strlcat (buf, " ms", sizeof (buf)); + + // standard deviation + if (hud_ping_show_dev->value) + strlcat (buf, va(" (%.1f)", ping_dev), sizeof (buf)); + + // pl + if (hud_ping_show_pl->value) + strlcat (buf, va(" ^Ue08f %d%%", pl), sizeof (buf)); + + // display that on screen + width = strlen(buf) * 8; + height = 8; + + if (HUD_PrepareDraw(hud, width, height, &x, &y)) + { + if (hud_ping_style->value) + { + Draw_Alt_String(x, y, buf); + } + else + { + Draw_String(x, y, buf); + } + } +} + +static const char *SCR_HUD_ClockFormat(int format) +{ + switch (format) { + case 1: return "%I:%M %p"; + case 2: return "%I:%M:%S %p"; + case 3: return "%H:%M"; + default: case 0: return "%H:%M:%S"; + } +} + +//--------------------- +// +// draw HUD clock +// +void SCR_HUD_DrawClock(hud_t *hud) +{ + int width, height; + int x, y; + const char *t; + + static cvar_t + *hud_clock_big = NULL, + *hud_clock_style, + *hud_clock_blink, + *hud_clock_scale, + *hud_clock_format; + + if (hud_clock_big == NULL) // first time + { + hud_clock_big = HUD_FindVar(hud, "big"); + hud_clock_style = HUD_FindVar(hud, "style"); + hud_clock_blink = HUD_FindVar(hud, "blink"); + hud_clock_scale = HUD_FindVar(hud, "scale"); + hud_clock_format= HUD_FindVar(hud, "format"); + } + + t = SCR_GetTimeString(TIMETYPE_CLOCK, SCR_HUD_ClockFormat(hud_clock_format->ival)); + width = SCR_GetClockStringWidth(t, hud_clock_big->ival, hud_clock_scale->value); + height = SCR_GetClockStringHeight(hud_clock_big->ival, hud_clock_scale->value); + + if (HUD_PrepareDraw(hud, width, height, &x, &y)) + { + if (hud_clock_big->value) + SCR_DrawBigClock(x, y, hud_clock_style->value, hud_clock_blink->value, hud_clock_scale->value, t); + else + SCR_DrawSmallClock(x, y, hud_clock_style->value, hud_clock_blink->value, hud_clock_scale->value, t); + } +} + +//--------------------- +// +// draw HUD notify +// + +static void SCR_HUD_DrawNotify(hud_t* hud) +{ + static cvar_t* hud_notify_rows = NULL; + static cvar_t* hud_notify_scale; + static cvar_t* hud_notify_time; + static cvar_t* hud_notify_cols; + + int x; + int y; + int width; + int height; + + if (hud_notify_rows == NULL) // First time. + { + hud_notify_rows = HUD_FindVar(hud, "rows"); + hud_notify_cols = HUD_FindVar(hud, "cols"); + hud_notify_scale = HUD_FindVar(hud, "scale"); + hud_notify_time = HUD_FindVar(hud, "time"); + } + + height = hud_notify_rows->ival * 8 * hud_notify_scale->value; + width = 8 * hud_notify_cols->ival * hud_notify_scale->value; + + if (HUD_PrepareDraw(hud, width, height, &x, &y)) + { + pCvar_SetFloat("con_notify_x", (float)x / vid.width); + pCvar_SetFloat("con_notify_y", (float)y / vid.height); + pCvar_SetFloat("con_notify_w", (float)width / vid.width); + pCvar_SetFloat("con_numnotifylines",(int)(height/(8*hud_notify_scale->value) + 0.01)); + pCvar_SetFloat("con_notifytime", (float)hud_notify_time->ival); + pCvar_SetFloat("con_textsize", 8.0 * hud_notify_scale->value); +// SCR_DrawNotify(x, y, hud_notify_scale->value, hud_notify_time->ival, hud_notify_rows->ival, hud_notify_cols->ival); + } +} + +//--------------------- +// +// draw HUD gameclock +// +void SCR_HUD_DrawGameClock(hud_t *hud) +{ + int width, height; + int x, y; + int timetype; + const char *t; + + static cvar_t + *hud_gameclock_big = NULL, + *hud_gameclock_style, + *hud_gameclock_blink, + *hud_gameclock_countdown, + *hud_gameclock_scale +// *hud_gameclock_offset + ; + + if (hud_gameclock_big == NULL) // first time + { + hud_gameclock_big = HUD_FindVar(hud, "big"); + hud_gameclock_style = HUD_FindVar(hud, "style"); + hud_gameclock_blink = HUD_FindVar(hud, "blink"); + hud_gameclock_countdown = HUD_FindVar(hud, "countdown"); + hud_gameclock_scale = HUD_FindVar(hud, "scale"); +// hud_gameclock_offset = HUD_FindVar(hud, "offset"); +// gameclockoffset = &hud_gameclock_offset->ival; + } + + timetype = (hud_gameclock_countdown->value) ? TIMETYPE_GAMECLOCKINV : TIMETYPE_GAMECLOCK; + t = SCR_GetTimeString(timetype, NULL); + width = SCR_GetClockStringWidth(t, hud_gameclock_big->ival, hud_gameclock_scale->value); + height = SCR_GetClockStringHeight(hud_gameclock_big->ival, hud_gameclock_scale->value); + + if (HUD_PrepareDraw(hud, width, height, &x, &y)) + { + if (hud_gameclock_big->value) + SCR_DrawBigClock(x, y, hud_gameclock_style->value, hud_gameclock_blink->value, hud_gameclock_scale->value, t); + else + SCR_DrawSmallClock(x, y, hud_gameclock_style->value, hud_gameclock_blink->value, hud_gameclock_scale->value, t); + } +} + +//--------------------- +// +// draw HUD democlock +// +void SCR_HUD_DrawDemoClock(hud_t *hud) +{ + int width = 0; + int height = 0; + int x = 0; + int y = 0; + const char *t; + static cvar_t + *hud_democlock_big = NULL, + *hud_democlock_style, + *hud_democlock_blink, + *hud_democlock_scale; + + if (!cls.demoplayback || cls.mvdplayback == 2) + { + HUD_PrepareDraw(hud, width, height, &x, &y); + return; + } + + if (hud_democlock_big == NULL) // first time + { + hud_democlock_big = HUD_FindVar(hud, "big"); + hud_democlock_style = HUD_FindVar(hud, "style"); + hud_democlock_blink = HUD_FindVar(hud, "blink"); + hud_democlock_scale = HUD_FindVar(hud, "scale"); + } + + t = SCR_GetTimeString(TIMETYPE_DEMOCLOCK, NULL); + width = SCR_GetClockStringWidth(t, hud_democlock_big->ival, hud_democlock_scale->value); + height = SCR_GetClockStringHeight(hud_democlock_big->ival, hud_democlock_scale->value); + + if (HUD_PrepareDraw(hud, width, height, &x, &y)) + { + if (hud_democlock_big->value) + SCR_DrawBigClock(x, y, hud_democlock_style->value, hud_democlock_blink->value, hud_democlock_scale->value, t); + else + SCR_DrawSmallClock(x, y, hud_democlock_style->value, hud_democlock_blink->value, hud_democlock_scale->value, t); + } +} + +//--------------------- +// +// network statistics +// static void SCR_NetStats(int x, int y, float period, vmnetinfo_t *netinfo) { char line[128]; @@ -1062,1222 +1062,1222 @@ static void SCR_NetStats(int x, int y, float period, vmnetinfo_t *netinfo) Draw_String(x, y, line); y+=8; } - -static void SCR_HUD_DrawNetStats(hud_t *hud) -{ - int width, height; - int x, y; - - vmnetinfo_t *netinfo = GetNetworkInfo(); - - static cvar_t *hud_net_period = NULL; - - if (hud_net_period == NULL) // first time - { - hud_net_period = HUD_FindVar(hud, "period"); - } - - width = 16*8 ; - height = 12 + 8 + 8 + 8 + 8 + 16 + 8 + 8 + 8 + 8 + 16 + 8 + 8 + 8; - - if (!netinfo || netinfo->capturing==2) - HUD_PrepareDraw(hud, 0, 0, &x, &y); - else if (HUD_PrepareDraw(hud, width, height, &x, &y)) - { - SCR_NetStats(x, y, hud_net_period->value, netinfo); - } -} - -#define SPEED_GREEN "52" -#define SPEED_BROWN_RED "100" -#define SPEED_DARK_RED "72" -#define SPEED_BLUE "216" -#define SPEED_RED "229" - -#define SPEED_STOPPED SPEED_GREEN -#define SPEED_NORMAL SPEED_BROWN_RED -#define SPEED_FAST SPEED_DARK_RED -#define SPEED_FASTEST SPEED_BLUE -#define SPEED_INSANE SPEED_RED - -//--------------------- -// -// speed-o-meter -// -#ifdef HAXX -static void SCR_HUD_DrawSpeed(hud_t *hud) -{ - int width, height; - int x, y; - - static cvar_t *hud_speed_xyz = NULL, - *hud_speed_width, - *hud_speed_height, - *hud_speed_tick_spacing, - *hud_speed_opacity, - *hud_speed_color_stopped, - *hud_speed_color_normal, - *hud_speed_color_fast, - *hud_speed_color_fastest, - *hud_speed_color_insane, - *hud_speed_vertical, - *hud_speed_vertical_text, - *hud_speed_text_align, - *hud_speed_style; - - if (hud_speed_xyz == NULL) // first time - { - hud_speed_xyz = HUD_FindVar(hud, "xyz"); - hud_speed_width = HUD_FindVar(hud, "width"); - hud_speed_height = HUD_FindVar(hud, "height"); - hud_speed_tick_spacing = HUD_FindVar(hud, "tick_spacing"); - hud_speed_opacity = HUD_FindVar(hud, "opacity"); - hud_speed_color_stopped = HUD_FindVar(hud, "color_stopped"); - hud_speed_color_normal = HUD_FindVar(hud, "color_normal"); - hud_speed_color_fast = HUD_FindVar(hud, "color_fast"); - hud_speed_color_fastest = HUD_FindVar(hud, "color_fastest"); - hud_speed_color_insane = HUD_FindVar(hud, "color_insane"); - hud_speed_vertical = HUD_FindVar(hud, "vertical"); - hud_speed_vertical_text = HUD_FindVar(hud, "vertical_text"); - hud_speed_text_align = HUD_FindVar(hud, "text_align"); - hud_speed_style = HUD_FindVar(hud, "style"); - } - - width = max(0, hud_speed_width->value); - height = max(0, hud_speed_height->value); - - if (HUD_PrepareDraw(hud, width, height, &x, &y)) - { - SCR_DrawHUDSpeed(x, y, width, height, - hud_speed_xyz->value, - hud_speed_tick_spacing->value, - hud_speed_opacity->value, - hud_speed_vertical->value, - hud_speed_vertical_text->value, - hud_speed_text_align->value, - hud_speed_color_stopped->value, - hud_speed_color_normal->value, - hud_speed_color_fast->value, - hud_speed_color_fastest->value, - hud_speed_color_insane->value, - hud_speed_style->ival); - } -} -#endif - -#define HUD_SPEED2_ORIENTATION_UP 0 -#define HUD_SPEED2_ORIENTATION_DOWN 1 -#define HUD_SPEED2_ORIENTATION_RIGHT 2 -#define HUD_SPEED2_ORIENTATION_LEFT 3 - -void SCR_HUD_DrawSpeed2(hud_t *hud) -{ - int width, height; - int x, y; - - static cvar_t *hud_speed2_xyz = NULL, -// *hud_speed2_opacity, - *hud_speed2_color_stopped, - *hud_speed2_color_normal, - *hud_speed2_color_fast, - *hud_speed2_color_fastest, - *hud_speed2_color_insane, - *hud_speed2_radius, - *hud_speed2_wrapspeed, - *hud_speed2_orientation; - - if (hud_speed2_xyz == NULL) // first time - { - hud_speed2_xyz = HUD_FindVar(hud, "xyz"); -// hud_speed2_opacity = HUD_FindVar(hud, "opacity"); - hud_speed2_color_stopped = HUD_FindVar(hud, "color_stopped"); - hud_speed2_color_normal = HUD_FindVar(hud, "color_normal"); - hud_speed2_color_fast = HUD_FindVar(hud, "color_fast"); - hud_speed2_color_fastest = HUD_FindVar(hud, "color_fastest"); - hud_speed2_color_insane = HUD_FindVar(hud, "color_insane"); - hud_speed2_radius = HUD_FindVar(hud, "radius"); - hud_speed2_wrapspeed = HUD_FindVar(hud, "wrapspeed"); - hud_speed2_orientation = HUD_FindVar(hud, "orientation"); - } - - // Calculate the height and width based on the radius. - switch((int)hud_speed2_orientation->value) - { - case HUD_SPEED2_ORIENTATION_LEFT : - case HUD_SPEED2_ORIENTATION_RIGHT : - height = max(0, 2*hud_speed2_radius->value); - width = max(0, (hud_speed2_radius->value)); - break; - case HUD_SPEED2_ORIENTATION_DOWN : - case HUD_SPEED2_ORIENTATION_UP : - default : - // Include the height of the speed text in the height. - height = max(0, (hud_speed2_radius->value)); - width = max(0, 2*hud_speed2_radius->value); - break; - } - - if (HUD_PrepareDraw(hud, width, height, &x, &y)) - { - int player_speed; - int arc_length; - int color1, color2; - int text_x = x; - int text_y = y; - vec_t *velocity; - - // Start and end points for the needle - int needle_start_x = 0; - int needle_start_y = 0; - int needle_end_x = 0; - int needle_end_y = 0; - - // The length of the arc between the zero point - // and where the needle is pointing at. - int needle_offset = 0; - - // The angle between the zero point and the position - // that the needle is drawn on. - float needle_angle = 0.0; - - // The angle where to start drawing the half circle and where to end. - // This depends on the orientation of the circle (left, right, up, down). - float circle_startangle = 0.0; - float circle_endangle = 0.0; - - // Avoid divison by zero. - if(hud_speed2_radius->value <= 0) - { - return; - } - - // Get the velocity. -#ifdef HAXX - if (cl.players[cl.playernum].spectator && Cam_TrackNum() >= 0) - { - velocity = cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK].playerstate[Cam_TrackNum()].velocity; - } - else -#endif - { - velocity = cl.simvel; - } - - // Calculate the speed - if (!hud_speed2_xyz->value) - { - // Based on XY. - player_speed = sqrt(velocity[0]*velocity[0] - + velocity[1]*velocity[1]); - } - else - { - // Based on XYZ. - player_speed = sqrt(velocity[0]*velocity[0] - + velocity[1]*velocity[1] - + velocity[2]*velocity[2]); - } - - // Set the color based on the wrap speed. - switch ((int)(player_speed / hud_speed2_wrapspeed->value)) - { - case 0: - color1 = hud_speed2_color_stopped->ival; - color2 = hud_speed2_color_normal->ival; - break; - case 1: - color1 = hud_speed2_color_normal->ival; - color2 = hud_speed2_color_fast->ival; - break; - case 2: - color1 = hud_speed2_color_fast->ival; - color2 = hud_speed2_color_fastest->ival; - break; - default: - color1 = hud_speed2_color_fastest->ival; - color2 = hud_speed2_color_insane->ival; - break; - } - - // Set some properties how to draw the half circle, needle and text - // based on the orientation of the hud item. - switch((int)hud_speed2_orientation->value) - { - case HUD_SPEED2_ORIENTATION_LEFT : - { - x += width; - y += height / 2; - circle_startangle = M_PI / 2.0; - circle_endangle = (3*M_PI) / 2.0; - - text_x = x - 32; - text_y = y - 4; - break; - } - case HUD_SPEED2_ORIENTATION_RIGHT : - { - y += height / 2; - circle_startangle = (3*M_PI) / 2.0; - circle_endangle = (5*M_PI) / 2.0; - needle_end_y = y + hud_speed2_radius->value * sin (needle_angle); - - text_x = x; - text_y = y - 4; - break; - } - case HUD_SPEED2_ORIENTATION_DOWN : - { - x += width / 2; - circle_startangle = M_PI; - circle_endangle = 2*M_PI; - needle_end_y = y + hud_speed2_radius->value * sin (needle_angle); - - text_x = x - 16; - text_y = y; - break; - } - case HUD_SPEED2_ORIENTATION_UP : - default : - { - x += width / 2; - y += height; - circle_startangle = 0; - circle_endangle = M_PI; - needle_end_y = y - hud_speed2_radius->value * sin (needle_angle); - - text_x = x - 16; - text_y = y - 8; - break; - } - } - - // - // Calculate the offsets and angles. - // - { - // Calculate the arc length of the half circle background. - arc_length = fabs((circle_endangle - circle_startangle) * hud_speed2_radius->value); - - // Calculate the angle where the speed needle should point. - needle_offset = arc_length * (player_speed % Q_rint(hud_speed2_wrapspeed->value)) / Q_rint(hud_speed2_wrapspeed->value); - needle_angle = needle_offset / hud_speed2_radius->value; - - // Draw from the center of the half circle. - needle_start_x = x; - needle_start_y = y; - } - - // Set the needle end point depending on the orientation of the hud item. - - switch((int)hud_speed2_orientation->value) - { - case HUD_SPEED2_ORIENTATION_LEFT : - { - needle_end_x = x - hud_speed2_radius->value * sin (needle_angle); - needle_end_y = y + hud_speed2_radius->value * cos (needle_angle); - break; - } - case HUD_SPEED2_ORIENTATION_RIGHT : - { - needle_end_x = x + hud_speed2_radius->value * sin (needle_angle); - needle_end_y = y - hud_speed2_radius->value * cos (needle_angle); - break; - } - case HUD_SPEED2_ORIENTATION_DOWN : - { - needle_end_x = x + hud_speed2_radius->value * cos (needle_angle); - needle_end_y = y + hud_speed2_radius->value * sin (needle_angle); - break; - } - case HUD_SPEED2_ORIENTATION_UP : - default : - { - needle_end_x = x - hud_speed2_radius->value * cos (needle_angle); - needle_end_y = y - hud_speed2_radius->value * sin (needle_angle); - break; - } - } - -#ifdef HAXX - // Draw the speed-o-meter background. - Draw_AlphaPieSlice (x, y, // Position - hud_speed2_radius->value, // Radius - circle_startangle, // Start angle - circle_endangle - needle_angle, // End angle - 1, // Thickness - true, // Fill - color1, // Color - hud_speed2_opacity->value); // Opacity - - // Draw a pie slice that shows the "color" of the speed. - Draw_AlphaPieSlice (x, y, // Position - hud_speed2_radius->value, // Radius - circle_endangle - needle_angle, // Start angle - circle_endangle, // End angle - 1, // Thickness - true, // Fill - color2, // Color - hud_speed2_opacity->value); // Opacity - - // Draw the "needle attachment" circle. - Draw_AlphaCircle (x, y, 2.0, 1, true, 15, hud_speed2_opacity->value); - - // Draw the speed needle. - Draw_AlphaLineRGB (needle_start_x, needle_start_y, needle_end_x, needle_end_y, 1, RGBA_TO_COLOR(250, 250, 250, 255 * hud_speed2_opacity->value)); -#else - (void)color1; - (void)color2; - (void)needle_start_x; - (void)needle_start_y; - (void)needle_end_x; - (void)needle_end_y; -#endif - - // Draw the speed. - Draw_String (text_x, text_y, va("%d", player_speed)); - } -} - -// ======================================================= -// -// s t a t u s b a r e l e m e n t s -// -// - - -// ----------- -// gunz -// -void SCR_HUD_DrawGunByNum (hud_t *hud, int num, float scale, int style, int wide) -{ - int i = num - 2; - int width, height; - int x, y; - char *tmp; - - scale = max(scale, 0.01); - - switch (style) - { - case 3: // opposite colors of case 1 - case 1: // text, gold inactive, white active - width = 16 * scale; - height = 8 * scale; - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - return; - if ( HUD_Stats(STAT_ITEMS) & (IT_SHOTGUN<= 10) - { - if ( HUD_Stats(STAT_ACTIVEWEAPON) == (IT_SHOTGUN<value, style->value, 0); -} -void SCR_HUD_DrawGun3 (hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawGunByNum (hud, 3, scale->value, style->value, 0); -} -void SCR_HUD_DrawGun4 (hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawGunByNum (hud, 4, scale->value, style->value, 0); -} -void SCR_HUD_DrawGun5 (hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawGunByNum (hud, 5, scale->value, style->value, 0); -} -void SCR_HUD_DrawGun6 (hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawGunByNum (hud, 6, scale->value, style->value, 0); -} -void SCR_HUD_DrawGun7 (hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawGunByNum (hud, 7, scale->value, style->value, 0); -} -void SCR_HUD_DrawGun8 (hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *wide; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - wide = HUD_FindVar(hud, "wide"); - } - SCR_HUD_DrawGunByNum (hud, 8, scale->value, style->value, wide->value); -} -void SCR_HUD_DrawGunCurrent (hud_t *hud) -{ - int gun; - static cvar_t *scale = NULL, *style, *wide; - - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - wide = HUD_FindVar(hud, "wide"); - } - - if (ShowPreselectedWeap()) { - // using weapon pre-selection so show info for current best pre-selected weapon - gun = IN_BestWeapon(); - if (gun < 2) { - return; - } - } else { - // not using weapon pre-selection or player is dead so show current selected weapon - switch (HUD_Stats(STAT_ACTIVEWEAPON)) - { - case IT_SHOTGUN << 0: gun = 2; break; - case IT_SHOTGUN << 1: gun = 3; break; - case IT_SHOTGUN << 2: gun = 4; break; - case IT_SHOTGUN << 3: gun = 5; break; - case IT_SHOTGUN << 4: gun = 6; break; - case IT_SHOTGUN << 5: gun = 7; break; - case IT_SHOTGUN << 6: gun = 8; break; - default: return; - } - } - - SCR_HUD_DrawGunByNum (hud, gun, scale->value, style->value, wide->value); -} - -// ---------------- -// powerzz -// -void SCR_HUD_DrawPowerup(hud_t *hud, int num, float scale, int style) -{ - int x, y, width, height; - int c; - - scale = max(scale, 0.01); - - switch (style) - { - case 1: // letter - width = height = 8 * scale; - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - return; - if (HUD_Stats(STAT_ITEMS) & (1<<(17+num))) - { - switch (num) - { - case 0: c = '1'; break; - case 1: c = '2'; break; - case 2: c = 'r'; break; - case 3: c = 'p'; break; - case 4: c = 's'; break; - case 5: c = 'q'; break; - default: c = '?'; - } - Draw_SCharacter(x, y, c, scale); - } - break; - default: // classic - pics - width = height = scale * 16; - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - return; - if (HUD_Stats(STAT_ITEMS) & (1<<(17+num))) - Draw_SPic (x, y, sb_items[num], scale); - break; - } -} - -void SCR_HUD_DrawKey1(hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawPowerup(hud, 0, scale->value, style->value); -} -void SCR_HUD_DrawKey2(hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawPowerup(hud, 1, scale->value, style->value); -} -void SCR_HUD_DrawRing(hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawPowerup(hud, 2, scale->value, style->value); -} -void SCR_HUD_DrawPent(hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawPowerup(hud, 3, scale->value, style->value); -} -void SCR_HUD_DrawSuit(hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawPowerup(hud, 4, scale->value, style->value); -} -void SCR_HUD_DrawQuad(hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawPowerup(hud, 5, scale->value, style->value); -} - -// ----------- -// sigils -// -void SCR_HUD_DrawSigil(hud_t *hud, int num, float scale, int style) -{ - int x, y; - - scale = max(scale, 0.01); - - switch (style) - { - case 1: // sigil number - if (!HUD_PrepareDraw(hud, 8*scale, 8*scale, &x, &y)) - return; - if (HUD_Stats(STAT_ITEMS) & (1<<(28+num))) - Draw_SCharacter(x, y, num + '0', scale); - break; - default: // classic - picture - if (!HUD_PrepareDraw(hud, 8*scale, 16*scale, &x, &y)) - return; - if (HUD_Stats(STAT_ITEMS) & (1<<(28+num))) - Draw_SPic(x, y, sb_sigil[num], scale); - break; - } -} - -void SCR_HUD_DrawSigil1(hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawSigil(hud, 0, scale->value, style->value); -} -void SCR_HUD_DrawSigil2(hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawSigil(hud, 1, scale->value, style->value); -} -void SCR_HUD_DrawSigil3(hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawSigil(hud, 2, scale->value, style->value); -} -void SCR_HUD_DrawSigil4(hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawSigil(hud, 3, scale->value, style->value); -} - -// icons - active ammo, armor, face etc.. -void SCR_HUD_DrawAmmoIcon(hud_t *hud, int num, float scale, int style) -{ - int x, y, width, height; - - scale = max(scale, 0.01); - - width = height = (style ? 8 : 24) * scale; - - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - return; - - if (style) - { - switch (num) - { - case 1: Draw_SAlt_String(x, y, "s", scale); break; - case 2: Draw_SAlt_String(x, y, "n", scale); break; - case 3: Draw_SAlt_String(x, y, "r", scale); break; - case 4: Draw_SAlt_String(x, y, "c", scale); break; - } - } - else - { - Draw_SPic (x, y, sb_ammo[num-1], scale); - } -} -void SCR_HUD_DrawAmmoIconCurrent (hud_t *hud) -{ - int num; - static cvar_t *scale = NULL, *style; - - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - - if (ShowPreselectedWeap()) { - // using weapon pre-selection so show info for current best pre-selected weapon ammo - if (!(num = State_AmmoNumForWeapon(IN_BestWeapon()))) - return; - } else { - // not using weapon pre-selection or player is dead so show current selected ammo - if (HUD_Stats(STAT_ITEMS) & IT_SHELLS) - num = 1; - else if (HUD_Stats(STAT_ITEMS) & IT_NAILS) - num = 2; - else if (HUD_Stats(STAT_ITEMS) & IT_ROCKETS) - num = 3; - else if (HUD_Stats(STAT_ITEMS) & IT_CELLS) - num = 4; - else if (TP_TeamFortressEngineerSpanner()) - num = 4; - else - return; - } - - SCR_HUD_DrawAmmoIcon(hud, num, scale->value, style->value); -} -void SCR_HUD_DrawAmmoIcon1 (hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawAmmoIcon(hud, 1, scale->value, style->value); -} -void SCR_HUD_DrawAmmoIcon2 (hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawAmmoIcon(hud, 2, scale->value, style->value); -} -void SCR_HUD_DrawAmmoIcon3 (hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawAmmoIcon(hud, 3, scale->value, style->value); -} -void SCR_HUD_DrawAmmoIcon4 (hud_t *hud) -{ - static cvar_t *scale = NULL, *style; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - } - SCR_HUD_DrawAmmoIcon(hud, 4, scale->value, style->value); -} - -void SCR_HUD_DrawArmorIcon(hud_t *hud) -{ - int x, y, width, height; - - int style; - float scale; - - static cvar_t *v_scale = NULL, *v_style; - if (v_scale == NULL) // first time called - { - v_scale = HUD_FindVar(hud, "scale"); - v_style = HUD_FindVar(hud, "style"); - } - - scale = max(v_scale->value, 0.01); - style = (int)(v_style->value); - - width = height = (style ? 8 : 24) * scale; - - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - return; - - if (style) - { - int c; - - if (HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY) - c = '@'; - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3) - c = 'r'; - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR2) - c = 'y'; - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1) - c = 'g'; - else return; - - c += 128; - - Draw_SCharacter(x, y, c, scale); - } - else - { - mpic_t *pic; - - if (HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY) - pic = sb_disc; - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3) - pic = sb_armor[2]; - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR2) - pic = sb_armor[1]; - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1) - pic = sb_armor[0]; - else return; - - Draw_SPic (x, y, pic, scale); - } -} - -// face -void SCR_HUD_DrawFace(hud_t *hud) -{ - int f, anim; - int x, y; - float scale; - - static cvar_t *v_scale = NULL; - if (v_scale == NULL) // first time called - { - v_scale = HUD_FindVar(hud, "scale"); - } - - scale = max(v_scale->value, 0.01); - - if (!HUD_PrepareDraw(hud, 24*scale, 24*scale, &x, &y)) - return; - - if ( (HUD_Stats(STAT_ITEMS) & (IT_INVISIBILITY | IT_INVULNERABILITY) ) - == (IT_INVISIBILITY | IT_INVULNERABILITY) ) - { - Draw_SPic (x, y, sb_face_invis_invuln, scale); - return; - } - if (HUD_Stats(STAT_ITEMS) & IT_QUAD) - { - Draw_SPic (x, y, sb_face_quad, scale); - return; - } - if (HUD_Stats(STAT_ITEMS) & IT_INVISIBILITY) - { - Draw_SPic (x, y, sb_face_invis, scale); - return; - } - if (HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY) - { - Draw_SPic (x, y, sb_face_invuln, scale); - return; - } - - if (HUD_Stats(STAT_HEALTH) >= 100) - f = 4; - else - f = max(0, HUD_Stats(STAT_HEALTH)) / 20; - - if (cl.time <= cl.faceanimtime) - anim = 1; - else - anim = 0; - Draw_SPic (x, y, sb_faces[f][anim], scale); -} - - -// status numbers -void SCR_HUD_DrawNum(hud_t *hud, int num, qbool low, - float scale, int style, int digits, char *s_align) -{ - int i; - char buf[sizeof(int) * 3]; // each byte need <= 3 chars - int len; - - int width, height, x, y; - int size; - int align; - - clamp(num, -99999, 999999); - - scale = max(scale, 0.01); - - if (digits > 0) - clamp(digits, 1, 6); - else - digits = 0; // auto-resize - - align = 2; - switch (tolower(s_align[0])) - { - default: - case 'l': // 'l'eft - align = 0; break; - case 'c': // 'c'enter - align = 1; break; - case 'r': // 'r'ight - align = 2; break; - } - - snprintf(buf, sizeof (buf), "%d", (style == 2 || style == 3) ? num : abs(num)); - - if(digits) - { - switch (hud_digits_trim->ival) - { - case 0: // 10030 -> 999 - len = strlen(buf); - if (len > digits) - { - char *p = buf; - if(num < 0) - *p++ = '-'; - for (i = (num < 0) ? 1 : 0 ; i < digits; i++) - *p++ = '9'; - *p = 0; - len = digits; - } - break; - default: - case 1: // 10030 -> 030 - len = strlen(buf); - if(len > digits) - { - char *p = buf; - memmove(p, p + (len - digits), digits); - buf[digits] = '\0'; - len = strlen(buf); - } - break; - case 2: // 10030 -> 100 - buf[digits] = '\0'; - len = strlen(buf); - break; - } - } - else - { - len = strlen(buf); - } - - switch (style) - { - case 1: - case 3: - size = 8; - break; - case 0: - case 2: - default: - size = 24; - break; - } - - if(digits) - width = digits * size; - else - width = size * len; - - height = size; - - switch (style) - { - case 1: - case 3: - if (!HUD_PrepareDraw(hud, scale*width, scale*height, &x, &y)) - return; - switch (align) - { - case 0: break; - case 1: x += scale * (width - size * len) / 2; break; - case 2: x += scale * (width - size * len); break; - } - if (low) - Draw_SAlt_String(x, y, buf, scale); - else - Draw_SString(x, y, buf, scale); - break; - - case 0: - case 2: - default: - if (!HUD_PrepareDraw(hud, scale*width, scale*height, &x, &y)) - return; - switch (align) - { - case 0: break; - case 1: x += scale * (width - size * len) / 2; break; - case 2: x += scale * (width - size * len); break; - } - for (i = 0; i < len; i++) - { - if(buf[i] == '-' && style == 2) - { - Draw_STransPic (x, y, sb_nums[low ? 1 : 0][STAT_MINUS], scale); - x += 24 * scale; - } - else - { - Draw_STransPic (x, y, sb_nums[low ? 1 : 0][buf[i] - '0'], scale); - x += 24 * scale; - } - } - break; - } -} - -void SCR_HUD_DrawHealth(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *digits, *align; - static int value; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - } - value = HUD_Stats(STAT_HEALTH); - SCR_HUD_DrawNum(hud, (value < 0 ? 0 : value), HUD_HealthLow(), - scale->value, style->value, digits->value, align->string); -} - -void SCR_HUD_DrawArmor(hud_t *hud) -{ - int level; - qbool low; - static cvar_t *scale = NULL, *style, *digits, *align, *pent_666; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - pent_666 = HUD_FindVar(hud, "pent_666"); // Show 666 or armor value when carrying pentagram - } - - if (HUD_Stats(STAT_HEALTH) > 0) - { - if ((HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY) && pent_666->ival) - { - level = 666; - low = true; - } - else - { - level = HUD_Stats(STAT_ARMOR); - low = HUD_ArmorLow(); - } - } - else - { - level = 0; - low = true; - } - - SCR_HUD_DrawNum(hud, level, low, - scale->value, style->value, digits->value, align->string); -} - -//void Draw_AMFStatLoss (int stat, hud_t* hud); + +static void SCR_HUD_DrawNetStats(hud_t *hud) +{ + int width, height; + int x, y; + + vmnetinfo_t *netinfo = GetNetworkInfo(); + + static cvar_t *hud_net_period = NULL; + + if (hud_net_period == NULL) // first time + { + hud_net_period = HUD_FindVar(hud, "period"); + } + + width = 16*8 ; + height = 12 + 8 + 8 + 8 + 8 + 16 + 8 + 8 + 8 + 8 + 16 + 8 + 8 + 8; + + if (!netinfo || netinfo->capturing==2) + HUD_PrepareDraw(hud, 0, 0, &x, &y); + else if (HUD_PrepareDraw(hud, width, height, &x, &y)) + { + SCR_NetStats(x, y, hud_net_period->value, netinfo); + } +} + +#define SPEED_GREEN "52" +#define SPEED_BROWN_RED "100" +#define SPEED_DARK_RED "72" +#define SPEED_BLUE "216" +#define SPEED_RED "229" + +#define SPEED_STOPPED SPEED_GREEN +#define SPEED_NORMAL SPEED_BROWN_RED +#define SPEED_FAST SPEED_DARK_RED +#define SPEED_FASTEST SPEED_BLUE +#define SPEED_INSANE SPEED_RED + +//--------------------- +// +// speed-o-meter +// +#ifdef HAXX +static void SCR_HUD_DrawSpeed(hud_t *hud) +{ + int width, height; + int x, y; + + static cvar_t *hud_speed_xyz = NULL, + *hud_speed_width, + *hud_speed_height, + *hud_speed_tick_spacing, + *hud_speed_opacity, + *hud_speed_color_stopped, + *hud_speed_color_normal, + *hud_speed_color_fast, + *hud_speed_color_fastest, + *hud_speed_color_insane, + *hud_speed_vertical, + *hud_speed_vertical_text, + *hud_speed_text_align, + *hud_speed_style; + + if (hud_speed_xyz == NULL) // first time + { + hud_speed_xyz = HUD_FindVar(hud, "xyz"); + hud_speed_width = HUD_FindVar(hud, "width"); + hud_speed_height = HUD_FindVar(hud, "height"); + hud_speed_tick_spacing = HUD_FindVar(hud, "tick_spacing"); + hud_speed_opacity = HUD_FindVar(hud, "opacity"); + hud_speed_color_stopped = HUD_FindVar(hud, "color_stopped"); + hud_speed_color_normal = HUD_FindVar(hud, "color_normal"); + hud_speed_color_fast = HUD_FindVar(hud, "color_fast"); + hud_speed_color_fastest = HUD_FindVar(hud, "color_fastest"); + hud_speed_color_insane = HUD_FindVar(hud, "color_insane"); + hud_speed_vertical = HUD_FindVar(hud, "vertical"); + hud_speed_vertical_text = HUD_FindVar(hud, "vertical_text"); + hud_speed_text_align = HUD_FindVar(hud, "text_align"); + hud_speed_style = HUD_FindVar(hud, "style"); + } + + width = max(0, hud_speed_width->value); + height = max(0, hud_speed_height->value); + + if (HUD_PrepareDraw(hud, width, height, &x, &y)) + { + SCR_DrawHUDSpeed(x, y, width, height, + hud_speed_xyz->value, + hud_speed_tick_spacing->value, + hud_speed_opacity->value, + hud_speed_vertical->value, + hud_speed_vertical_text->value, + hud_speed_text_align->value, + hud_speed_color_stopped->value, + hud_speed_color_normal->value, + hud_speed_color_fast->value, + hud_speed_color_fastest->value, + hud_speed_color_insane->value, + hud_speed_style->ival); + } +} +#endif + +#define HUD_SPEED2_ORIENTATION_UP 0 +#define HUD_SPEED2_ORIENTATION_DOWN 1 +#define HUD_SPEED2_ORIENTATION_RIGHT 2 +#define HUD_SPEED2_ORIENTATION_LEFT 3 + +void SCR_HUD_DrawSpeed2(hud_t *hud) +{ + int width, height; + int x, y; + + static cvar_t *hud_speed2_xyz = NULL, +// *hud_speed2_opacity, + *hud_speed2_color_stopped, + *hud_speed2_color_normal, + *hud_speed2_color_fast, + *hud_speed2_color_fastest, + *hud_speed2_color_insane, + *hud_speed2_radius, + *hud_speed2_wrapspeed, + *hud_speed2_orientation; + + if (hud_speed2_xyz == NULL) // first time + { + hud_speed2_xyz = HUD_FindVar(hud, "xyz"); +// hud_speed2_opacity = HUD_FindVar(hud, "opacity"); + hud_speed2_color_stopped = HUD_FindVar(hud, "color_stopped"); + hud_speed2_color_normal = HUD_FindVar(hud, "color_normal"); + hud_speed2_color_fast = HUD_FindVar(hud, "color_fast"); + hud_speed2_color_fastest = HUD_FindVar(hud, "color_fastest"); + hud_speed2_color_insane = HUD_FindVar(hud, "color_insane"); + hud_speed2_radius = HUD_FindVar(hud, "radius"); + hud_speed2_wrapspeed = HUD_FindVar(hud, "wrapspeed"); + hud_speed2_orientation = HUD_FindVar(hud, "orientation"); + } + + // Calculate the height and width based on the radius. + switch((int)hud_speed2_orientation->value) + { + case HUD_SPEED2_ORIENTATION_LEFT : + case HUD_SPEED2_ORIENTATION_RIGHT : + height = max(0, 2*hud_speed2_radius->value); + width = max(0, (hud_speed2_radius->value)); + break; + case HUD_SPEED2_ORIENTATION_DOWN : + case HUD_SPEED2_ORIENTATION_UP : + default : + // Include the height of the speed text in the height. + height = max(0, (hud_speed2_radius->value)); + width = max(0, 2*hud_speed2_radius->value); + break; + } + + if (HUD_PrepareDraw(hud, width, height, &x, &y)) + { + int player_speed; + int arc_length; + int color1, color2; + int text_x = x; + int text_y = y; + vec_t *velocity; + + // Start and end points for the needle + int needle_start_x = 0; + int needle_start_y = 0; + int needle_end_x = 0; + int needle_end_y = 0; + + // The length of the arc between the zero point + // and where the needle is pointing at. + int needle_offset = 0; + + // The angle between the zero point and the position + // that the needle is drawn on. + float needle_angle = 0.0; + + // The angle where to start drawing the half circle and where to end. + // This depends on the orientation of the circle (left, right, up, down). + float circle_startangle = 0.0; + float circle_endangle = 0.0; + + // Avoid divison by zero. + if(hud_speed2_radius->value <= 0) + { + return; + } + + // Get the velocity. +#ifdef HAXX + if (cl.players[cl.playernum].spectator && Cam_TrackNum() >= 0) + { + velocity = cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK].playerstate[Cam_TrackNum()].velocity; + } + else +#endif + { + velocity = cl.simvel; + } + + // Calculate the speed + if (!hud_speed2_xyz->value) + { + // Based on XY. + player_speed = sqrt(velocity[0]*velocity[0] + + velocity[1]*velocity[1]); + } + else + { + // Based on XYZ. + player_speed = sqrt(velocity[0]*velocity[0] + + velocity[1]*velocity[1] + + velocity[2]*velocity[2]); + } + + // Set the color based on the wrap speed. + switch ((int)(player_speed / hud_speed2_wrapspeed->value)) + { + case 0: + color1 = hud_speed2_color_stopped->ival; + color2 = hud_speed2_color_normal->ival; + break; + case 1: + color1 = hud_speed2_color_normal->ival; + color2 = hud_speed2_color_fast->ival; + break; + case 2: + color1 = hud_speed2_color_fast->ival; + color2 = hud_speed2_color_fastest->ival; + break; + default: + color1 = hud_speed2_color_fastest->ival; + color2 = hud_speed2_color_insane->ival; + break; + } + + // Set some properties how to draw the half circle, needle and text + // based on the orientation of the hud item. + switch((int)hud_speed2_orientation->value) + { + case HUD_SPEED2_ORIENTATION_LEFT : + { + x += width; + y += height / 2; + circle_startangle = M_PI / 2.0; + circle_endangle = (3*M_PI) / 2.0; + + text_x = x - 32; + text_y = y - 4; + break; + } + case HUD_SPEED2_ORIENTATION_RIGHT : + { + y += height / 2; + circle_startangle = (3*M_PI) / 2.0; + circle_endangle = (5*M_PI) / 2.0; + needle_end_y = y + hud_speed2_radius->value * sin (needle_angle); + + text_x = x; + text_y = y - 4; + break; + } + case HUD_SPEED2_ORIENTATION_DOWN : + { + x += width / 2; + circle_startangle = M_PI; + circle_endangle = 2*M_PI; + needle_end_y = y + hud_speed2_radius->value * sin (needle_angle); + + text_x = x - 16; + text_y = y; + break; + } + case HUD_SPEED2_ORIENTATION_UP : + default : + { + x += width / 2; + y += height; + circle_startangle = 0; + circle_endangle = M_PI; + needle_end_y = y - hud_speed2_radius->value * sin (needle_angle); + + text_x = x - 16; + text_y = y - 8; + break; + } + } + + // + // Calculate the offsets and angles. + // + { + // Calculate the arc length of the half circle background. + arc_length = fabs((circle_endangle - circle_startangle) * hud_speed2_radius->value); + + // Calculate the angle where the speed needle should point. + needle_offset = arc_length * (player_speed % Q_rint(hud_speed2_wrapspeed->value)) / Q_rint(hud_speed2_wrapspeed->value); + needle_angle = needle_offset / hud_speed2_radius->value; + + // Draw from the center of the half circle. + needle_start_x = x; + needle_start_y = y; + } + + // Set the needle end point depending on the orientation of the hud item. + + switch((int)hud_speed2_orientation->value) + { + case HUD_SPEED2_ORIENTATION_LEFT : + { + needle_end_x = x - hud_speed2_radius->value * sin (needle_angle); + needle_end_y = y + hud_speed2_radius->value * cos (needle_angle); + break; + } + case HUD_SPEED2_ORIENTATION_RIGHT : + { + needle_end_x = x + hud_speed2_radius->value * sin (needle_angle); + needle_end_y = y - hud_speed2_radius->value * cos (needle_angle); + break; + } + case HUD_SPEED2_ORIENTATION_DOWN : + { + needle_end_x = x + hud_speed2_radius->value * cos (needle_angle); + needle_end_y = y + hud_speed2_radius->value * sin (needle_angle); + break; + } + case HUD_SPEED2_ORIENTATION_UP : + default : + { + needle_end_x = x - hud_speed2_radius->value * cos (needle_angle); + needle_end_y = y - hud_speed2_radius->value * sin (needle_angle); + break; + } + } + +#ifdef HAXX + // Draw the speed-o-meter background. + Draw_AlphaPieSlice (x, y, // Position + hud_speed2_radius->value, // Radius + circle_startangle, // Start angle + circle_endangle - needle_angle, // End angle + 1, // Thickness + true, // Fill + color1, // Color + hud_speed2_opacity->value); // Opacity + + // Draw a pie slice that shows the "color" of the speed. + Draw_AlphaPieSlice (x, y, // Position + hud_speed2_radius->value, // Radius + circle_endangle - needle_angle, // Start angle + circle_endangle, // End angle + 1, // Thickness + true, // Fill + color2, // Color + hud_speed2_opacity->value); // Opacity + + // Draw the "needle attachment" circle. + Draw_AlphaCircle (x, y, 2.0, 1, true, 15, hud_speed2_opacity->value); + + // Draw the speed needle. + Draw_AlphaLineRGB (needle_start_x, needle_start_y, needle_end_x, needle_end_y, 1, RGBA_TO_COLOR(250, 250, 250, 255 * hud_speed2_opacity->value)); +#else + (void)color1; + (void)color2; + (void)needle_start_x; + (void)needle_start_y; + (void)needle_end_x; + (void)needle_end_y; +#endif + + // Draw the speed. + Draw_String (text_x, text_y, va("%d", player_speed)); + } +} + +// ======================================================= +// +// s t a t u s b a r e l e m e n t s +// +// + + +// ----------- +// gunz +// +void SCR_HUD_DrawGunByNum (hud_t *hud, int num, float scale, int style, int wide) +{ + int i = num - 2; + int width, height; + int x, y; + char *tmp; + + scale = max(scale, 0.01); + + switch (style) + { + case 3: // opposite colors of case 1 + case 1: // text, gold inactive, white active + width = 16 * scale; + height = 8 * scale; + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + if ( HUD_Stats(STAT_ITEMS) & (IT_SHOTGUN<= 10) + { + if ( HUD_Stats(STAT_ACTIVEWEAPON) == (IT_SHOTGUN<value, style->value, 0); +} +void SCR_HUD_DrawGun3 (hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawGunByNum (hud, 3, scale->value, style->value, 0); +} +void SCR_HUD_DrawGun4 (hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawGunByNum (hud, 4, scale->value, style->value, 0); +} +void SCR_HUD_DrawGun5 (hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawGunByNum (hud, 5, scale->value, style->value, 0); +} +void SCR_HUD_DrawGun6 (hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawGunByNum (hud, 6, scale->value, style->value, 0); +} +void SCR_HUD_DrawGun7 (hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawGunByNum (hud, 7, scale->value, style->value, 0); +} +void SCR_HUD_DrawGun8 (hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *wide; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + wide = HUD_FindVar(hud, "wide"); + } + SCR_HUD_DrawGunByNum (hud, 8, scale->value, style->value, wide->value); +} +void SCR_HUD_DrawGunCurrent (hud_t *hud) +{ + int gun; + static cvar_t *scale = NULL, *style, *wide; + + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + wide = HUD_FindVar(hud, "wide"); + } + + if (ShowPreselectedWeap()) { + // using weapon pre-selection so show info for current best pre-selected weapon + gun = IN_BestWeapon(); + if (gun < 2) { + return; + } + } else { + // not using weapon pre-selection or player is dead so show current selected weapon + switch (HUD_Stats(STAT_ACTIVEWEAPON)) + { + case IT_SHOTGUN << 0: gun = 2; break; + case IT_SHOTGUN << 1: gun = 3; break; + case IT_SHOTGUN << 2: gun = 4; break; + case IT_SHOTGUN << 3: gun = 5; break; + case IT_SHOTGUN << 4: gun = 6; break; + case IT_SHOTGUN << 5: gun = 7; break; + case IT_SHOTGUN << 6: gun = 8; break; + default: return; + } + } + + SCR_HUD_DrawGunByNum (hud, gun, scale->value, style->value, wide->value); +} + +// ---------------- +// powerzz +// +void SCR_HUD_DrawPowerup(hud_t *hud, int num, float scale, int style) +{ + int x, y, width, height; + int c; + + scale = max(scale, 0.01); + + switch (style) + { + case 1: // letter + width = height = 8 * scale; + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + if (HUD_Stats(STAT_ITEMS) & (1<<(17+num))) + { + switch (num) + { + case 0: c = '1'; break; + case 1: c = '2'; break; + case 2: c = 'r'; break; + case 3: c = 'p'; break; + case 4: c = 's'; break; + case 5: c = 'q'; break; + default: c = '?'; + } + Draw_SCharacter(x, y, c, scale); + } + break; + default: // classic - pics + width = height = scale * 16; + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + if (HUD_Stats(STAT_ITEMS) & (1<<(17+num))) + Draw_SPic (x, y, sb_items[num], scale); + break; + } +} + +void SCR_HUD_DrawKey1(hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawPowerup(hud, 0, scale->value, style->value); +} +void SCR_HUD_DrawKey2(hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawPowerup(hud, 1, scale->value, style->value); +} +void SCR_HUD_DrawRing(hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawPowerup(hud, 2, scale->value, style->value); +} +void SCR_HUD_DrawPent(hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawPowerup(hud, 3, scale->value, style->value); +} +void SCR_HUD_DrawSuit(hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawPowerup(hud, 4, scale->value, style->value); +} +void SCR_HUD_DrawQuad(hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawPowerup(hud, 5, scale->value, style->value); +} + +// ----------- +// sigils +// +void SCR_HUD_DrawSigil(hud_t *hud, int num, float scale, int style) +{ + int x, y; + + scale = max(scale, 0.01); + + switch (style) + { + case 1: // sigil number + if (!HUD_PrepareDraw(hud, 8*scale, 8*scale, &x, &y)) + return; + if (HUD_Stats(STAT_ITEMS) & (1<<(28+num))) + Draw_SCharacter(x, y, num + '0', scale); + break; + default: // classic - picture + if (!HUD_PrepareDraw(hud, 8*scale, 16*scale, &x, &y)) + return; + if (HUD_Stats(STAT_ITEMS) & (1<<(28+num))) + Draw_SPic(x, y, sb_sigil[num], scale); + break; + } +} + +void SCR_HUD_DrawSigil1(hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawSigil(hud, 0, scale->value, style->value); +} +void SCR_HUD_DrawSigil2(hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawSigil(hud, 1, scale->value, style->value); +} +void SCR_HUD_DrawSigil3(hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawSigil(hud, 2, scale->value, style->value); +} +void SCR_HUD_DrawSigil4(hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawSigil(hud, 3, scale->value, style->value); +} + +// icons - active ammo, armor, face etc.. +void SCR_HUD_DrawAmmoIcon(hud_t *hud, int num, float scale, int style) +{ + int x, y, width, height; + + scale = max(scale, 0.01); + + width = height = (style ? 8 : 24) * scale; + + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + + if (style) + { + switch (num) + { + case 1: Draw_SAlt_String(x, y, "s", scale); break; + case 2: Draw_SAlt_String(x, y, "n", scale); break; + case 3: Draw_SAlt_String(x, y, "r", scale); break; + case 4: Draw_SAlt_String(x, y, "c", scale); break; + } + } + else + { + Draw_SPic (x, y, sb_ammo[num-1], scale); + } +} +void SCR_HUD_DrawAmmoIconCurrent (hud_t *hud) +{ + int num; + static cvar_t *scale = NULL, *style; + + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + + if (ShowPreselectedWeap()) { + // using weapon pre-selection so show info for current best pre-selected weapon ammo + if (!(num = State_AmmoNumForWeapon(IN_BestWeapon()))) + return; + } else { + // not using weapon pre-selection or player is dead so show current selected ammo + if (HUD_Stats(STAT_ITEMS) & IT_SHELLS) + num = 1; + else if (HUD_Stats(STAT_ITEMS) & IT_NAILS) + num = 2; + else if (HUD_Stats(STAT_ITEMS) & IT_ROCKETS) + num = 3; + else if (HUD_Stats(STAT_ITEMS) & IT_CELLS) + num = 4; + else if (TP_TeamFortressEngineerSpanner()) + num = 4; + else + return; + } + + SCR_HUD_DrawAmmoIcon(hud, num, scale->value, style->value); +} +void SCR_HUD_DrawAmmoIcon1 (hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawAmmoIcon(hud, 1, scale->value, style->value); +} +void SCR_HUD_DrawAmmoIcon2 (hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawAmmoIcon(hud, 2, scale->value, style->value); +} +void SCR_HUD_DrawAmmoIcon3 (hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawAmmoIcon(hud, 3, scale->value, style->value); +} +void SCR_HUD_DrawAmmoIcon4 (hud_t *hud) +{ + static cvar_t *scale = NULL, *style; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + } + SCR_HUD_DrawAmmoIcon(hud, 4, scale->value, style->value); +} + +void SCR_HUD_DrawArmorIcon(hud_t *hud) +{ + int x, y, width, height; + + int style; + float scale; + + static cvar_t *v_scale = NULL, *v_style; + if (v_scale == NULL) // first time called + { + v_scale = HUD_FindVar(hud, "scale"); + v_style = HUD_FindVar(hud, "style"); + } + + scale = max(v_scale->value, 0.01); + style = (int)(v_style->value); + + width = height = (style ? 8 : 24) * scale; + + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + + if (style) + { + int c; + + if (HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY) + c = '@'; + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3) + c = 'r'; + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR2) + c = 'y'; + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1) + c = 'g'; + else return; + + c += 128; + + Draw_SCharacter(x, y, c, scale); + } + else + { + mpic_t *pic; + + if (HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY) + pic = sb_disc; + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3) + pic = sb_armor[2]; + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR2) + pic = sb_armor[1]; + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1) + pic = sb_armor[0]; + else return; + + Draw_SPic (x, y, pic, scale); + } +} + +// face +void SCR_HUD_DrawFace(hud_t *hud) +{ + int f, anim; + int x, y; + float scale; + + static cvar_t *v_scale = NULL; + if (v_scale == NULL) // first time called + { + v_scale = HUD_FindVar(hud, "scale"); + } + + scale = max(v_scale->value, 0.01); + + if (!HUD_PrepareDraw(hud, 24*scale, 24*scale, &x, &y)) + return; + + if ( (HUD_Stats(STAT_ITEMS) & (IT_INVISIBILITY | IT_INVULNERABILITY) ) + == (IT_INVISIBILITY | IT_INVULNERABILITY) ) + { + Draw_SPic (x, y, sb_face_invis_invuln, scale); + return; + } + if (HUD_Stats(STAT_ITEMS) & IT_QUAD) + { + Draw_SPic (x, y, sb_face_quad, scale); + return; + } + if (HUD_Stats(STAT_ITEMS) & IT_INVISIBILITY) + { + Draw_SPic (x, y, sb_face_invis, scale); + return; + } + if (HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY) + { + Draw_SPic (x, y, sb_face_invuln, scale); + return; + } + + if (HUD_Stats(STAT_HEALTH) >= 100) + f = 4; + else + f = max(0, HUD_Stats(STAT_HEALTH)) / 20; + + if (cl.time <= cl.faceanimtime) + anim = 1; + else + anim = 0; + Draw_SPic (x, y, sb_faces[f][anim], scale); +} + + +// status numbers +void SCR_HUD_DrawNum(hud_t *hud, int num, qbool low, + float scale, int style, int digits, char *s_align) +{ + int i; + char buf[sizeof(int) * 3]; // each byte need <= 3 chars + int len; + + int width, height, x, y; + int size; + int align; + + clamp(num, -99999, 999999); + + scale = max(scale, 0.01); + + if (digits > 0) + clamp(digits, 1, 6); + else + digits = 0; // auto-resize + + align = 2; + switch (tolower(s_align[0])) + { + default: + case 'l': // 'l'eft + align = 0; break; + case 'c': // 'c'enter + align = 1; break; + case 'r': // 'r'ight + align = 2; break; + } + + snprintf(buf, sizeof (buf), "%d", (style == 2 || style == 3) ? num : abs(num)); + + if(digits) + { + switch (hud_digits_trim->ival) + { + case 0: // 10030 -> 999 + len = strlen(buf); + if (len > digits) + { + char *p = buf; + if(num < 0) + *p++ = '-'; + for (i = (num < 0) ? 1 : 0 ; i < digits; i++) + *p++ = '9'; + *p = 0; + len = digits; + } + break; + default: + case 1: // 10030 -> 030 + len = strlen(buf); + if(len > digits) + { + char *p = buf; + memmove(p, p + (len - digits), digits); + buf[digits] = '\0'; + len = strlen(buf); + } + break; + case 2: // 10030 -> 100 + buf[digits] = '\0'; + len = strlen(buf); + break; + } + } + else + { + len = strlen(buf); + } + + switch (style) + { + case 1: + case 3: + size = 8; + break; + case 0: + case 2: + default: + size = 24; + break; + } + + if(digits) + width = digits * size; + else + width = size * len; + + height = size; + + switch (style) + { + case 1: + case 3: + if (!HUD_PrepareDraw(hud, scale*width, scale*height, &x, &y)) + return; + switch (align) + { + case 0: break; + case 1: x += scale * (width - size * len) / 2; break; + case 2: x += scale * (width - size * len); break; + } + if (low) + Draw_SAlt_String(x, y, buf, scale); + else + Draw_SString(x, y, buf, scale); + break; + + case 0: + case 2: + default: + if (!HUD_PrepareDraw(hud, scale*width, scale*height, &x, &y)) + return; + switch (align) + { + case 0: break; + case 1: x += scale * (width - size * len) / 2; break; + case 2: x += scale * (width - size * len); break; + } + for (i = 0; i < len; i++) + { + if(buf[i] == '-' && style == 2) + { + Draw_STransPic (x, y, sb_nums[low ? 1 : 0][STAT_MINUS], scale); + x += 24 * scale; + } + else + { + Draw_STransPic (x, y, sb_nums[low ? 1 : 0][buf[i] - '0'], scale); + x += 24 * scale; + } + } + break; + } +} + +void SCR_HUD_DrawHealth(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *digits, *align; + static int value; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + } + value = HUD_Stats(STAT_HEALTH); + SCR_HUD_DrawNum(hud, (value < 0 ? 0 : value), HUD_HealthLow(), + scale->value, style->value, digits->value, align->string); +} + +void SCR_HUD_DrawArmor(hud_t *hud) +{ + int level; + qbool low; + static cvar_t *scale = NULL, *style, *digits, *align, *pent_666; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + pent_666 = HUD_FindVar(hud, "pent_666"); // Show 666 or armor value when carrying pentagram + } + + if (HUD_Stats(STAT_HEALTH) > 0) + { + if ((HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY) && pent_666->ival) + { + level = 666; + low = true; + } + else + { + level = HUD_Stats(STAT_ARMOR); + low = HUD_ArmorLow(); + } + } + else + { + level = 0; + low = true; + } + + SCR_HUD_DrawNum(hud, level, low, + scale->value, style->value, digits->value, align->string); +} + +//void Draw_AMFStatLoss (int stat, hud_t* hud); static int vxdamagecount, vxdamagecount_time, vxdamagecount_oldhealth; -static int vxdamagecountarmour, vxdamagecountarmour_time, vxdamagecountarmour_oldhealth; -void Amf_Reset_DamageStats(void) -{ +static int vxdamagecountarmour, vxdamagecountarmour_time, vxdamagecountarmour_oldhealth; +void Amf_Reset_DamageStats(void) +{ vxdamagecount = vxdamagecount_time = vxdamagecount_oldhealth = 0; - vxdamagecountarmour = vxdamagecountarmour_time = vxdamagecountarmour_oldhealth = 0; -} + vxdamagecountarmour = vxdamagecountarmour_time = vxdamagecountarmour_oldhealth = 0; +} void Draw_AMFStatLoss (int stat, hud_t* hud) { //fixme: should reset these on pov change int * vxdmgcnt, * vxdmgcnt_t, * vxdmgcnt_o; @@ -2328,3120 +2328,3120 @@ void Draw_AMFStatLoss (int stat, hud_t* hud) { scale[elem]->value, style[elem]->value, digits[elem]->ival, align[elem]->string); } pDraw_Colour4f(1,1,1,1); -} - -static void SCR_HUD_DrawHealthDamage(hud_t *hud) -{ - Draw_AMFStatLoss (STAT_HEALTH, hud); - if (HUD_Stats(STAT_HEALTH) <= 0) - { - Amf_Reset_DamageStats(); - } -} - -static void SCR_HUD_DrawArmorDamage(hud_t *hud) -{ - Draw_AMFStatLoss (STAT_ARMOR, hud); -} - -void SCR_HUD_DrawAmmo(hud_t *hud, int num, - float scale, int style, int digits, char *s_align) -{ - int value, num_old; - qbool low; - - num_old = num; - if (num < 1 || num > 4) - { // draw 'current' ammo, which one is it? - - if (ShowPreselectedWeap()) { - // using weapon pre-selection so show info for current best pre-selected weapon ammo - if (!(num = State_AmmoNumForWeapon(IN_BestWeapon()))) - return; - } else { - // not using weapon pre-selection or player is dead so show current selected ammo - if (HUD_Stats(STAT_ITEMS) & IT_SHELLS) - num = 1; - else if (HUD_Stats(STAT_ITEMS) & IT_NAILS) - num = 2; - else if (HUD_Stats(STAT_ITEMS) & IT_ROCKETS) - num = 3; - else if (HUD_Stats(STAT_ITEMS) & IT_CELLS) - num = 4; - else if (TP_TeamFortressEngineerSpanner()) - num = 4; - else - return; - } - } - - low = HUD_AmmoLowByWeapon(num * 2); - if (num_old == 0 && (!ShowPreselectedWeap() || cl.standby)) { - // this check is here to display a feature from KTPRO/KTX where you can see received damage in prewar - // also we make sure this applies only to 'ammo' element - // weapon preselection must always use HUD_Stats() - value = cl.stats[STAT_AMMO]; - } else { - value = HUD_Stats(STAT_SHELLS + num - 1); - } - - if (style < 2) - { - // simply draw number - SCR_HUD_DrawNum(hud, value, low, scale, style, digits, s_align); - } - else - { - // else - draw classic ammo-count box with background - char buf[8]; - int x, y; - - scale = max(scale, 0.01); - - if (!HUD_PrepareDraw(hud, 42*scale, 11*scale, &x, &y)) - return; - - snprintf (buf, sizeof (buf), "%3i", value); - Draw_SSubPic(x, y, sb_ibar, 3+((num-1)*48), 0, 42, 11, scale); - if (buf[0] != ' ') Draw_SCharacter (x + 7*scale, y, 18+buf[0]-'0', scale); - if (buf[1] != ' ') Draw_SCharacter (x + 15*scale, y, 18+buf[1]-'0', scale); - if (buf[2] != ' ') Draw_SCharacter (x + 23*scale, y, 18+buf[2]-'0', scale); - } -} - -void SCR_HUD_DrawAmmoCurrent(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *digits, *align; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - } - SCR_HUD_DrawAmmo(hud, 0, scale->value, style->value, digits->value, align->string); -} -void SCR_HUD_DrawAmmo1(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *digits, *align; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - } - SCR_HUD_DrawAmmo(hud, 1, scale->value, style->value, digits->value, align->string); -} -void SCR_HUD_DrawAmmo2(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *digits, *align; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - } - SCR_HUD_DrawAmmo(hud, 2, scale->value, style->value, digits->value, align->string); -} -void SCR_HUD_DrawAmmo3(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *digits, *align; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - } - SCR_HUD_DrawAmmo(hud, 3, scale->value, style->value, digits->value, align->string); -} -void SCR_HUD_DrawAmmo4(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *digits, *align; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - } - SCR_HUD_DrawAmmo(hud, 4, scale->value, style->value, digits->value, align->string); -} - -// Problem icon, Net - -static void SCR_HUD_NetProblem (hud_t *hud) { - static cvar_t *scale = NULL; - int x, y; - extern qbool hud_editor; - vmnetinfo_t *netinfo = GetNetworkInfo(); - - float picwidth = 64; - float picheight = 64; - pDraw_ImageSize((intptr_t)sb_net, &picwidth, &picheight); - - if(scale == NULL) - scale = HUD_FindVar(hud, "scale"); - - if (netinfo->loss.dropped < 1) - { - if (hud_editor) - HUD_PrepareDraw(hud, picwidth, picheight, &x, &y); - return; - } - - if (!HUD_PrepareDraw(hud, picwidth, picheight, &x, &y)) - return; - - Draw_SPic (x, y, sb_net, scale->value); -} - -// ============================================================================0 -// Groups -// ============================================================================0 - -mpic_t *hud_pic_group1; -mpic_t *hud_pic_group2; -mpic_t *hud_pic_group3; -mpic_t *hud_pic_group4; -mpic_t *hud_pic_group5; -mpic_t *hud_pic_group6; -mpic_t *hud_pic_group7; -mpic_t *hud_pic_group8; -mpic_t *hud_pic_group9; - -void SCR_HUD_DrawGroup(hud_t *hud, int width, int height, mpic_t *pic, int pic_scalemode, float pic_alpha) -{ - #define HUD_GROUP_SCALEMODE_TILE 1 - #define HUD_GROUP_SCALEMODE_STRETCH 2 - #define HUD_GROUP_SCALEMODE_GROW 3 - #define HUD_GROUP_SCALEMODE_CENTER 4 - - int x, y; - - float picwidth = 64; - float picheight = 64; - - if (pic && pDraw_ImageSize((intptr_t)pic, &picwidth, &picheight) <= 0) - { - pic = NULL; - picwidth = 64; - picheight = 64; - } - - clamp(width, 1, 99999); - clamp(height, 1, 99999); - - // Set it to this, because 1.0 will make the colors - // completly saturated, and no semi-transparency will show. - pic_alpha = (pic_alpha) >= 1.0 ? 0.99 : pic_alpha; - - // Grow the group if necessary. - if (pic_scalemode == HUD_GROUP_SCALEMODE_GROW - && pic != NULL && picheight > 0 && picwidth > 0) - { - width = max(picwidth, width); - height = max(picheight, height); - } - - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - { - return; - } - - // Draw the picture if it's set. - if (pic != NULL && picheight > 0) - { - int pw, ph; - - if (pic_scalemode == HUD_GROUP_SCALEMODE_TILE) - { - // Tile. - int cx = 0, cy = 0; - while (cy < height) - { - while (cx < width) - { - pw = min(picwidth, width - cx); - ph = min(picheight, height - cy); - - if (pw >= picwidth && ph >= picheight) - { - Draw_AlphaPic (x + cx , y + cy, pic, pic_alpha); - } - else - { - Draw_AlphaSubPic (x + cx, y + cy, pic, 0, 0, pw, ph, pic_alpha); - } - - cx += picwidth; - } - - cx = 0; - cy += picheight; - } - } - else if (pic_scalemode == HUD_GROUP_SCALEMODE_STRETCH) - { - // Stretch or shrink the picture to fit. - float scale_x = (float)width / picwidth; - float scale_y = (float)height / picheight; - - Draw_SAlphaSubPic2 (x, y, pic, 0, 0, picwidth, picheight, scale_x, scale_y, pic_alpha); - } - else if (pic_scalemode == HUD_GROUP_SCALEMODE_CENTER) - { - // Center the picture in the group. - int pic_x = x + (width - picwidth) / 2; - int pic_y = y + (height - picheight) / 2; - - int src_x = 0; - int src_y = 0; - - if(x > pic_x) - { - src_x = x - pic_x; - pic_x = x; - } - - if(y > pic_y) - { - src_y = y - pic_y; - pic_y = y; - } - - Draw_AlphaSubPic (pic_x, pic_y, pic, src_x, src_y, min(width, picwidth), min(height, picheight), pic_alpha); - } - else - { - // Normal. Draw in the top left corner. - Draw_AlphaSubPic (x, y, pic, 0, 0, min(width, picwidth), min(height, picheight), pic_alpha); - } - } -} - -void SCR_HUD_LoadGroupPic(cvar_t *var, mpic_t **hud_pic, char *oldval) -{ - char *newpic = var->string; - #define HUD_GROUP_PIC_BASEPATH "gfx/%s" - - mpic_t *temp_pic = NULL; - char pic_path[MAX_QPATH]; - - if (!hud_pic) - { - Com_Printf ("Couldn't load picture %s for hud group. HUD PIC is null\n", newpic); - return; - } - - // If we have no pic name. - if(!newpic || !strcmp (newpic, "")) - { - *hud_pic = NULL; - return; - } - - // Get the path for the pic. - snprintf (pic_path, sizeof(pic_path), HUD_GROUP_PIC_BASEPATH, newpic); - - // Try loading the pic. - if (!(temp_pic = Draw_CachePicSafe(pic_path, false, true))) - { - Com_Printf("Couldn't load picture %s for hud group.\n", newpic); - pCvar_SetString(var->name, ""); - return; - } - - // Save the pic. - if (hud_pic) - *hud_pic = temp_pic; - - return; -} - -void SCR_HUD_OnChangePic_Group1(cvar_t *var, char *oldval) -{ - SCR_HUD_LoadGroupPic(var, &hud_pic_group1, oldval); -} - -void SCR_HUD_OnChangePic_Group2(cvar_t *var, char *oldval) -{ - SCR_HUD_LoadGroupPic(var, &hud_pic_group2, oldval); -} - -void SCR_HUD_OnChangePic_Group3(cvar_t *var, char *oldval) -{ - SCR_HUD_LoadGroupPic(var, &hud_pic_group3, oldval); -} - -void SCR_HUD_OnChangePic_Group4(cvar_t *var, char *oldval) -{ - SCR_HUD_LoadGroupPic(var, &hud_pic_group4, oldval); -} - -void SCR_HUD_OnChangePic_Group5(cvar_t *var, char *oldval) -{ - SCR_HUD_LoadGroupPic(var, &hud_pic_group5, oldval); -} - -void SCR_HUD_OnChangePic_Group6(cvar_t *var, char *oldval) -{ - SCR_HUD_LoadGroupPic(var, &hud_pic_group6, oldval); -} - -void SCR_HUD_OnChangePic_Group7(cvar_t *var, char *oldval) -{ - SCR_HUD_LoadGroupPic(var, &hud_pic_group7, oldval); -} - -void SCR_HUD_OnChangePic_Group8(cvar_t *var, char *oldval) -{ - SCR_HUD_LoadGroupPic(var, &hud_pic_group8, oldval); -} - -void SCR_HUD_OnChangePic_Group9(cvar_t *var, char *oldval) -{ - SCR_HUD_LoadGroupPic(var, &hud_pic_group9, oldval); -} - -void SCR_HUD_Group1(hud_t *hud) -{ - static cvar_t *width = NULL, - *height, - *picture, - *pic_alpha, - *pic_scalemode; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - picture = HUD_FindVar(hud, "picture"); - pic_alpha = HUD_FindVar(hud, "pic_alpha"); - pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); - - picture->callback = SCR_HUD_OnChangePic_Group1; - SCR_HUD_LoadGroupPic(picture, &hud_pic_group1, picture->string); - } - - SCR_HUD_DrawGroup(hud, - width->value, - height->value, - hud_pic_group1, - pic_scalemode->value, - pic_alpha->value); -} - -void SCR_HUD_Group2(hud_t *hud) -{ - extern void DrawNewText(int x, int y, char *text); - static cvar_t *width = NULL, - *height, - *picture, - *pic_alpha, - *pic_scalemode; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - picture = HUD_FindVar(hud, "picture"); - pic_alpha = HUD_FindVar(hud, "pic_alpha"); - pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); - - picture->callback = SCR_HUD_OnChangePic_Group2; - SCR_HUD_LoadGroupPic(picture, &hud_pic_group2, picture->string); - } - - SCR_HUD_DrawGroup(hud, - width->value, - height->value, - hud_pic_group2, - pic_scalemode->value, - pic_alpha->value); -} - -void SCR_HUD_Group3(hud_t *hud) -{ - static cvar_t *width = NULL, - *height, - *picture, - *pic_alpha, - *pic_scalemode; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - picture = HUD_FindVar(hud, "picture"); - pic_alpha = HUD_FindVar(hud, "pic_alpha"); - pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); - - picture->callback = SCR_HUD_OnChangePic_Group3; - SCR_HUD_LoadGroupPic(picture, &hud_pic_group3, picture->string); - } - - SCR_HUD_DrawGroup(hud, - width->value, - height->value, - hud_pic_group3, - pic_scalemode->value, - pic_alpha->value); -} - -void SCR_HUD_Group4(hud_t *hud) -{ - static cvar_t *width = NULL, - *height, - *picture, - *pic_alpha, - *pic_scalemode; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - picture = HUD_FindVar(hud, "picture"); - pic_alpha = HUD_FindVar(hud, "pic_alpha"); - pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); - - picture->callback = SCR_HUD_OnChangePic_Group4; - SCR_HUD_LoadGroupPic(picture, &hud_pic_group4, picture->string); - } - - SCR_HUD_DrawGroup(hud, - width->value, - height->value, - hud_pic_group4, - pic_scalemode->value, - pic_alpha->value); -} - -void SCR_HUD_Group5(hud_t *hud) -{ - static cvar_t *width = NULL, - *height, - *picture, - *pic_alpha, - *pic_scalemode; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - picture = HUD_FindVar(hud, "picture"); - pic_alpha = HUD_FindVar(hud, "pic_alpha"); - pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); - - picture->callback = SCR_HUD_OnChangePic_Group5; - SCR_HUD_LoadGroupPic(picture, &hud_pic_group5, picture->string); - } - - SCR_HUD_DrawGroup(hud, - width->value, - height->value, - hud_pic_group5, - pic_scalemode->value, - pic_alpha->value); -} - -void SCR_HUD_Group6(hud_t *hud) -{ - static cvar_t *width = NULL, - *height, - *picture, - *pic_alpha, - *pic_scalemode; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - picture = HUD_FindVar(hud, "picture"); - pic_alpha = HUD_FindVar(hud, "pic_alpha"); - pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); - - picture->callback = SCR_HUD_OnChangePic_Group6; - SCR_HUD_LoadGroupPic(picture, &hud_pic_group6, picture->string); - } - - SCR_HUD_DrawGroup(hud, - width->value, - height->value, - hud_pic_group6, - pic_scalemode->value, - pic_alpha->value); -} - -void SCR_HUD_Group7(hud_t *hud) -{ - static cvar_t *width = NULL, - *height, - *picture, - *pic_alpha, - *pic_scalemode; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - picture = HUD_FindVar(hud, "picture"); - pic_alpha = HUD_FindVar(hud, "pic_alpha"); - pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); - - picture->callback = SCR_HUD_OnChangePic_Group7; - SCR_HUD_LoadGroupPic(picture, &hud_pic_group7, picture->string); - } - - SCR_HUD_DrawGroup(hud, - width->value, - height->value, - hud_pic_group7, - pic_scalemode->value, - pic_alpha->value); -} - -void SCR_HUD_Group8(hud_t *hud) -{ - static cvar_t *width = NULL, - *height, - *picture, - *pic_alpha, - *pic_scalemode; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - picture = HUD_FindVar(hud, "picture"); - pic_alpha = HUD_FindVar(hud, "pic_alpha"); - pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); - - picture->callback = SCR_HUD_OnChangePic_Group8; - SCR_HUD_LoadGroupPic(picture, &hud_pic_group8, picture->string); - } - - SCR_HUD_DrawGroup(hud, - width->value, - height->value, - hud_pic_group8, - pic_scalemode->value, - pic_alpha->value); -} - -void SCR_HUD_Group9(hud_t *hud) -{ - static cvar_t *width = NULL, - *height, - *picture, - *pic_alpha, - *pic_scalemode; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - picture = HUD_FindVar(hud, "picture"); - pic_alpha = HUD_FindVar(hud, "pic_alpha"); - pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); - - picture->callback = SCR_HUD_OnChangePic_Group9; - SCR_HUD_LoadGroupPic(picture, &hud_pic_group9, picture->string); - } - - SCR_HUD_DrawGroup(hud, - width->value, - height->value, - hud_pic_group9, - pic_scalemode->value, - pic_alpha->value); -} - -// player sorting -// for frags and players -typedef struct sort_teams_info_s -{ - char *name; - int frags; - int min_ping; - int avg_ping; - int max_ping; - int nplayers; - int top, bottom; // leader colours - int rlcount; // Number of RL's present in the team. (Cokeman 2006-05-27) -} -sort_teams_info_t; - -typedef struct sort_players_info_s -{ - int playernum; - sort_teams_info_t *team; -} -sort_players_info_t; - -static sort_players_info_t sorted_players[MAX_CLIENTS]; -static sort_teams_info_t sorted_teams[MAX_CLIENTS]; -static int n_teams; -static int n_players; -static int n_spectators; -static int sort_teamsort = 0; - -static int HUD_ComparePlayers(const void *vp1, const void *vp2) -{ - const sort_players_info_t *p1 = vp1; - const sort_players_info_t *p2 = vp2; - - int r = 0; - player_info_t *i1 = &cl.players[p1->playernum]; - player_info_t *i2 = &cl.players[p2->playernum]; - - if (i1->spectator && !i2->spectator) - { - r = -1; - } - else if (!i1->spectator && i2->spectator) - { - r = 1; - } - else if (i1->spectator && i2->spectator) - { - r = strcmp(i1->name, i2->name); - } - else - { - // - // Both are players. - // - if(sort_teamsort && cl.teamplay && p1->team && p2->team) - { - // Leading team on top, sort players inside of the teams. - - // Teamsort 1, first sort on team frags. - if (sort_teamsort == 1) - { - r = p1->team->frags - p2->team->frags; - } - - // Teamsort == 2, sort on team name only. - r = (r == 0) ? -strcmp(p1->team->name, p2->team->name) : r; - } - - r = (r == 0) ? i1->frags - i2->frags : r; - r = (r == 0) ? strcmp(i1->name, i2->name) : r; - } - - r = (r == 0) ? (p1->playernum - p2->playernum) : r; - - // qsort() sorts ascending by default, we want descending. - // So negate the result. - return -r; -} - -static int HUD_CompareTeams(const void *vt1, const void *vt2) -{ - int r = 0; - const sort_teams_info_t *t1 = vt1; - const sort_teams_info_t *t2 = vt2; - - r = (t1->frags - t2->frags); - r = !r ? strcmp(t1->name, t2->name) : r; - - // qsort() sorts ascending by default, we want descending. - // So negate the result. - return -r; -} - -#define HUD_SCOREBOARD_ALL 0xffffffff -#define HUD_SCOREBOARD_SORT_TEAMS (1 << 0) -#define HUD_SCOREBOARD_SORT_PLAYERS (1 << 1) -#define HUD_SCOREBOARD_UPDATE (1 << 2) -#define HUD_SCOREBOARD_AVG_PING (1 << 3) - -static void HUD_Sort_Scoreboard(int flags) -{ - int i; - int team; - - n_teams = 0; - n_players = 0; - n_spectators = 0; - - // Set team properties. - if(flags & HUD_SCOREBOARD_UPDATE) - { - memset(sorted_teams, 0, sizeof(sorted_teams)); - - for (i=0; i < MAX_CLIENTS; i++) - { - if (cl.players[i].name[0] && !cl.players[i].spectator) - { - // Find players team - for (team = 0; team < n_teams; team++) - { - if (!strcmp(cl.players[i].team, sorted_teams[team].name) - && sorted_teams[team].name[0]) - { - break; - } - } - - // The team wasn't found in the list of existing teams - // so add a new team. - if (team == n_teams) - { - team = n_teams++; - sorted_teams[team].avg_ping = 0; - sorted_teams[team].max_ping = 0; - sorted_teams[team].min_ping = 999; - sorted_teams[team].nplayers = 0; - sorted_teams[team].frags = 0; - sorted_teams[team].top = Sbar_TopColor(&cl.players[i]); - sorted_teams[team].bottom = Sbar_BottomColor(&cl.players[i]); - sorted_teams[team].name = cl.players[i].team; - sorted_teams[team].rlcount = 0; - } - - sorted_teams[team].nplayers++; - sorted_teams[team].frags += cl.players[i].frags; - sorted_teams[team].avg_ping += cl.players[i].ping; - sorted_teams[team].min_ping = min(sorted_teams[team].min_ping, cl.players[i].ping); - sorted_teams[team].max_ping = max(sorted_teams[team].max_ping, cl.players[i].ping); - -#ifdef HAXX - // The total RL count for the players team. - if(cl.players[i].stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER) - { - sorted_teams[team].rlcount++; - } -#endif - - // Set player data. - sorted_players[n_players + n_spectators].playernum = i; - //sorted_players[n_players + n_spectators].team = &sorted_teams[team]; - - // Increase the count. - if (cl.players[i].spectator) - { - n_spectators++; - } - else - { - n_players++; - } - } - } - } - - // Calc avg ping. - if(flags & HUD_SCOREBOARD_AVG_PING) - { - for (team = 0; team < n_teams; team++) - { - sorted_teams[team].avg_ping /= sorted_teams[team].nplayers; - } - } - - // Sort teams. - if(flags & HUD_SCOREBOARD_SORT_TEAMS) - { - qsort(sorted_teams, n_teams, sizeof(sort_teams_info_t), HUD_CompareTeams); - - // BUGFIX, this needs to happen AFTER the team array has been sorted, otherwise the - // players might be pointing to the incorrect team adress. - for (i = 0; i < MAX_CLIENTS; i++) - { - player_info_t *player = &cl.players[sorted_players[i].playernum]; - sorted_players[i].team = NULL; - - // Find players team. - for (team = 0; team < n_teams; team++) - { - if (!strcmp(player->team, sorted_teams[team].name) - && sorted_teams[team].name[0]) - { - sorted_players[i].team = &sorted_teams[team]; - break; - } - } - } - } - - // Sort players. - if(flags & HUD_SCOREBOARD_SORT_PLAYERS) - { - qsort(sorted_players, n_players + n_spectators, sizeof(sort_players_info_t), HUD_ComparePlayers); - } -} - -void Frags_DrawColors(int x, int y, int width, int height, - int top_color, int bottom_color, float color_alpha, - int frags, int drawBrackets, int style, - float bignum) -{ - char buf[32]; - int posy = 0; - int char_size = (bignum > 0) ? Q_rint(24 * bignum) : 8; - - Draw_AlphaFill(x, y, width, height / 2, top_color, color_alpha); - Draw_AlphaFill(x, y + height / 2, width, height - height / 2, bottom_color, color_alpha); - - posy = y + (height - char_size) / 2; - - if (bignum > 0) - { - // - // Scaled big numbers for frags. - // - char *t = buf; - int char_x; - int char_y; - snprintf(buf, sizeof (buf), "%d", frags); - - char_x = max(x, x + (width - (int)strlen(buf) * char_size) / 2); - char_y = max(y, posy); - - while (*t) - { - if (*t >= '0' && *t <= '9') - { - Draw_STransPic(char_x, char_y, sb_nums[0][*t - '0'], bignum); - char_x += char_size; - } - else if (*t == '-') - { - Draw_STransPic(char_x, char_y, sb_nums[0][STAT_MINUS], bignum); - char_x += char_size; - } - - t++; - } - } - else - { - // Normal text size. - snprintf(buf, sizeof (buf), "%3d", frags); - Draw_String(x - 2 + (width - char_size * strlen(buf) - 2) / 2, posy, buf); - } - - if(drawBrackets) - { - // Brackets [] are not available scaled, so use normal size even - // if we're drawing big frag nums. - int brack_posy = y + (height - 8) / 2; - int d = (width >= 32) ? 0 : 1; - - switch(style) - { - case 1 : - Draw_Character(x - 8, posy, 13); - break; - case 2 : - // Red outline. - Draw_Fill(x, y - 1, width, 1, 0x4f); - Draw_Fill(x, y - 1, 1, height + 2, 0x4f); - Draw_Fill(x + width - 1, y - 1, 1, height + 2, 0x4f); - Draw_Fill(x, y + height, width, 1, 0x4f); - break; - case 0 : - default : - Draw_Character(x - 2 - 2 * d, brack_posy, 16); // [ - Draw_Character(x + width - 8 + 1 + d, brack_posy, 17); // ] - break; - } - } -} - -#define FRAGS_HEALTHBAR_WIDTH 5 - -#define FRAGS_HEALTHBAR_NORMAL_COLOR 75 -#define FRAGS_HEALTHBAR_MEGA_COLOR 251 -#define FRAGS_HEALTHBAR_TWO_MEGA_COLOR 238 -#define FRAGS_HEALTHBAR_UNNATURAL_COLOR 144 - -void Frags_DrawHealthBar(int original_health, int x, int y, int height, int width) -{ - float health_height = 0.0; - int health; - - // Get the health. - health = original_health; - health = min(100, health); - - // Draw a health bar. - health_height = Q_rint((height / 100.0) * health); - health_height = (health_height > 0.0 && health_height < 1.0) ? 1 : health_height; - health_height = (health_height < 0.0) ? 0.0 : health_height; - Draw_Fill(x, y + height - (int)health_height, 3, (int)health_height, FRAGS_HEALTHBAR_NORMAL_COLOR); - - // Get the health again to check if health is more than 100. - health = original_health; - if(health > 100 && health <= 200) - { - health_height = (int)Q_rint((height / 100.0) * (health - 100)); - Draw_Fill(x, y + height - health_height, width, health_height, FRAGS_HEALTHBAR_MEGA_COLOR); - } - else if(health > 200 && health <= 250) - { - health_height = (int)Q_rint((height / 100.0) * (health - 200)); - Draw_Fill(x, y, width, height, FRAGS_HEALTHBAR_MEGA_COLOR); - Draw_Fill(x, y + height - health_height, width, health_height, FRAGS_HEALTHBAR_TWO_MEGA_COLOR); - } - else if(health > 250) - { - // This will never happen during a normal game. - Draw_Fill(x, y, width, health_height, FRAGS_HEALTHBAR_UNNATURAL_COLOR); - } -} - -#define TEAMFRAGS_EXTRA_SPEC_NONE 0 -#define TEAMFRAGS_EXTRA_SPEC_BEFORE 1 -#define TEAMFRAGS_EXTRA_SPEC_ONTOP 2 -#define TEAMFRAGS_EXTRA_SPEC_NOICON 3 -#define TEAMFRAGS_EXTRA_SPEC_RLTEXT 4 - -int TeamFrags_DrawExtraSpecInfo(int num, int px, int py, int width, int height, int style) -{ - float rl_width, rl_height; - mpic_t *pic = sb_weapons[0][5]; - pDraw_ImageSize((intptr_t)pic, &rl_width, &rl_height); - - // Only allow this for spectators. - if (!(cls.demoplayback || cl.spectator) - || style > TEAMFRAGS_EXTRA_SPEC_RLTEXT - || style <= TEAMFRAGS_EXTRA_SPEC_NONE - || !style) - { - return px; - } - - // Check if the team has any RL's. - if(sorted_teams[num].rlcount > 0) - { - int y_pos = py; - - // - // Draw the RL + count depending on style. - // - - if((style == TEAMFRAGS_EXTRA_SPEC_BEFORE || style == TEAMFRAGS_EXTRA_SPEC_NOICON) - && style != TEAMFRAGS_EXTRA_SPEC_RLTEXT) - { - y_pos = Q_rint(py + (height / 2.0) - 4); - Draw_ColoredString(px, y_pos, va("%d", sorted_teams[num].rlcount), 0); - px += 8 + 1; - } - - if(style != TEAMFRAGS_EXTRA_SPEC_NOICON && style != TEAMFRAGS_EXTRA_SPEC_RLTEXT) - { - y_pos = Q_rint(py + (height / 2.0) - (rl_height / 2.0)); - Draw_SSubPic (px, y_pos, pic, 0, 0, rl_width, rl_height, 1); - px += rl_width + 1; - } - - if(style == TEAMFRAGS_EXTRA_SPEC_ONTOP && style != TEAMFRAGS_EXTRA_SPEC_RLTEXT) - { - y_pos = Q_rint(py + (height / 2.0) - 4); - Draw_ColoredString(px - 14, y_pos, va("%d", sorted_teams[num].rlcount), 0); - } - - if(style == TEAMFRAGS_EXTRA_SPEC_RLTEXT) - { - y_pos = Q_rint(py + (height / 2.0) - 4); - Draw_ColoredString(px, y_pos, va("&ce00RL&cfff%d", sorted_teams[num].rlcount), 0); - px += 8*3 + 1; - } - } - else - { - // If the team has no RL's just pad with nothing. - if(style == TEAMFRAGS_EXTRA_SPEC_BEFORE) - { - // Draw the rl count before the rl icon. - px += rl_width + 8 + 1 + 1; - } - else if(style == TEAMFRAGS_EXTRA_SPEC_ONTOP) - { - // Draw the rl count on top of the RL instead of infront. - px += rl_width + 1; - } - else if(style == TEAMFRAGS_EXTRA_SPEC_NOICON) - { - // Only draw the rl count. - px += 8 + 1; - } - else if(style == TEAMFRAGS_EXTRA_SPEC_RLTEXT) - { - px += 8*3 + 1; - } - } - - return px; -} - -static qbool hud_frags_extra_spec_info = true; -static qbool hud_frags_show_rl = true; -static qbool hud_frags_show_armor = true; -static qbool hud_frags_show_health = true; -static qbool hud_frags_show_powerup = true; -static qbool hud_frags_textonly = false; - -static void QDECL Frags_OnChangeExtraSpecInfo(cvar_t *var, char *oldvalue) -{ - // Parse the extra spec info. - hud_frags_show_rl = Utils_RegExpMatch("RL|ALL", var->string); - hud_frags_show_armor = Utils_RegExpMatch("ARMOR|ALL", var->string); - hud_frags_show_health = Utils_RegExpMatch("HEALTH|ALL", var->string); - hud_frags_show_powerup = Utils_RegExpMatch("POWERUP|ALL", var->string); - hud_frags_textonly = Utils_RegExpMatch("TEXT", var->string); - - hud_frags_extra_spec_info = (hud_frags_show_rl || hud_frags_show_armor || hud_frags_show_health || hud_frags_show_powerup); -} - -static int Frags_DrawExtraSpecInfo(player_info_t *info, - int px, int py, - int cell_width, int cell_height, - int space_x, int space_y, int flip) -{ -#ifdef HAXX - mpic_t *rl_picture = sb_weapons[0][5]; // Picture of RL. - float rl_width, rl_height; - - float armor_height = 0.0; - int armor = 0; - int armor_bg_color = 0; - float armor_bg_power = 0; - int health_spacing = 1; - int weapon_width = 24; - - pDraw_ImageSize((intptr_t)rl_picture, &rl_width, &rl_height); - - // Only allow this for spectators. - if (!(cls.demoplayback || cl.spectator)) - { - return px; - } - - // Set width based on text or picture. - weapon_width = hud_frags_textonly ? rl_width : 24; - - // Draw health bar. (flipped) - if(flip && hud_frags_show_health) - { - Frags_DrawHealthBar(info->stats[STAT_HEALTH], px, py, cell_height, 3); - px += 3 + health_spacing; - } - - armor = info->stats[STAT_ARMOR]; - - // If the player has any armor, draw it in the appropriate color. - if(info->stats[STAT_ITEMS] & IT_ARMOR1) - { - armor_bg_power = 100; - armor_bg_color = 178; // Green armor. - } - else if(info->stats[STAT_ITEMS] & IT_ARMOR2) - { - armor_bg_power = 150; - armor_bg_color = 111; // Yellow armor. - } - else if(info->stats[STAT_ITEMS] & IT_ARMOR3) - { - armor_bg_power = 200; - armor_bg_color = 79; // Red armor. - } - - // Only draw the armor if the current player has one and if the style allows it. - if(armor_bg_power && hud_frags_show_armor) - { - armor_height = Q_rint((cell_height / armor_bg_power) * armor); - - Draw_AlphaFill(px, // x - py + cell_height - (int)armor_height, // y (draw from bottom up) - weapon_width, // width - (int)armor_height, // height - armor_bg_color, // color - 0.3); // alpha - } - - // Draw the rl if the current player has it and the style allows it. - if(info->stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER && hud_frags_show_rl) - { - if(!hud_frags_textonly) - { - // Draw the rl-pic. - Draw_SSubPic (px, - py + Q_rint((cell_height/2.0)) - (rl_height/2.0), - rl_picture, 0, 0, - rl_width, - rl_height, 1); - } - else - { - // Just print "RL" instead. - Draw_String(px + 12 - 8, py + Q_rint((cell_height/2.0)) - 4, "RL"); - } - } - - // Only draw powerups is the current player has it and the style allows it. - if(hud_frags_show_powerup) - { - - //float powerups_x = px + (spec_extra_weapon_w / 2.0); - float powerups_x = px + (weapon_width / 2.0); - - if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY - && info->stats[STAT_ITEMS] & IT_INVISIBILITY - && info->stats[STAT_ITEMS] & IT_QUAD) - { - Draw_ColoredString(Q_rint(powerups_x - 10), py, "&c0ffQ&cf00P&cff0R", 0); - } - else if(info->stats[STAT_ITEMS] & IT_QUAD - && info->stats[STAT_ITEMS] & IT_INVULNERABILITY) - { - Draw_ColoredString(Q_rint(powerups_x - 8), py, "&c0ffQ&cf00P", 0); - } - else if(info->stats[STAT_ITEMS] & IT_QUAD - && info->stats[STAT_ITEMS] & IT_INVISIBILITY) - { - Draw_ColoredString(Q_rint(powerups_x - 8), py, "&c0ffQ&cff0R", 0); - } - else if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY - && info->stats[STAT_ITEMS] & IT_INVISIBILITY) - { - Draw_ColoredString(Q_rint(powerups_x - 8), py, "&cf00P&cff0R", 0); - } - else if(info->stats[STAT_ITEMS] & IT_QUAD) - { - Draw_ColoredString(Q_rint(powerups_x - 4), py, "&c0ffQ", 0); - } - else if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY) - { - Draw_ColoredString(Q_rint(powerups_x - 4), py, "&cf00P", 0); - } - else if(info->stats[STAT_ITEMS] & IT_INVISIBILITY) - { - Draw_ColoredString(Q_rint(powerups_x - 4), py, "&cff0R", 0); - } - } - - px += weapon_width + health_spacing; - - // Draw health bar. (not flipped) - if(!flip && hud_frags_show_health) - { - Frags_DrawHealthBar(info->stats[STAT_HEALTH], px, py, cell_height, 3); - px += 3 + health_spacing; - } -#endif - return px; -} - -void Frags_DrawBackground(int px, int py, int cell_width, int cell_height, - int space_x, int space_y, int max_name_length, int max_team_length, - int bg_color, int shownames, int showteams, int drawBrackets, int style) -{ - int bg_width = cell_width + space_x; - //int bg_color = Sbar_BottomColor(info); - float bg_alpha = 0.3; - - if(style == 4 - || style == 6 - || style == 8) - bg_alpha = 0; - - if(shownames) - bg_width += max_name_length*8 + space_x; - - if(showteams) - bg_width += max_team_length * 8 + space_x; - - if(drawBrackets) - bg_alpha = 0.7; - - if(style == 7 || style == 8) - bg_color = 0x4f; - - Draw_AlphaFill(px - 1, py - space_y / 2, bg_width, cell_height + space_y, bg_color, bg_alpha); - - if(drawBrackets && (style == 5 || style == 6)) - { - Draw_Fill(px - 1, py - 1 - space_y / 2, bg_width, 1, 0x4f); - - Draw_Fill(px - 1, py - space_y / 2, 1, cell_height + space_y, 0x4f); - Draw_Fill(px + bg_width - 1, py - 1 - space_y / 2, 1, cell_height + 1 + space_y, 0x4f); - - Draw_Fill(px - 1, py + cell_height + space_y / 2, bg_width + 1, 1, 0x4f); - } -} - -int Frags_DrawText(int px, int py, - int cell_width, int cell_height, - int space_x, int space_y, - int max_name_length, int max_team_length, - int flip, int pad, - int shownames, int showteams, - char* name, char* team) -{ - char _name[MAX_SCOREBOARDNAME + 1]; - char _team[MAX_SCOREBOARDNAME + 1]; - int team_length = 0; - int name_length = 0; - int char_size = 8; - int y_pos; - - y_pos = Q_rint(py + (cell_height / 2.0) - 4); - - // Draw team - if(showteams && cl.teamplay) - { - strlcpy(_team, team, clamp(max_team_length, 0, sizeof(_team))); - team_length = strlen(_team); - - if(!flip) - px += space_x; - - if(pad && flip) - { - px += (max_team_length - team_length) * char_size; - Draw_String(px, y_pos, _team); - px += team_length * char_size; - } - else if(pad) - { - Draw_String(px, y_pos, _team); - px += max_team_length * char_size; - } - else - { - Draw_String(px, y_pos, _team); - px += team_length * char_size; - } - - if(flip) - px += space_x; - } - - if(shownames) - { - // Draw name - strlcpy(_name, name, clamp(max_name_length, 0, sizeof(_name))); - name_length = strlen(_name); - - if(flip && pad) - { - px += (max_name_length - name_length) * char_size; - Draw_String(px, y_pos, _name); - px += name_length * char_size; - } - else if(pad) - { - Draw_String(px, y_pos, _name); - px += max_name_length * char_size; - } - else - { - Draw_String(px, y_pos, _name); - px += name_length * char_size; - } - - px += space_x; - } - - return px; -} - -void SCR_HUD_DrawFrags(hud_t *hud) -{ - int width = 0, height = 0; - int x, y; - int max_team_length = 0; - int max_name_length = 0; - - int rows, cols, cell_width, cell_height, space_x, space_y; - int a_rows, a_cols; // actual - - static cvar_t - *hud_frags_cell_width = NULL, - *hud_frags_cell_height, - *hud_frags_rows, - *hud_frags_cols, - *hud_frags_space_x, - *hud_frags_space_y, - *hud_frags_vertical, - *hud_frags_strip, - *hud_frags_teamsort, - *hud_frags_shownames, - *hud_frags_teams, - *hud_frags_padtext, - *hud_frags_showself, - *hud_frags_extra_spec, - *hud_frags_fliptext, - *hud_frags_style, - *hud_frags_bignum, - *hud_frags_colors_alpha, - *hud_frags_maxname, - *hud_frags_notintp; - - mpic_t *rl_picture = sb_weapons[0][5]; - float rl_width, rl_height; - pDraw_ImageSize((intptr_t)rl_picture, &rl_width, &rl_height); - - if (hud_frags_cell_width == NULL) // first time - { - char specval[256]; - - hud_frags_cell_width = HUD_FindVar(hud, "cell_width"); - hud_frags_cell_height = HUD_FindVar(hud, "cell_height"); - hud_frags_rows = HUD_FindVar(hud, "rows"); - hud_frags_cols = HUD_FindVar(hud, "cols"); - hud_frags_space_x = HUD_FindVar(hud, "space_x"); - hud_frags_space_y = HUD_FindVar(hud, "space_y"); - hud_frags_teamsort = HUD_FindVar(hud, "teamsort"); - hud_frags_strip = HUD_FindVar(hud, "strip"); - hud_frags_vertical = HUD_FindVar(hud, "vertical"); - hud_frags_shownames = HUD_FindVar(hud, "shownames"); - hud_frags_teams = HUD_FindVar(hud, "showteams"); - hud_frags_padtext = HUD_FindVar(hud, "padtext"); - hud_frags_showself = HUD_FindVar(hud, "showself_always"); - hud_frags_extra_spec = HUD_FindVar(hud, "extra_spec_info"); - hud_frags_fliptext = HUD_FindVar(hud, "fliptext"); - hud_frags_style = HUD_FindVar(hud, "style"); - hud_frags_bignum = HUD_FindVar(hud, "bignum"); - hud_frags_colors_alpha = HUD_FindVar(hud, "colors_alpha"); - hud_frags_maxname = HUD_FindVar(hud, "maxname"); - hud_frags_notintp = HUD_FindVar(hud, "notintp"); - - // Set the OnChange function for extra spec info. - hud_frags_extra_spec->callback = Frags_OnChangeExtraSpecInfo; - strlcpy(specval, hud_frags_extra_spec->string, sizeof(specval)); - Cvar_Set(hud_frags_extra_spec, specval); - } - - // Don't draw the frags if we're in teamplay. - if(hud_frags_notintp->value && cl.teamplay) - { - HUD_PrepareDraw(hud, width, height, &x, &y); - return; - } - - // - // Clamp values to be "sane". - // - { - rows = hud_frags_rows->value; - clamp(rows, 1, MAX_CLIENTS); - - cols = hud_frags_cols->value; - clamp(cols, 1, MAX_CLIENTS); - - // Some users doesn't want to show the actual frags, just - // extra_spec_info stuff + names. - cell_width = hud_frags_cell_width->value; - clamp(cell_width, 0, 128); - - cell_height = hud_frags_cell_height->value; - clamp(cell_height, 7, 32); - - space_x = hud_frags_space_x->value; - clamp(space_x, 0, 128); - - space_y = hud_frags_space_y->value; - clamp(space_y, 0, 128); - } - - sort_teamsort = hud_frags_teamsort->ival; - - if (hud_frags_strip->ival) - { - // Auto set the number of rows / cols based on the number of players. - // (This is kinda fucked up, but I won't mess with it for the sake of backwards compability). - - if (hud_frags_vertical->value) - { - a_cols = min((n_players + rows - 1) / rows, cols); - a_rows = min(rows, n_players); - } - else - { - a_rows = min((n_players + cols - 1) / cols, rows); - a_cols = min(cols, n_players); - } - } - else - { - a_rows = rows; - a_cols = cols; - } - - width = (a_cols * cell_width) + ((a_cols + 1) * space_x); - height = (a_rows * cell_height) + ((a_rows + 1) * space_y); - - // Get the longest name/team name for padding. - if(hud_frags_shownames->value || hud_frags_teams->value) - { - int cur_length = 0; - int n; - - for(n = 0; n < n_players; n++) - { - player_info_t *info = &cl.players[sorted_players[n].playernum]; - cur_length = strlen(info->name); - - // Name. - if(cur_length >= max_name_length) - { - max_name_length = cur_length + 1; - } - - cur_length = strlen(info->team); - - // Team name. - if(cur_length >= max_team_length) - { - max_team_length = cur_length + 1; - } - } - - // If the user has set a limit on how many chars that - // are allowed to be shown for a name/teamname. - max_name_length = min(max(0, (int)hud_frags_maxname->value), max_name_length) + 1; - max_team_length = min(max(0, (int)hud_frags_maxname->value), max_team_length) + 1; - - // We need a wider box to draw in if we show the names. - if(hud_frags_shownames->value) - { - width += (a_cols * (max_name_length + 3) * 8) + ((a_cols + 1) * space_x); - } - - if(cl.teamplay && hud_frags_teams->value) - { - width += (a_cols * max_team_length * 8) + ((a_cols + 1) * space_x); - } - } - - // Make room for the extra spectator stuff. - if(hud_frags_extra_spec_info && (cls.demoplayback || cl.spectator) ) - { - width += a_cols * (rl_width + FRAGS_HEALTHBAR_WIDTH); - } - - if (HUD_PrepareDraw(hud, width, height, &x, &y)) - { - int i = 0; - int player_x = 0; - int player_y = 0; - int num = 0; - int drawBrackets = 0; - - // The number of players that are to be visible. - int limit = min(n_players, a_rows * a_cols); - - // Always show my current frags (don't just show the leaders). - // TODO: When all players aren't being shown in the frags, draw - // a small arrow that indicates that there are more frags to be seen. - if(hud_frags_showself->value && !cl_multiview->value) - { - int player_pos = 0; - - // Find my position in the scoreboard. - for(player_pos = 0; i < n_players; player_pos++) - { - if (cls.demoplayback || cl.spectator) - { - if (spec_track == sorted_players[player_pos].playernum) - { - break; - } - } - else if(sorted_players[player_pos].playernum == cl.playernum) - { - break; - } - } - - if(player_pos + 1 <= (a_rows * a_cols)) - { - // If I'm not "outside" the shown frags, start drawing from the top. - num = 0; - } - else - { - // Always include me in the shown frags. - num = abs((a_rows * a_cols) - (player_pos + 1)); - } - - // Make sure we're not trying to go outside the player array. - num = (num < 0 || num > n_players) ? 0 : num; - } - - //num = 0; // FIXME! johnnycz; (see fixme below) - - // - // Loop through all the positions that should be drawn (columns * rows or number of players). - // - // Start drawing player "num", usually the first player in the array, but if - // showself_always is set this might be someone else (since we need to make sure the current - // player is always shown). - // - for (i = 0; i < limit; i++) - { - player_info_t *info = &cl.players[sorted_players[num].playernum]; // FIXME! johnnycz; causes crashed on some demos - - // - // Set the coordinates where to draw the next element. - // - if (hud_frags_vertical->value) - { - if (i % a_rows == 0) - { - // We're drawing a new column. - - int element_width = cell_width + space_x; - - // Get the width of all the stuff that is shown, the name, frag cell and so on. - - if(hud_frags_shownames->value) - { - element_width += (max_name_length) * 8; - } - - if(hud_frags_teams->value) - { - element_width += (max_team_length) * 8; - } - - if(hud_frags_extra_spec_info && (cls.demoplayback || cl.spectator) ) - { - element_width += rl_width; - } - - player_x = x + space_x + ((i / a_rows) * element_width); - - // New column. - player_y = y + space_y; - } - } - else - { - if (i % a_cols == 0) - { - // Drawing new row. - player_x = x + space_x; - player_y = y + space_y + (i / a_cols) * (cell_height + space_y); - } - } - - drawBrackets = 0; - - // Bug fix. Before the wrong player would be higlighted - // during qwd-playback, since you ARE the player that you're - // being spectated (you're not a spectator). - if(cls.demoplayback && !cl.spectator && !cls.mvdplayback) - { - drawBrackets = (sorted_players[num].playernum == cl.playernum); - } - else if (cls.demoplayback || cl.spectator) - { - drawBrackets = (spec_track == sorted_players[num].playernum && Cam_TrackNum() >= 0); - } - else - { - drawBrackets = (sorted_players[num].playernum == cl.playernum); - } - - // Don't draw any brackets in multiview since we're - // tracking several players. - if (cl_multiview->value > 1 && cls.mvdplayback) - { - // TODO: Highlight all players being tracked (See tracking hud-element) - drawBrackets = 0; - } - - if(hud_frags_shownames->value || hud_frags_teams->value || hud_frags_extra_spec_info) - { - // Relative x coordinate where we draw the subitems. - int rel_player_x = player_x; - - if(hud_frags_style->value >= 4 && hud_frags_style->value <= 8) - { - // Draw background based on the style. - - Frags_DrawBackground(player_x, player_y, cell_width, cell_height, space_x, space_y, - max_name_length, max_team_length, Sbar_BottomColor(info), - hud_frags_shownames->value, hud_frags_teams->value, drawBrackets, - hud_frags_style->value); - } - - if(hud_frags_fliptext->value) - { - // - // Flip the text - // NAME | TEAM | FRAGS | EXTRA_SPEC_INFO - // - - // Draw name. - rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height, - space_x, space_y, max_name_length, max_team_length, - hud_frags_fliptext->value, hud_frags_padtext->value, - hud_frags_shownames->value, 0, - info->name, info->team); - - // Draw team. - rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height, - space_x, space_y, max_name_length, max_team_length, - hud_frags_fliptext->value, hud_frags_padtext->value, - 0, hud_frags_teams->value, - info->name, info->team); - - Frags_DrawColors(rel_player_x, player_y, cell_width, cell_height, - Sbar_TopColor(info), Sbar_BottomColor(info), hud_frags_colors_alpha->value, - info->frags, - drawBrackets, - hud_frags_style->value, - hud_frags_bignum->value); - - rel_player_x += cell_width + space_x; - - // Show extra information about all the players if spectating: - // - What armor they have. - // - How much health. - // - If they have RL or not. - rel_player_x = Frags_DrawExtraSpecInfo(info, rel_player_x, player_y, cell_width, cell_height, - space_x, space_y, - hud_frags_fliptext->value); - - } - else - { - // - // Don't flip the text - // EXTRA_SPEC_INFO | FRAGS | TEAM | NAME - // - - rel_player_x = Frags_DrawExtraSpecInfo(info, rel_player_x, player_y, cell_width, cell_height, - space_x, space_y, - hud_frags_fliptext->value); - - Frags_DrawColors(rel_player_x, player_y, cell_width, cell_height, - Sbar_TopColor(info), Sbar_BottomColor(info), hud_frags_colors_alpha->value, - info->frags, - drawBrackets, - hud_frags_style->value, - hud_frags_bignum->value); - - rel_player_x += cell_width + space_x; - - // Draw team. - rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height, - space_x, space_y, max_name_length, max_team_length, - hud_frags_fliptext->value, hud_frags_padtext->value, - 0, hud_frags_teams->value, - info->name, info->team); - - // Draw name. - rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height, - space_x, space_y, max_name_length, max_team_length, - hud_frags_fliptext->value, hud_frags_padtext->value, - hud_frags_shownames->value, 0, - info->name, info->team); - } - - if(hud_frags_vertical->value) - { - // Next row. - player_y += cell_height + space_y; - } - else - { - // Next column. - player_x = rel_player_x + space_x; - } - } - else - { - // Only showing the frags, no names or extra spec info. - - Frags_DrawColors(player_x, player_y, cell_width, cell_height, - Sbar_TopColor(info), Sbar_BottomColor(info), hud_frags_colors_alpha->value, - info->frags, - drawBrackets, - hud_frags_style->value, - hud_frags_bignum->value); - - if (hud_frags_vertical->value) - { - // Next row. - player_y += cell_height + space_y; - } - else - { - // Next column. - player_x += cell_width + space_x; - } - } - - // Next player. - num++; - } - } -} - -void SCR_HUD_DrawTeamFrags(hud_t *hud) -{ - int width = 0, height = 0; - int x, y; - int max_team_length = 0, num = 0; - int rows, cols, cell_width, cell_height, space_x, space_y; - int a_rows, a_cols; // actual - - static cvar_t - *hud_teamfrags_cell_width, - *hud_teamfrags_cell_height, - *hud_teamfrags_rows, - *hud_teamfrags_cols, - *hud_teamfrags_space_x, - *hud_teamfrags_space_y, - *hud_teamfrags_vertical, - *hud_teamfrags_strip, - *hud_teamfrags_shownames, - *hud_teamfrags_fliptext, - *hud_teamfrags_padtext, - *hud_teamfrags_style, - *hud_teamfrags_extra_spec, - *hud_teamfrags_onlytp, - *hud_teamfrags_bignum, - *hud_teamfrags_colors_alpha; - - mpic_t *rl_picture = sb_weapons[0][5]; - float rl_width, rl_height; - pDraw_ImageSize((intptr_t)rl_picture, &rl_width, &rl_height); - - if (hud_teamfrags_cell_width == 0) // first time - { - hud_teamfrags_cell_width = HUD_FindVar(hud, "cell_width"); - hud_teamfrags_cell_height = HUD_FindVar(hud, "cell_height"); - hud_teamfrags_rows = HUD_FindVar(hud, "rows"); - hud_teamfrags_cols = HUD_FindVar(hud, "cols"); - hud_teamfrags_space_x = HUD_FindVar(hud, "space_x"); - hud_teamfrags_space_y = HUD_FindVar(hud, "space_y"); - hud_teamfrags_strip = HUD_FindVar(hud, "strip"); - hud_teamfrags_vertical = HUD_FindVar(hud, "vertical"); - hud_teamfrags_shownames = HUD_FindVar(hud, "shownames"); - hud_teamfrags_fliptext = HUD_FindVar(hud, "fliptext"); - hud_teamfrags_padtext = HUD_FindVar(hud, "padtext"); - hud_teamfrags_style = HUD_FindVar(hud, "style"); - hud_teamfrags_extra_spec = HUD_FindVar(hud, "extra_spec_info"); - hud_teamfrags_onlytp = HUD_FindVar(hud, "onlytp"); - hud_teamfrags_bignum = HUD_FindVar(hud, "bignum"); - hud_teamfrags_colors_alpha = HUD_FindVar(hud, "colors_alpha"); - } - - // Don't draw the frags if we're not in teamplay. - if(hud_teamfrags_onlytp->value && !cl.teamplay) - { - HUD_PrepareDraw(hud, width, height, &x, &y); - return; - } - - rows = hud_teamfrags_rows->value; - clamp(rows, 1, MAX_CLIENTS); - cols = hud_teamfrags_cols->value; - clamp(cols, 1, MAX_CLIENTS); - cell_width = hud_teamfrags_cell_width->value; - clamp(cell_width, 28, 128); - cell_height = hud_teamfrags_cell_height->value; - clamp(cell_height, 7, 32); - space_x = hud_teamfrags_space_x->value; - clamp(space_x, 0, 128); - space_y = hud_teamfrags_space_y->value; - clamp(space_y, 0, 128); - - if (hud_teamfrags_strip->value) - { - if (hud_teamfrags_vertical->value) - { - a_cols = min((n_teams+rows-1) / rows, cols); - a_rows = min(rows, n_teams); - } - else - { - a_rows = min((n_teams+cols-1) / cols, rows); - a_cols = min(cols, n_teams); - } - } - else - { - a_rows = rows; - a_cols = cols; - } - - width = a_cols*cell_width + (a_cols+1)*space_x; - height = a_rows*cell_height + (a_rows+1)*space_y; - - // Get the longest team name for padding. - if(hud_teamfrags_shownames->value || hud_teamfrags_extra_spec->value) - { - int rlcount_width = 0; - - int cur_length = 0; - int n; - - for(n=0; n < n_teams; n++) - { - if(hud_teamfrags_shownames->value) - { - cur_length = strlen(sorted_teams[n].name); - - // Team name - if(cur_length >= max_team_length) - { - max_team_length = cur_length + 1; - } - } - } - - // Calculate the length of the extra spec info. - if(hud_teamfrags_extra_spec->value && (cls.demoplayback || cl.spectator)) - { - if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_BEFORE) - { - // Draw the rl count before the rl icon. - rlcount_width = rl_width + 8 + 1 + 1; - } - else if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_ONTOP) - { - // Draw the rl count on top of the RL instead of infront. - rlcount_width = rl_width + 1; - } - else if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_NOICON) - { - // Only draw the rl count. - rlcount_width = 8 + 1; - } - else if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_RLTEXT) - { - rlcount_width = 8*3 + 1; - } - } - - width += a_cols*max_team_length*8 + (a_cols+1)*space_x + a_cols*rlcount_width; - } - - if (HUD_PrepareDraw(hud, width, height, &x, &y)) - { - int i; - int px = 0; - int py = 0; - int drawBrackets; - int limit = min(n_teams, a_rows*a_cols); - - for (i=0; i < limit; i++) - { - if (hud_teamfrags_vertical->value) - { - if (i % a_rows == 0) - { - px = x + space_x + (i/a_rows) * (cell_width+space_x); - py = y + space_y; - } - } - else - { - if (i % a_cols == 0) - { - px = x + space_x; - py = y + space_y + (i/a_cols) * (cell_height+space_y); - } - } - - drawBrackets = 0; - - // Bug fix. Before the wrong player would be higlighted - // during qwd-playback, since you ARE the player that you're - // being spectated. - if(cls.demoplayback && !cl.spectator && !cls.mvdplayback) - { - // QWD Playback. - if (!strcmp(sorted_teams[num].name, cl.players[cl.playernum].team)) - { - drawBrackets = 1; - } - } - else if (cls.demoplayback || cl.spectator) - { - // MVD playback / spectating. - if (!strcmp(cl.players[spec_track].team, sorted_teams[num].name) && Cam_TrackNum() >= 0) - { - drawBrackets = 1; - } - } - else - { - // Normal player. - if (!strcmp(sorted_teams[num].name, cl.players[cl.playernum].team)) - { - drawBrackets = 1; - } - } - - if (cl_multiview->value && cl.splitscreenview != 0 ) // Only draw bracket for first view, might make todo below unnecessary - { - // TODO: Check if "track team" is set, if it is then draw brackets around that team. - //cl.players[nPlayernum] - - drawBrackets = 0; - } - - if(hud_teamfrags_shownames->value || hud_teamfrags_extra_spec->value) - { - int _px = px; - - // Draw a background if the style tells us to. - if(hud_teamfrags_style->value >= 4 && hud_teamfrags_style->value <= 8) - { - Frags_DrawBackground(px, py, cell_width, cell_height, space_x, space_y, - 0, max_team_length, sorted_teams[num].bottom, - 0, hud_teamfrags_shownames->value, drawBrackets, - hud_teamfrags_style->value); - } - - // Draw the text on the left or right side of the score? - if(hud_teamfrags_fliptext->value) - { - // Draw team. - _px = Frags_DrawText(_px, py, cell_width, cell_height, - space_x, space_y, 0, max_team_length, - hud_teamfrags_fliptext->value, hud_teamfrags_padtext->value, - 0, hud_teamfrags_shownames->value, - "", sorted_teams[num].name); - - Frags_DrawColors(_px, py, cell_width, cell_height, - sorted_teams[num].top, - sorted_teams[num].bottom, - hud_teamfrags_colors_alpha->value, - sorted_teams[num].frags, - drawBrackets, - hud_teamfrags_style->value, - hud_teamfrags_bignum->value); - - _px += cell_width + space_x; - - // Draw the rl if the current player has it and the style allows it. - _px = TeamFrags_DrawExtraSpecInfo(num, _px, py, cell_width, cell_height, hud_teamfrags_extra_spec->value); - - } - else - { - // Draw the rl if the current player has it and the style allows it. - _px = TeamFrags_DrawExtraSpecInfo(num, _px, py, cell_width, cell_height, hud_teamfrags_extra_spec->value); - - Frags_DrawColors(_px, py, cell_width, cell_height, - sorted_teams[num].top, - sorted_teams[num].bottom, - hud_teamfrags_colors_alpha->value, - sorted_teams[num].frags, - drawBrackets, - hud_teamfrags_style->value, - hud_teamfrags_bignum->value); - - _px += cell_width + space_x; - - // Draw team. - _px = Frags_DrawText(_px, py, cell_width, cell_height, - space_x, space_y, 0, max_team_length, - hud_teamfrags_fliptext->value, hud_teamfrags_padtext->value, - 0, hud_teamfrags_shownames->value, - "", sorted_teams[num].name); - } - - if(hud_teamfrags_vertical->value) - { - py += cell_height + space_y; - } - else - { - px = _px + space_x; - } - } - else - { - Frags_DrawColors(px, py, cell_width, cell_height, - sorted_teams[num].top, - sorted_teams[num].bottom, - hud_teamfrags_colors_alpha->value, - sorted_teams[num].frags, - drawBrackets, - hud_teamfrags_style->value, - hud_teamfrags_bignum->value); - - if (hud_teamfrags_vertical->value) - { - py += cell_height + space_y; - } - else - { - px += cell_width + space_x; - } - } - num ++; - } - } -} - -char *Get_MP3_HUD_style(float style, char *st) -{ - static char HUD_style[32]; - if(style == 1.0) - { - strlcpy(HUD_style, va("%s:", st), sizeof(HUD_style)); - } - else if(style == 2.0) - { - strlcpy(HUD_style, va("^Ue010%s^Ue011", st), sizeof(HUD_style)); - } - else - { - strlcpy(HUD_style, "", sizeof(HUD_style)); - } - return HUD_style; -} - -// Draws MP3 Title. -void SCR_HUD_DrawMP3_Title(hud_t *hud) -{ - int x=0, y=0/*, n=1*/; - int width = 64; - int height = 8; - -#ifdef WITH_MP3_PLAYER - //int width_as_text = 0; - static int title_length = 0; - //int row_break = 0; - //int i=0; - int status = 0; - static char title[MP3_MAXSONGTITLE]; - double t; // current time - static double lastframetime; // last refresh - - static cvar_t *style = NULL, *width_var, *height_var, *scroll, *scroll_delay, *on_scoreboard, *wordwrap; - - if (style == NULL) // first time called - { - style = HUD_FindVar(hud, "style"); - width_var = HUD_FindVar(hud, "width"); - height_var = HUD_FindVar(hud, "height"); - scroll = HUD_FindVar(hud, "scroll"); - scroll_delay = HUD_FindVar(hud, "scroll_delay"); - on_scoreboard = HUD_FindVar(hud, "on_scoreboard"); - wordwrap = HUD_FindVar(hud, "wordwrap"); - } - - if(on_scoreboard->value) - { - hud->flags |= HUD_ON_SCORES; - } - else if((int)on_scoreboard->value & HUD_ON_SCORES) - { - hud->flags -= HUD_ON_SCORES; - } - - width = (int)width_var->value; - height = (int)height_var->value; - - if(width < 0) width = 0; - if(width > vid.width) width = vid.width; - if(height < 0) height = 0; - if(height > vid.width) height = vid.height; - - t = Sys_DoubleTime(); - - if ((t - lastframetime) >= 2) { // 2 sec refresh rate - lastframetime = t; - status = MP3_GetStatus(); - - switch(status) - { - case MP3_PLAYING : - title_length = snprintf(title, sizeof(title)-1, "%s %s", Get_MP3_HUD_style(style->value, "Playing"), MP3_Macro_MP3Info()); - break; - case MP3_PAUSED : - title_length = snprintf(title, sizeof(title)-1, "%s %s", Get_MP3_HUD_style(style->value, "Paused"), MP3_Macro_MP3Info()); - break; - case MP3_STOPPED : - title_length = snprintf(title, sizeof(title)-1, "%s %s", Get_MP3_HUD_style(style->value, "Stopped"), MP3_Macro_MP3Info()); - break; - case MP3_NOTRUNNING : - default : - status = MP3_NOTRUNNING; - title_length = snprintf (title, sizeof (title), "%s is not running.", mp3_player->PlayerName_AllCaps); - break; - } - - if(title_length < 0) - { - snprintf(title, sizeof (title), "Error retrieving current song."); - } - } - - if (HUD_PrepareDraw(hud, width , height, &x, &y)) - { - SCR_DrawWordWrapString(x, y, 8, width, height, (int)wordwrap->value, (int)scroll->value, (float)scroll_delay->value, title); - } -#else - HUD_PrepareDraw(hud, width , height, &x, &y); -#endif -} - -// Draws MP3 Time as a HUD-element. -void SCR_HUD_DrawMP3_Time(hud_t *hud) -{ - int x = 0, y = 0, width = 0, height = 0; -#ifdef WITH_MP3_PLAYER - int elapsed = 0; - int remain = 0; - int total = 0; - static char time_string[MP3_MAXSONGTITLE]; - static char elapsed_string[MP3_MAXSONGTITLE]; - double t; // current time - static double lastframetime; // last refresh - - static cvar_t *style = NULL, *on_scoreboard; - - if(style == NULL) - { - style = HUD_FindVar(hud, "style"); - on_scoreboard = HUD_FindVar(hud, "on_scoreboard"); - } - - if(on_scoreboard->value) - { - hud->flags |= HUD_ON_SCORES; - } - else if((int)on_scoreboard->value & HUD_ON_SCORES) - { - hud->flags -= HUD_ON_SCORES; - } - - t = Sys_DoubleTime(); - if ((t - lastframetime) >= 2) { // 2 sec refresh rate - lastframetime = t; - - if(!MP3_GetOutputtime(&elapsed, &total) || elapsed < 0 || total < 0) - { - snprintf (time_string, sizeof (time_string), "^Ue010-:-^Ue011"); - } - else - { - switch((int)style->value) - { - case 1 : - remain = total - elapsed; - strlcpy (elapsed_string, SecondsToMinutesString (remain), sizeof (elapsed_string)); - snprintf (time_string, sizeof (time_string), "^Ue010-%s/%s^Ue011", elapsed_string, SecondsToMinutesString (total)); - break; - case 2 : - remain = total - elapsed; - snprintf (time_string, sizeof (time_string), "^Ue010-%s^Ue011", SecondsToMinutesString (remain)); - break; - case 3 : - snprintf (time_string, sizeof (time_string), "^Ue010%s^Ue011", SecondsToMinutesString (elapsed)); - break; - case 4 : - remain = total - elapsed; - strlcpy (elapsed_string, SecondsToMinutesString (remain), sizeof (elapsed_string)); - snprintf (time_string, sizeof (time_string), "%s/%s", elapsed_string, SecondsToMinutesString (total)); - break; - case 5 : - strlcpy (elapsed_string, SecondsToMinutesString (elapsed), sizeof (elapsed_string)); - snprintf (time_string, sizeof (time_string), "-%s/%s", elapsed_string, SecondsToMinutesString (total)); - break; - case 6 : - remain = total - elapsed; - snprintf (time_string, sizeof (time_string), "-%s", SecondsToMinutesString (remain)); - break; - case 7 : - snprintf (time_string, sizeof (time_string), "%s", SecondsToMinutesString (elapsed)); - break; - case 0 : - default : - strlcpy (elapsed_string, SecondsToMinutesString (elapsed), sizeof (elapsed_string)); - snprintf (time_string, sizeof (time_string), "^Ue010%s/%s^Ue011", elapsed_string, SecondsToMinutesString (total)); - break; - } - } - - } - - // Don't allow showing the timer if ruleset disallows it - // It could be used for timing powerups - // Use same check that is used for any external communication - if(Rulesets_RestrictPacket()) - snprintf (time_string, sizeof (time_string), "^Ue010%s^Ue011", "Not allowed"); - - width = strlen (time_string) * 8; - height = 8; - - if (HUD_PrepareDraw(hud, width , height, &x, &y)) - Draw_String(x, y, time_string); -#else - HUD_PrepareDraw(hud, width , height, &x, &y); -#endif -} - -#ifdef WITH_PNG - -// Map picture to draw for the mapoverview hud control. -mpic_t *radar_pic; -static qbool radar_pic_found = false; - -// The conversion formula used for converting from quake coordinates to pixel coordinates -// when drawing on the map overview. -static float map_x_slope; -static float map_x_intercept; -static float map_y_slope; -static float map_y_intercept; -static qbool conversion_formula_found = false; - -// Used for drawing the height of the player. -static float map_height_diff = 0.0; - -#define RADAR_BASE_PATH_FORMAT "radars/%s.png" - -// -// Is run when a new map is loaded. -// -void HUD_NewRadarMap() -{ - int i = 0; - int len = 0; - int n_textcount = 0; - mpic_t *radar_pic_p = NULL; - png_textp txt = NULL; - char *radar_filename = NULL; - - if (!cl.worldmodel) - return; // seems we are not ready to do that - - // Reset the radar pic status. - radar_pic = NULL; - radar_pic_found = false; - conversion_formula_found = false; - - // Allocate a string for the path to the radar image. - len = strlen (RADAR_BASE_PATH_FORMAT) + strlen (host_mapname.string); - radar_filename = Q_calloc (len, sizeof(char)); - snprintf (radar_filename, len, RADAR_BASE_PATH_FORMAT, host_mapname.string); - - // Load the map picture. - if ((radar_pic_p = GL_LoadPicImage (radar_filename, host_mapname.string, 0, 0, TEX_ALPHA)) != NULL) - { - radar_pic = *radar_pic_p; - radar_pic_found = true; - - // Calculate the height of the map. - map_height_diff = abs(cl.worldmodel->maxs[2] - cl.worldmodel->mins[2]); - - // Get the comments from the PNG. - txt = Image_LoadPNG_Comments(radar_filename, &n_textcount); - - // Check if we found any comments. - if(txt != NULL) - { - int found_count = 0; - - // Find the conversion formula in the comments found in the PNG. - for(i = 0; i < n_textcount; i++) - { - if(!strcmp(txt[i].key, "QWLMConversionSlopeX")) - { - map_x_slope = atof(txt[i].text); - found_count++; - } - else if(!strcmp(txt[i].key, "QWLMConversionInterceptX")) - { - map_x_intercept = atof(txt[i].text); - found_count++; - } - else if(!strcmp(txt[i].key, "QWLMConversionSlopeY")) - { - map_y_slope = atof(txt[i].text); - found_count++; - } - else if(!strcmp(txt[i].key, "QWLMConversionInterceptY")) - { - map_y_intercept = atof(txt[i].text); - found_count++; - } - - conversion_formula_found = (found_count == 4); - } - - // Free the text chunks. - Q_free(txt); - } - else - { - conversion_formula_found = false; - } - } - else - { - // No radar pic found. - memset (&radar_pic, 0, sizeof(radar_pic)); - radar_pic_found = false; - conversion_formula_found = false; - } - - // Free the path string to the radar png. - Q_free (radar_filename); -} -#endif // WITH_PNG - -#define TEMPHUD_NAME "_temphud" -#define TEMPHUD_FULLPATH "configs/"TEMPHUD_NAME".cfg" - -// will check if user wants to un/load external MVD HUD automatically -void HUD_AutoLoad_MVD(int autoload) { -#ifdef HAXX - char *cfg_suffix = "custom"; - extern cvar_t *scr_fov; - extern cvar_t *scr_newHud; - extern void Cmd_Exec_f (void); - extern void DumpConfig(char *name); - - if (autoload && cls.mvdplayback) { - // Turn autohud ON here - - Com_DPrintf("Loading MVD Hud\n"); - // Store current settings. - if (!autohud.active) - { - // Save old cfg_save values so that we don't screw the users - // settings when saving the temp config. - int old_cmdline = pCvar_GetFloat("cfg_save_cmdline"); - int old_cvars = pCvar_GetFloat("cfg_save_cvars"); - int old_cmds = pCvar_GetFloat("cfg_save_cmds"); - int old_aliases = pCvar_GetFloat("cfg_save_aliases"); - int old_binds = pCvar_GetFloat("cfg_save_binds"); - - autohud.old_fov = (int) scr_fov->value; - autohud.old_multiview = (int) cl_multiview->value; - autohud.old_newhud = (int) scr_newHud->value; - - // Make sure everything current settings are saved. - pCvar_SetFloat("cfg_save_cmdline", 1); - pCvar_SetFloat("cfg_save_cvars", 1); - pCvar_SetFloat("cfg_save_cmds", 1); - pCvar_SetFloat("cfg_save_aliases", 1); - pCvar_SetFloat("cfg_save_binds", 1); - - // Save a temporary config. - DumpConfig(TEMPHUD_NAME".cfg"); - - pCvar_SetFloat("cfg_save_cmdline", old_cmdline); - pCvar_SetFloat("cfg_save_cvars", old_cvars); - pCvar_SetFloat("cfg_save_cmds", old_cmds); - pCvar_SetFloat("cfg_save_aliases", old_aliases); - pCvar_SetFloat("cfg_save_binds", old_binds); - } - - // load MVD HUD config - switch ((int) autoload) { - case 1: // load 1on1 or 4on4 or custom according to $matchtype - if (!strncmp(Macro_MatchType(), "duel", 4)) { - cfg_suffix = "1on1"; - } else if (!strncmp(Macro_MatchType(), "4on4", 4)) { - cfg_suffix = "4on4"; - } else { - cfg_suffix = "custom"; - } - break; - default: - case 2: - cfg_suffix = "custom"; - break; - } - - Cbuf_AddText(va("exec cfg/mvdhud_%s.cfg\n", cfg_suffix)); - - autohud.active = true; - return; - } - - if ((!cls.mvdplayback || !autoload) && autohud.active) { - // either user decided to turn mvd autohud off or mvd playback is over - // -> Turn autohud OFF here - FILE *tempfile; - char *fullname = va("%s/ezquake/"TEMPHUD_FULLPATH, com_basedir); - - Com_DPrintf("Unloading MVD Hud\n"); - // load stored settings - pCvar_SetFloat(scr_fov->name, autohud.old_fov); - pCvar_SetFloat(cl_multiview->name, autohud.old_multiview); - pCvar_SetFloat(scr_newHud->name, autohud.old_newhud); - //Cmd_TokenizeString("exec "TEMPHUD_FULLPATH); - Cmd_TokenizeString("cfg_load "TEMPHUD_FULLPATH); - Cmd_Exec_f(); - - // delete temp config with hud_* settings - if ((tempfile = fopen(fullname, "rb")) && (fclose(tempfile) != EOF)) - unlink(fullname); - - autohud.active = false; - return; - } -#endif -} - -void OnAutoHudChange(cvar_t *var, char *value, qbool *cancel) { - HUD_AutoLoad_MVD(Q_atoi(value)); -} - -// Is run when a new map is loaded. -void HUD_NewMap() { -#if defined(WITH_PNG) - HUD_NewRadarMap(); -#endif // WITH_PNG - - autohud_loaded = false; -} - -#define HUD_SHOW_ONLY_IN_TEAMPLAY 1 -#define HUD_SHOW_ONLY_IN_DEMOPLAYBACK 2 - -qbool HUD_ShowInDemoplayback(int val) -{ - if(!cl.teamplay && val == HUD_SHOW_ONLY_IN_TEAMPLAY) - { - return false; - } - else if(!cls.demoplayback && val == HUD_SHOW_ONLY_IN_DEMOPLAYBACK) - { - return false; - } - else if(!cl.teamplay && !cls.demoplayback - && val == HUD_SHOW_ONLY_IN_TEAMPLAY + HUD_SHOW_ONLY_IN_DEMOPLAYBACK) - { - return false; - } - - return true; -} - -// Team hold filters. -static qbool teamhold_show_pent = false; -static qbool teamhold_show_quad = false; -static qbool teamhold_show_ring = false; -static qbool teamhold_show_suit = false; -static qbool teamhold_show_rl = false; -static qbool teamhold_show_lg = false; -static qbool teamhold_show_gl = false; -static qbool teamhold_show_sng = false; -static qbool teamhold_show_mh = false; -static qbool teamhold_show_ra = false; -static qbool teamhold_show_ya = false; -static qbool teamhold_show_ga = false; - -void TeamHold_DrawBars(int x, int y, int width, int height, - float team1_percent, float team2_percent, - int team1_color, int team2_color, - float opacity) -{ - int team1_width = 0; - int team2_width = 0; - int bar_height = 0; - - bar_height = Q_rint (height/2.0); - team1_width = (int) (width * team1_percent); - team2_width = (int) (width * team2_percent); - - clamp(team1_width, 0, width); - clamp(team2_width, 0, width); - - Draw_AlphaFill(x, y, team1_width, bar_height, team1_color, opacity); - - y += bar_height; - - Draw_AlphaFill(x, y, team2_width, bar_height, team2_color, opacity); -} - -void TeamHold_DrawPercentageBar(int x, int y, int width, int height, - float team1_percent, float team2_percent, - int team1_color, int team2_color, - int show_text, int vertical, - int vertical_text, float opacity) -{ - int _x, _y; - int _width, _height; - - if(vertical) - { - // - // Draw vertical. - // - - // Team 1. - _x = x; - _y = y; - _width = max(0, width); - _height = Q_rint(height * team1_percent); - _height = max(0, height); - - Draw_AlphaFill(_x, _y, _width, _height, team1_color, opacity); - - // Team 2. - _x = x; - _y = Q_rint(y + (height * team1_percent)); - _width = max(0, width); - _height = Q_rint(height * team2_percent); - _height = max(0, _height); - - Draw_AlphaFill(_x, _y, _width, _height, team2_color, opacity); - - // Show the percentages in numbers also. - if(show_text) - { - // TODO: Move this to a separate function (since it's prett much copy and paste for both teams). - // Team 1. - if(team1_percent > 0.05) - { - if(vertical_text) - { - int percent = 0; - int percent10 = 0; - int percent100 = 0; - - _x = x + (width / 2) - 4; - _y = Q_rint(y + (height * team1_percent)/2 - 12); - - percent = Q_rint(100 * team1_percent); - - if((percent100 = percent / 100)) - { - Draw_String(_x, _y, va("%d", percent100)); - _y += 8; - } - - if((percent10 = percent / 10)) - { - Draw_String(_x, _y, va("%d", percent10)); - _y += 8; - } - - Draw_String(_x, _y, va("%d", percent % 10)); - _y += 8; - - Draw_String(_x, _y, "%"); - } - else - { - _x = x + (width / 2) - 12; - _y = Q_rint(y + (height * team1_percent)/2 - 4); - Draw_String(_x, _y, va("%2.0f%%", 100 * team1_percent)); - } - } - - // Team 2. - if(team2_percent > 0.05) - { - if(vertical_text) - { - int percent = 0; - int percent10 = 0; - int percent100 = 0; - - _x = x + (width / 2) - 4; - _y = Q_rint(y + (height * team1_percent) + (height * team2_percent)/2 - 12); - - percent = Q_rint(100 * team2_percent); - - if((percent100 = percent / 100)) - { - Draw_String(_x, _y, va("%d", percent100)); - _y += 8; - } - - if((percent10 = percent / 10)) - { - Draw_String(_x, _y, va("%d", percent10)); - _y += 8; - } - - Draw_String(_x, _y, va("%d", percent % 10)); - _y += 8; - - Draw_String(_x, _y, "%"); - } - else - { - _x = x + (width / 2) - 12; - _y = Q_rint(y + (height * team1_percent) + (height * team2_percent)/2 - 4); - Draw_String(_x, _y, va("%2.0f%%", 100 * team2_percent)); - } - } - } - } - else - { - // - // Draw horizontal. - // - - // Team 1. - _x = x; - _y = y; - _width = Q_rint(width * team1_percent); - _width = max(0, _width); - _height = max(0, height); - - Draw_AlphaFill(_x, _y, _width, _height, team1_color, opacity); - - // Team 2. - _x = Q_rint(x + (width * team1_percent)); - _y = y; - _width = Q_rint(width * team2_percent); - _width = max(0, _width); - _height = max(0, height); - - Draw_AlphaFill(_x, _y, _width, _height, team2_color, opacity); - - // Show the percentages in numbers also. - if(show_text) - { - // Team 1. - if(team1_percent > 0.05) - { - _x = Q_rint(x + (width * team1_percent)/2 - 8); - _y = y + (height / 2) - 4; - Draw_String(_x, _y, va("%2.0f%%", 100 * team1_percent)); - } - - // Team 2. - if(team2_percent > 0.05) - { - _x = Q_rint(x + (width * team1_percent) + (width * team2_percent)/2 - 8); - _y = y + (height / 2) - 4; - Draw_String(_x, _y, va("%2.0f%%", 100 * team2_percent)); - } - } - } -} - -#ifdef HAXX -static void SCR_HUD_DrawTeamHoldBar(hud_t *hud) -{ - int x, y; - int height = 8; - int width = 0; - float team1_percent = 0; - float team2_percent = 0; - - static cvar_t - *hud_teamholdbar_style = NULL, - *hud_teamholdbar_opacity, - *hud_teamholdbar_width, - *hud_teamholdbar_height, - *hud_teamholdbar_vertical, - *hud_teamholdbar_show_text, - *hud_teamholdbar_onlytp, - *hud_teamholdbar_vertical_text; - - if (hud_teamholdbar_style == NULL) // first time - { - hud_teamholdbar_style = HUD_FindVar(hud, "style"); - hud_teamholdbar_opacity = HUD_FindVar(hud, "opacity"); - hud_teamholdbar_width = HUD_FindVar(hud, "width"); - hud_teamholdbar_height = HUD_FindVar(hud, "height"); - hud_teamholdbar_vertical = HUD_FindVar(hud, "vertical"); - hud_teamholdbar_show_text = HUD_FindVar(hud, "show_text"); - hud_teamholdbar_onlytp = HUD_FindVar(hud, "onlytp"); - hud_teamholdbar_vertical_text = HUD_FindVar(hud, "vertical_text"); - } - - height = max(1, hud_teamholdbar_height->value); - width = max(0, hud_teamholdbar_width->value); - - // Don't show when not in teamplay/demoplayback. - if(!HUD_ShowInDemoplayback(hud_teamholdbar_onlytp->value)) - { - HUD_PrepareDraw(hud, width , height, &x, &y); - return; - } - - if (HUD_PrepareDraw(hud, width , height, &x, &y)) - { - // We need something to work with. - if(stats_grid != NULL) - { - // Check if we have any hold values to calculate from. - if(stats_grid->teams[STATS_TEAM1].hold_count + stats_grid->teams[STATS_TEAM2].hold_count > 0) - { - // Calculate the percentage for the two teams for the "team strength bar". - team1_percent = ((float)stats_grid->teams[STATS_TEAM1].hold_count) / (stats_grid->teams[STATS_TEAM1].hold_count + stats_grid->teams[STATS_TEAM2].hold_count); - team2_percent = ((float)stats_grid->teams[STATS_TEAM2].hold_count) / (stats_grid->teams[STATS_TEAM1].hold_count + stats_grid->teams[STATS_TEAM2].hold_count); - - team1_percent = fabs(max(0, team1_percent)); - team2_percent = fabs(max(0, team2_percent)); - } - else - { - Draw_AlphaFill(x, y, hud_teamholdbar_width->value, height, 0, hud_teamholdbar_opacity->value*0.5); - return; - } - - // Draw the percentage bar. - TeamHold_DrawPercentageBar(x, y, width, height, - team1_percent, team2_percent, - stats_grid->teams[STATS_TEAM1].color, - stats_grid->teams[STATS_TEAM2].color, - hud_teamholdbar_show_text->value, - hud_teamholdbar_vertical->value, - hud_teamholdbar_vertical_text->value, - hud_teamholdbar_opacity->value); - } - else - { - // If there's no stats grid available we don't know what to show, so just show a black frame. - Draw_AlphaFill(x, y, hud_teamholdbar_width->value, height, 0, hud_teamholdbar_opacity->value * 0.5); - } - } -} -#endif - -void TeamHold_OnChangeItemFilterInfo(cvar_t *var, char *oldvalue) -{ -// char *start = var->string; -// char *end = start; -// int order = 0; - - // Parse the item filter. - teamhold_show_rl = Utils_RegExpMatch("RL", var->string); - teamhold_show_quad = Utils_RegExpMatch("QUAD", var->string); - teamhold_show_ring = Utils_RegExpMatch("RING", var->string); - teamhold_show_pent = Utils_RegExpMatch("PENT", var->string); - teamhold_show_suit = Utils_RegExpMatch("SUIT", var->string); - teamhold_show_lg = Utils_RegExpMatch("LG", var->string); - teamhold_show_gl = Utils_RegExpMatch("GL", var->string); - teamhold_show_sng = Utils_RegExpMatch("SNG", var->string); - teamhold_show_mh = Utils_RegExpMatch("MH", var->string); - teamhold_show_ra = Utils_RegExpMatch("RA", var->string); - teamhold_show_ya = Utils_RegExpMatch("YA", var->string); - teamhold_show_ga = Utils_RegExpMatch("GA", var->string); -#ifdef HAXX - // Reset the ordering of the items. - StatsGrid_ResetHoldItemsOrder(); - - // Trim spaces from the start of the word. - while (*start && *start == ' ') - { - start++; - } - - end = start; - - // Go through the string word for word and set a - // rising order for each hold item based on their - // order in the string. - while (*end) - { - if (*end != ' ') - { - // Not at the end of the word yet. - end++; - continue; - } - else - { - // We've found a word end. - char temp[256]; - - // Try matching the current word with a hold item - // and set it's ordering according to it's placement - // in the string. - strlcpy (temp, start, min(end - start, sizeof(temp))); - StatsGrid_SetHoldItemOrder(temp, order); - order++; - - // Get rid of any additional spaces. - while (*end && *end == ' ') - { - end++; - } - - // Start trying to find a new word. - start = end; - } - } - - // Order the hold items. - StatsGrid_SortHoldItems(); -#endif -} - -#define HUD_TEAMHOLDINFO_STYLE_TEAM_NAMES 0 -#define HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS 1 -#define HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS2 2 - -#ifdef HAXX -static void SCR_HUD_DrawTeamHoldInfo(hud_t *hud) -{ - int i; - int x, y; - int width, height; - - static cvar_t - *hud_teamholdinfo_style = NULL, - *hud_teamholdinfo_opacity, - *hud_teamholdinfo_width, - *hud_teamholdinfo_height, - *hud_teamholdinfo_onlytp, - *hud_teamholdinfo_itemfilter; - - if (hud_teamholdinfo_style == NULL) // first time - { - char val[256]; - - hud_teamholdinfo_style = HUD_FindVar(hud, "style"); - hud_teamholdinfo_opacity = HUD_FindVar(hud, "opacity"); - hud_teamholdinfo_width = HUD_FindVar(hud, "width"); - hud_teamholdinfo_height = HUD_FindVar(hud, "height"); - hud_teamholdinfo_onlytp = HUD_FindVar(hud, "onlytp"); - hud_teamholdinfo_itemfilter = HUD_FindVar(hud, "itemfilter"); - - // Unecessary to parse the item filter string on each frame. - hud_teamholdinfo_itemfilter->OnChange = TeamHold_OnChangeItemFilterInfo; - - // Parse the item filter the first time (trigger the OnChange function above). - strlcpy (val, hud_teamholdinfo_itemfilter->string, sizeof(val)); - Cvar_Set (hud_teamholdinfo_itemfilter, val); - } - - // Get the height based on how many items we have, or what the user has set it to. - height = max(0, hud_teamholdinfo_height->value); - width = max(0, hud_teamholdinfo_width->value); - - // Don't show when not in teamplay/demoplayback. - if(!HUD_ShowInDemoplayback(hud_teamholdinfo_onlytp->value)) - { - HUD_PrepareDraw(hud, width , height, &x, &y); - return; - } - - // We don't have anything to show. - if(stats_important_ents == NULL || stats_grid == NULL) - { - HUD_PrepareDraw(hud, width , height, &x, &y); - return; - } - - if (HUD_PrepareDraw(hud, width , height, &x, &y)) - { - int _y = 0; - - _y = y; - - // Go through all the items and print the stats for them. - for(i = 0; i < stats_important_ents->count; i++) - { - float team1_percent; - float team2_percent; - int team1_hold_count = 0; - int team2_hold_count = 0; - int names_width = 0; - - // Don't draw outside the specified height. - if((_y - y) + 8 > height) - { - break; - } - - // If the item isn't of the specified type, then skip it. - if(!( (teamhold_show_rl && !strncmp(stats_important_ents->list[i].name, "RL", 2)) - || (teamhold_show_quad && !strncmp(stats_important_ents->list[i].name, "QUAD", 4)) - || (teamhold_show_ring && !strncmp(stats_important_ents->list[i].name, "RING", 4)) - || (teamhold_show_pent && !strncmp(stats_important_ents->list[i].name, "PENT", 4)) - || (teamhold_show_suit && !strncmp(stats_important_ents->list[i].name, "SUIT", 4)) - || (teamhold_show_lg && !strncmp(stats_important_ents->list[i].name, "LG", 2)) - || (teamhold_show_gl && !strncmp(stats_important_ents->list[i].name, "GL", 2)) - || (teamhold_show_sng && !strncmp(stats_important_ents->list[i].name, "SNG", 3)) - || (teamhold_show_mh && !strncmp(stats_important_ents->list[i].name, "MH", 2)) - || (teamhold_show_ra && !strncmp(stats_important_ents->list[i].name, "RA", 2)) - || (teamhold_show_ya && !strncmp(stats_important_ents->list[i].name, "YA", 2)) - || (teamhold_show_ga && !strncmp(stats_important_ents->list[i].name, "GA", 2)) - )) - { - continue; - } - - // Calculate the width of the longest item name so we can use it for padding. - names_width = 8 * (stats_important_ents->longest_name + 1); - - // Calculate the percentages of this item that the two teams holds. - team1_hold_count = stats_important_ents->list[i].teams_hold_count[STATS_TEAM1]; - team2_hold_count = stats_important_ents->list[i].teams_hold_count[STATS_TEAM2]; - - team1_percent = ((float)team1_hold_count) / (team1_hold_count + team2_hold_count); - team2_percent = ((float)team2_hold_count) / (team1_hold_count + team2_hold_count); - - team1_percent = fabs(max(0, team1_percent)); - team2_percent = fabs(max(0, team2_percent)); - - // Write the name of the item. - Draw_ColoredString(x, _y, va("&cff0%s:", stats_important_ents->list[i].name), 0); - - if(hud_teamholdinfo_style->value == HUD_TEAMHOLDINFO_STYLE_TEAM_NAMES) - { - // - // Prints the team name that holds the item. - // - if(team1_percent > team2_percent) - { - Draw_ColoredString(x + names_width, _y, stats_important_ents->teams[STATS_TEAM1].name, 0); - } - else if(team1_percent < team2_percent) - { - Draw_ColoredString(x + names_width, _y, stats_important_ents->teams[STATS_TEAM2].name, 0); - } - } - else if(hud_teamholdinfo_style->value == HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS) - { - // - // Show a percenteage bar for the item. - // - TeamHold_DrawPercentageBar(x + names_width, _y, - Q_rint(hud_teamholdinfo_width->value - names_width), 8, - team1_percent, team2_percent, - stats_important_ents->teams[STATS_TEAM1].color, - stats_important_ents->teams[STATS_TEAM2].color, - 0, // Don't show percentage values, get's too cluttered. - false, - false, - hud_teamholdinfo_opacity->value); - } - else if(hud_teamholdinfo_style->value == HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS2) - { - TeamHold_DrawBars(x + names_width, _y, - Q_rint(hud_teamholdinfo_width->value - names_width), 8, - team1_percent, team2_percent, - stats_important_ents->teams[STATS_TEAM1].color, - stats_important_ents->teams[STATS_TEAM2].color, - hud_teamholdinfo_opacity->value); - } - - // Next line. - _y += 8; - } - } -} -#endif - -static int SCR_HudDrawTeamInfoPlayer(teamplayerinfo_t *ti_cl, int x, int y, int maxname, int maxloc, qbool width_only, hud_t *hud); - -#define FONTWIDTH 8 -static void SCR_HUD_DrawTeamInfo(hud_t *hud) -{ - int x, y, _y, width, height; - int i, j, k, slots_num, maxname, maxloc; - char tmp[1024], *nick; - teamplayerinfo_t ti_clients[MAX_CLIENTS]; - - extern qbool hud_editor; - - static cvar_t - *hud_teaminfo_weapon_style = NULL, - *hud_teaminfo_align_right, - *hud_teaminfo_loc_width, - *hud_teaminfo_name_width, - *hud_teaminfo_show_enemies, - *hud_teaminfo_show_self, - *hud_teaminfo_scale; - - if (hud_teaminfo_weapon_style == NULL) // first time - { - hud_teaminfo_weapon_style = HUD_FindVar(hud, "weapon_style"); - hud_teaminfo_align_right = HUD_FindVar(hud, "align_right"); - hud_teaminfo_loc_width = HUD_FindVar(hud, "loc_width"); - hud_teaminfo_name_width = HUD_FindVar(hud, "name_width"); - hud_teaminfo_show_enemies = HUD_FindVar(hud, "show_enemies"); - hud_teaminfo_show_self = HUD_FindVar(hud, "show_self"); - hud_teaminfo_scale = HUD_FindVar(hud, "scale"); - } - - // Don't update hud item unless first view is beeing displayed -// if ( CURRVIEW != 1 && CURRVIEW != 0) -// return; - - slots_num = pGetTeamInfo(ti_clients, countof(ti_clients), hud_teaminfo_show_enemies->ival, hud_teaminfo_show_self->ival); - - // fill data we require to draw teaminfo - for ( maxloc = maxname = i = 0; i < slots_num; i++ ) { - // dynamically guess max length of name/location - nick = (ti_clients[i].nick[0] ? ti_clients[i].nick : cl.players[i].name); // we use nick or name - maxname = max(maxname, strlen(TP_ParseFunChars(nick, false))); - - strlcpy(tmp, TP_LocationName(ti_clients[i].org), sizeof(tmp)); - maxloc = max(maxloc, strlen(TP_ParseFunChars(tmp, false))); - } - - // well, better use fixed loc length - maxloc = bound(0, hud_teaminfo_loc_width->ival, 100); - // limit name length - maxname = bound(0, maxname, hud_teaminfo_name_width->ival); - - // this does't draw anything, just calculate width - width = FONTWIDTH * hud_teaminfo_scale->value * SCR_HudDrawTeamInfoPlayer(&ti_clients[0], 0, 0, maxname, maxloc, true, hud); - height = FONTWIDTH * hud_teaminfo_scale->value * (hud_teaminfo_show_enemies->ival?slots_num+n_teams:slots_num); - - if (hud_editor) - HUD_PrepareDraw(hud, width , FONTWIDTH, &x, &y); - - if ( !slots_num ) - return; - - if (!cl.teamplay) // non teamplay mode - return; - - if (!HUD_PrepareDraw(hud, width , height, &x, &y)) - return; - - _y = y ; - x = (hud_teaminfo_align_right->value ? x - (width * (FONTWIDTH * hud_teaminfo_scale->value)) : x); - - // If multiple teams are displayed then sort the display and print team header on overlay - k=0; - if (hud_teaminfo_show_enemies->ival) - { - while (sorted_teams[k].name) - { - Draw_SString (x, _y, sorted_teams[k].name, hud_teaminfo_scale->value); - sprintf(tmp,"%s %i",TP_ParseFunChars("$.",false), sorted_teams[k].frags); - Draw_SString (x+(strlen(sorted_teams[k].name)+1)*FONTWIDTH, _y, tmp, hud_teaminfo_scale->value); - _y += FONTWIDTH * hud_teaminfo_scale->value; - for ( j = 0; j < slots_num; j++ ) - { - i = ti_clients[j].client; - if (!strcmp(cl.players[i].team,sorted_teams[k].name)) - { - SCR_HudDrawTeamInfoPlayer(&ti_clients[j], x, _y, maxname, maxloc, false, hud); - _y += FONTWIDTH * hud_teaminfo_scale->value; - } - } - k++; - } - } - else - { - for ( j = 0; j < slots_num; j++ ) { - SCR_HudDrawTeamInfoPlayer(&ti_clients[j], x, _y, maxname, maxloc, false, hud); - _y += FONTWIDTH * hud_teaminfo_scale->value; - } - } -} - -qbool Has_Both_RL_and_LG (int flags) { return (flags & IT_ROCKET_LAUNCHER) && (flags & IT_LIGHTNING); } -#define FONTWIDTH 8 +} + +static void SCR_HUD_DrawHealthDamage(hud_t *hud) +{ + Draw_AMFStatLoss (STAT_HEALTH, hud); + if (HUD_Stats(STAT_HEALTH) <= 0) + { + Amf_Reset_DamageStats(); + } +} + +static void SCR_HUD_DrawArmorDamage(hud_t *hud) +{ + Draw_AMFStatLoss (STAT_ARMOR, hud); +} + +void SCR_HUD_DrawAmmo(hud_t *hud, int num, + float scale, int style, int digits, char *s_align) +{ + int value, num_old; + qbool low; + + num_old = num; + if (num < 1 || num > 4) + { // draw 'current' ammo, which one is it? + + if (ShowPreselectedWeap()) { + // using weapon pre-selection so show info for current best pre-selected weapon ammo + if (!(num = State_AmmoNumForWeapon(IN_BestWeapon()))) + return; + } else { + // not using weapon pre-selection or player is dead so show current selected ammo + if (HUD_Stats(STAT_ITEMS) & IT_SHELLS) + num = 1; + else if (HUD_Stats(STAT_ITEMS) & IT_NAILS) + num = 2; + else if (HUD_Stats(STAT_ITEMS) & IT_ROCKETS) + num = 3; + else if (HUD_Stats(STAT_ITEMS) & IT_CELLS) + num = 4; + else if (TP_TeamFortressEngineerSpanner()) + num = 4; + else + return; + } + } + + low = HUD_AmmoLowByWeapon(num * 2); + if (num_old == 0 && (!ShowPreselectedWeap() || cl.standby)) { + // this check is here to display a feature from KTPRO/KTX where you can see received damage in prewar + // also we make sure this applies only to 'ammo' element + // weapon preselection must always use HUD_Stats() + value = cl.stats[STAT_AMMO]; + } else { + value = HUD_Stats(STAT_SHELLS + num - 1); + } + + if (style < 2) + { + // simply draw number + SCR_HUD_DrawNum(hud, value, low, scale, style, digits, s_align); + } + else + { + // else - draw classic ammo-count box with background + char buf[8]; + int x, y; + + scale = max(scale, 0.01); + + if (!HUD_PrepareDraw(hud, 42*scale, 11*scale, &x, &y)) + return; + + snprintf (buf, sizeof (buf), "%3i", value); + Draw_SSubPic(x, y, sb_ibar, 3+((num-1)*48), 0, 42, 11, scale); + if (buf[0] != ' ') Draw_SCharacter (x + 7*scale, y, 18+buf[0]-'0', scale); + if (buf[1] != ' ') Draw_SCharacter (x + 15*scale, y, 18+buf[1]-'0', scale); + if (buf[2] != ' ') Draw_SCharacter (x + 23*scale, y, 18+buf[2]-'0', scale); + } +} + +void SCR_HUD_DrawAmmoCurrent(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *digits, *align; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + } + SCR_HUD_DrawAmmo(hud, 0, scale->value, style->value, digits->value, align->string); +} +void SCR_HUD_DrawAmmo1(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *digits, *align; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + } + SCR_HUD_DrawAmmo(hud, 1, scale->value, style->value, digits->value, align->string); +} +void SCR_HUD_DrawAmmo2(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *digits, *align; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + } + SCR_HUD_DrawAmmo(hud, 2, scale->value, style->value, digits->value, align->string); +} +void SCR_HUD_DrawAmmo3(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *digits, *align; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + } + SCR_HUD_DrawAmmo(hud, 3, scale->value, style->value, digits->value, align->string); +} +void SCR_HUD_DrawAmmo4(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *digits, *align; + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + } + SCR_HUD_DrawAmmo(hud, 4, scale->value, style->value, digits->value, align->string); +} + +// Problem icon, Net + +static void SCR_HUD_NetProblem (hud_t *hud) { + static cvar_t *scale = NULL; + int x, y; + extern qbool hud_editor; + vmnetinfo_t *netinfo = GetNetworkInfo(); + + float picwidth = 64; + float picheight = 64; + pDraw_ImageSize((intptr_t)sb_net, &picwidth, &picheight); + + if(scale == NULL) + scale = HUD_FindVar(hud, "scale"); + + if (netinfo->loss.dropped < 1) + { + if (hud_editor) + HUD_PrepareDraw(hud, picwidth, picheight, &x, &y); + return; + } + + if (!HUD_PrepareDraw(hud, picwidth, picheight, &x, &y)) + return; + + Draw_SPic (x, y, sb_net, scale->value); +} + +// ============================================================================0 +// Groups +// ============================================================================0 + +mpic_t *hud_pic_group1; +mpic_t *hud_pic_group2; +mpic_t *hud_pic_group3; +mpic_t *hud_pic_group4; +mpic_t *hud_pic_group5; +mpic_t *hud_pic_group6; +mpic_t *hud_pic_group7; +mpic_t *hud_pic_group8; +mpic_t *hud_pic_group9; + +void SCR_HUD_DrawGroup(hud_t *hud, int width, int height, mpic_t *pic, int pic_scalemode, float pic_alpha) +{ + #define HUD_GROUP_SCALEMODE_TILE 1 + #define HUD_GROUP_SCALEMODE_STRETCH 2 + #define HUD_GROUP_SCALEMODE_GROW 3 + #define HUD_GROUP_SCALEMODE_CENTER 4 + + int x, y; + + float picwidth = 64; + float picheight = 64; + + if (pic && pDraw_ImageSize((intptr_t)pic, &picwidth, &picheight) <= 0) + { + pic = NULL; + picwidth = 64; + picheight = 64; + } + + clamp(width, 1, 99999); + clamp(height, 1, 99999); + + // Set it to this, because 1.0 will make the colors + // completly saturated, and no semi-transparency will show. + pic_alpha = (pic_alpha) >= 1.0 ? 0.99 : pic_alpha; + + // Grow the group if necessary. + if (pic_scalemode == HUD_GROUP_SCALEMODE_GROW + && pic != NULL && picheight > 0 && picwidth > 0) + { + width = max(picwidth, width); + height = max(picheight, height); + } + + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + { + return; + } + + // Draw the picture if it's set. + if (pic != NULL && picheight > 0) + { + int pw, ph; + + if (pic_scalemode == HUD_GROUP_SCALEMODE_TILE) + { + // Tile. + int cx = 0, cy = 0; + while (cy < height) + { + while (cx < width) + { + pw = min(picwidth, width - cx); + ph = min(picheight, height - cy); + + if (pw >= picwidth && ph >= picheight) + { + Draw_AlphaPic (x + cx , y + cy, pic, pic_alpha); + } + else + { + Draw_AlphaSubPic (x + cx, y + cy, pic, 0, 0, pw, ph, pic_alpha); + } + + cx += picwidth; + } + + cx = 0; + cy += picheight; + } + } + else if (pic_scalemode == HUD_GROUP_SCALEMODE_STRETCH) + { + // Stretch or shrink the picture to fit. + float scale_x = (float)width / picwidth; + float scale_y = (float)height / picheight; + + Draw_SAlphaSubPic2 (x, y, pic, 0, 0, picwidth, picheight, scale_x, scale_y, pic_alpha); + } + else if (pic_scalemode == HUD_GROUP_SCALEMODE_CENTER) + { + // Center the picture in the group. + int pic_x = x + (width - picwidth) / 2; + int pic_y = y + (height - picheight) / 2; + + int src_x = 0; + int src_y = 0; + + if(x > pic_x) + { + src_x = x - pic_x; + pic_x = x; + } + + if(y > pic_y) + { + src_y = y - pic_y; + pic_y = y; + } + + Draw_AlphaSubPic (pic_x, pic_y, pic, src_x, src_y, min(width, picwidth), min(height, picheight), pic_alpha); + } + else + { + // Normal. Draw in the top left corner. + Draw_AlphaSubPic (x, y, pic, 0, 0, min(width, picwidth), min(height, picheight), pic_alpha); + } + } +} + +void SCR_HUD_LoadGroupPic(cvar_t *var, mpic_t **hud_pic, char *oldval) +{ + char *newpic = var->string; + #define HUD_GROUP_PIC_BASEPATH "gfx/%s" + + mpic_t *temp_pic = NULL; + char pic_path[MAX_QPATH]; + + if (!hud_pic) + { + Com_Printf ("Couldn't load picture %s for hud group. HUD PIC is null\n", newpic); + return; + } + + // If we have no pic name. + if(!newpic || !strcmp (newpic, "")) + { + *hud_pic = NULL; + return; + } + + // Get the path for the pic. + snprintf (pic_path, sizeof(pic_path), HUD_GROUP_PIC_BASEPATH, newpic); + + // Try loading the pic. + if (!(temp_pic = Draw_CachePicSafe(pic_path, false, true))) + { + Com_Printf("Couldn't load picture %s for hud group.\n", newpic); + pCvar_SetString(var->name, ""); + return; + } + + // Save the pic. + if (hud_pic) + *hud_pic = temp_pic; + + return; +} + +void SCR_HUD_OnChangePic_Group1(cvar_t *var, char *oldval) +{ + SCR_HUD_LoadGroupPic(var, &hud_pic_group1, oldval); +} + +void SCR_HUD_OnChangePic_Group2(cvar_t *var, char *oldval) +{ + SCR_HUD_LoadGroupPic(var, &hud_pic_group2, oldval); +} + +void SCR_HUD_OnChangePic_Group3(cvar_t *var, char *oldval) +{ + SCR_HUD_LoadGroupPic(var, &hud_pic_group3, oldval); +} + +void SCR_HUD_OnChangePic_Group4(cvar_t *var, char *oldval) +{ + SCR_HUD_LoadGroupPic(var, &hud_pic_group4, oldval); +} + +void SCR_HUD_OnChangePic_Group5(cvar_t *var, char *oldval) +{ + SCR_HUD_LoadGroupPic(var, &hud_pic_group5, oldval); +} + +void SCR_HUD_OnChangePic_Group6(cvar_t *var, char *oldval) +{ + SCR_HUD_LoadGroupPic(var, &hud_pic_group6, oldval); +} + +void SCR_HUD_OnChangePic_Group7(cvar_t *var, char *oldval) +{ + SCR_HUD_LoadGroupPic(var, &hud_pic_group7, oldval); +} + +void SCR_HUD_OnChangePic_Group8(cvar_t *var, char *oldval) +{ + SCR_HUD_LoadGroupPic(var, &hud_pic_group8, oldval); +} + +void SCR_HUD_OnChangePic_Group9(cvar_t *var, char *oldval) +{ + SCR_HUD_LoadGroupPic(var, &hud_pic_group9, oldval); +} + +void SCR_HUD_Group1(hud_t *hud) +{ + static cvar_t *width = NULL, + *height, + *picture, + *pic_alpha, + *pic_scalemode; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + picture = HUD_FindVar(hud, "picture"); + pic_alpha = HUD_FindVar(hud, "pic_alpha"); + pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); + + picture->callback = SCR_HUD_OnChangePic_Group1; + SCR_HUD_LoadGroupPic(picture, &hud_pic_group1, picture->string); + } + + SCR_HUD_DrawGroup(hud, + width->value, + height->value, + hud_pic_group1, + pic_scalemode->value, + pic_alpha->value); +} + +void SCR_HUD_Group2(hud_t *hud) +{ + extern void DrawNewText(int x, int y, char *text); + static cvar_t *width = NULL, + *height, + *picture, + *pic_alpha, + *pic_scalemode; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + picture = HUD_FindVar(hud, "picture"); + pic_alpha = HUD_FindVar(hud, "pic_alpha"); + pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); + + picture->callback = SCR_HUD_OnChangePic_Group2; + SCR_HUD_LoadGroupPic(picture, &hud_pic_group2, picture->string); + } + + SCR_HUD_DrawGroup(hud, + width->value, + height->value, + hud_pic_group2, + pic_scalemode->value, + pic_alpha->value); +} + +void SCR_HUD_Group3(hud_t *hud) +{ + static cvar_t *width = NULL, + *height, + *picture, + *pic_alpha, + *pic_scalemode; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + picture = HUD_FindVar(hud, "picture"); + pic_alpha = HUD_FindVar(hud, "pic_alpha"); + pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); + + picture->callback = SCR_HUD_OnChangePic_Group3; + SCR_HUD_LoadGroupPic(picture, &hud_pic_group3, picture->string); + } + + SCR_HUD_DrawGroup(hud, + width->value, + height->value, + hud_pic_group3, + pic_scalemode->value, + pic_alpha->value); +} + +void SCR_HUD_Group4(hud_t *hud) +{ + static cvar_t *width = NULL, + *height, + *picture, + *pic_alpha, + *pic_scalemode; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + picture = HUD_FindVar(hud, "picture"); + pic_alpha = HUD_FindVar(hud, "pic_alpha"); + pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); + + picture->callback = SCR_HUD_OnChangePic_Group4; + SCR_HUD_LoadGroupPic(picture, &hud_pic_group4, picture->string); + } + + SCR_HUD_DrawGroup(hud, + width->value, + height->value, + hud_pic_group4, + pic_scalemode->value, + pic_alpha->value); +} + +void SCR_HUD_Group5(hud_t *hud) +{ + static cvar_t *width = NULL, + *height, + *picture, + *pic_alpha, + *pic_scalemode; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + picture = HUD_FindVar(hud, "picture"); + pic_alpha = HUD_FindVar(hud, "pic_alpha"); + pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); + + picture->callback = SCR_HUD_OnChangePic_Group5; + SCR_HUD_LoadGroupPic(picture, &hud_pic_group5, picture->string); + } + + SCR_HUD_DrawGroup(hud, + width->value, + height->value, + hud_pic_group5, + pic_scalemode->value, + pic_alpha->value); +} + +void SCR_HUD_Group6(hud_t *hud) +{ + static cvar_t *width = NULL, + *height, + *picture, + *pic_alpha, + *pic_scalemode; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + picture = HUD_FindVar(hud, "picture"); + pic_alpha = HUD_FindVar(hud, "pic_alpha"); + pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); + + picture->callback = SCR_HUD_OnChangePic_Group6; + SCR_HUD_LoadGroupPic(picture, &hud_pic_group6, picture->string); + } + + SCR_HUD_DrawGroup(hud, + width->value, + height->value, + hud_pic_group6, + pic_scalemode->value, + pic_alpha->value); +} + +void SCR_HUD_Group7(hud_t *hud) +{ + static cvar_t *width = NULL, + *height, + *picture, + *pic_alpha, + *pic_scalemode; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + picture = HUD_FindVar(hud, "picture"); + pic_alpha = HUD_FindVar(hud, "pic_alpha"); + pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); + + picture->callback = SCR_HUD_OnChangePic_Group7; + SCR_HUD_LoadGroupPic(picture, &hud_pic_group7, picture->string); + } + + SCR_HUD_DrawGroup(hud, + width->value, + height->value, + hud_pic_group7, + pic_scalemode->value, + pic_alpha->value); +} + +void SCR_HUD_Group8(hud_t *hud) +{ + static cvar_t *width = NULL, + *height, + *picture, + *pic_alpha, + *pic_scalemode; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + picture = HUD_FindVar(hud, "picture"); + pic_alpha = HUD_FindVar(hud, "pic_alpha"); + pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); + + picture->callback = SCR_HUD_OnChangePic_Group8; + SCR_HUD_LoadGroupPic(picture, &hud_pic_group8, picture->string); + } + + SCR_HUD_DrawGroup(hud, + width->value, + height->value, + hud_pic_group8, + pic_scalemode->value, + pic_alpha->value); +} + +void SCR_HUD_Group9(hud_t *hud) +{ + static cvar_t *width = NULL, + *height, + *picture, + *pic_alpha, + *pic_scalemode; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + picture = HUD_FindVar(hud, "picture"); + pic_alpha = HUD_FindVar(hud, "pic_alpha"); + pic_scalemode = HUD_FindVar(hud, "pic_scalemode"); + + picture->callback = SCR_HUD_OnChangePic_Group9; + SCR_HUD_LoadGroupPic(picture, &hud_pic_group9, picture->string); + } + + SCR_HUD_DrawGroup(hud, + width->value, + height->value, + hud_pic_group9, + pic_scalemode->value, + pic_alpha->value); +} + +// player sorting +// for frags and players +typedef struct sort_teams_info_s +{ + char *name; + int frags; + int min_ping; + int avg_ping; + int max_ping; + int nplayers; + int top, bottom; // leader colours + int rlcount; // Number of RL's present in the team. (Cokeman 2006-05-27) +} +sort_teams_info_t; + +typedef struct sort_players_info_s +{ + int playernum; + sort_teams_info_t *team; +} +sort_players_info_t; + +static sort_players_info_t sorted_players[MAX_CLIENTS]; +static sort_teams_info_t sorted_teams[MAX_CLIENTS]; +static int n_teams; +static int n_players; +static int n_spectators; +static int sort_teamsort = 0; + +static int HUD_ComparePlayers(const void *vp1, const void *vp2) +{ + const sort_players_info_t *p1 = vp1; + const sort_players_info_t *p2 = vp2; + + int r = 0; + player_info_t *i1 = &cl.players[p1->playernum]; + player_info_t *i2 = &cl.players[p2->playernum]; + + if (i1->spectator && !i2->spectator) + { + r = -1; + } + else if (!i1->spectator && i2->spectator) + { + r = 1; + } + else if (i1->spectator && i2->spectator) + { + r = strcmp(i1->name, i2->name); + } + else + { + // + // Both are players. + // + if(sort_teamsort && cl.teamplay && p1->team && p2->team) + { + // Leading team on top, sort players inside of the teams. + + // Teamsort 1, first sort on team frags. + if (sort_teamsort == 1) + { + r = p1->team->frags - p2->team->frags; + } + + // Teamsort == 2, sort on team name only. + r = (r == 0) ? -strcmp(p1->team->name, p2->team->name) : r; + } + + r = (r == 0) ? i1->frags - i2->frags : r; + r = (r == 0) ? strcmp(i1->name, i2->name) : r; + } + + r = (r == 0) ? (p1->playernum - p2->playernum) : r; + + // qsort() sorts ascending by default, we want descending. + // So negate the result. + return -r; +} + +static int HUD_CompareTeams(const void *vt1, const void *vt2) +{ + int r = 0; + const sort_teams_info_t *t1 = vt1; + const sort_teams_info_t *t2 = vt2; + + r = (t1->frags - t2->frags); + r = !r ? strcmp(t1->name, t2->name) : r; + + // qsort() sorts ascending by default, we want descending. + // So negate the result. + return -r; +} + +#define HUD_SCOREBOARD_ALL 0xffffffff +#define HUD_SCOREBOARD_SORT_TEAMS (1 << 0) +#define HUD_SCOREBOARD_SORT_PLAYERS (1 << 1) +#define HUD_SCOREBOARD_UPDATE (1 << 2) +#define HUD_SCOREBOARD_AVG_PING (1 << 3) + +static void HUD_Sort_Scoreboard(int flags) +{ + int i; + int team; + + n_teams = 0; + n_players = 0; + n_spectators = 0; + + // Set team properties. + if(flags & HUD_SCOREBOARD_UPDATE) + { + memset(sorted_teams, 0, sizeof(sorted_teams)); + + for (i=0; i < MAX_CLIENTS; i++) + { + if (cl.players[i].name[0] && !cl.players[i].spectator) + { + // Find players team + for (team = 0; team < n_teams; team++) + { + if (!strcmp(cl.players[i].team, sorted_teams[team].name) + && sorted_teams[team].name[0]) + { + break; + } + } + + // The team wasn't found in the list of existing teams + // so add a new team. + if (team == n_teams) + { + team = n_teams++; + sorted_teams[team].avg_ping = 0; + sorted_teams[team].max_ping = 0; + sorted_teams[team].min_ping = 999; + sorted_teams[team].nplayers = 0; + sorted_teams[team].frags = 0; + sorted_teams[team].top = Sbar_TopColor(&cl.players[i]); + sorted_teams[team].bottom = Sbar_BottomColor(&cl.players[i]); + sorted_teams[team].name = cl.players[i].team; + sorted_teams[team].rlcount = 0; + } + + sorted_teams[team].nplayers++; + sorted_teams[team].frags += cl.players[i].frags; + sorted_teams[team].avg_ping += cl.players[i].ping; + sorted_teams[team].min_ping = min(sorted_teams[team].min_ping, cl.players[i].ping); + sorted_teams[team].max_ping = max(sorted_teams[team].max_ping, cl.players[i].ping); + +#ifdef HAXX + // The total RL count for the players team. + if(cl.players[i].stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER) + { + sorted_teams[team].rlcount++; + } +#endif + + // Set player data. + sorted_players[n_players + n_spectators].playernum = i; + //sorted_players[n_players + n_spectators].team = &sorted_teams[team]; + + // Increase the count. + if (cl.players[i].spectator) + { + n_spectators++; + } + else + { + n_players++; + } + } + } + } + + // Calc avg ping. + if(flags & HUD_SCOREBOARD_AVG_PING) + { + for (team = 0; team < n_teams; team++) + { + sorted_teams[team].avg_ping /= sorted_teams[team].nplayers; + } + } + + // Sort teams. + if(flags & HUD_SCOREBOARD_SORT_TEAMS) + { + qsort(sorted_teams, n_teams, sizeof(sort_teams_info_t), HUD_CompareTeams); + + // BUGFIX, this needs to happen AFTER the team array has been sorted, otherwise the + // players might be pointing to the incorrect team adress. + for (i = 0; i < MAX_CLIENTS; i++) + { + player_info_t *player = &cl.players[sorted_players[i].playernum]; + sorted_players[i].team = NULL; + + // Find players team. + for (team = 0; team < n_teams; team++) + { + if (!strcmp(player->team, sorted_teams[team].name) + && sorted_teams[team].name[0]) + { + sorted_players[i].team = &sorted_teams[team]; + break; + } + } + } + } + + // Sort players. + if(flags & HUD_SCOREBOARD_SORT_PLAYERS) + { + qsort(sorted_players, n_players + n_spectators, sizeof(sort_players_info_t), HUD_ComparePlayers); + } +} + +void Frags_DrawColors(int x, int y, int width, int height, + int top_color, int bottom_color, float color_alpha, + int frags, int drawBrackets, int style, + float bignum) +{ + char buf[32]; + int posy = 0; + int char_size = (bignum > 0) ? Q_rint(24 * bignum) : 8; + + Draw_AlphaFill(x, y, width, height / 2, top_color, color_alpha); + Draw_AlphaFill(x, y + height / 2, width, height - height / 2, bottom_color, color_alpha); + + posy = y + (height - char_size) / 2; + + if (bignum > 0) + { + // + // Scaled big numbers for frags. + // + char *t = buf; + int char_x; + int char_y; + snprintf(buf, sizeof (buf), "%d", frags); + + char_x = max(x, x + (width - (int)strlen(buf) * char_size) / 2); + char_y = max(y, posy); + + while (*t) + { + if (*t >= '0' && *t <= '9') + { + Draw_STransPic(char_x, char_y, sb_nums[0][*t - '0'], bignum); + char_x += char_size; + } + else if (*t == '-') + { + Draw_STransPic(char_x, char_y, sb_nums[0][STAT_MINUS], bignum); + char_x += char_size; + } + + t++; + } + } + else + { + // Normal text size. + snprintf(buf, sizeof (buf), "%3d", frags); + Draw_String(x - 2 + (width - char_size * strlen(buf) - 2) / 2, posy, buf); + } + + if(drawBrackets) + { + // Brackets [] are not available scaled, so use normal size even + // if we're drawing big frag nums. + int brack_posy = y + (height - 8) / 2; + int d = (width >= 32) ? 0 : 1; + + switch(style) + { + case 1 : + Draw_Character(x - 8, posy, 13); + break; + case 2 : + // Red outline. + Draw_Fill(x, y - 1, width, 1, 0x4f); + Draw_Fill(x, y - 1, 1, height + 2, 0x4f); + Draw_Fill(x + width - 1, y - 1, 1, height + 2, 0x4f); + Draw_Fill(x, y + height, width, 1, 0x4f); + break; + case 0 : + default : + Draw_Character(x - 2 - 2 * d, brack_posy, 16); // [ + Draw_Character(x + width - 8 + 1 + d, brack_posy, 17); // ] + break; + } + } +} + +#define FRAGS_HEALTHBAR_WIDTH 5 + +#define FRAGS_HEALTHBAR_NORMAL_COLOR 75 +#define FRAGS_HEALTHBAR_MEGA_COLOR 251 +#define FRAGS_HEALTHBAR_TWO_MEGA_COLOR 238 +#define FRAGS_HEALTHBAR_UNNATURAL_COLOR 144 + +void Frags_DrawHealthBar(int original_health, int x, int y, int height, int width) +{ + float health_height = 0.0; + int health; + + // Get the health. + health = original_health; + health = min(100, health); + + // Draw a health bar. + health_height = Q_rint((height / 100.0) * health); + health_height = (health_height > 0.0 && health_height < 1.0) ? 1 : health_height; + health_height = (health_height < 0.0) ? 0.0 : health_height; + Draw_Fill(x, y + height - (int)health_height, 3, (int)health_height, FRAGS_HEALTHBAR_NORMAL_COLOR); + + // Get the health again to check if health is more than 100. + health = original_health; + if(health > 100 && health <= 200) + { + health_height = (int)Q_rint((height / 100.0) * (health - 100)); + Draw_Fill(x, y + height - health_height, width, health_height, FRAGS_HEALTHBAR_MEGA_COLOR); + } + else if(health > 200 && health <= 250) + { + health_height = (int)Q_rint((height / 100.0) * (health - 200)); + Draw_Fill(x, y, width, height, FRAGS_HEALTHBAR_MEGA_COLOR); + Draw_Fill(x, y + height - health_height, width, health_height, FRAGS_HEALTHBAR_TWO_MEGA_COLOR); + } + else if(health > 250) + { + // This will never happen during a normal game. + Draw_Fill(x, y, width, health_height, FRAGS_HEALTHBAR_UNNATURAL_COLOR); + } +} + +#define TEAMFRAGS_EXTRA_SPEC_NONE 0 +#define TEAMFRAGS_EXTRA_SPEC_BEFORE 1 +#define TEAMFRAGS_EXTRA_SPEC_ONTOP 2 +#define TEAMFRAGS_EXTRA_SPEC_NOICON 3 +#define TEAMFRAGS_EXTRA_SPEC_RLTEXT 4 + +int TeamFrags_DrawExtraSpecInfo(int num, int px, int py, int width, int height, int style) +{ + float rl_width, rl_height; + mpic_t *pic = sb_weapons[0][5]; + pDraw_ImageSize((intptr_t)pic, &rl_width, &rl_height); + + // Only allow this for spectators. + if (!(cls.demoplayback || cl.spectator) + || style > TEAMFRAGS_EXTRA_SPEC_RLTEXT + || style <= TEAMFRAGS_EXTRA_SPEC_NONE + || !style) + { + return px; + } + + // Check if the team has any RL's. + if(sorted_teams[num].rlcount > 0) + { + int y_pos = py; + + // + // Draw the RL + count depending on style. + // + + if((style == TEAMFRAGS_EXTRA_SPEC_BEFORE || style == TEAMFRAGS_EXTRA_SPEC_NOICON) + && style != TEAMFRAGS_EXTRA_SPEC_RLTEXT) + { + y_pos = Q_rint(py + (height / 2.0) - 4); + Draw_ColoredString(px, y_pos, va("%d", sorted_teams[num].rlcount), 0); + px += 8 + 1; + } + + if(style != TEAMFRAGS_EXTRA_SPEC_NOICON && style != TEAMFRAGS_EXTRA_SPEC_RLTEXT) + { + y_pos = Q_rint(py + (height / 2.0) - (rl_height / 2.0)); + Draw_SSubPic (px, y_pos, pic, 0, 0, rl_width, rl_height, 1); + px += rl_width + 1; + } + + if(style == TEAMFRAGS_EXTRA_SPEC_ONTOP && style != TEAMFRAGS_EXTRA_SPEC_RLTEXT) + { + y_pos = Q_rint(py + (height / 2.0) - 4); + Draw_ColoredString(px - 14, y_pos, va("%d", sorted_teams[num].rlcount), 0); + } + + if(style == TEAMFRAGS_EXTRA_SPEC_RLTEXT) + { + y_pos = Q_rint(py + (height / 2.0) - 4); + Draw_ColoredString(px, y_pos, va("&ce00RL&cfff%d", sorted_teams[num].rlcount), 0); + px += 8*3 + 1; + } + } + else + { + // If the team has no RL's just pad with nothing. + if(style == TEAMFRAGS_EXTRA_SPEC_BEFORE) + { + // Draw the rl count before the rl icon. + px += rl_width + 8 + 1 + 1; + } + else if(style == TEAMFRAGS_EXTRA_SPEC_ONTOP) + { + // Draw the rl count on top of the RL instead of infront. + px += rl_width + 1; + } + else if(style == TEAMFRAGS_EXTRA_SPEC_NOICON) + { + // Only draw the rl count. + px += 8 + 1; + } + else if(style == TEAMFRAGS_EXTRA_SPEC_RLTEXT) + { + px += 8*3 + 1; + } + } + + return px; +} + +static qbool hud_frags_extra_spec_info = true; +static qbool hud_frags_show_rl = true; +static qbool hud_frags_show_armor = true; +static qbool hud_frags_show_health = true; +static qbool hud_frags_show_powerup = true; +static qbool hud_frags_textonly = false; + +static void QDECL Frags_OnChangeExtraSpecInfo(cvar_t *var, char *oldvalue) +{ + // Parse the extra spec info. + hud_frags_show_rl = Utils_RegExpMatch("RL|ALL", var->string); + hud_frags_show_armor = Utils_RegExpMatch("ARMOR|ALL", var->string); + hud_frags_show_health = Utils_RegExpMatch("HEALTH|ALL", var->string); + hud_frags_show_powerup = Utils_RegExpMatch("POWERUP|ALL", var->string); + hud_frags_textonly = Utils_RegExpMatch("TEXT", var->string); + + hud_frags_extra_spec_info = (hud_frags_show_rl || hud_frags_show_armor || hud_frags_show_health || hud_frags_show_powerup); +} + +static int Frags_DrawExtraSpecInfo(player_info_t *info, + int px, int py, + int cell_width, int cell_height, + int space_x, int space_y, int flip) +{ +#ifdef HAXX + mpic_t *rl_picture = sb_weapons[0][5]; // Picture of RL. + float rl_width, rl_height; + + float armor_height = 0.0; + int armor = 0; + int armor_bg_color = 0; + float armor_bg_power = 0; + int health_spacing = 1; + int weapon_width = 24; + + pDraw_ImageSize((intptr_t)rl_picture, &rl_width, &rl_height); + + // Only allow this for spectators. + if (!(cls.demoplayback || cl.spectator)) + { + return px; + } + + // Set width based on text or picture. + weapon_width = hud_frags_textonly ? rl_width : 24; + + // Draw health bar. (flipped) + if(flip && hud_frags_show_health) + { + Frags_DrawHealthBar(info->stats[STAT_HEALTH], px, py, cell_height, 3); + px += 3 + health_spacing; + } + + armor = info->stats[STAT_ARMOR]; + + // If the player has any armor, draw it in the appropriate color. + if(info->stats[STAT_ITEMS] & IT_ARMOR1) + { + armor_bg_power = 100; + armor_bg_color = 178; // Green armor. + } + else if(info->stats[STAT_ITEMS] & IT_ARMOR2) + { + armor_bg_power = 150; + armor_bg_color = 111; // Yellow armor. + } + else if(info->stats[STAT_ITEMS] & IT_ARMOR3) + { + armor_bg_power = 200; + armor_bg_color = 79; // Red armor. + } + + // Only draw the armor if the current player has one and if the style allows it. + if(armor_bg_power && hud_frags_show_armor) + { + armor_height = Q_rint((cell_height / armor_bg_power) * armor); + + Draw_AlphaFill(px, // x + py + cell_height - (int)armor_height, // y (draw from bottom up) + weapon_width, // width + (int)armor_height, // height + armor_bg_color, // color + 0.3); // alpha + } + + // Draw the rl if the current player has it and the style allows it. + if(info->stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER && hud_frags_show_rl) + { + if(!hud_frags_textonly) + { + // Draw the rl-pic. + Draw_SSubPic (px, + py + Q_rint((cell_height/2.0)) - (rl_height/2.0), + rl_picture, 0, 0, + rl_width, + rl_height, 1); + } + else + { + // Just print "RL" instead. + Draw_String(px + 12 - 8, py + Q_rint((cell_height/2.0)) - 4, "RL"); + } + } + + // Only draw powerups is the current player has it and the style allows it. + if(hud_frags_show_powerup) + { + + //float powerups_x = px + (spec_extra_weapon_w / 2.0); + float powerups_x = px + (weapon_width / 2.0); + + if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY + && info->stats[STAT_ITEMS] & IT_INVISIBILITY + && info->stats[STAT_ITEMS] & IT_QUAD) + { + Draw_ColoredString(Q_rint(powerups_x - 10), py, "&c0ffQ&cf00P&cff0R", 0); + } + else if(info->stats[STAT_ITEMS] & IT_QUAD + && info->stats[STAT_ITEMS] & IT_INVULNERABILITY) + { + Draw_ColoredString(Q_rint(powerups_x - 8), py, "&c0ffQ&cf00P", 0); + } + else if(info->stats[STAT_ITEMS] & IT_QUAD + && info->stats[STAT_ITEMS] & IT_INVISIBILITY) + { + Draw_ColoredString(Q_rint(powerups_x - 8), py, "&c0ffQ&cff0R", 0); + } + else if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY + && info->stats[STAT_ITEMS] & IT_INVISIBILITY) + { + Draw_ColoredString(Q_rint(powerups_x - 8), py, "&cf00P&cff0R", 0); + } + else if(info->stats[STAT_ITEMS] & IT_QUAD) + { + Draw_ColoredString(Q_rint(powerups_x - 4), py, "&c0ffQ", 0); + } + else if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY) + { + Draw_ColoredString(Q_rint(powerups_x - 4), py, "&cf00P", 0); + } + else if(info->stats[STAT_ITEMS] & IT_INVISIBILITY) + { + Draw_ColoredString(Q_rint(powerups_x - 4), py, "&cff0R", 0); + } + } + + px += weapon_width + health_spacing; + + // Draw health bar. (not flipped) + if(!flip && hud_frags_show_health) + { + Frags_DrawHealthBar(info->stats[STAT_HEALTH], px, py, cell_height, 3); + px += 3 + health_spacing; + } +#endif + return px; +} + +void Frags_DrawBackground(int px, int py, int cell_width, int cell_height, + int space_x, int space_y, int max_name_length, int max_team_length, + int bg_color, int shownames, int showteams, int drawBrackets, int style) +{ + int bg_width = cell_width + space_x; + //int bg_color = Sbar_BottomColor(info); + float bg_alpha = 0.3; + + if(style == 4 + || style == 6 + || style == 8) + bg_alpha = 0; + + if(shownames) + bg_width += max_name_length*8 + space_x; + + if(showteams) + bg_width += max_team_length * 8 + space_x; + + if(drawBrackets) + bg_alpha = 0.7; + + if(style == 7 || style == 8) + bg_color = 0x4f; + + Draw_AlphaFill(px - 1, py - space_y / 2, bg_width, cell_height + space_y, bg_color, bg_alpha); + + if(drawBrackets && (style == 5 || style == 6)) + { + Draw_Fill(px - 1, py - 1 - space_y / 2, bg_width, 1, 0x4f); + + Draw_Fill(px - 1, py - space_y / 2, 1, cell_height + space_y, 0x4f); + Draw_Fill(px + bg_width - 1, py - 1 - space_y / 2, 1, cell_height + 1 + space_y, 0x4f); + + Draw_Fill(px - 1, py + cell_height + space_y / 2, bg_width + 1, 1, 0x4f); + } +} + +int Frags_DrawText(int px, int py, + int cell_width, int cell_height, + int space_x, int space_y, + int max_name_length, int max_team_length, + int flip, int pad, + int shownames, int showteams, + char* name, char* team) +{ + char _name[MAX_SCOREBOARDNAME + 1]; + char _team[MAX_SCOREBOARDNAME + 1]; + int team_length = 0; + int name_length = 0; + int char_size = 8; + int y_pos; + + y_pos = Q_rint(py + (cell_height / 2.0) - 4); + + // Draw team + if(showteams && cl.teamplay) + { + strlcpy(_team, team, clamp(max_team_length, 0, sizeof(_team))); + team_length = strlen(_team); + + if(!flip) + px += space_x; + + if(pad && flip) + { + px += (max_team_length - team_length) * char_size; + Draw_String(px, y_pos, _team); + px += team_length * char_size; + } + else if(pad) + { + Draw_String(px, y_pos, _team); + px += max_team_length * char_size; + } + else + { + Draw_String(px, y_pos, _team); + px += team_length * char_size; + } + + if(flip) + px += space_x; + } + + if(shownames) + { + // Draw name + strlcpy(_name, name, clamp(max_name_length, 0, sizeof(_name))); + name_length = strlen(_name); + + if(flip && pad) + { + px += (max_name_length - name_length) * char_size; + Draw_String(px, y_pos, _name); + px += name_length * char_size; + } + else if(pad) + { + Draw_String(px, y_pos, _name); + px += max_name_length * char_size; + } + else + { + Draw_String(px, y_pos, _name); + px += name_length * char_size; + } + + px += space_x; + } + + return px; +} + +void SCR_HUD_DrawFrags(hud_t *hud) +{ + int width = 0, height = 0; + int x, y; + int max_team_length = 0; + int max_name_length = 0; + + int rows, cols, cell_width, cell_height, space_x, space_y; + int a_rows, a_cols; // actual + + static cvar_t + *hud_frags_cell_width = NULL, + *hud_frags_cell_height, + *hud_frags_rows, + *hud_frags_cols, + *hud_frags_space_x, + *hud_frags_space_y, + *hud_frags_vertical, + *hud_frags_strip, + *hud_frags_teamsort, + *hud_frags_shownames, + *hud_frags_teams, + *hud_frags_padtext, + *hud_frags_showself, + *hud_frags_extra_spec, + *hud_frags_fliptext, + *hud_frags_style, + *hud_frags_bignum, + *hud_frags_colors_alpha, + *hud_frags_maxname, + *hud_frags_notintp; + + mpic_t *rl_picture = sb_weapons[0][5]; + float rl_width, rl_height; + pDraw_ImageSize((intptr_t)rl_picture, &rl_width, &rl_height); + + if (hud_frags_cell_width == NULL) // first time + { + char specval[256]; + + hud_frags_cell_width = HUD_FindVar(hud, "cell_width"); + hud_frags_cell_height = HUD_FindVar(hud, "cell_height"); + hud_frags_rows = HUD_FindVar(hud, "rows"); + hud_frags_cols = HUD_FindVar(hud, "cols"); + hud_frags_space_x = HUD_FindVar(hud, "space_x"); + hud_frags_space_y = HUD_FindVar(hud, "space_y"); + hud_frags_teamsort = HUD_FindVar(hud, "teamsort"); + hud_frags_strip = HUD_FindVar(hud, "strip"); + hud_frags_vertical = HUD_FindVar(hud, "vertical"); + hud_frags_shownames = HUD_FindVar(hud, "shownames"); + hud_frags_teams = HUD_FindVar(hud, "showteams"); + hud_frags_padtext = HUD_FindVar(hud, "padtext"); + hud_frags_showself = HUD_FindVar(hud, "showself_always"); + hud_frags_extra_spec = HUD_FindVar(hud, "extra_spec_info"); + hud_frags_fliptext = HUD_FindVar(hud, "fliptext"); + hud_frags_style = HUD_FindVar(hud, "style"); + hud_frags_bignum = HUD_FindVar(hud, "bignum"); + hud_frags_colors_alpha = HUD_FindVar(hud, "colors_alpha"); + hud_frags_maxname = HUD_FindVar(hud, "maxname"); + hud_frags_notintp = HUD_FindVar(hud, "notintp"); + + // Set the OnChange function for extra spec info. + hud_frags_extra_spec->callback = Frags_OnChangeExtraSpecInfo; + strlcpy(specval, hud_frags_extra_spec->string, sizeof(specval)); + Cvar_Set(hud_frags_extra_spec, specval); + } + + // Don't draw the frags if we're in teamplay. + if(hud_frags_notintp->value && cl.teamplay) + { + HUD_PrepareDraw(hud, width, height, &x, &y); + return; + } + + // + // Clamp values to be "sane". + // + { + rows = hud_frags_rows->value; + clamp(rows, 1, MAX_CLIENTS); + + cols = hud_frags_cols->value; + clamp(cols, 1, MAX_CLIENTS); + + // Some users doesn't want to show the actual frags, just + // extra_spec_info stuff + names. + cell_width = hud_frags_cell_width->value; + clamp(cell_width, 0, 128); + + cell_height = hud_frags_cell_height->value; + clamp(cell_height, 7, 32); + + space_x = hud_frags_space_x->value; + clamp(space_x, 0, 128); + + space_y = hud_frags_space_y->value; + clamp(space_y, 0, 128); + } + + sort_teamsort = hud_frags_teamsort->ival; + + if (hud_frags_strip->ival) + { + // Auto set the number of rows / cols based on the number of players. + // (This is kinda fucked up, but I won't mess with it for the sake of backwards compability). + + if (hud_frags_vertical->value) + { + a_cols = min((n_players + rows - 1) / rows, cols); + a_rows = min(rows, n_players); + } + else + { + a_rows = min((n_players + cols - 1) / cols, rows); + a_cols = min(cols, n_players); + } + } + else + { + a_rows = rows; + a_cols = cols; + } + + width = (a_cols * cell_width) + ((a_cols + 1) * space_x); + height = (a_rows * cell_height) + ((a_rows + 1) * space_y); + + // Get the longest name/team name for padding. + if(hud_frags_shownames->value || hud_frags_teams->value) + { + int cur_length = 0; + int n; + + for(n = 0; n < n_players; n++) + { + player_info_t *info = &cl.players[sorted_players[n].playernum]; + cur_length = strlen(info->name); + + // Name. + if(cur_length >= max_name_length) + { + max_name_length = cur_length + 1; + } + + cur_length = strlen(info->team); + + // Team name. + if(cur_length >= max_team_length) + { + max_team_length = cur_length + 1; + } + } + + // If the user has set a limit on how many chars that + // are allowed to be shown for a name/teamname. + max_name_length = min(max(0, (int)hud_frags_maxname->value), max_name_length) + 1; + max_team_length = min(max(0, (int)hud_frags_maxname->value), max_team_length) + 1; + + // We need a wider box to draw in if we show the names. + if(hud_frags_shownames->value) + { + width += (a_cols * (max_name_length + 3) * 8) + ((a_cols + 1) * space_x); + } + + if(cl.teamplay && hud_frags_teams->value) + { + width += (a_cols * max_team_length * 8) + ((a_cols + 1) * space_x); + } + } + + // Make room for the extra spectator stuff. + if(hud_frags_extra_spec_info && (cls.demoplayback || cl.spectator) ) + { + width += a_cols * (rl_width + FRAGS_HEALTHBAR_WIDTH); + } + + if (HUD_PrepareDraw(hud, width, height, &x, &y)) + { + int i = 0; + int player_x = 0; + int player_y = 0; + int num = 0; + int drawBrackets = 0; + + // The number of players that are to be visible. + int limit = min(n_players, a_rows * a_cols); + + // Always show my current frags (don't just show the leaders). + // TODO: When all players aren't being shown in the frags, draw + // a small arrow that indicates that there are more frags to be seen. + if(hud_frags_showself->value && !cl_multiview->value) + { + int player_pos = 0; + + // Find my position in the scoreboard. + for(player_pos = 0; i < n_players; player_pos++) + { + if (cls.demoplayback || cl.spectator) + { + if (spec_track == sorted_players[player_pos].playernum) + { + break; + } + } + else if(sorted_players[player_pos].playernum == cl.playernum) + { + break; + } + } + + if(player_pos + 1 <= (a_rows * a_cols)) + { + // If I'm not "outside" the shown frags, start drawing from the top. + num = 0; + } + else + { + // Always include me in the shown frags. + num = abs((a_rows * a_cols) - (player_pos + 1)); + } + + // Make sure we're not trying to go outside the player array. + num = (num < 0 || num > n_players) ? 0 : num; + } + + //num = 0; // FIXME! johnnycz; (see fixme below) + + // + // Loop through all the positions that should be drawn (columns * rows or number of players). + // + // Start drawing player "num", usually the first player in the array, but if + // showself_always is set this might be someone else (since we need to make sure the current + // player is always shown). + // + for (i = 0; i < limit; i++) + { + player_info_t *info = &cl.players[sorted_players[num].playernum]; // FIXME! johnnycz; causes crashed on some demos + + // + // Set the coordinates where to draw the next element. + // + if (hud_frags_vertical->value) + { + if (i % a_rows == 0) + { + // We're drawing a new column. + + int element_width = cell_width + space_x; + + // Get the width of all the stuff that is shown, the name, frag cell and so on. + + if(hud_frags_shownames->value) + { + element_width += (max_name_length) * 8; + } + + if(hud_frags_teams->value) + { + element_width += (max_team_length) * 8; + } + + if(hud_frags_extra_spec_info && (cls.demoplayback || cl.spectator) ) + { + element_width += rl_width; + } + + player_x = x + space_x + ((i / a_rows) * element_width); + + // New column. + player_y = y + space_y; + } + } + else + { + if (i % a_cols == 0) + { + // Drawing new row. + player_x = x + space_x; + player_y = y + space_y + (i / a_cols) * (cell_height + space_y); + } + } + + drawBrackets = 0; + + // Bug fix. Before the wrong player would be higlighted + // during qwd-playback, since you ARE the player that you're + // being spectated (you're not a spectator). + if(cls.demoplayback && !cl.spectator && !cls.mvdplayback) + { + drawBrackets = (sorted_players[num].playernum == cl.playernum); + } + else if (cls.demoplayback || cl.spectator) + { + drawBrackets = (spec_track == sorted_players[num].playernum && Cam_TrackNum() >= 0); + } + else + { + drawBrackets = (sorted_players[num].playernum == cl.playernum); + } + + // Don't draw any brackets in multiview since we're + // tracking several players. + if (cl_multiview->value > 1 && cls.mvdplayback) + { + // TODO: Highlight all players being tracked (See tracking hud-element) + drawBrackets = 0; + } + + if(hud_frags_shownames->value || hud_frags_teams->value || hud_frags_extra_spec_info) + { + // Relative x coordinate where we draw the subitems. + int rel_player_x = player_x; + + if(hud_frags_style->value >= 4 && hud_frags_style->value <= 8) + { + // Draw background based on the style. + + Frags_DrawBackground(player_x, player_y, cell_width, cell_height, space_x, space_y, + max_name_length, max_team_length, Sbar_BottomColor(info), + hud_frags_shownames->value, hud_frags_teams->value, drawBrackets, + hud_frags_style->value); + } + + if(hud_frags_fliptext->value) + { + // + // Flip the text + // NAME | TEAM | FRAGS | EXTRA_SPEC_INFO + // + + // Draw name. + rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height, + space_x, space_y, max_name_length, max_team_length, + hud_frags_fliptext->value, hud_frags_padtext->value, + hud_frags_shownames->value, 0, + info->name, info->team); + + // Draw team. + rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height, + space_x, space_y, max_name_length, max_team_length, + hud_frags_fliptext->value, hud_frags_padtext->value, + 0, hud_frags_teams->value, + info->name, info->team); + + Frags_DrawColors(rel_player_x, player_y, cell_width, cell_height, + Sbar_TopColor(info), Sbar_BottomColor(info), hud_frags_colors_alpha->value, + info->frags, + drawBrackets, + hud_frags_style->value, + hud_frags_bignum->value); + + rel_player_x += cell_width + space_x; + + // Show extra information about all the players if spectating: + // - What armor they have. + // - How much health. + // - If they have RL or not. + rel_player_x = Frags_DrawExtraSpecInfo(info, rel_player_x, player_y, cell_width, cell_height, + space_x, space_y, + hud_frags_fliptext->value); + + } + else + { + // + // Don't flip the text + // EXTRA_SPEC_INFO | FRAGS | TEAM | NAME + // + + rel_player_x = Frags_DrawExtraSpecInfo(info, rel_player_x, player_y, cell_width, cell_height, + space_x, space_y, + hud_frags_fliptext->value); + + Frags_DrawColors(rel_player_x, player_y, cell_width, cell_height, + Sbar_TopColor(info), Sbar_BottomColor(info), hud_frags_colors_alpha->value, + info->frags, + drawBrackets, + hud_frags_style->value, + hud_frags_bignum->value); + + rel_player_x += cell_width + space_x; + + // Draw team. + rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height, + space_x, space_y, max_name_length, max_team_length, + hud_frags_fliptext->value, hud_frags_padtext->value, + 0, hud_frags_teams->value, + info->name, info->team); + + // Draw name. + rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height, + space_x, space_y, max_name_length, max_team_length, + hud_frags_fliptext->value, hud_frags_padtext->value, + hud_frags_shownames->value, 0, + info->name, info->team); + } + + if(hud_frags_vertical->value) + { + // Next row. + player_y += cell_height + space_y; + } + else + { + // Next column. + player_x = rel_player_x + space_x; + } + } + else + { + // Only showing the frags, no names or extra spec info. + + Frags_DrawColors(player_x, player_y, cell_width, cell_height, + Sbar_TopColor(info), Sbar_BottomColor(info), hud_frags_colors_alpha->value, + info->frags, + drawBrackets, + hud_frags_style->value, + hud_frags_bignum->value); + + if (hud_frags_vertical->value) + { + // Next row. + player_y += cell_height + space_y; + } + else + { + // Next column. + player_x += cell_width + space_x; + } + } + + // Next player. + num++; + } + } +} + +void SCR_HUD_DrawTeamFrags(hud_t *hud) +{ + int width = 0, height = 0; + int x, y; + int max_team_length = 0, num = 0; + int rows, cols, cell_width, cell_height, space_x, space_y; + int a_rows, a_cols; // actual + + static cvar_t + *hud_teamfrags_cell_width, + *hud_teamfrags_cell_height, + *hud_teamfrags_rows, + *hud_teamfrags_cols, + *hud_teamfrags_space_x, + *hud_teamfrags_space_y, + *hud_teamfrags_vertical, + *hud_teamfrags_strip, + *hud_teamfrags_shownames, + *hud_teamfrags_fliptext, + *hud_teamfrags_padtext, + *hud_teamfrags_style, + *hud_teamfrags_extra_spec, + *hud_teamfrags_onlytp, + *hud_teamfrags_bignum, + *hud_teamfrags_colors_alpha; + + mpic_t *rl_picture = sb_weapons[0][5]; + float rl_width, rl_height; + pDraw_ImageSize((intptr_t)rl_picture, &rl_width, &rl_height); + + if (hud_teamfrags_cell_width == 0) // first time + { + hud_teamfrags_cell_width = HUD_FindVar(hud, "cell_width"); + hud_teamfrags_cell_height = HUD_FindVar(hud, "cell_height"); + hud_teamfrags_rows = HUD_FindVar(hud, "rows"); + hud_teamfrags_cols = HUD_FindVar(hud, "cols"); + hud_teamfrags_space_x = HUD_FindVar(hud, "space_x"); + hud_teamfrags_space_y = HUD_FindVar(hud, "space_y"); + hud_teamfrags_strip = HUD_FindVar(hud, "strip"); + hud_teamfrags_vertical = HUD_FindVar(hud, "vertical"); + hud_teamfrags_shownames = HUD_FindVar(hud, "shownames"); + hud_teamfrags_fliptext = HUD_FindVar(hud, "fliptext"); + hud_teamfrags_padtext = HUD_FindVar(hud, "padtext"); + hud_teamfrags_style = HUD_FindVar(hud, "style"); + hud_teamfrags_extra_spec = HUD_FindVar(hud, "extra_spec_info"); + hud_teamfrags_onlytp = HUD_FindVar(hud, "onlytp"); + hud_teamfrags_bignum = HUD_FindVar(hud, "bignum"); + hud_teamfrags_colors_alpha = HUD_FindVar(hud, "colors_alpha"); + } + + // Don't draw the frags if we're not in teamplay. + if(hud_teamfrags_onlytp->value && !cl.teamplay) + { + HUD_PrepareDraw(hud, width, height, &x, &y); + return; + } + + rows = hud_teamfrags_rows->value; + clamp(rows, 1, MAX_CLIENTS); + cols = hud_teamfrags_cols->value; + clamp(cols, 1, MAX_CLIENTS); + cell_width = hud_teamfrags_cell_width->value; + clamp(cell_width, 28, 128); + cell_height = hud_teamfrags_cell_height->value; + clamp(cell_height, 7, 32); + space_x = hud_teamfrags_space_x->value; + clamp(space_x, 0, 128); + space_y = hud_teamfrags_space_y->value; + clamp(space_y, 0, 128); + + if (hud_teamfrags_strip->value) + { + if (hud_teamfrags_vertical->value) + { + a_cols = min((n_teams+rows-1) / rows, cols); + a_rows = min(rows, n_teams); + } + else + { + a_rows = min((n_teams+cols-1) / cols, rows); + a_cols = min(cols, n_teams); + } + } + else + { + a_rows = rows; + a_cols = cols; + } + + width = a_cols*cell_width + (a_cols+1)*space_x; + height = a_rows*cell_height + (a_rows+1)*space_y; + + // Get the longest team name for padding. + if(hud_teamfrags_shownames->value || hud_teamfrags_extra_spec->value) + { + int rlcount_width = 0; + + int cur_length = 0; + int n; + + for(n=0; n < n_teams; n++) + { + if(hud_teamfrags_shownames->value) + { + cur_length = strlen(sorted_teams[n].name); + + // Team name + if(cur_length >= max_team_length) + { + max_team_length = cur_length + 1; + } + } + } + + // Calculate the length of the extra spec info. + if(hud_teamfrags_extra_spec->value && (cls.demoplayback || cl.spectator)) + { + if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_BEFORE) + { + // Draw the rl count before the rl icon. + rlcount_width = rl_width + 8 + 1 + 1; + } + else if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_ONTOP) + { + // Draw the rl count on top of the RL instead of infront. + rlcount_width = rl_width + 1; + } + else if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_NOICON) + { + // Only draw the rl count. + rlcount_width = 8 + 1; + } + else if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_RLTEXT) + { + rlcount_width = 8*3 + 1; + } + } + + width += a_cols*max_team_length*8 + (a_cols+1)*space_x + a_cols*rlcount_width; + } + + if (HUD_PrepareDraw(hud, width, height, &x, &y)) + { + int i; + int px = 0; + int py = 0; + int drawBrackets; + int limit = min(n_teams, a_rows*a_cols); + + for (i=0; i < limit; i++) + { + if (hud_teamfrags_vertical->value) + { + if (i % a_rows == 0) + { + px = x + space_x + (i/a_rows) * (cell_width+space_x); + py = y + space_y; + } + } + else + { + if (i % a_cols == 0) + { + px = x + space_x; + py = y + space_y + (i/a_cols) * (cell_height+space_y); + } + } + + drawBrackets = 0; + + // Bug fix. Before the wrong player would be higlighted + // during qwd-playback, since you ARE the player that you're + // being spectated. + if(cls.demoplayback && !cl.spectator && !cls.mvdplayback) + { + // QWD Playback. + if (!strcmp(sorted_teams[num].name, cl.players[cl.playernum].team)) + { + drawBrackets = 1; + } + } + else if (cls.demoplayback || cl.spectator) + { + // MVD playback / spectating. + if (!strcmp(cl.players[spec_track].team, sorted_teams[num].name) && Cam_TrackNum() >= 0) + { + drawBrackets = 1; + } + } + else + { + // Normal player. + if (!strcmp(sorted_teams[num].name, cl.players[cl.playernum].team)) + { + drawBrackets = 1; + } + } + + if (cl_multiview->value && cl.splitscreenview != 0 ) // Only draw bracket for first view, might make todo below unnecessary + { + // TODO: Check if "track team" is set, if it is then draw brackets around that team. + //cl.players[nPlayernum] + + drawBrackets = 0; + } + + if(hud_teamfrags_shownames->value || hud_teamfrags_extra_spec->value) + { + int _px = px; + + // Draw a background if the style tells us to. + if(hud_teamfrags_style->value >= 4 && hud_teamfrags_style->value <= 8) + { + Frags_DrawBackground(px, py, cell_width, cell_height, space_x, space_y, + 0, max_team_length, sorted_teams[num].bottom, + 0, hud_teamfrags_shownames->value, drawBrackets, + hud_teamfrags_style->value); + } + + // Draw the text on the left or right side of the score? + if(hud_teamfrags_fliptext->value) + { + // Draw team. + _px = Frags_DrawText(_px, py, cell_width, cell_height, + space_x, space_y, 0, max_team_length, + hud_teamfrags_fliptext->value, hud_teamfrags_padtext->value, + 0, hud_teamfrags_shownames->value, + "", sorted_teams[num].name); + + Frags_DrawColors(_px, py, cell_width, cell_height, + sorted_teams[num].top, + sorted_teams[num].bottom, + hud_teamfrags_colors_alpha->value, + sorted_teams[num].frags, + drawBrackets, + hud_teamfrags_style->value, + hud_teamfrags_bignum->value); + + _px += cell_width + space_x; + + // Draw the rl if the current player has it and the style allows it. + _px = TeamFrags_DrawExtraSpecInfo(num, _px, py, cell_width, cell_height, hud_teamfrags_extra_spec->value); + + } + else + { + // Draw the rl if the current player has it and the style allows it. + _px = TeamFrags_DrawExtraSpecInfo(num, _px, py, cell_width, cell_height, hud_teamfrags_extra_spec->value); + + Frags_DrawColors(_px, py, cell_width, cell_height, + sorted_teams[num].top, + sorted_teams[num].bottom, + hud_teamfrags_colors_alpha->value, + sorted_teams[num].frags, + drawBrackets, + hud_teamfrags_style->value, + hud_teamfrags_bignum->value); + + _px += cell_width + space_x; + + // Draw team. + _px = Frags_DrawText(_px, py, cell_width, cell_height, + space_x, space_y, 0, max_team_length, + hud_teamfrags_fliptext->value, hud_teamfrags_padtext->value, + 0, hud_teamfrags_shownames->value, + "", sorted_teams[num].name); + } + + if(hud_teamfrags_vertical->value) + { + py += cell_height + space_y; + } + else + { + px = _px + space_x; + } + } + else + { + Frags_DrawColors(px, py, cell_width, cell_height, + sorted_teams[num].top, + sorted_teams[num].bottom, + hud_teamfrags_colors_alpha->value, + sorted_teams[num].frags, + drawBrackets, + hud_teamfrags_style->value, + hud_teamfrags_bignum->value); + + if (hud_teamfrags_vertical->value) + { + py += cell_height + space_y; + } + else + { + px += cell_width + space_x; + } + } + num ++; + } + } +} + +char *Get_MP3_HUD_style(float style, char *st) +{ + static char HUD_style[32]; + if(style == 1.0) + { + strlcpy(HUD_style, va("%s:", st), sizeof(HUD_style)); + } + else if(style == 2.0) + { + strlcpy(HUD_style, va("^Ue010%s^Ue011", st), sizeof(HUD_style)); + } + else + { + strlcpy(HUD_style, "", sizeof(HUD_style)); + } + return HUD_style; +} + +// Draws MP3 Title. +void SCR_HUD_DrawMP3_Title(hud_t *hud) +{ + int x=0, y=0/*, n=1*/; + int width = 64; + int height = 8; + +#ifdef WITH_MP3_PLAYER + //int width_as_text = 0; + static int title_length = 0; + //int row_break = 0; + //int i=0; + int status = 0; + static char title[MP3_MAXSONGTITLE]; + double t; // current time + static double lastframetime; // last refresh + + static cvar_t *style = NULL, *width_var, *height_var, *scroll, *scroll_delay, *on_scoreboard, *wordwrap; + + if (style == NULL) // first time called + { + style = HUD_FindVar(hud, "style"); + width_var = HUD_FindVar(hud, "width"); + height_var = HUD_FindVar(hud, "height"); + scroll = HUD_FindVar(hud, "scroll"); + scroll_delay = HUD_FindVar(hud, "scroll_delay"); + on_scoreboard = HUD_FindVar(hud, "on_scoreboard"); + wordwrap = HUD_FindVar(hud, "wordwrap"); + } + + if(on_scoreboard->value) + { + hud->flags |= HUD_ON_SCORES; + } + else if((int)on_scoreboard->value & HUD_ON_SCORES) + { + hud->flags -= HUD_ON_SCORES; + } + + width = (int)width_var->value; + height = (int)height_var->value; + + if(width < 0) width = 0; + if(width > vid.width) width = vid.width; + if(height < 0) height = 0; + if(height > vid.width) height = vid.height; + + t = Sys_DoubleTime(); + + if ((t - lastframetime) >= 2) { // 2 sec refresh rate + lastframetime = t; + status = MP3_GetStatus(); + + switch(status) + { + case MP3_PLAYING : + title_length = snprintf(title, sizeof(title)-1, "%s %s", Get_MP3_HUD_style(style->value, "Playing"), MP3_Macro_MP3Info()); + break; + case MP3_PAUSED : + title_length = snprintf(title, sizeof(title)-1, "%s %s", Get_MP3_HUD_style(style->value, "Paused"), MP3_Macro_MP3Info()); + break; + case MP3_STOPPED : + title_length = snprintf(title, sizeof(title)-1, "%s %s", Get_MP3_HUD_style(style->value, "Stopped"), MP3_Macro_MP3Info()); + break; + case MP3_NOTRUNNING : + default : + status = MP3_NOTRUNNING; + title_length = snprintf (title, sizeof (title), "%s is not running.", mp3_player->PlayerName_AllCaps); + break; + } + + if(title_length < 0) + { + snprintf(title, sizeof (title), "Error retrieving current song."); + } + } + + if (HUD_PrepareDraw(hud, width , height, &x, &y)) + { + SCR_DrawWordWrapString(x, y, 8, width, height, (int)wordwrap->value, (int)scroll->value, (float)scroll_delay->value, title); + } +#else + HUD_PrepareDraw(hud, width , height, &x, &y); +#endif +} + +// Draws MP3 Time as a HUD-element. +void SCR_HUD_DrawMP3_Time(hud_t *hud) +{ + int x = 0, y = 0, width = 0, height = 0; +#ifdef WITH_MP3_PLAYER + int elapsed = 0; + int remain = 0; + int total = 0; + static char time_string[MP3_MAXSONGTITLE]; + static char elapsed_string[MP3_MAXSONGTITLE]; + double t; // current time + static double lastframetime; // last refresh + + static cvar_t *style = NULL, *on_scoreboard; + + if(style == NULL) + { + style = HUD_FindVar(hud, "style"); + on_scoreboard = HUD_FindVar(hud, "on_scoreboard"); + } + + if(on_scoreboard->value) + { + hud->flags |= HUD_ON_SCORES; + } + else if((int)on_scoreboard->value & HUD_ON_SCORES) + { + hud->flags -= HUD_ON_SCORES; + } + + t = Sys_DoubleTime(); + if ((t - lastframetime) >= 2) { // 2 sec refresh rate + lastframetime = t; + + if(!MP3_GetOutputtime(&elapsed, &total) || elapsed < 0 || total < 0) + { + snprintf (time_string, sizeof (time_string), "^Ue010-:-^Ue011"); + } + else + { + switch((int)style->value) + { + case 1 : + remain = total - elapsed; + strlcpy (elapsed_string, SecondsToMinutesString (remain), sizeof (elapsed_string)); + snprintf (time_string, sizeof (time_string), "^Ue010-%s/%s^Ue011", elapsed_string, SecondsToMinutesString (total)); + break; + case 2 : + remain = total - elapsed; + snprintf (time_string, sizeof (time_string), "^Ue010-%s^Ue011", SecondsToMinutesString (remain)); + break; + case 3 : + snprintf (time_string, sizeof (time_string), "^Ue010%s^Ue011", SecondsToMinutesString (elapsed)); + break; + case 4 : + remain = total - elapsed; + strlcpy (elapsed_string, SecondsToMinutesString (remain), sizeof (elapsed_string)); + snprintf (time_string, sizeof (time_string), "%s/%s", elapsed_string, SecondsToMinutesString (total)); + break; + case 5 : + strlcpy (elapsed_string, SecondsToMinutesString (elapsed), sizeof (elapsed_string)); + snprintf (time_string, sizeof (time_string), "-%s/%s", elapsed_string, SecondsToMinutesString (total)); + break; + case 6 : + remain = total - elapsed; + snprintf (time_string, sizeof (time_string), "-%s", SecondsToMinutesString (remain)); + break; + case 7 : + snprintf (time_string, sizeof (time_string), "%s", SecondsToMinutesString (elapsed)); + break; + case 0 : + default : + strlcpy (elapsed_string, SecondsToMinutesString (elapsed), sizeof (elapsed_string)); + snprintf (time_string, sizeof (time_string), "^Ue010%s/%s^Ue011", elapsed_string, SecondsToMinutesString (total)); + break; + } + } + + } + + // Don't allow showing the timer if ruleset disallows it + // It could be used for timing powerups + // Use same check that is used for any external communication + if(Rulesets_RestrictPacket()) + snprintf (time_string, sizeof (time_string), "^Ue010%s^Ue011", "Not allowed"); + + width = strlen (time_string) * 8; + height = 8; + + if (HUD_PrepareDraw(hud, width , height, &x, &y)) + Draw_String(x, y, time_string); +#else + HUD_PrepareDraw(hud, width , height, &x, &y); +#endif +} + +#ifdef WITH_PNG + +// Map picture to draw for the mapoverview hud control. +mpic_t *radar_pic; +static qbool radar_pic_found = false; + +// The conversion formula used for converting from quake coordinates to pixel coordinates +// when drawing on the map overview. +static float map_x_slope; +static float map_x_intercept; +static float map_y_slope; +static float map_y_intercept; +static qbool conversion_formula_found = false; + +// Used for drawing the height of the player. +static float map_height_diff = 0.0; + +#define RADAR_BASE_PATH_FORMAT "radars/%s.png" + +// +// Is run when a new map is loaded. +// +void HUD_NewRadarMap() +{ + int i = 0; + int len = 0; + int n_textcount = 0; + mpic_t *radar_pic_p = NULL; + png_textp txt = NULL; + char *radar_filename = NULL; + + if (!cl.worldmodel) + return; // seems we are not ready to do that + + // Reset the radar pic status. + radar_pic = NULL; + radar_pic_found = false; + conversion_formula_found = false; + + // Allocate a string for the path to the radar image. + len = strlen (RADAR_BASE_PATH_FORMAT) + strlen (host_mapname.string); + radar_filename = Q_calloc (len, sizeof(char)); + snprintf (radar_filename, len, RADAR_BASE_PATH_FORMAT, host_mapname.string); + + // Load the map picture. + if ((radar_pic_p = GL_LoadPicImage (radar_filename, host_mapname.string, 0, 0, TEX_ALPHA)) != NULL) + { + radar_pic = *radar_pic_p; + radar_pic_found = true; + + // Calculate the height of the map. + map_height_diff = abs(cl.worldmodel->maxs[2] - cl.worldmodel->mins[2]); + + // Get the comments from the PNG. + txt = Image_LoadPNG_Comments(radar_filename, &n_textcount); + + // Check if we found any comments. + if(txt != NULL) + { + int found_count = 0; + + // Find the conversion formula in the comments found in the PNG. + for(i = 0; i < n_textcount; i++) + { + if(!strcmp(txt[i].key, "QWLMConversionSlopeX")) + { + map_x_slope = atof(txt[i].text); + found_count++; + } + else if(!strcmp(txt[i].key, "QWLMConversionInterceptX")) + { + map_x_intercept = atof(txt[i].text); + found_count++; + } + else if(!strcmp(txt[i].key, "QWLMConversionSlopeY")) + { + map_y_slope = atof(txt[i].text); + found_count++; + } + else if(!strcmp(txt[i].key, "QWLMConversionInterceptY")) + { + map_y_intercept = atof(txt[i].text); + found_count++; + } + + conversion_formula_found = (found_count == 4); + } + + // Free the text chunks. + Q_free(txt); + } + else + { + conversion_formula_found = false; + } + } + else + { + // No radar pic found. + memset (&radar_pic, 0, sizeof(radar_pic)); + radar_pic_found = false; + conversion_formula_found = false; + } + + // Free the path string to the radar png. + Q_free (radar_filename); +} +#endif // WITH_PNG + +#define TEMPHUD_NAME "_temphud" +#define TEMPHUD_FULLPATH "configs/"TEMPHUD_NAME".cfg" + +// will check if user wants to un/load external MVD HUD automatically +void HUD_AutoLoad_MVD(int autoload) { +#ifdef HAXX + char *cfg_suffix = "custom"; + extern cvar_t *scr_fov; + extern cvar_t *scr_newHud; + extern void Cmd_Exec_f (void); + extern void DumpConfig(char *name); + + if (autoload && cls.mvdplayback) { + // Turn autohud ON here + + Com_DPrintf("Loading MVD Hud\n"); + // Store current settings. + if (!autohud.active) + { + // Save old cfg_save values so that we don't screw the users + // settings when saving the temp config. + int old_cmdline = pCvar_GetFloat("cfg_save_cmdline"); + int old_cvars = pCvar_GetFloat("cfg_save_cvars"); + int old_cmds = pCvar_GetFloat("cfg_save_cmds"); + int old_aliases = pCvar_GetFloat("cfg_save_aliases"); + int old_binds = pCvar_GetFloat("cfg_save_binds"); + + autohud.old_fov = (int) scr_fov->value; + autohud.old_multiview = (int) cl_multiview->value; + autohud.old_newhud = (int) scr_newHud->value; + + // Make sure everything current settings are saved. + pCvar_SetFloat("cfg_save_cmdline", 1); + pCvar_SetFloat("cfg_save_cvars", 1); + pCvar_SetFloat("cfg_save_cmds", 1); + pCvar_SetFloat("cfg_save_aliases", 1); + pCvar_SetFloat("cfg_save_binds", 1); + + // Save a temporary config. + DumpConfig(TEMPHUD_NAME".cfg"); + + pCvar_SetFloat("cfg_save_cmdline", old_cmdline); + pCvar_SetFloat("cfg_save_cvars", old_cvars); + pCvar_SetFloat("cfg_save_cmds", old_cmds); + pCvar_SetFloat("cfg_save_aliases", old_aliases); + pCvar_SetFloat("cfg_save_binds", old_binds); + } + + // load MVD HUD config + switch ((int) autoload) { + case 1: // load 1on1 or 4on4 or custom according to $matchtype + if (!strncmp(Macro_MatchType(), "duel", 4)) { + cfg_suffix = "1on1"; + } else if (!strncmp(Macro_MatchType(), "4on4", 4)) { + cfg_suffix = "4on4"; + } else { + cfg_suffix = "custom"; + } + break; + default: + case 2: + cfg_suffix = "custom"; + break; + } + + Cbuf_AddText(va("exec cfg/mvdhud_%s.cfg\n", cfg_suffix)); + + autohud.active = true; + return; + } + + if ((!cls.mvdplayback || !autoload) && autohud.active) { + // either user decided to turn mvd autohud off or mvd playback is over + // -> Turn autohud OFF here + FILE *tempfile; + char *fullname = va("%s/ezquake/"TEMPHUD_FULLPATH, com_basedir); + + Com_DPrintf("Unloading MVD Hud\n"); + // load stored settings + pCvar_SetFloat(scr_fov->name, autohud.old_fov); + pCvar_SetFloat(cl_multiview->name, autohud.old_multiview); + pCvar_SetFloat(scr_newHud->name, autohud.old_newhud); + //Cmd_TokenizeString("exec "TEMPHUD_FULLPATH); + Cmd_TokenizeString("cfg_load "TEMPHUD_FULLPATH); + Cmd_Exec_f(); + + // delete temp config with hud_* settings + if ((tempfile = fopen(fullname, "rb")) && (fclose(tempfile) != EOF)) + unlink(fullname); + + autohud.active = false; + return; + } +#endif +} + +void OnAutoHudChange(cvar_t *var, char *value, qbool *cancel) { + HUD_AutoLoad_MVD(Q_atoi(value)); +} + +// Is run when a new map is loaded. +void HUD_NewMap() { +#if defined(WITH_PNG) + HUD_NewRadarMap(); +#endif // WITH_PNG + + autohud_loaded = false; +} + +#define HUD_SHOW_ONLY_IN_TEAMPLAY 1 +#define HUD_SHOW_ONLY_IN_DEMOPLAYBACK 2 + +qbool HUD_ShowInDemoplayback(int val) +{ + if(!cl.teamplay && val == HUD_SHOW_ONLY_IN_TEAMPLAY) + { + return false; + } + else if(!cls.demoplayback && val == HUD_SHOW_ONLY_IN_DEMOPLAYBACK) + { + return false; + } + else if(!cl.teamplay && !cls.demoplayback + && val == HUD_SHOW_ONLY_IN_TEAMPLAY + HUD_SHOW_ONLY_IN_DEMOPLAYBACK) + { + return false; + } + + return true; +} + +// Team hold filters. +static qbool teamhold_show_pent = false; +static qbool teamhold_show_quad = false; +static qbool teamhold_show_ring = false; +static qbool teamhold_show_suit = false; +static qbool teamhold_show_rl = false; +static qbool teamhold_show_lg = false; +static qbool teamhold_show_gl = false; +static qbool teamhold_show_sng = false; +static qbool teamhold_show_mh = false; +static qbool teamhold_show_ra = false; +static qbool teamhold_show_ya = false; +static qbool teamhold_show_ga = false; + +void TeamHold_DrawBars(int x, int y, int width, int height, + float team1_percent, float team2_percent, + int team1_color, int team2_color, + float opacity) +{ + int team1_width = 0; + int team2_width = 0; + int bar_height = 0; + + bar_height = Q_rint (height/2.0); + team1_width = (int) (width * team1_percent); + team2_width = (int) (width * team2_percent); + + clamp(team1_width, 0, width); + clamp(team2_width, 0, width); + + Draw_AlphaFill(x, y, team1_width, bar_height, team1_color, opacity); + + y += bar_height; + + Draw_AlphaFill(x, y, team2_width, bar_height, team2_color, opacity); +} + +void TeamHold_DrawPercentageBar(int x, int y, int width, int height, + float team1_percent, float team2_percent, + int team1_color, int team2_color, + int show_text, int vertical, + int vertical_text, float opacity) +{ + int _x, _y; + int _width, _height; + + if(vertical) + { + // + // Draw vertical. + // + + // Team 1. + _x = x; + _y = y; + _width = max(0, width); + _height = Q_rint(height * team1_percent); + _height = max(0, height); + + Draw_AlphaFill(_x, _y, _width, _height, team1_color, opacity); + + // Team 2. + _x = x; + _y = Q_rint(y + (height * team1_percent)); + _width = max(0, width); + _height = Q_rint(height * team2_percent); + _height = max(0, _height); + + Draw_AlphaFill(_x, _y, _width, _height, team2_color, opacity); + + // Show the percentages in numbers also. + if(show_text) + { + // TODO: Move this to a separate function (since it's prett much copy and paste for both teams). + // Team 1. + if(team1_percent > 0.05) + { + if(vertical_text) + { + int percent = 0; + int percent10 = 0; + int percent100 = 0; + + _x = x + (width / 2) - 4; + _y = Q_rint(y + (height * team1_percent)/2 - 12); + + percent = Q_rint(100 * team1_percent); + + if((percent100 = percent / 100)) + { + Draw_String(_x, _y, va("%d", percent100)); + _y += 8; + } + + if((percent10 = percent / 10)) + { + Draw_String(_x, _y, va("%d", percent10)); + _y += 8; + } + + Draw_String(_x, _y, va("%d", percent % 10)); + _y += 8; + + Draw_String(_x, _y, "%"); + } + else + { + _x = x + (width / 2) - 12; + _y = Q_rint(y + (height * team1_percent)/2 - 4); + Draw_String(_x, _y, va("%2.0f%%", 100 * team1_percent)); + } + } + + // Team 2. + if(team2_percent > 0.05) + { + if(vertical_text) + { + int percent = 0; + int percent10 = 0; + int percent100 = 0; + + _x = x + (width / 2) - 4; + _y = Q_rint(y + (height * team1_percent) + (height * team2_percent)/2 - 12); + + percent = Q_rint(100 * team2_percent); + + if((percent100 = percent / 100)) + { + Draw_String(_x, _y, va("%d", percent100)); + _y += 8; + } + + if((percent10 = percent / 10)) + { + Draw_String(_x, _y, va("%d", percent10)); + _y += 8; + } + + Draw_String(_x, _y, va("%d", percent % 10)); + _y += 8; + + Draw_String(_x, _y, "%"); + } + else + { + _x = x + (width / 2) - 12; + _y = Q_rint(y + (height * team1_percent) + (height * team2_percent)/2 - 4); + Draw_String(_x, _y, va("%2.0f%%", 100 * team2_percent)); + } + } + } + } + else + { + // + // Draw horizontal. + // + + // Team 1. + _x = x; + _y = y; + _width = Q_rint(width * team1_percent); + _width = max(0, _width); + _height = max(0, height); + + Draw_AlphaFill(_x, _y, _width, _height, team1_color, opacity); + + // Team 2. + _x = Q_rint(x + (width * team1_percent)); + _y = y; + _width = Q_rint(width * team2_percent); + _width = max(0, _width); + _height = max(0, height); + + Draw_AlphaFill(_x, _y, _width, _height, team2_color, opacity); + + // Show the percentages in numbers also. + if(show_text) + { + // Team 1. + if(team1_percent > 0.05) + { + _x = Q_rint(x + (width * team1_percent)/2 - 8); + _y = y + (height / 2) - 4; + Draw_String(_x, _y, va("%2.0f%%", 100 * team1_percent)); + } + + // Team 2. + if(team2_percent > 0.05) + { + _x = Q_rint(x + (width * team1_percent) + (width * team2_percent)/2 - 8); + _y = y + (height / 2) - 4; + Draw_String(_x, _y, va("%2.0f%%", 100 * team2_percent)); + } + } + } +} + +#ifdef HAXX +static void SCR_HUD_DrawTeamHoldBar(hud_t *hud) +{ + int x, y; + int height = 8; + int width = 0; + float team1_percent = 0; + float team2_percent = 0; + + static cvar_t + *hud_teamholdbar_style = NULL, + *hud_teamholdbar_opacity, + *hud_teamholdbar_width, + *hud_teamholdbar_height, + *hud_teamholdbar_vertical, + *hud_teamholdbar_show_text, + *hud_teamholdbar_onlytp, + *hud_teamholdbar_vertical_text; + + if (hud_teamholdbar_style == NULL) // first time + { + hud_teamholdbar_style = HUD_FindVar(hud, "style"); + hud_teamholdbar_opacity = HUD_FindVar(hud, "opacity"); + hud_teamholdbar_width = HUD_FindVar(hud, "width"); + hud_teamholdbar_height = HUD_FindVar(hud, "height"); + hud_teamholdbar_vertical = HUD_FindVar(hud, "vertical"); + hud_teamholdbar_show_text = HUD_FindVar(hud, "show_text"); + hud_teamholdbar_onlytp = HUD_FindVar(hud, "onlytp"); + hud_teamholdbar_vertical_text = HUD_FindVar(hud, "vertical_text"); + } + + height = max(1, hud_teamholdbar_height->value); + width = max(0, hud_teamholdbar_width->value); + + // Don't show when not in teamplay/demoplayback. + if(!HUD_ShowInDemoplayback(hud_teamholdbar_onlytp->value)) + { + HUD_PrepareDraw(hud, width , height, &x, &y); + return; + } + + if (HUD_PrepareDraw(hud, width , height, &x, &y)) + { + // We need something to work with. + if(stats_grid != NULL) + { + // Check if we have any hold values to calculate from. + if(stats_grid->teams[STATS_TEAM1].hold_count + stats_grid->teams[STATS_TEAM2].hold_count > 0) + { + // Calculate the percentage for the two teams for the "team strength bar". + team1_percent = ((float)stats_grid->teams[STATS_TEAM1].hold_count) / (stats_grid->teams[STATS_TEAM1].hold_count + stats_grid->teams[STATS_TEAM2].hold_count); + team2_percent = ((float)stats_grid->teams[STATS_TEAM2].hold_count) / (stats_grid->teams[STATS_TEAM1].hold_count + stats_grid->teams[STATS_TEAM2].hold_count); + + team1_percent = fabs(max(0, team1_percent)); + team2_percent = fabs(max(0, team2_percent)); + } + else + { + Draw_AlphaFill(x, y, hud_teamholdbar_width->value, height, 0, hud_teamholdbar_opacity->value*0.5); + return; + } + + // Draw the percentage bar. + TeamHold_DrawPercentageBar(x, y, width, height, + team1_percent, team2_percent, + stats_grid->teams[STATS_TEAM1].color, + stats_grid->teams[STATS_TEAM2].color, + hud_teamholdbar_show_text->value, + hud_teamholdbar_vertical->value, + hud_teamholdbar_vertical_text->value, + hud_teamholdbar_opacity->value); + } + else + { + // If there's no stats grid available we don't know what to show, so just show a black frame. + Draw_AlphaFill(x, y, hud_teamholdbar_width->value, height, 0, hud_teamholdbar_opacity->value * 0.5); + } + } +} +#endif + +void TeamHold_OnChangeItemFilterInfo(cvar_t *var, char *oldvalue) +{ +// char *start = var->string; +// char *end = start; +// int order = 0; + + // Parse the item filter. + teamhold_show_rl = Utils_RegExpMatch("RL", var->string); + teamhold_show_quad = Utils_RegExpMatch("QUAD", var->string); + teamhold_show_ring = Utils_RegExpMatch("RING", var->string); + teamhold_show_pent = Utils_RegExpMatch("PENT", var->string); + teamhold_show_suit = Utils_RegExpMatch("SUIT", var->string); + teamhold_show_lg = Utils_RegExpMatch("LG", var->string); + teamhold_show_gl = Utils_RegExpMatch("GL", var->string); + teamhold_show_sng = Utils_RegExpMatch("SNG", var->string); + teamhold_show_mh = Utils_RegExpMatch("MH", var->string); + teamhold_show_ra = Utils_RegExpMatch("RA", var->string); + teamhold_show_ya = Utils_RegExpMatch("YA", var->string); + teamhold_show_ga = Utils_RegExpMatch("GA", var->string); +#ifdef HAXX + // Reset the ordering of the items. + StatsGrid_ResetHoldItemsOrder(); + + // Trim spaces from the start of the word. + while (*start && *start == ' ') + { + start++; + } + + end = start; + + // Go through the string word for word and set a + // rising order for each hold item based on their + // order in the string. + while (*end) + { + if (*end != ' ') + { + // Not at the end of the word yet. + end++; + continue; + } + else + { + // We've found a word end. + char temp[256]; + + // Try matching the current word with a hold item + // and set it's ordering according to it's placement + // in the string. + strlcpy (temp, start, min(end - start, sizeof(temp))); + StatsGrid_SetHoldItemOrder(temp, order); + order++; + + // Get rid of any additional spaces. + while (*end && *end == ' ') + { + end++; + } + + // Start trying to find a new word. + start = end; + } + } + + // Order the hold items. + StatsGrid_SortHoldItems(); +#endif +} + +#define HUD_TEAMHOLDINFO_STYLE_TEAM_NAMES 0 +#define HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS 1 +#define HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS2 2 + +#ifdef HAXX +static void SCR_HUD_DrawTeamHoldInfo(hud_t *hud) +{ + int i; + int x, y; + int width, height; + + static cvar_t + *hud_teamholdinfo_style = NULL, + *hud_teamholdinfo_opacity, + *hud_teamholdinfo_width, + *hud_teamholdinfo_height, + *hud_teamholdinfo_onlytp, + *hud_teamholdinfo_itemfilter; + + if (hud_teamholdinfo_style == NULL) // first time + { + char val[256]; + + hud_teamholdinfo_style = HUD_FindVar(hud, "style"); + hud_teamholdinfo_opacity = HUD_FindVar(hud, "opacity"); + hud_teamholdinfo_width = HUD_FindVar(hud, "width"); + hud_teamholdinfo_height = HUD_FindVar(hud, "height"); + hud_teamholdinfo_onlytp = HUD_FindVar(hud, "onlytp"); + hud_teamholdinfo_itemfilter = HUD_FindVar(hud, "itemfilter"); + + // Unecessary to parse the item filter string on each frame. + hud_teamholdinfo_itemfilter->OnChange = TeamHold_OnChangeItemFilterInfo; + + // Parse the item filter the first time (trigger the OnChange function above). + strlcpy (val, hud_teamholdinfo_itemfilter->string, sizeof(val)); + Cvar_Set (hud_teamholdinfo_itemfilter, val); + } + + // Get the height based on how many items we have, or what the user has set it to. + height = max(0, hud_teamholdinfo_height->value); + width = max(0, hud_teamholdinfo_width->value); + + // Don't show when not in teamplay/demoplayback. + if(!HUD_ShowInDemoplayback(hud_teamholdinfo_onlytp->value)) + { + HUD_PrepareDraw(hud, width , height, &x, &y); + return; + } + + // We don't have anything to show. + if(stats_important_ents == NULL || stats_grid == NULL) + { + HUD_PrepareDraw(hud, width , height, &x, &y); + return; + } + + if (HUD_PrepareDraw(hud, width , height, &x, &y)) + { + int _y = 0; + + _y = y; + + // Go through all the items and print the stats for them. + for(i = 0; i < stats_important_ents->count; i++) + { + float team1_percent; + float team2_percent; + int team1_hold_count = 0; + int team2_hold_count = 0; + int names_width = 0; + + // Don't draw outside the specified height. + if((_y - y) + 8 > height) + { + break; + } + + // If the item isn't of the specified type, then skip it. + if(!( (teamhold_show_rl && !strncmp(stats_important_ents->list[i].name, "RL", 2)) + || (teamhold_show_quad && !strncmp(stats_important_ents->list[i].name, "QUAD", 4)) + || (teamhold_show_ring && !strncmp(stats_important_ents->list[i].name, "RING", 4)) + || (teamhold_show_pent && !strncmp(stats_important_ents->list[i].name, "PENT", 4)) + || (teamhold_show_suit && !strncmp(stats_important_ents->list[i].name, "SUIT", 4)) + || (teamhold_show_lg && !strncmp(stats_important_ents->list[i].name, "LG", 2)) + || (teamhold_show_gl && !strncmp(stats_important_ents->list[i].name, "GL", 2)) + || (teamhold_show_sng && !strncmp(stats_important_ents->list[i].name, "SNG", 3)) + || (teamhold_show_mh && !strncmp(stats_important_ents->list[i].name, "MH", 2)) + || (teamhold_show_ra && !strncmp(stats_important_ents->list[i].name, "RA", 2)) + || (teamhold_show_ya && !strncmp(stats_important_ents->list[i].name, "YA", 2)) + || (teamhold_show_ga && !strncmp(stats_important_ents->list[i].name, "GA", 2)) + )) + { + continue; + } + + // Calculate the width of the longest item name so we can use it for padding. + names_width = 8 * (stats_important_ents->longest_name + 1); + + // Calculate the percentages of this item that the two teams holds. + team1_hold_count = stats_important_ents->list[i].teams_hold_count[STATS_TEAM1]; + team2_hold_count = stats_important_ents->list[i].teams_hold_count[STATS_TEAM2]; + + team1_percent = ((float)team1_hold_count) / (team1_hold_count + team2_hold_count); + team2_percent = ((float)team2_hold_count) / (team1_hold_count + team2_hold_count); + + team1_percent = fabs(max(0, team1_percent)); + team2_percent = fabs(max(0, team2_percent)); + + // Write the name of the item. + Draw_ColoredString(x, _y, va("&cff0%s:", stats_important_ents->list[i].name), 0); + + if(hud_teamholdinfo_style->value == HUD_TEAMHOLDINFO_STYLE_TEAM_NAMES) + { + // + // Prints the team name that holds the item. + // + if(team1_percent > team2_percent) + { + Draw_ColoredString(x + names_width, _y, stats_important_ents->teams[STATS_TEAM1].name, 0); + } + else if(team1_percent < team2_percent) + { + Draw_ColoredString(x + names_width, _y, stats_important_ents->teams[STATS_TEAM2].name, 0); + } + } + else if(hud_teamholdinfo_style->value == HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS) + { + // + // Show a percenteage bar for the item. + // + TeamHold_DrawPercentageBar(x + names_width, _y, + Q_rint(hud_teamholdinfo_width->value - names_width), 8, + team1_percent, team2_percent, + stats_important_ents->teams[STATS_TEAM1].color, + stats_important_ents->teams[STATS_TEAM2].color, + 0, // Don't show percentage values, get's too cluttered. + false, + false, + hud_teamholdinfo_opacity->value); + } + else if(hud_teamholdinfo_style->value == HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS2) + { + TeamHold_DrawBars(x + names_width, _y, + Q_rint(hud_teamholdinfo_width->value - names_width), 8, + team1_percent, team2_percent, + stats_important_ents->teams[STATS_TEAM1].color, + stats_important_ents->teams[STATS_TEAM2].color, + hud_teamholdinfo_opacity->value); + } + + // Next line. + _y += 8; + } + } +} +#endif + +static int SCR_HudDrawTeamInfoPlayer(teamplayerinfo_t *ti_cl, int x, int y, int maxname, int maxloc, qbool width_only, hud_t *hud); + +#define FONTWIDTH 8 +static void SCR_HUD_DrawTeamInfo(hud_t *hud) +{ + int x, y, _y, width, height; + int i, j, k, slots_num, maxname, maxloc; + char tmp[1024], *nick; + teamplayerinfo_t ti_clients[MAX_CLIENTS]; + + extern qbool hud_editor; + + static cvar_t + *hud_teaminfo_weapon_style = NULL, + *hud_teaminfo_align_right, + *hud_teaminfo_loc_width, + *hud_teaminfo_name_width, + *hud_teaminfo_show_enemies, + *hud_teaminfo_show_self, + *hud_teaminfo_scale; + + if (hud_teaminfo_weapon_style == NULL) // first time + { + hud_teaminfo_weapon_style = HUD_FindVar(hud, "weapon_style"); + hud_teaminfo_align_right = HUD_FindVar(hud, "align_right"); + hud_teaminfo_loc_width = HUD_FindVar(hud, "loc_width"); + hud_teaminfo_name_width = HUD_FindVar(hud, "name_width"); + hud_teaminfo_show_enemies = HUD_FindVar(hud, "show_enemies"); + hud_teaminfo_show_self = HUD_FindVar(hud, "show_self"); + hud_teaminfo_scale = HUD_FindVar(hud, "scale"); + } + + // Don't update hud item unless first view is beeing displayed +// if ( CURRVIEW != 1 && CURRVIEW != 0) +// return; + + slots_num = pGetTeamInfo(ti_clients, countof(ti_clients), hud_teaminfo_show_enemies->ival, hud_teaminfo_show_self->ival); + + // fill data we require to draw teaminfo + for ( maxloc = maxname = i = 0; i < slots_num; i++ ) { + // dynamically guess max length of name/location + nick = (ti_clients[i].nick[0] ? ti_clients[i].nick : cl.players[i].name); // we use nick or name + maxname = max(maxname, strlen(TP_ParseFunChars(nick, false))); + + strlcpy(tmp, TP_LocationName(ti_clients[i].org), sizeof(tmp)); + maxloc = max(maxloc, strlen(TP_ParseFunChars(tmp, false))); + } + + // well, better use fixed loc length + maxloc = bound(0, hud_teaminfo_loc_width->ival, 100); + // limit name length + maxname = bound(0, maxname, hud_teaminfo_name_width->ival); + + // this does't draw anything, just calculate width + width = FONTWIDTH * hud_teaminfo_scale->value * SCR_HudDrawTeamInfoPlayer(&ti_clients[0], 0, 0, maxname, maxloc, true, hud); + height = FONTWIDTH * hud_teaminfo_scale->value * (hud_teaminfo_show_enemies->ival?slots_num+n_teams:slots_num); + + if (hud_editor) + HUD_PrepareDraw(hud, width , FONTWIDTH, &x, &y); + + if ( !slots_num ) + return; + + if (!cl.teamplay) // non teamplay mode + return; + + if (!HUD_PrepareDraw(hud, width , height, &x, &y)) + return; + + _y = y ; + x = (hud_teaminfo_align_right->value ? x - (width * (FONTWIDTH * hud_teaminfo_scale->value)) : x); + + // If multiple teams are displayed then sort the display and print team header on overlay + k=0; + if (hud_teaminfo_show_enemies->ival) + { + while (sorted_teams[k].name) + { + Draw_SString (x, _y, sorted_teams[k].name, hud_teaminfo_scale->value); + sprintf(tmp,"%s %i",TP_ParseFunChars("$.",false), sorted_teams[k].frags); + Draw_SString (x+(strlen(sorted_teams[k].name)+1)*FONTWIDTH, _y, tmp, hud_teaminfo_scale->value); + _y += FONTWIDTH * hud_teaminfo_scale->value; + for ( j = 0; j < slots_num; j++ ) + { + i = ti_clients[j].client; + if (!strcmp(cl.players[i].team,sorted_teams[k].name)) + { + SCR_HudDrawTeamInfoPlayer(&ti_clients[j], x, _y, maxname, maxloc, false, hud); + _y += FONTWIDTH * hud_teaminfo_scale->value; + } + } + k++; + } + } + else + { + for ( j = 0; j < slots_num; j++ ) { + SCR_HudDrawTeamInfoPlayer(&ti_clients[j], x, _y, maxname, maxloc, false, hud); + _y += FONTWIDTH * hud_teaminfo_scale->value; + } + } +} + +qbool Has_Both_RL_and_LG (int flags) { return (flags & IT_ROCKET_LAUNCHER) && (flags & IT_LIGHTNING); } +#define FONTWIDTH 8 void str_align_right (char *target, size_t size, const char *source, size_t length) { if (length > size - 1) @@ -5459,3034 +5459,3034 @@ void str_align_right (char *target, size_t size, const char *source, size_t leng strlcpy(target + i, source, size - i); } -} -int Player_GetTrackId(int uid) -{ - return uid; -} -unsigned int BestWeaponFromStatItems(unsigned int items) -{ - int i; - for (i = 1<<7; i; i>>=1) - { - if (items & i) - return i; - } - return 0; -} -mpic_t * SCR_GetWeaponIconByFlag (int flag) -{ - int i, j; - for (i = 0, j = 1; i < 7; i++, j*=2) - { - if (flag == j) - return sb_weapons[0][i]; - } - return NULL; -} -static int SCR_HudDrawTeamInfoPlayer(teamplayerinfo_t *ti_cl, int x, int y, int maxname, int maxloc, qbool width_only, hud_t *hud) -{ - extern mpic_t * SCR_GetWeaponIconByFlag (int flag); - - char *s, *loc, tmp[1024], tmp2[1024], *aclr; - int x_in = x; // save x - int i; - mpic_t *pic; - float scale = HUD_FindVar(hud, "scale")->value; - - if (!ti_cl) - return 0; - - i = ti_cl->client; - - if (i < 0 || i >= MAX_CLIENTS) - { - Com_DPrintf("SCR_Draw_TeamInfoPlayer: wrong client %d\n", i); - return 0; - } - - // this limit len of string because TP_ParseFunChars() do not check overflow - strlcpy(tmp2, HUD_FindVar(hud, "layout")->string , sizeof(tmp2)); - strlcpy(tmp2, TP_ParseFunChars(tmp2, false), sizeof(tmp2)); - s = tmp2; - - // - // parse/draw string like this "%n %h:%a %l %p %w" - // - - for ( ; *s; s++) { - switch( (int) s[0] ) { - case '%': - - s++; // advance - - switch( (int) s[0] ) { - case 'n': // draw name - - if(!width_only) { - char *nick = TP_ParseFunChars(ti_cl->nick[0] ? ti_cl->nick : cl.players[i].name, false); - str_align_right(tmp, sizeof(tmp), nick, maxname); - Draw_SString (x, y, tmp, scale); - } - x += maxname * FONTWIDTH * scale; - - break; - case 'w': // draw "best" weapon icon/name - - switch (HUD_FindVar(hud, "weapon_style")->ival) { - case 1: - if(!width_only) { - if (Has_Both_RL_and_LG(ti_cl->items)) { - char *weap_str = pCvar_GetNVFDG("tp_name_rlg", "rlg", 0, NULL, NULL)->string; - char weap_white_stripped[32]; - Util_SkipChars(weap_str, "{}", weap_white_stripped, 32); - Draw_ColoredString (x, y, weap_white_stripped, false); - } - else { - char *weap_str = TP_ItemName(BestWeaponFromStatItems( ti_cl->items )); - char weap_white_stripped[32]; - Util_SkipChars(weap_str, "{}", weap_white_stripped, 32); - Draw_ColoredString (x, y, weap_white_stripped, false); - } - } - x += 3 * FONTWIDTH * scale; - - break; - default: // draw image by default - if(!width_only) - if ( (pic = SCR_GetWeaponIconByFlag(BestWeaponFromStatItems( ti_cl->items ))) ) - Draw_SPic (x, y, pic, 0.5 * scale); - x += 2 * FONTWIDTH * scale; - - break; - } - - break; - case 'h': // draw health, padding with space on left side - case 'H': // draw health, padding with space on right side - - if(!width_only) { - snprintf(tmp, sizeof(tmp), (s[0] == 'h' ? "%s%3d" : "%s%-3d"), (ti_cl->health < HUD_FindVar(hud, "low_health")->ival ? "&cf00" : ""), (int)ti_cl->health); - Draw_SString (x, y, tmp, scale); - } - x += 3 * FONTWIDTH * scale; - - break; - case 'a': // draw armor, padded with space on left side - case 'A': // draw armor, padded with space on right side - - aclr = ""; - - // - // different styles of armor - // - switch (HUD_FindVar(hud,"armor_style")->ival) { - case 1: // image prefixed armor value - if(!width_only) { - if (ti_cl->items & IT_ARMOR3) - Draw_SPic (x, y, sb_armor[2], 1.0/3 * scale); - else if (ti_cl->items & IT_ARMOR2) - Draw_SPic (x, y, sb_armor[1], 1.0/3 * scale); - else if (ti_cl->items & IT_ARMOR1) - Draw_SPic (x, y, sb_armor[0], 1.0/3 * scale); - } - x += FONTWIDTH * scale; - - break; - case 2: // colored background of armor value - /* - if(!width_only) { - byte col[4] = {255, 255, 255, 0}; - - if (ti_cl->items & IT_ARMOR3) { - col[0] = 255; col[1] = 0; col[2] = 0; col[3] = 255; - } - else if (ti_cl->items & IT_ARMOR2) { - col[0] = 255; col[1] = 255; col[2] = 0; col[3] = 255; - } - else if (ti_cl->items & IT_ARMOR1) { - col[0] = 0; col[1] = 255; col[2] = 0; col[3] = 255; - } - } - */ - - break; - case 3: // colored armor value - if(!width_only) { - if (ti_cl->items & IT_ARMOR3) - aclr = "&cf00"; - else if (ti_cl->items & IT_ARMOR2) - aclr = "&cff0"; - else if (ti_cl->items & IT_ARMOR1) - aclr = "&c0f0"; - } - - break; - case 4: // armor value prefixed with letter - if(!width_only) { - if (ti_cl->items & IT_ARMOR3) - Draw_SString (x, y, "r", scale); - else if (ti_cl->items & IT_ARMOR2) - Draw_SString (x, y, "y", scale); - else if (ti_cl->items & IT_ARMOR1) - Draw_SString (x, y, "g", scale); - } - x += FONTWIDTH * scale; - - break; - } - - if(!width_only) { // value drawed no matter which style - snprintf(tmp, sizeof(tmp), (s[0] == 'a' ? "%s%3d" : "%s%-3d"), aclr, (int)ti_cl->armor); - Draw_SString (x, y, tmp, scale); - } - x += 3 * FONTWIDTH * scale; - - break; - case 'l': // draw location - - if(!width_only) { - loc = TP_LocationName(ti_cl->org); - if (!loc[0]) - loc = "unknown"; - - str_align_right(tmp, sizeof(tmp), TP_ParseFunChars(loc, false), maxloc); - Draw_SString (x, y, tmp, scale); - } - x += maxloc * FONTWIDTH * scale; - - break; - case 'p': // draw powerups - switch (HUD_FindVar(hud, "powerup_style")->ival) { - case 1: // quad/pent/ring image - if(!width_only) { - if (ti_cl->items & IT_QUAD) - Draw_SPic (x, y, sb_items[5], 1.0/2); - x += FONTWIDTH; - if (ti_cl->items & IT_INVULNERABILITY) - Draw_SPic (x, y, sb_items[3], 1.0/2); - x += FONTWIDTH; - if (ti_cl->items & IT_INVISIBILITY) - Draw_SPic (x, y, sb_items[2], 1.0/2); - x += FONTWIDTH; - } - else { x += 3* FONTWIDTH; } - break; - - case 2: // player powerup face - if(!width_only) { - if ( sb_face_quad && (ti_cl->items & IT_QUAD)) - Draw_SPic (x, y, sb_face_quad, 1.0/3); - x += FONTWIDTH; - if ( sb_face_invuln && (ti_cl->items & IT_INVULNERABILITY)) - Draw_SPic (x, y, sb_face_invuln, 1.0/3); - x += FONTWIDTH; - if ( sb_face_invis && (ti_cl->items & IT_INVISIBILITY)) - Draw_SPic (x, y, sb_face_invis, 1.0/3); - x += FONTWIDTH; - } - else { x += 3* FONTWIDTH; } - break; - - case 3: // colored font (QPR) - if(!width_only) { - if (ti_cl->items & IT_QUAD) - Draw_ColoredString (x, y, "&c03fQ", false); - x += FONTWIDTH; - if (ti_cl->items & IT_INVULNERABILITY) - Draw_ColoredString (x, y, "&cf00P", false); - x += FONTWIDTH; - if (ti_cl->items & IT_INVISIBILITY) - Draw_ColoredString (x, y, "&cff0R", false); - x += FONTWIDTH; - } - else { x += 3* FONTWIDTH; } - break; - } - break; - - case 't': - if(!width_only) - { - sprintf(tmp, "%i", Player_GetTrackId(cl.players[ti_cl->client].userid)); - Draw_SString (x, y, tmp, scale); - } - x += FONTWIDTH * scale; // will break if tracknumber is double digits - break; - - case '%': // wow, %% result in one %, how smart - - if(!width_only) - Draw_SString (x, y, "%", scale); - x += FONTWIDTH * scale; - - break; - - default: // print %x - that mean sequence unknown - - if(!width_only) { - snprintf(tmp, sizeof(tmp), "%%%c", s[0]); - Draw_SString (x, y, tmp, scale); - } - x += (s[0] ? 2 : 1) * FONTWIDTH * scale; - - break; - } - - break; - - default: // print x - if(!width_only) { - snprintf(tmp, sizeof(tmp), "%c", s[0]); - if (s[0] != ' ') // inhuman smart optimization, do not print space! - Draw_SString (x, y, tmp, scale); - } - x += FONTWIDTH * scale; - - break; - } - } - - return (x - x_in) / (FONTWIDTH * scale); // return width -} - -#ifdef HAXX -void SCR_HUD_DrawItemsClock(hud_t *hud) -{ - extern qbool hud_editor; - int width, height; - int x, y; - static cvar_t *hud_itemsclock_timelimit = NULL, *hud_itemsclock_style; - - if (hud_itemsclock_timelimit == NULL) { - hud_itemsclock_timelimit = HUD_FindVar(hud, "timelimit"); - hud_itemsclock_style = HUD_FindVar(hud, "style"); - } - - MVD_ClockList_TopItems_DimensionsGet(hud_itemsclock_timelimit->value, hud_itemsclock_style->ival, &width, &height); - - if (hud_editor) - HUD_PrepareDraw(hud, width, LETTERHEIGHT, &x, &y); - - if (!height) - return; - - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - return; - - MVD_ClockList_TopItems_Draw(hud_itemsclock_timelimit->value, hud_itemsclock_style->ival, x, y); -} -#endif - -// -// TODO: decide what to do in freefly mode (and how to catch it?!), now all score_* hud elements just draws "0" -// -void SCR_HUD_DrawScoresTeam(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *digits, *align, *colorize; - int value = 0; - int i; - - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - colorize = HUD_FindVar(hud, "colorize"); - } - - // - // AAS: someone please tell me how to do it in a proper way! - // - if(cl.teamplay) - { - for(i = 0; i < n_teams; i++) - { - // playing qwd demo || mvd spec/demo || playing - if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) || - ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) || - (strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ) - { - value = sorted_teams[i].frags; - break; - } - } - } - else if(cl.deathmatch) - { - for(i = 0; i < n_players; i++) - { - if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) || - ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) || - (strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ) - { - value = cl.players[sorted_players[i].playernum].frags; - break; - } - } - } - - SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); -} - -void SCR_HUD_DrawScoresEnemy(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *digits, *align, *colorize; - int value = 0; - int i; - - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - colorize = HUD_FindVar(hud, "colorize"); - } - - // - // AAS: voodoo, again - // - if(cl.teamplay) - { - for(i = 0; i < n_teams; i++) - { - - if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) || - ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) || - (strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ) - { - if(n_teams > 1) - value = sorted_teams[i == 0 ? 1 : 0].frags; - break; - } - } - } - else if(cl.deathmatch) - { - for(i = 0; i < n_players; i++) - { - if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) || - ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) || - (strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ) - { - if(n_players > 1) - value = cl.players[sorted_players[i == 0 ? 1 : 0].playernum].frags; - break; - } - } - } - - SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); -} - -void SCR_HUD_DrawScoresDifference(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *digits, *align, *colorize; - int value = 0; - int i; - - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - colorize = HUD_FindVar(hud, "colorize"); - } - - // - // AAS: more voodoo - // - if(cl.teamplay) - { - for(i = 0; i < n_teams; i++) - { - if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) || - ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) || - (strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ) - { - if(i == 0) - { - if(n_teams > 1) - value = sorted_teams[0].frags - sorted_teams[1].frags; - else - value = sorted_teams[0].frags; - } - else - { - if(n_teams > 1) - value = sorted_teams[i].frags - sorted_teams[0].frags; - } - break; - } - } - } - else if(cl.deathmatch) - { - for(i = 0; i < n_players; i++) - { - if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) || - ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) || - (strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ) - { - if(i == 0) - { - if(n_players > 1) - value = cl.players[sorted_players[0].playernum].frags - cl.players[sorted_players[1].playernum].frags; - else - value = cl.players[sorted_players[0].playernum].frags; - } - else - { - if(n_players > 1) - value = cl.players[sorted_players[i].playernum].frags - cl.players[sorted_players[0].playernum].frags; - } - break; - } - } - } - - SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); -} - -void SCR_HUD_DrawScoresPosition(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *digits, *align, *colorize; - int value = 0; - int i; - - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); - colorize = HUD_FindVar(hud, "colorize"); - } - - // - // AAS: someone, please stop me - // - if(cl.teamplay) - { - for(i = 0; i < n_teams; i++) - { - if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) || - ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) || - (strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ) - { - value = i; - break; - } - } - } - else if(cl.deathmatch) - { - for(i = 0; i < n_players; i++) - { - if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) || - ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) || - (strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ) - { - value = i; - break; - } - } - } - - SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); -} - -/* - ezQuake's analogue of +scores of KTX - ( t:x e:x [x] ) -*/ -void SCR_HUD_DrawScoresBar(hud_t *hud) -{ - static cvar_t *scale = NULL, *style, *format_big, *format_small; - int width = 0, height = 0, x, y; - int i = 0; - - int s_team = 0, s_enemy = 0, s_difference = 0; - char *n_team = "T", *n_enemy = "E"; - - char buf[256]; - char c, *out, *temp, *in; - - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - format_big = HUD_FindVar(hud, "format_big"); - format_small= HUD_FindVar(hud, "format_small"); - } - - // - // AAS: nightmare comes back - // - if(cl.teamplay) - { - for(i = 0; i < n_teams; i++) - { - if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) || - ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) || - (strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ) - { - s_team = sorted_teams[i].frags; - n_team = sorted_teams[i].name; - if(n_teams > 1) - { - s_enemy = sorted_teams[i == 0 ? 1 : 0].frags; - n_enemy = sorted_teams[i == 0 ? 1 : 0].name; - } - s_difference = s_team - s_enemy; - break; - } - } - } - else if(cl.deathmatch) - { - for(i = 0; i < n_players; i++) - { - if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) || - ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) || - (strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ) - { - s_team = cl.players[sorted_players[i].playernum].frags; - if(n_players > 1) - { - s_enemy = cl.players[sorted_players[i == 0 ? 1 : 0].playernum].frags; - } - s_difference = s_team - s_enemy; - break; - } - } - } - - - // two pots of delicious customized copypasta from math_tools.c - switch(style->ival) - { - // Big - case 1: - in = TP_ParseFunChars(format_big->string, false); - buf[0] = 0; - out = buf; - - while((c = *in++) && (out - buf < sizeof(buf) - 1)) - { - if((c == '%') && *in) - { - switch((c = *in++)) - { - // c = colorize, r = reset - case 'd': - temp = va("%d", s_difference); - width += (s_difference >= 0) ? strlen(temp) * 24 : ((strlen(temp) - 1) * 24) + 16; - break; - case 'D': - temp = va("c%dr", s_difference); - width += (s_difference >= 0) ? (strlen(temp) - 2) * 24 : ((strlen(temp) - 3) * 24) + 16; - break; - case 'e': - temp = va("%d", s_enemy); - width += (s_enemy >= 0) ? strlen(temp) * 24 : ((strlen(temp) - 1) * 24) + 16; - break; - case 'E': - temp = va("c%dr", s_enemy); - width += (s_enemy >= 0) ? (strlen(temp) - 2) * 24 : ((strlen(temp) - 3) * 24) + 16; - break; - case 'p': - temp = va("%d", i + 1); - width += 24; - break; - case 't': - temp = va("%d", s_team); - width += (s_team >= 0) ? strlen(temp) * 24 : ((strlen(temp) - 1) * 24) + 16; - break; - case 'T': - temp = va("c%dr", s_team); - width += (s_team >= 0) ? (strlen(temp) - 2) * 24 : ((strlen(temp) - 3) * 24) + 16; - break; - case 'z': - if(s_difference >= 0) - { - temp = va("%d", s_difference); - width += strlen(temp) * 24; - } - else - { - temp = va("c%dr", -(s_difference)); - width += (strlen(temp) - 2) * 24; - } - break; - case 'Z': - if(s_difference >= 0) - { - temp = va("c%dr", s_difference); - width += (strlen(temp) - 2) * 24; - } - else - { - temp = va("%d", -(s_difference)); - width += strlen(temp) * 24; - } - break; - default: - temp = NULL; - break; - } - - if(temp != NULL) - { - strlcpy(out, temp, sizeof(buf) - (out - buf)); - out += strlen(temp); - } - } - else if (c == ':' || c == '/' || c == '-' || c == ' ') - { - width += 16; - *out++ = c; - } - } - *out = 0; - break; - - // Small - case 0: - default: - in = TP_ParseFunChars(format_small->string, false); - buf[0] = 0; - out = buf; - - while((c = *in++) && (out - buf < sizeof(buf) - 1)) - { - if((c == '%') && *in) - { - switch((c = *in++)) - { - case '%': - temp = "%"; - break; - case 't': - temp = va("%d", s_team); - break; - case 'e': - temp = va("%d", s_enemy); - break; - case 'd': - temp = va("%d", s_difference); - break; - case 'p': - temp = va("%d", i + 1); - break; - case 'T': - temp = n_team; - break; - case 'E': - temp = n_enemy; - break; - case 'D': - temp = va("%+d", s_difference); - break; - default: - temp = va("%%%c", c); - break; - } - strlcpy(out, temp, sizeof(buf) - (out - buf)); - out += strlen(temp); - } - else - { - *out++ = c; - } - } - *out = 0; - break; - } - - switch(style->ival) - { - // Big - case 1: - width *= scale->value; - height = 24 * scale->value; - - if(HUD_PrepareDraw(hud, width, height, &x, &y)) - { - SCR_DrawWadString(x, y, scale->value, buf); - } - break; - - // Small - case 0: - default: - width = 8 * strlen_color(buf) * scale->value; - height = 8 * scale->value; - - if(HUD_PrepareDraw(hud, width, height, &x, &y)) - { - Draw_SString(x, y, buf, scale->value); - } - break; - } -} - -void SCR_HUD_DrawBarArmor(hud_t *hud) -{ - static cvar_t *width = NULL, *height, *direction, *color_noarmor, *color_ga, *color_ya, *color_ra, *color_unnatural; - int x, y; - int armor = HUD_Stats(STAT_ARMOR); - qbool alive = cl.stats[STAT_HEALTH] > 0; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - direction = HUD_FindVar(hud, "direction"); - color_noarmor = HUD_FindVar(hud, "color_noarmor"); - color_ga = HUD_FindVar(hud, "color_ga"); - color_ya = HUD_FindVar(hud, "color_ya"); - color_ra = HUD_FindVar(hud, "color_ra"); - color_unnatural = HUD_FindVar(hud, "color_unnatural"); - } - - if(HUD_PrepareDraw(hud, width->ival, height->ival, &x, &y)) - { - if(!width->ival || !height->ival) - return; - - if(HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY && alive) - { - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_unnatural->vec4, x, y, width->ival, height->ival); - } - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3 && alive) - { - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); - SCR_HUD_DrawBar(direction->ival, armor, 200.0, color_ra->vec4, x, y, width->ival, height->ival); - } - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR2 && alive) - { - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); - SCR_HUD_DrawBar(direction->ival, armor, 150.0, color_ya->vec4, x, y, width->ival, height->ival); - } - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1 && alive) - { - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); - SCR_HUD_DrawBar(direction->ival, armor, 100.0, color_ga->vec4, x, y, width->ival, height->ival); - } - else - { - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); - } - } -} - -void SCR_HUD_DrawBarHealth(hud_t *hud) -{ - static cvar_t *width = NULL, *height, *direction, *color_nohealth, *color_normal, *color_mega, *color_twomega, *color_unnatural; - int x, y; - int health = cl.stats[STAT_HEALTH]; - - if (width == NULL) // first time called - { - width = HUD_FindVar(hud, "width"); - height = HUD_FindVar(hud, "height"); - direction = HUD_FindVar(hud, "direction"); - color_nohealth = HUD_FindVar(hud, "color_nohealth"); - color_normal = HUD_FindVar(hud, "color_normal"); - color_mega = HUD_FindVar(hud, "color_mega"); - color_twomega = HUD_FindVar(hud, "color_twomega"); - color_unnatural = HUD_FindVar(hud, "color_unnatural"); - } - - if(HUD_PrepareDraw(hud, width->ival, height->ival, &x, &y)) - { - if(!width->ival || !height->ival) - return; - - if(health > 250) - { - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_unnatural->vec4, x, y, width->ival, height->ival); - } - else if(health > 200) - { - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_normal->vec4, x, y, width->ival, height->ival); - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_mega->vec4, x, y, width->ival, height->ival); - SCR_HUD_DrawBar(direction->ival, health - 200, 100.0, color_twomega->vec4, x, y, width->ival, height->ival); - } - else if(health > 100) - { - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_normal->vec4, x, y, width->ival, height->ival); - SCR_HUD_DrawBar(direction->ival, health - 100, 100.0, color_mega->vec4, x, y, width->ival, height->ival); - } - else if(health > 0) - { - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_nohealth->vec4, x, y, width->ival, height->ival); - SCR_HUD_DrawBar(direction->ival, health, 100.0, color_normal->vec4, x, y, width->ival, height->ival); - } - else - { - SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_nohealth->vec4, x, y, width->ival, height->ival); - } - } -} - -void SCR_HUD_DrawOwnFrags(hud_t *hud) -{ - // not implemented yet: scale, color - // fixme: add appropriate opengl functions that will add alpha, scale and color - char ownfragtext[256]; - float age; - int width; - int height = 8; - int x, y; - double alpha; - static cvar_t - *hud_ownfrags_timeout = NULL, - *hud_ownfrags_scale = NULL; -// *hud_ownfrags_color = NULL; - extern qbool hud_editor; - - if (hud_ownfrags_timeout == NULL) // first time - { - hud_ownfrags_scale = HUD_FindVar(hud, "scale"); - // hud_ownfrags_color = HUD_FindVar(hud, "color"); - hud_ownfrags_timeout = HUD_FindVar(hud, "timeout"); - } - - if (hud_editor) - { - strcpy(ownfragtext, "Own Frags"); - age = 0; - } - else if (BUILTINISVALID(GetTrackerOwnFrags)) - age = pGetTrackerOwnFrags(0, ownfragtext, sizeof(ownfragtext)); - else - { - strcpy(ownfragtext, "Engine does not support OwnFrags"); - age = 0; - } - width = strlen(ownfragtext)*8; - - width *= hud_ownfrags_scale->value; - height *= hud_ownfrags_scale->value; - - if (age >= hud_ownfrags_timeout->value) - width = 0; - - alpha = 2 - age / hud_ownfrags_timeout->value * 2; - alpha = bound(0, alpha, 1); - - if (!width) - { - HUD_PrepareDraw(hud, width, height, NULL, NULL); - return; - } - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - return; - - pDraw_Colour4f(1, 1, 1, alpha); - Draw_SString(x, y, ownfragtext, hud_ownfrags_scale->value); - pDraw_Colour4f(1, 1, 1, 1); -} - -static struct wstats_s *findweapon(struct wstats_s *w, size_t wc, char *wn) -{ - for (; wc>0; wc--, w++) - { - if (!strcmp(wn, w->wname)) - return w; - } - return NULL; -} -static void SCR_HUD_DrawWeaponStats(hud_t *hud) -{ - char line[1024], *o, *i; - int width; - int height = 8; - int x, y; - static cvar_t *hud_weaponstats_scale = NULL; - static cvar_t *hud_weaponstats_fmt = NULL; - extern qbool hud_editor; - - int ws; - struct wstats_s wstats[16]; - if (BUILTINISVALID(GetWeaponStats)) - ws = pGetWeaponStats(-1, wstats, countof(wstats)); - else - ws = 0; - - if (hud_editor) - { - ws = 0; - strcpy(wstats[ws].wname, "axe"); - wstats[ws].hit = 20; - wstats[ws].total = 100; - ws++; - strcpy(wstats[ws].wname, "rl"); - wstats[ws].hit = 60; - wstats[ws].total = 120; - ws++; - strcpy(wstats[ws].wname, "lg"); - wstats[ws].hit = 20; - wstats[ws].total = 100; - ws++; - } - - if (hud_weaponstats_scale == NULL) // first time - { - hud_weaponstats_scale = HUD_FindVar(hud, "scale"); - hud_weaponstats_fmt = HUD_FindVar(hud, "fmt"); -// "&c990sg&r:[%sg] &c099ssg&r:[%ssg] &c900rl&r:[#rl] &c009lg&r:[%lg]" - } - - height = 8; - for (o = line, i = hud_weaponstats_fmt->string; ws && *i && o < line+countof(line)-1; ) - { - if (i[0] == '[' && (i[1] == '%' || i[1] == '#')) - { - struct wstats_s *w; - char wname[16]; - int pct = i[1]=='%', j; - i+=2; - for (j = 0; *i && j < countof(wname)-1; j++) - { - if (*i == ']') - { - i++; - break; - } - wname[j] = *i++; - } - wname[j] = 0; - w = findweapon(wstats, ws, wname); - if (pct && w && w->total) - snprintf(wname, sizeof(wname), "%.1f", (100.0 * w->hit) / w->total); - else if (pct) - snprintf(wname, sizeof(wname), "%.1f", 0.0); - else if (w) - snprintf(wname, sizeof(wname), "%u", w->hit); - else - snprintf(wname, sizeof(wname), "%u", 0); - - for (j = 0; wname[j] && o < line+countof(line)-1; j++) - *o++ = wname[j]; - } - else if (*i == '\n') - { - height += 8; - *o++ = *i++; - } - else - *o++ = *i++; - } - *o++ = 0; - - width = 8*strlen_color(line); - - width *= hud_weaponstats_scale->value; - height *= hud_weaponstats_scale->value; - - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - return; - - Draw_SString(x, y, line, hud_weaponstats_scale->value); -} - -void SCR_HUD_DrawKeys(hud_t *hud) -{ - char line1[32], line2[32]; - int width, height, x, y; - usercmd_t b; - static cvar_t* vscale = NULL; - float scale; - - memset(&b, 0, sizeof(b)); - if (BUILTINISVALID(GetLastInputFrame)) - pGetLastInputFrame(0, &b); - - if (!vscale) { - vscale = HUD_FindVar(hud, "scale"); - } - - scale = vscale->value; - scale = max(0, scale); - - snprintf(line1, sizeof(line1), "^{%x}^{%x}^{%x}", - 0xe000 + 'x' + ((b.buttons & 1)?0x80:0), - 0xe000 + '^' + ((b.forwardmove > 0)?0x80:0), - 0xe000 + 'J' + ((b.buttons & 2)?0x80:0)); - snprintf(line2, sizeof(line2), "^{%x}^{%x}^{%x}", - 0xe000 + '<' + ((b.sidemove < 0)?0x80:0), - 0xe000 + '_' + ((b.forwardmove < 0)?0x80:0), - 0xe000 + '>' + ((b.sidemove > 0)?0x80:0)); - - width = 8 * 3 * scale; - height = 8 * 2 * scale; - - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - return; - - Draw_SString(x, y, line1, scale); - Draw_SString(x, y + 8*scale, line2, scale); -} - -#ifdef WITH_PNG -// What stats to draw. -#define HUD_RADAR_STATS_NONE 0 -#define HUD_RADAR_STATS_BOTH_TEAMS_HOLD 1 -#define HUD_RADAR_STATS_TEAM1_HOLD 2 -#define HUD_RADAR_STATS_TEAM2_HOLD 3 -#define HUD_RADAR_STATS_BOTH_TEAMS_DEATHS 4 -#define HUD_RADAR_STATS_TEAM1_DEATHS 5 -#define HUD_RADAR_STATS_TEAM2_DEATHS 6 - -void Radar_DrawGrid(stats_weight_grid_t *grid, int x, int y, float scale, int pic_width, int pic_height, int style) -{ - int row, col; - - // Don't try to draw anything if we got no data. - if(grid == NULL || grid->cells == NULL || style == HUD_RADAR_STATS_NONE) - { - return; - } - - // Go through all the cells and draw them based on their weight. - for(row = 0; row < grid->row_count; row++) - { - // Just to be safe if something went wrong with the allocation. - if(grid->cells[row] == NULL) - { - continue; - } - - for(col = 0; col < grid->col_count; col++) - { - float weight = 0.0; - int color = 0; - - float tl_x, tl_y; // The pixel coordinate of the top left corner of a grid cell. - float p_cell_length_x; // The pixel length of a cell. - float p_cell_length_y; // The pixel "length" on the Y-axis. We calculate this - // seperatly because we'll get errors when converting from - // quake coordinates -> pixel coordinates. - - // Calculate the pixel coordinates of the top left corner of the current cell. - // (This is times 8 because the conversion formula was calculated from a .loc-file) - tl_x = (map_x_slope * (8.0 * grid->cells[row][col].tl_x) + map_x_intercept) * scale; - tl_y = (map_y_slope * (8.0 * grid->cells[row][col].tl_y) + map_y_intercept) * scale; - - // Calculate the cell length in pixel length. - p_cell_length_x = map_x_slope*(8.0 * grid->cell_length) * scale; - p_cell_length_y = map_y_slope*(8.0 * grid->cell_length) * scale; - - // Add rounding errors (so that we don't get weird gaps in the grid). - p_cell_length_x += tl_x - Q_rint(tl_x); - p_cell_length_y += tl_y - Q_rint(tl_y); - - // Don't draw the stats stuff outside the picture. - if(tl_x + p_cell_length_x > pic_width || tl_y + p_cell_length_y > pic_height || x + tl_x < x || y + tl_y < y) - { - continue; - } - - // - // Death stats. - // - if(grid->cells[row][col].teams[STATS_TEAM1].death_weight + grid->cells[row][col].teams[STATS_TEAM2].death_weight > 0) - { - weight = 0; - - if(style == HUD_RADAR_STATS_BOTH_TEAMS_DEATHS || style == HUD_RADAR_STATS_TEAM1_DEATHS) - { - weight = grid->cells[row][col].teams[STATS_TEAM1].death_weight; - } - - if(style == HUD_RADAR_STATS_BOTH_TEAMS_DEATHS || style == HUD_RADAR_STATS_TEAM2_DEATHS) - { - weight += grid->cells[row][col].teams[STATS_TEAM2].death_weight; - } - - color = 79; - } - - // - // Team stats. - // - { - // No point in drawing if we have no weight. - if(grid->cells[row][col].teams[STATS_TEAM1].weight + grid->cells[row][col].teams[STATS_TEAM2].weight <= 0 - && (style == HUD_RADAR_STATS_BOTH_TEAMS_HOLD - || style == HUD_RADAR_STATS_TEAM1_HOLD - || style == HUD_RADAR_STATS_TEAM2_HOLD)) - { - continue; - } - - // Get the team with the highest weight for this cell. - if(grid->cells[row][col].teams[STATS_TEAM1].weight > grid->cells[row][col].teams[STATS_TEAM2].weight - && (style == HUD_RADAR_STATS_BOTH_TEAMS_HOLD - || style == HUD_RADAR_STATS_TEAM1_HOLD)) - { - weight = grid->cells[row][col].teams[STATS_TEAM1].weight; - color = stats_grid->teams[STATS_TEAM1].color; - } - else if(style == HUD_RADAR_STATS_BOTH_TEAMS_HOLD || style == HUD_RADAR_STATS_TEAM2_HOLD) - { - weight = grid->cells[row][col].teams[STATS_TEAM2].weight; - color = stats_grid->teams[STATS_TEAM2].color; - } - } - - // Draw the cell in the color of the team with the - // biggest weight for this cell. Or draw deaths. - Draw_AlphaFill( - x + Q_rint(tl_x), // X. - y + Q_rint(tl_y), // Y. - Q_rint(p_cell_length_x), // Width. - Q_rint(p_cell_length_y), // Height. - color, // Color. - weight); // Alpha. - } - } -} - -// The skinnum property in the entity_s structure is used -// for determening what type of armor to draw on the radar. -#define HUD_RADAR_GA 0 -#define HUD_RADAR_YA 1 -#define HUD_RADAR_RA 2 - -// Radar filters. -#define RADAR_SHOW_WEAPONS (radar_show_ssg || radar_show_ng || radar_show_sng || radar_show_gl || radar_show_rl || radar_show_lg) -static qbool radar_show_ssg = false; -static qbool radar_show_ng = false; -static qbool radar_show_sng = false; -static qbool radar_show_gl = false; -static qbool radar_show_rl = false; -static qbool radar_show_lg = false; - -#define RADAR_SHOW_ITEMS (radar_show_backpacks || radar_show_health || radar_show_ra || radar_show_ya || radar_show_ga || radar_show_rockets || radar_show_nails || radar_show_cells || radar_show_shells || radar_show_quad || radar_show_pent || radar_show_ring || radar_show_suit) -static qbool radar_show_backpacks = false; -static qbool radar_show_health = false; -static qbool radar_show_ra = false; -static qbool radar_show_ya = false; -static qbool radar_show_ga = false; -static qbool radar_show_rockets = false; -static qbool radar_show_nails = false; -static qbool radar_show_cells = false; -static qbool radar_show_shells = false; -static qbool radar_show_quad = false; -static qbool radar_show_pent = false; -static qbool radar_show_ring = false; -static qbool radar_show_suit = false; -static qbool radar_show_mega = false; - -#define RADAR_SHOW_OTHER (radar_show_gibs || radar_show_explosions || radar_show_nails_p || radar_show_rockets_p || radar_show_shaft_p || radar_show_teleport || radar_show_shotgun) -static qbool radar_show_nails_p = false; -static qbool radar_show_rockets_p = false; -static qbool radar_show_shaft_p = false; -static qbool radar_show_gibs = false; -static qbool radar_show_explosions = false; -static qbool radar_show_teleport = false; -static qbool radar_show_shotgun = false; - -void Radar_OnChangeWeaponFilter(cvar_t *var, char *oldval) -{ - // Parse the weapon filter. - radar_show_ssg = Utils_RegExpMatch("SSG|SUPERSHOTGUN|ALL", var->string); - radar_show_ng = Utils_RegExpMatch("([^S]|^)NG|NAILGUN|ALL", var->string); // Yes very ugly, but we don't want to match SNG. - radar_show_sng = Utils_RegExpMatch("SNG|SUPERNAILGUN|ALL", var->string); - radar_show_rl = Utils_RegExpMatch("RL|ROCKETLAUNCHER|ALL", var->string); - radar_show_gl = Utils_RegExpMatch("GL|GRENADELAUNCHER|ALL", var->string); - radar_show_lg = Utils_RegExpMatch("LG|SHAFT|LIGHTNING|ALL", var->string); -} - -void Radar_OnChangeItemFilter(cvar_t *var, char *oldval) -{ - // Parse the item filter. - radar_show_backpacks = Utils_RegExpMatch("BP|BACKPACK|ALL", var->string); - radar_show_health = Utils_RegExpMatch("HP|HEALTH|ALL", var->string); - radar_show_ra = Utils_RegExpMatch("RA|REDARMOR|ARMOR|ALL", var->string); - radar_show_ya = Utils_RegExpMatch("YA|YELLOWARMOR|ARMOR|ALL", var->string); - radar_show_ga = Utils_RegExpMatch("GA|GREENARMOR|ARMOR|ALL", var->string); - radar_show_rockets = Utils_RegExpMatch("ROCKETS|ROCKS|AMMO|ALL", var->string); - radar_show_nails = Utils_RegExpMatch("NAILS|SPIKES|AMMO|ALL", var->string); - radar_show_cells = Utils_RegExpMatch("CELLS|BATTERY|AMMO|ALL", var->string); - radar_show_shells = Utils_RegExpMatch("SHELLS|AMMO|ALL", var->string); - radar_show_quad = Utils_RegExpMatch("QUAD|POWERUPS|ALL", var->string); - radar_show_pent = Utils_RegExpMatch("PENT|PENTAGRAM|666|POWERUPS|ALL", var->string); - radar_show_ring = Utils_RegExpMatch("RING|INVISIBLE|EYES|POWERUPS|ALL", var->string); - radar_show_suit = Utils_RegExpMatch("SUIT|POWERUPS|ALL", var->string); - radar_show_mega = Utils_RegExpMatch("MH|MEGA|MEGAHEALTH|100\\+|ALL", var->string); -} - -void Radar_OnChangeOtherFilter(cvar_t *var, char *oldval) -{ - // Parse the "other" filter. - radar_show_nails_p = Utils_RegExpMatch("NAILS|PROJECTILES|ALL", var->string); - radar_show_rockets_p = Utils_RegExpMatch("ROCKETS|PROJECTILES|ALL", var->string); - radar_show_shaft_p = Utils_RegExpMatch("SHAFT|PROJECTILES|ALL", var->string); - radar_show_gibs = Utils_RegExpMatch("GIBS|ALL", var->string); - radar_show_explosions = Utils_RegExpMatch("EXPLOSIONS|ALL", var->string); - radar_show_teleport = Utils_RegExpMatch("TELE|ALL", var->string); - radar_show_shotgun = Utils_RegExpMatch("SHOTGUN|SG|BUCK|ALL", var->string); -} - - -#define HUD_COLOR_DEFAULT_TRANSPARENCY 75 - -byte hud_radar_highlight_color[4] = {255, 255, 0, HUD_COLOR_DEFAULT_TRANSPARENCY}; - -void Radar_OnChangeHighlightColor(cvar_t *var, char *newval, qbool *cancel) -{ - char *new_color; - char buf[MAX_COM_TOKEN]; - - // Translate a colors name to RGB values. - new_color = ColorNameToRGBString(newval); - - // Parse the colors. - //color = StringToRGB(new_color); - strlcpy(buf,new_color,sizeof(buf)); - memcpy(hud_radar_highlight_color, StringToRGB(buf), sizeof(byte) * 4); - - // Set the cvar to contain the new color string - // (if the user entered "red" it will be "255 0 0"). - Cvar_Set(var, new_color); -} - -void Radar_DrawEntities(int x, int y, float scale, float player_size, int show_hold_areas) -{ - int i; - - // Entities (weapons and such). cl_main.c - extern visentlist_t cl_visents; - - // Go through all the entities and draw the ones we're supposed to. - for (i = 0; i < cl_visents.count; i++) - { - int entity_q_x = 0; - int entity_q_y = 0; - int entity_p_x = 0; - int entity_p_y = 0; - - // Get quake coordinates (times 8 to get them in the same format as .locs). - entity_q_x = cl_visents.list[i].origin[0]*8; - entity_q_y = cl_visents.list[i].origin[1]*8; - - // Convert from quake coordiantes -> pixel coordinates. - entity_p_x = x + Q_rint((map_x_slope*entity_q_x + map_x_intercept) * scale); - entity_p_y = y + Q_rint((map_y_slope*entity_q_y + map_y_intercept) * scale); - - // TODO: Replace all model name comparison below with MOD_HINT's instead for less comparisons (create new ones in Mod_LoadAliasModel() in r_model.c and gl_model.c/.h for the ones that don't have one already). - - // - // Powerups. - // - - if(radar_show_pent && !strcmp(cl_visents.list[i].model->name, "progs/invulner.mdl")) - { - // Pentagram. - Draw_ColoredString(entity_p_x, entity_p_y, "&cf00P", 0); - } - else if(radar_show_quad && !strcmp(cl_visents.list[i].model->name, "progs/quaddama.mdl")) - { - // Quad. - Draw_ColoredString(entity_p_x, entity_p_y, "&c0ffQ", 0); - } - else if(radar_show_ring && !strcmp(cl_visents.list[i].model->name, "progs/invisibl.mdl")) - { - // Ring. - Draw_ColoredString(entity_p_x, entity_p_y, "&cff0R", 0); - } - else if(radar_show_suit && !strcmp(cl_visents.list[i].model->name, "progs/suit.mdl")) - { - // Suit. - Draw_ColoredString(entity_p_x, entity_p_y, "&c0f0S", 0); - } - - // - // Show RL, LG and backpacks. - // - if(radar_show_rl && !strcmp(cl_visents.list[i].model->name, "progs/g_rock2.mdl")) - { - // RL. - Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "RL"); - } - else if(radar_show_lg && !strcmp(cl_visents.list[i].model->name, "progs/g_light.mdl")) - { - // LG. - Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "LG"); - } - else if(radar_show_backpacks && cl_visents.list[i].model->modhint == MOD_BACKPACK) - { - // Back packs. - float back_pack_size = 0; - - back_pack_size = max(player_size * 0.5, 0.05); - - Draw_AlphaCircleFill (entity_p_x, entity_p_y, back_pack_size, 114, 1); - Draw_AlphaCircleOutline (entity_p_x, entity_p_y, back_pack_size, 1.0, 0, 1); - } - - if(!strcmp(cl_visents.list[i].model->name, "progs/armor.mdl")) - { - // - // Show armors. - // - - if(radar_show_ga && cl_visents.list[i].skinnum == HUD_RADAR_GA) - { - // GA. - Draw_AlphaCircleFill (entity_p_x, entity_p_y, 3.0, 178, 1.0); - } - else if(radar_show_ya && cl_visents.list[i].skinnum == HUD_RADAR_YA) - { - // YA. - Draw_AlphaCircleFill (entity_p_x, entity_p_y, 3.0, 192, 1.0); - } - else if(radar_show_ra && cl_visents.list[i].skinnum == HUD_RADAR_RA) - { - // RA. - Draw_AlphaCircleFill (entity_p_x, entity_p_y, 3.0, 251, 1.0); - } - - Draw_AlphaCircleOutline (entity_p_x, entity_p_y, 3.0, 1.0, 0, 1.0); - } - - if(radar_show_mega && !strcmp(cl_visents.list[i].model->name, "maps/b_bh100.bsp")) - { - // - // Show megahealth. - // - - // Draw a red border around the cross. - Draw_AlphaRectangleRGB(entity_p_x - 3, entity_p_y - 3, 8, 8, 1, false, RGBA_TO_COLOR(200, 0, 0, 200)); - - // Draw a black outline cross. - Draw_AlphaFill(entity_p_x - 3, entity_p_y - 1, 8, 4, 0, 1); - Draw_AlphaFill(entity_p_x - 1, entity_p_y - 3, 4, 8, 0, 1); - - // Draw a 2 pixel cross. - Draw_AlphaFill(entity_p_x - 2, entity_p_y, 6, 2, 79, 1); - Draw_AlphaFill(entity_p_x, entity_p_y - 2, 2, 6, 79, 1); - } - - if(radar_show_ssg && !strcmp(cl_visents.list[i].model->name, "progs/g_shot.mdl")) - { - // SSG. - Draw_String(entity_p_x - (3*8)/2, entity_p_y - 4, "SSG"); - } - else if(radar_show_ng && !strcmp(cl_visents.list[i].model->name, "progs/g_nail.mdl")) - { - // NG. - Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "NG"); - } - else if(radar_show_sng && !strcmp(cl_visents.list[i].model->name, "progs/g_nail2.mdl")) - { - // SNG. - Draw_String(entity_p_x - (3*8)/2, entity_p_y - 4, "SNG"); - } - else if(radar_show_gl && !strcmp(cl_visents.list[i].model->name, "progs/g_rock.mdl")) - { - // GL. - Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "GL"); - } - - if(radar_show_gibs - &&(!strcmp(cl_visents.list[i].model->name, "progs/gib1.mdl") - || !strcmp(cl_visents.list[i].model->name, "progs/gib2.mdl") - || !strcmp(cl_visents.list[i].model->name, "progs/gib3.mdl"))) - { - // - // Gibs. - // - - Draw_AlphaCircleFill(entity_p_x, entity_p_y, 2.0, 251, 1); - } - - if(radar_show_health - &&(!strcmp(cl_visents.list[i].model->name, "maps/b_bh25.bsp") - || !strcmp(cl_visents.list[i].model->name, "maps/b_bh10.bsp"))) - { - // - // Health. - // - - // Draw a black outline cross. - Draw_AlphaFill (entity_p_x - 3, entity_p_y - 1, 7, 3, 0, 1); - Draw_AlphaFill (entity_p_x - 1, entity_p_y - 3, 3, 7, 0, 1); - - // Draw a cross. - Draw_AlphaFill (entity_p_x - 2, entity_p_y, 5, 1, 79, 1); - Draw_AlphaFill (entity_p_x, entity_p_y - 2, 1, 5, 79, 1); - } - - // - // Ammo. - // - if(radar_show_rockets - &&(!strcmp(cl_visents.list[i].model->name, "maps/b_rock0.bsp") - || !strcmp(cl_visents.list[i].model->name, "maps/b_rock1.bsp"))) - { - // - // Rockets. - // - - // Draw a black outline. - Draw_AlphaFill (entity_p_x - 1, entity_p_y - 6, 3, 5, 0, 1); - Draw_AlphaFill (entity_p_x - 2, entity_p_y - 1, 5, 5, 0, 1); - - // The brown rocket. - Draw_AlphaFill (entity_p_x, entity_p_y - 5, 1, 5, 120, 1); - Draw_AlphaFill (entity_p_x - 1, entity_p_y, 1, 3, 120, 1); - Draw_AlphaFill (entity_p_x + 1, entity_p_y, 1, 3, 120, 1); - } - - if(radar_show_cells - &&(!strcmp(cl_visents.list[i].model->name, "maps/b_batt0.bsp") - || !strcmp(cl_visents.list[i].model->name, "maps/b_batt1.bsp"))) - { - // - // Cells. - // - - // Draw a black outline. - Draw_AlphaLine(entity_p_x - 3, entity_p_y, entity_p_x + 4, entity_p_y - 5, 3, 0, 1); - Draw_AlphaLine(entity_p_x - 3, entity_p_y, entity_p_x + 3 , entity_p_y, 3, 0, 1); - Draw_AlphaLine(entity_p_x + 3, entity_p_y, entity_p_x - 3, entity_p_y + 4, 3, 0, 1); - - // Draw a yellow lightning! - Draw_AlphaLine(entity_p_x - 2, entity_p_y, entity_p_x + 3, entity_p_y - 4, 1, 111, 1); - Draw_AlphaLine(entity_p_x - 2, entity_p_y, entity_p_x + 2 , entity_p_y, 1, 111, 1); - Draw_AlphaLine(entity_p_x + 2, entity_p_y, entity_p_x - 2, entity_p_y + 3, 1, 111, 1); - } - - if(radar_show_nails - &&(!strcmp(cl_visents.list[i].model->name, "maps/b_nail0.bsp") - || !strcmp(cl_visents.list[i].model->name, "maps/b_nail1.bsp"))) - { - // - // Nails. - // - - // Draw a black outline. - Draw_AlphaFill (entity_p_x - 3, entity_p_y - 3, 7, 3, 0, 1); - Draw_AlphaFill (entity_p_x - 2, entity_p_y - 2, 5, 3, 0, 0.5); - Draw_AlphaFill (entity_p_x - 1, entity_p_y, 3, 3, 0, 1); - Draw_AlphaFill (entity_p_x - 1, entity_p_y + 3, 1, 1, 0, 0.5); - Draw_AlphaFill (entity_p_x + 1, entity_p_y + 3, 1, 1, 0, 0.5); - Draw_AlphaFill (entity_p_x, entity_p_y + 4, 1, 1, 0, 1); - - Draw_AlphaFill (entity_p_x - 2, entity_p_y - 2, 5, 1, 6, 1); - Draw_AlphaFill (entity_p_x - 1, entity_p_y - 1, 3, 1, 6, 0.5); - Draw_AlphaFill (entity_p_x, entity_p_y, 1, 4, 6, 1); - } - - if(radar_show_shells - &&(!strcmp(cl_visents.list[i].model->name, "maps/b_shell0.bsp") - || !strcmp(cl_visents.list[i].model->name, "maps/b_shell1.bsp"))) - { - // - // Shells. - // - - // Draw a black outline. - Draw_AlphaFill (entity_p_x - 2, entity_p_y - 3, 5, 9, 0, 1); - - // Draw 2 shotgun shells. - Draw_AlphaFill (entity_p_x - 1, entity_p_y - 2, 1, 4, 73, 1); - Draw_AlphaFill (entity_p_x - 1, entity_p_y - 2 + 5, 1, 2, 104, 1); - - Draw_AlphaFill (entity_p_x + 1, entity_p_y - 2, 1, 4, 73, 1); - Draw_AlphaFill (entity_p_x + 1, entity_p_y - 2 + 5, 1, 2, 104, 1); - } - - // - // Show projectiles (rockets, grenades, nails, shaft). - // - - if(radar_show_nails_p - && (!strcmp(cl_visents.list[i].model->name, "progs/s_spike.mdl") - || !strcmp(cl_visents.list[i].model->name, "progs/spike.mdl"))) - { - // - // Spikes from SNG and NG. - // - - Draw_AlphaFill(entity_p_x, entity_p_y, 1, 1, 254, 1); - } - else if(radar_show_rockets_p - && (!strcmp(cl_visents.list[i].model->name, "progs/missile.mdl") - || !strcmp(cl_visents.list[i].model->name, "progs/grenade.mdl"))) - { - // - // Rockets and grenades. - // - - float entity_angle = 0; - int x_line_end = 0; - int y_line_end = 0; - - // Get the entity angle in radians. - entity_angle = DEG2RAD(cl_visents.list[i].angles[1]); - - x_line_end = entity_p_x + 5 * cos(entity_angle) * scale; - y_line_end = entity_p_y - 5 * sin(entity_angle) * scale; - - // Draw the rocket/grenade showing it's angle also. - Draw_AlphaLine (entity_p_x, entity_p_y, x_line_end, y_line_end, 1.0, 254, 1); - } - else if(radar_show_shaft_p - && (!strcmp(cl_visents.list[i].model->name, "progs/bolt.mdl") - || !strcmp(cl_visents.list[i].model->name, "progs/bolt2.mdl") - || !strcmp(cl_visents.list[i].model->name, "progs/bolt3.mdl"))) - { - // - // Shaft beam. - // - - float entity_angle = 0; - float shaft_length = 0; - float x_line_end = 0; - float y_line_end = 0; - - // Get the length and angle of the shaft. - shaft_length = cl_visents.list[i].model->maxs[1]; - entity_angle = (cl_visents.list[i].angles[1]*M_PI)/180; - - // Calculate where the shaft beam's ending point. - x_line_end = entity_p_x + shaft_length * cos(entity_angle); - y_line_end = entity_p_y - shaft_length * sin(entity_angle); - - // Draw the shaft beam. - Draw_AlphaLine (entity_p_x, entity_p_y, x_line_end, y_line_end, 1.0, 254, 1); - } - } - - // Draw a circle around "hold areas", the grid cells within this circle - // are the ones that are counted for that particular hold area. The team - // that has the most percentage of these cells is considered to hold that area. - if(show_hold_areas && stats_important_ents != NULL && stats_important_ents->list != NULL) - { - int entity_p_x = 0; - int entity_p_y = 0; - - for(i = 0; i < stats_important_ents->count; i++) - { - entity_p_x = x + Q_rint((map_x_slope*8*stats_important_ents->list[i].origin[0] + map_x_intercept) * scale); - entity_p_y = y + Q_rint((map_y_slope*8*stats_important_ents->list[i].origin[1] + map_y_intercept) * scale); - - Draw_ColoredString(entity_p_x - (8 * strlen(stats_important_ents->list[i].name)) / 2.0, entity_p_y - 4, - va("&c55f%s", stats_important_ents->list[i].name), 0); - - Draw_AlphaCircleOutline(entity_p_x , entity_p_y, map_x_slope * 8 * stats_important_ents->hold_radius * scale, 1.0, 15, 0.2); - } - } - - // - // Draw temp entities (explosions, blood, teleport effects). - // - for(i = 0; i < MAX_TEMP_ENTITIES; i++) - { - float time_diff = 0.0; - - int entity_q_x = 0; - int entity_q_y = 0; - int entity_p_x = 0; - int entity_p_y = 0; - - // Get the time since the entity spawned. - if(cls.demoplayback) - { - time_diff = cls.demotime - temp_entities.list[i].time; - } - else - { - time_diff = cls.realtime - temp_entities.list[i].time; - } - - // Don't show temp entities for long. - if(time_diff < 0.25) - { - float radius = 0.0; - radius = (time_diff < 0.125) ? (time_diff * 32.0) : (time_diff * 32.0) - time_diff; - radius *= scale; - radius = min(max(radius, 0), 200); - - // Get quake coordinates (times 8 to get them in the same format as .locs). - entity_q_x = temp_entities.list[i].pos[0]*8; - entity_q_y = temp_entities.list[i].pos[1]*8; - - entity_p_x = x + Q_rint((map_x_slope*entity_q_x + map_x_intercept) * scale); - entity_p_y = y + Q_rint((map_y_slope*entity_q_y + map_y_intercept) * scale); - - if(radar_show_explosions - && (temp_entities.list[i].type == TE_EXPLOSION - || temp_entities.list[i].type == TE_TAREXPLOSION)) - { - // - // Explosions. - // - - Draw_AlphaCircleFill (entity_p_x, entity_p_y, radius, 235, 0.8); - } - else if(radar_show_teleport && temp_entities.list[i].type == TE_TELEPORT) - { - // - // Teleport effect. - // - - radius *= 1.5; - Draw_AlphaCircleFill (entity_p_x, entity_p_y, radius, 244, 0.8); - } - else if(radar_show_shotgun && temp_entities.list[i].type == TE_GUNSHOT) - { - // - // Shotgun fire. - // - - #define SHOTGUN_SPREAD 10 - int spread_x = 0; - int spread_y = 0; - int n = 0; - - for(n = 0; n < 10; n++) - { - spread_x = (int)(rand() / (((double)RAND_MAX + 1) / SHOTGUN_SPREAD)); - spread_y = (int)(rand() / (((double)RAND_MAX + 1) / SHOTGUN_SPREAD)); - - Draw_AlphaFill (entity_p_x + spread_x - (SHOTGUN_SPREAD/2), entity_p_y + spread_y - (SHOTGUN_SPREAD/2), 1, 1, 8, 0.9); - } - } - } - } -} - -void Radar_DrawPlayers(int x, int y, int width, int height, float scale, - float show_height, float show_powerups, - float player_size, float show_names, - float fade_players, float highlight, - char *highlight_color) -{ - int i; - player_state_t *state; - player_info_t *info; - - // Get player state so we can know where he is (or on rare occassions, she). - state = cl.frames[cl.oldparsecount & UPDATE_MASK].playerstate; - - // Get the info for the player. - info = cl.players; - - // - // Draw the players. - // - for (i = 0; i < MAX_CLIENTS; i++, info++, state++) - { - // Players quake coordinates - // (these are multiplied by 8, since the conversion formula was - // calculated using the coordinates in a .loc-file, which are in - // the format quake-coordainte*8). - int player_q_x = 0; - int player_q_y = 0; - - // The height of the player. - float player_z = 1.0; - float player_z_relative = 1.0; - - // Players pixel coordinates. - int player_p_x = 0; - int player_p_y = 0; - - // Used for drawing the the direction the - // player is looking at. - float player_angle = 0; - int x_line_start = 0; - int y_line_start = 0; - int x_line_end = 0; - int y_line_end = 0; - - // Color and opacity of the player. - int player_color = 0; - float player_alpha = 1.0; - - // Make sure we're not drawing any ghosts. - if(!info->name[0]) - { - continue; - } - - if (state->messagenum == cl.oldparsecount) - { - // TODO: Implement lerping to get smoother drawing. - - // Get the quake coordinates. Multiply by 8 since - // the conversion formula has been calculated using - // a .loc-file which is in that format. - player_q_x = state->origin[0]*8; - player_q_y = state->origin[1]*8; - - // Get the players view angle. - player_angle = cls.demoplayback ? state->viewangles[1] : cl.simangles[1]; - - // Convert from quake coordiantes -> pixel coordinates. - player_p_x = Q_rint((map_x_slope*player_q_x + map_x_intercept) * scale); - player_p_y = Q_rint((map_y_slope*player_q_y + map_y_intercept) * scale); - - player_color = Sbar_BottomColor(info); - - // Calculate the height of the player. - if(show_height) - { - player_z = state->origin[2]; - player_z += (player_z >= 0) ? fabs(cl.worldmodel->mins[2]) : fabs(cl.worldmodel->maxs[2]); - player_z_relative = min(fabs(player_z / map_height_diff), 1.0); - player_z_relative = max(player_z_relative, 0.2); - } - - // Make the players fade out as they get less armor/health. - if(fade_players) - { - int armor_strength = 0; - armor_strength = (info->stats[STAT_ITEMS] & IT_ARMOR1) ? 100 : - ((info->stats[STAT_ITEMS] & IT_ARMOR2) ? 150 : - ((info->stats[STAT_ITEMS] & IT_ARMOR3) ? 200 : 0)); - - // Don't let the players get completly transparent so add 0.2 to the final value. - player_alpha = ((info->stats[STAT_HEALTH] + (info->stats[STAT_ARMOR] * armor_strength)) / 100.0) + 0.2; - } - - // Turn dead people red. - if(info->stats[STAT_HEALTH] <= 0) - { - player_alpha = 1.0; - player_color = 79; - } - - // Draw a ring around players with powerups if it's enabled. - if(show_powerups) - { - if(info->stats[STAT_ITEMS] & IT_INVISIBILITY) - { - Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size*2*player_z_relative, 161, 0.2); - } - - if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY) - { - Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size*2*player_z_relative, 79, 0.5); - } - - if(info->stats[STAT_ITEMS] & IT_QUAD) - { - Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size*2*player_z_relative, 244, 0.2); - } - } - - #define HUD_RADAR_HIGHLIGHT_NONE 0 - #define HUD_RADAR_HIGHLIGHT_TEXT_ONLY 1 - #define HUD_RADAR_HIGHLIGHT_OUTLINE 2 - #define HUD_RADAR_HIGHLIGHT_FIXED_OUTLINE 3 - #define HUD_RADAR_HIGHLIGHT_CIRCLE 4 - #define HUD_RADAR_HIGHLIGHT_FIXED_CIRCLE 5 - #define HUD_RADAR_HIGHLIGHT_ARROW_BOTTOM 6 - #define HUD_RADAR_HIGHLIGHT_ARROW_CENTER 7 - #define HUD_RADAR_HIGHLIGHT_ARROW_TOP 8 - #define HUD_RADAR_HIGHLIGHT_CROSS_CORNERS 9 - - // Draw a circle around the tracked player. - if (highlight != HUD_RADAR_HIGHLIGHT_NONE && Cam_TrackNum() >= 0 && info->userid == cl.players[Cam_TrackNum()].userid) - { - color_t higlight_color = RGBAVECT_TO_COLOR(hud_radar_highlight_color); - - // Draw the highlight. - switch ((int)highlight) - { - case HUD_RADAR_HIGHLIGHT_CROSS_CORNERS : - { - // Top left - Draw_AlphaLineRGB (x, y, x + player_p_x, y + player_p_y, 2, higlight_color); - - // Top right. - Draw_AlphaLineRGB (x + width, y, x + player_p_x, y + player_p_y, 2, higlight_color); - - // Bottom left. - Draw_AlphaLineRGB (x, y + height, x + player_p_x, y + player_p_y, 2, higlight_color); - - // Bottom right. - Draw_AlphaLineRGB (x + width, y + height, x + player_p_x, y + player_p_y, 2, higlight_color); - break; - } - case HUD_RADAR_HIGHLIGHT_ARROW_TOP : - { - // Top center. - Draw_AlphaLineRGB (x + width / 2, y, x + player_p_x, y + player_p_y, 2, higlight_color); - break; - } - case HUD_RADAR_HIGHLIGHT_ARROW_CENTER : - { - // Center. - Draw_AlphaLineRGB (x + width / 2, y + height / 2, x + player_p_x, y + player_p_y, 2, higlight_color); - break; - } - case HUD_RADAR_HIGHLIGHT_ARROW_BOTTOM : - { - // Bottom center. - Draw_AlphaLineRGB (x + width / 2, y + height, x + player_p_x, y + player_p_y, 2, higlight_color); - break; - } - case HUD_RADAR_HIGHLIGHT_FIXED_CIRCLE : - { - Draw_AlphaCircleRGB (x + player_p_x, y + player_p_y, player_size * 1.5, 1.0, true, higlight_color); - break; - } - case HUD_RADAR_HIGHLIGHT_CIRCLE : - { - Draw_AlphaCircleRGB (x + player_p_x, y + player_p_y, player_size * player_z_relative * 2.0, 1.0, true, higlight_color); - break; - } - case HUD_RADAR_HIGHLIGHT_FIXED_OUTLINE : - { - Draw_AlphaCircleOutlineRGB (x + player_p_x, y + player_p_y, player_size * 1.5, 1.0, higlight_color); - break; - } - case HUD_RADAR_HIGHLIGHT_OUTLINE : - { - Draw_AlphaCircleOutlineRGB (x + player_p_x, y + player_p_y, player_size * player_z_relative * 2.0, 1.0, higlight_color); - break; - } - case HUD_RADAR_HIGHLIGHT_TEXT_ONLY : - default : - { - break; - } - } - } - - // Draw the actual player and a line showing what direction the player is looking in. - { - float relative_x = 0; - float relative_y = 0; - - x_line_start = x + player_p_x; - y_line_start = y + player_p_y; - - // Translate the angle into radians. - player_angle = DEG2RAD(player_angle); - - relative_x = cos(player_angle); - relative_y = sin(player_angle); - - // Draw a slightly larger line behind the colored one - // so that it get's an outline. - x_line_end = x_line_start + (player_size * 2 * player_z_relative + 1) * relative_x; - y_line_end = y_line_start - (player_size * 2 * player_z_relative + 1) * relative_y; - Draw_AlphaLine (x_line_start, y_line_start, x_line_end, y_line_end, 4.0, 0, 1.0); - - // Draw the colored line. - x_line_end = x_line_start + (player_size * 2 * player_z_relative) * relative_x; - y_line_end = y_line_start - (player_size * 2 * player_z_relative) * relative_y; - Draw_AlphaLine (x_line_start, y_line_start, x_line_end, y_line_end, 2.0, player_color, player_alpha); - - // Draw the player on the map. - Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size * player_z_relative, player_color, player_alpha); - Draw_AlphaCircleOutline (x + player_p_x, y + player_p_y, player_size * player_z_relative, 1.0, 0, 1.0); - } - - // Draw the players name. - if(show_names) - { - int name_x = 0; - int name_y = 0; - - name_x = x + player_p_x; - name_y = y + player_p_y; - - // Make sure we're not too far right. - while(name_x + 8 * strlen(info->name) > x + width) - { - name_x--; - } - - // Make sure we're not outside the radar to the left. - name_x = max(name_x, x); - - // Draw the name. - if (highlight >= HUD_RADAR_HIGHLIGHT_TEXT_ONLY - && info->userid == cl.players[Cam_TrackNum()].userid) - { - // Draw the tracked players name in the user specified color. - Draw_ColoredString (name_x, name_y, - va("&c%x%x%x%s", - (unsigned int)(hud_radar_highlight_color[0] * 15), - (unsigned int)(hud_radar_highlight_color[1] * 15), - (unsigned int)(hud_radar_highlight_color[2] * 15), info->name), 0); - } - else - { - // Draw other players in normal character color. - Draw_String (name_x, name_y, info->name); - } - } - - // Show if a person lost an RL-pack. - if(info->stats[STAT_HEALTH] <= 0 && info->stats[STAT_ACTIVEWEAPON] == IT_ROCKET_LAUNCHER) - { - Draw_AlphaCircleOutline (x + player_p_x, y + player_p_y, player_size*player_z_relative*2, 1.0, 254, player_alpha); - Draw_ColoredString (x + player_p_x, y + player_p_y, va("&cf00PACK!"), 1); - } - } - } -} - -// -// Draws a map of the current level and plots player movements on it. -// -void SCR_HUD_DrawRadar(hud_t *hud) -{ - int width, height, x, y; - float width_limit, height_limit; - float scale; - float x_scale; - float y_scale; - - static cvar_t - *hud_radar_opacity = NULL, - *hud_radar_width, - *hud_radar_height, - *hud_radar_autosize, - *hud_radar_fade_players, - *hud_radar_show_powerups, - *hud_radar_show_names, - *hud_radar_highlight, - *hud_radar_highlight_color, - *hud_radar_player_size, - *hud_radar_show_height, - *hud_radar_show_stats, - *hud_radar_show_hold, - *hud_radar_weaponfilter, - *hud_radar_itemfilter, - *hud_radar_onlytp, - *hud_radar_otherfilter; - - if (hud_radar_opacity == NULL) // first time - { - char checkval[256]; - - hud_radar_opacity = HUD_FindVar(hud, "opacity"); - hud_radar_width = HUD_FindVar(hud, "width"); - hud_radar_height = HUD_FindVar(hud, "height"); - hud_radar_autosize = HUD_FindVar(hud, "autosize"); - hud_radar_fade_players = HUD_FindVar(hud, "fade_players"); - hud_radar_show_powerups = HUD_FindVar(hud, "show_powerups"); - hud_radar_show_names = HUD_FindVar(hud, "show_names"); - hud_radar_player_size = HUD_FindVar(hud, "player_size"); - hud_radar_show_height = HUD_FindVar(hud, "show_height"); - hud_radar_show_stats = HUD_FindVar(hud, "show_stats"); - hud_radar_show_hold = HUD_FindVar(hud, "show_hold"); - hud_radar_weaponfilter = HUD_FindVar(hud, "weaponfilter"); - hud_radar_itemfilter = HUD_FindVar(hud, "itemfilter"); - hud_radar_otherfilter = HUD_FindVar(hud, "otherfilter"); - hud_radar_onlytp = HUD_FindVar(hud, "onlytp"); - hud_radar_highlight = HUD_FindVar(hud, "highlight"); - hud_radar_highlight_color = HUD_FindVar(hud, "highlight_color"); - - // - // Only parse the the filters when they change, not on each frame. - // - - // Weapon filter. - hud_radar_weaponfilter->OnChange = Radar_OnChangeWeaponFilter; - strlcpy(checkval, hud_radar_weaponfilter->string, sizeof(checkval)); - Cvar_Set(hud_radar_weaponfilter, checkval); - - // Item filter. - hud_radar_itemfilter->OnChange = Radar_OnChangeItemFilter; - strlcpy(checkval, hud_radar_itemfilter->string, sizeof(checkval)); - Cvar_Set(hud_radar_itemfilter, checkval); - - // Other filter. - hud_radar_otherfilter->OnChange = Radar_OnChangeOtherFilter; - strlcpy(checkval, hud_radar_otherfilter->string, sizeof(checkval)); - Cvar_Set(hud_radar_otherfilter, checkval); - - // Highlight color. - hud_radar_highlight_color->OnChange = Radar_OnChangeHighlightColor; - strlcpy(checkval, hud_radar_highlight_color->string, sizeof(checkval)); - Cvar_Set(hud_radar_highlight_color, checkval); - } - - // Don't show anything if it's a normal player. - if(!(cls.demoplayback || cl.spectator)) - { - HUD_PrepareDraw(hud, hud_radar_width->value, hud_radar_height->value, &x, &y); - return; - } - - // Don't show when not in teamplay/demoplayback. - if(!HUD_ShowInDemoplayback(hud_radar_onlytp->value)) - { - HUD_PrepareDraw(hud, hud_radar_width->value, hud_radar_height->value, &x, &y); - return; - } - - // Save the width and height of the HUD. We're using these because - // if autosize is on these will be altered and we don't want to change - // the settings that the user set, if we try, and the user turns off - // autosize again the size of the HUD will remain "autosized" until the user - // resets it by hand again. - width_limit = hud_radar_width->value; - height_limit = hud_radar_height->value; - - // we support also sizes specified as a percentage of total screen width/height - if (strchr(hud_radar_width->string, '%')) - width_limit = width_limit * vid.conwidth / 100.0; - if (strchr(hud_radar_height->string, '%')) - height_limit = hud_radar_height->value * vid.conheight / 100.0; - - // This map doesn't have a map pic. - if(!radar_pic_found) - { - if(HUD_PrepareDraw(hud, Q_rint(width_limit), Q_rint(height_limit), &x, &y)) - { - Draw_String(x, y, "No radar picture found!"); - } - return; - } - - // Make sure we can translate the coordinates. - if(!conversion_formula_found) - { - if(HUD_PrepareDraw(hud, Q_rint(width_limit), Q_rint(height_limit), &x, &y)) - { - Draw_String(x, y, "No conversion formula found!"); - } - return; - } - - x = 0; - y = 0; - - scale = 1; - - if(hud_radar_autosize->value) - { - // - // Autosize the hud element based on the size of the radar picture. - // - - width = width_limit = radar_pic.width; - height = height_limit = radar_pic.height; - } - else - { - // - // Size the picture so that it fits inside the hud element. - // - - // Set the scaling based on the picture dimensions. - x_scale = (width_limit / radar_pic.width); - y_scale = (height_limit / radar_pic.height); - - scale = (x_scale < y_scale) ? x_scale : y_scale; - - width = radar_pic.width * scale; - height = radar_pic.height * scale; - } - - if (HUD_PrepareDraw(hud, Q_rint(width_limit), Q_rint(height_limit), &x, &y)) - { - float player_size = 1.0; - static int lastframecount = -1; - - // Place the map picture in the center of the HUD element. - x += Q_rint((width_limit / 2.0) - (width / 2.0)); - x = max(0, x); - x = min(x + width, x); - - y += Q_rint((height_limit / 2.0) - (height / 2.0)); - y = max(0, y); - y = min(y + height, y); - - // Draw the radar background. - Draw_SAlphaPic (x, y, &radar_pic, hud_radar_opacity->value, scale); - - // Only draw once per frame. - if (cls.framecount == lastframecount) - { - return; - } - lastframecount = cls.framecount; - - if (!cl.oldparsecount || !cl.parsecount || cls.state < ca_active) - { - return; - } - - // Scale the player size after the size of the radar. - player_size = hud_radar_player_size->value * scale; - - // Draw team stats. - if(hud_radar_show_stats->value) - { - Radar_DrawGrid(stats_grid, x, y, scale, width, height, hud_radar_show_stats->value); - } - - // Draw entities such as powerups, weapons and backpacks. - if(RADAR_SHOW_WEAPONS || RADAR_SHOW_ITEMS || RADAR_SHOW_OTHER) - { - Radar_DrawEntities(x, y, scale, - player_size, - hud_radar_show_hold->value); - } - - // Draw the players. - Radar_DrawPlayers(x, y, width, height, scale, - hud_radar_show_height->value, - hud_radar_show_powerups->value, - player_size, - hud_radar_show_names->value, - hud_radar_fade_players->value, - hud_radar_highlight->value, - hud_radar_highlight_color->string); - } -} - -#endif // WITH_PNG - -// -// Run before HUD elements are drawn. -// Place stuff that is common for HUD elements here. -// -void HUD_BeforeDraw() -{ - // Only sort once per draw. - HUD_Sort_Scoreboard (HUD_SCOREBOARD_ALL); -} - -// -// Run after HUD elements are drawn. -// Place stuff that is common for HUD elements here. -// -void HUD_AfterDraw() -{ -} - - -#ifndef HAXX -static void SCR_HUD_DrawNotImplemented(hud_t *hud) -{ - char line1[64]; - int width, height, x, y; - - snprintf(line1, sizeof(line1), "%s not implemented", hud->name); - - width = 8 * strlen(line1); - height = 8; - - if (!HUD_PrepareDraw(hud, width, height, &x, &y)) - return; - - Draw_SString(x, y, line1, 1); -} -#define SCR_HUD_DrawSpeed SCR_HUD_DrawNotImplemented -#define SCR_HUD_DrawTeamHoldBar SCR_HUD_DrawNotImplemented -#define SCR_HUD_DrawTeamHoldInfo SCR_HUD_DrawNotImplemented -#define SCR_HUD_DrawItemsClock SCR_HUD_DrawNotImplemented -#endif - - -// ---------------- -// Init -// and add some common elements to hud (clock etc) -// - -void CommonDraw_Init(void) -{ - int i; - - HUD_InitSbarImages(); - - // variables - hud_planmode = pCvar_GetNVFDG("hud_planmode", "0", 0, NULL, "ezhud"); - hud_tp_need = pCvar_GetNVFDG("hud_tp_need", "0", 0, NULL, "ezhud"); - hud_digits_trim = pCvar_GetNVFDG("hud_digits_trim", "1", 0, NULL, "ezhud"); - mvd_autohud = pCvar_GetNVFDG("mvd_autohud", "0", 0, NULL, "ezhud"); - cl_weaponpreselect = pCvar_GetNVFDG("cl_weaponpreselect", "0", 0, NULL, "ezhud"); - cl_multiview = pCvar_GetNVFDG("cl_multiview", "0", 0, NULL, "ezhud"); - - - tp_need_health = pCvar_GetNVFDG("tp_need_health", "50", 0, NULL, "ezhud"); - tp_need_ra = pCvar_GetNVFDG("tp_need_ra", "50", 0, NULL, "ezhud"); - tp_need_ya = pCvar_GetNVFDG("tp_need_ya", "50", 0, NULL, "ezhud"); - tp_need_ga = pCvar_GetNVFDG("tp_need_ga", "50", 0, NULL, "ezhud"); - tp_weapon_order = pCvar_GetNVFDG("tp_weapon_order", "78654321", 0, NULL, "ezhud"); - tp_need_weapon = pCvar_GetNVFDG("tp_need_weapon", "35687", 0, NULL, "ezhud"); - tp_need_shells = pCvar_GetNVFDG("tp_need_shells", "10", 0, NULL, "ezhud"); - tp_need_nails = pCvar_GetNVFDG("tp_need_nails", "40", 0, NULL, "ezhud"); - tp_need_rockets = pCvar_GetNVFDG("tp_need_rockets", "5", 0, NULL, "ezhud"); - tp_need_cells = pCvar_GetNVFDG("tp_need_cells", "20", 0, NULL, "ezhud"); - - // init HUD STAT table - for (i=0; i < MAX_CL_STATS; i++) - hud_stats[i] = 0; - hud_stats[STAT_HEALTH] = 200; - hud_stats[STAT_AMMO] = 100; - hud_stats[STAT_ARMOR] = 200; - hud_stats[STAT_SHELLS] = 100; - hud_stats[STAT_NAILS] = 200; - hud_stats[STAT_ROCKETS] = 100; - hud_stats[STAT_CELLS] = 100; - hud_stats[STAT_ACTIVEWEAPON] = 32; - hud_stats[STAT_ITEMS] = 0xffffffff - IT_ARMOR2 - IT_ARMOR1; - - autohud.active = 0; - - // init gameclock - HUD_Register("gameclock", NULL, "Shows current game time (hh:mm:ss).", - HUD_PLUSMINUS, ca_disconnected, 8, SCR_HUD_DrawGameClock, - "1", "top", "right", "console", "0", "0", "0", "0 0 0", NULL, - "big", "1", - "style", "0", - "scale", "1", - "blink", "1", - "countdown","0", - "offset","0", - NULL); - - HUD_Register("notify", NULL, "Shows last console lines", - HUD_PLUSMINUS, ca_disconnected, 8, SCR_HUD_DrawNotify, - "0", "top", "left", "top", "0", "0", "0", "0 0 0", NULL, - "rows", "4", - "cols", "30", - "scale", "1", - "time", "4", - NULL); - - // fps - HUD_Register("fps", NULL, - "Shows your current framerate in frames per second (fps)." - "This can also show the minimum framerate that occured in the last measured period.", - HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawFPS, - "1", "gameclock", "center", "after", "0", "0", "0", "0 0 0", NULL, - "show_min", "0", - "style", "0", - "title", "1", - "drop", "70", - NULL); - - HUD_Register("vidlag", NULL, - "Shows the delay between the time a frame is rendered and the time it's displayed.", - HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawVidLag, - "0", "top", "right", "top", "0", "0", "0", "0 0 0", NULL, - "style", "0", - NULL); - - HUD_Register("mouserate", NULL, "Show your current mouse input rate", HUD_PLUSMINUS, ca_active, 9, - SCR_HUD_DrawMouserate, - "0", "screen", "left", "bottom", "0", "0", "0", "0 0 0", NULL, - "title", "1", - "interval", "1", - "style", "0", - NULL); - - // init clock - HUD_Register("clock", NULL, "Shows current local time (hh:mm:ss).", - HUD_PLUSMINUS, ca_disconnected, 8, SCR_HUD_DrawClock, - "0", "top", "right", "console", "0", "0", "0", "0 0 0", NULL, - "big", "1", - "style", "0", - "scale", "1", - "blink", "1", - "format", "0", - NULL); - - // init democlock - HUD_Register("democlock", NULL, "Shows current demo time (hh:mm:ss).", - HUD_PLUSMINUS, ca_disconnected, 7, SCR_HUD_DrawDemoClock, - "1", "top", "right", "console", "0", "8", "0", "0 0 0", NULL, - "big", "0", - "style", "0", - "scale", "1", - "blink", "0", - NULL); - - // init ping - HUD_Register("ping", NULL, "Shows most important net conditions, like ping and pl. Shown only when you are connected to a server.", - HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawPing, - "0", "screen", "left", "bottom", "0", "0", "0", "0 0 0", NULL, - "period", "1", - "show_pl", "1", - "show_min", "0", - "show_max", "0", - "show_dev", "0", - "style", "0", - "blink", "1", - NULL); - - // init net - HUD_Register("net", NULL, "Shows network statistics, like latency, packet loss, average packet sizes and bandwidth. Shown only when you are connected to a server.", - HUD_PLUSMINUS, ca_active, 7, SCR_HUD_DrawNetStats, - "0", "top", "left", "center", "0", "0", "0.2", "0 0 0", NULL, - "period", "1", - NULL); - - // init speed - HUD_Register("speed", NULL, "Shows your current running speed. It is measured over XY or XYZ axis depending on \'xyz\' property.", - HUD_PLUSMINUS, ca_active, 7, SCR_HUD_DrawSpeed, - "0", "top", "center", "bottom", "0", "-5", "0", "0 0 0", NULL, - "xyz", "0", - "width", "160", - "height", "15", - "opacity", "1.0", - "tick_spacing", "0.2", - "color_stopped", SPEED_STOPPED, - "color_normal", SPEED_NORMAL, - "color_fast", SPEED_FAST, - "color_fastest", SPEED_FASTEST, - "color_insane", SPEED_INSANE, - "vertical", "0", - "vertical_text", "1", - "text_align", "1", - "style", "0", - NULL); - - // Init speed2 (half circle thingie). - HUD_Register("speed2", NULL, "Shows your current running speed. It is measured over XY or XYZ axis depending on \'xyz\' property.", - HUD_PLUSMINUS, ca_active, 7, SCR_HUD_DrawSpeed2, - "0", "top", "center", "bottom", "0", "0", "0", "0 0 0", NULL, - "xyz", "0", - "opacity", "1.0", - "color_stopped", SPEED_STOPPED, - "color_normal", SPEED_NORMAL, - "color_fast", SPEED_FAST, - "color_fastest", SPEED_FASTEST, - "color_insane", SPEED_INSANE, - "radius", "50.0", - "wrapspeed", "500", - "orientation", "0", - NULL); - - // init guns - HUD_Register("gun", NULL, "Part of your inventory - current weapon.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGunCurrent, - "0", "ibar", "center", "bottom", "0", "0", "0", "0 0 0", NULL, - "wide", "0", - "style", "0", - "scale", "1", - NULL); - HUD_Register("gun2", NULL, "Part of your inventory - shotgun.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun2, - "1", "ibar", "left", "bottom", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("gun3", NULL, "Part of your inventory - super shotgun.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun3, - "1", "gun2", "after", "center", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("gun4", NULL, "Part of your inventory - nailgun.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun4, - "1", "gun3", "after", "center", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("gun5", NULL, "Part of your inventory - super nailgun.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun5, - "1", "gun4", "after", "center", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("gun6", NULL, "Part of your inventory - grenade launcher.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun6, - "1", "gun5", "after", "center", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("gun7", NULL, "Part of your inventory - rocket launcher.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun7, - "1", "gun6", "after", "center", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("gun8", NULL, "Part of your inventory - thunderbolt.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun8, - "1", "gun7", "after", "center", "0", "0", "0", "0 0 0", NULL, - "wide", "0", - "style", "0", - "scale", "1", - NULL); - - // init powerzz - HUD_Register("key1", NULL, "Part of your inventory - silver key.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawKey1, - "1", "ibar", "top", "left", "0", "64", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("key2", NULL, "Part of your inventory - gold key.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawKey2, - "1", "key1", "left", "after", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("ring", NULL, "Part of your inventory - invisibility.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawRing, - "1", "key2", "left", "after", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("pent", NULL, "Part of your inventory - invulnerability.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawPent, - "1", "ring", "left", "after", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("suit", NULL, "Part of your inventory - biosuit.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSuit, - "1", "pent", "left", "after", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("quad", NULL, "Part of your inventory - quad damage.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawQuad, - "1", "suit", "left", "after", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - - // netproblem icon - HUD_Register("netproblem", NULL, "Shows an icon if you are experiencing network problems", - HUD_NO_FRAME, ca_active, 0, SCR_HUD_NetProblem, - "1", "top", "left", "top", "0", "0", "0", "0 0 0", NULL, - "scale", "1", - NULL); - - // sigilzz - HUD_Register("sigil1", NULL, "Part of your inventory - sigil 1.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil1, - "0", "ibar", "left", "top", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("sigil2", NULL, "Part of your inventory - sigil 2.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil2, - "0", "sigil1", "after", "top", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("sigil3", NULL, "Part of your inventory - sigil 3.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil3, - "0", "sigil2", "after", "top", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("sigil4", NULL, "Part of your inventory - sigil 4.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil4, - "0", "sigil3", "after", "top", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - - // player face (health indicator) - HUD_Register("face", NULL, "Your bloody face.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawFace, - "1", "screen", "center", "bottom", "0", "0", "0", "0 0 0", NULL, - "scale", "1", - NULL); - - // health - HUD_Register("health", NULL, "Part of your status - health level.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawHealth, - "1", "face", "after", "center", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "3", - NULL); - - // ammo/s - HUD_Register("ammo", NULL, "Part of your inventory - ammo for active weapon.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoCurrent, - "1", "health", "after", "center", "32", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "3", - NULL); - HUD_Register("ammo1", NULL, "Part of your inventory - ammo - shells.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo1, - "0", "ibar", "left", "top", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "3", - NULL); - HUD_Register("ammo2", NULL, "Part of your inventory - ammo - nails.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo2, - "0", "ammo1", "after", "top", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "3", - NULL); - HUD_Register("ammo3", NULL, "Part of your inventory - ammo - rockets.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo3, - "0", "ammo2", "after", "top", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "3", - NULL); - HUD_Register("ammo4", NULL, "Part of your inventory - ammo - cells.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo4, - "0", "ammo3", "after", "top", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "3", - NULL); - - // ammo icon/s - HUD_Register("iammo", NULL, "Part of your inventory - ammo icon.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIconCurrent, - "1", "ammo", "before", "center", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - HUD_Register("iammo1", NULL, "Part of your inventory - ammo icon.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon1, - "0", "ibar", "left", "top", "0", "0", "0", "0 0 0", NULL, - "style", "2", - "scale", "1", - NULL); - HUD_Register("iammo2", NULL, "Part of your inventory - ammo icon.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon2, - "0", "iammo1", "after", "top", "0", "0", "0", "0 0 0", NULL, - "style", "2", - "scale", "1", - NULL); - HUD_Register("iammo3", NULL, "Part of your inventory - ammo icon.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon3, - "0", "iammo2", "after", "top", "0", "0", "0", "0 0 0", NULL, - "style", "2", - "scale", "1", - NULL); - HUD_Register("iammo4", NULL, "Part of your inventory - ammo icon.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon4, - "0", "iammo3", "after", "top", "0", "0", "0", "0 0 0", NULL, - "style", "2", - "scale", "1", - NULL); - - // armor count - HUD_Register("armor", NULL, "Part of your inventory - armor level.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawArmor, - "1", "face", "before", "center", "-32", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "3", - "pent_666", "1", // Show 666 instead of armor value - NULL); - - // armor icon - HUD_Register("iarmor", NULL, "Part of your inventory - armor icon.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawArmorIcon, - "1", "armor", "before", "center", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - NULL); - - // Tracking JohnNy_cz (Contains name of the player who's player we're watching at the moment) - HUD_Register("tracking", NULL, "Shows the name of tracked player.", - HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawTracking, - "1", "face", "center", "before", "0", "0", "0", "0 0 0", NULL, - "format", "^mTracking:^m %t %n"/*, ^mJUMP^m for next"*/, //"Tracking: team name, JUMP for next", "Tracking:" and "JUMP" are brown. default: "Tracking %t %n, [JUMP] for next" - "scale", "1", - NULL); - - // groups - HUD_Register("group1", NULL, "Group element.", - HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group1, - "0", "screen", "left", "top", "0", "0", ".5", "0 0 0", NULL, - "name", "group1", - "width", "64", - "height", "64", - "picture", "", - "pic_alpha", "1.0", - "pic_scalemode", "0", - NULL); - HUD_Register("group2", NULL, "Group element.", - HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group2, - "0", "screen", "center", "top", "0", "0", ".5", "0 0 0", NULL, - "name", "group2", - "width", "64", - "height", "64", - "picture", "", - "pic_alpha", "1.0", - "pic_scalemode", "0", - NULL); - HUD_Register("group3", NULL, "Group element.", - HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group3, - "0", "screen", "right", "top", "0", "0", ".5", "0 0 0", NULL, - "name", "group3", - "width", "64", - "height", "64", - "picture", "", - "pic_alpha", "1.0", - "pic_scalemode", "0", - NULL); - HUD_Register("group4", NULL, "Group element.", - HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group4, - "0", "screen", "left", "center", "0", "0", ".5", "0 0 0", NULL, - "name", "group4", - "width", "64", - "height", "64", - "picture", "", - "pic_alpha", "1.0", - "pic_scalemode", "0", - NULL); - HUD_Register("group5", NULL, "Group element.", - HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group5, - "0", "screen", "center", "center", "0", "0", ".5", "0 0 0", NULL, - "name", "group5", - "width", "64", - "height", "64", - "picture", "", - "pic_alpha", "1.0", - "pic_scalemode", "0", - NULL); - HUD_Register("group6", NULL, "Group element.", - HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group6, - "0", "screen", "right", "center", "0", "0", ".5", "0 0 0", NULL, - "name", "group6", - "width", "64", - "height", "64", - "picture", "", - "pic_alpha", "1.0", - "pic_scalemode", "0", - NULL); - HUD_Register("group7", NULL, "Group element.", - HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group7, - "0", "screen", "left", "bottom", "0", "0", ".5", "0 0 0", NULL, - "name", "group7", - "width", "64", - "height", "64", - "picture", "", - "pic_alpha", "1.0", - "pic_scalemode", "0", - NULL); - HUD_Register("group8", NULL, "Group element.", - HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group8, - "0", "screen", "center", "bottom", "0", "0", ".5", "0 0 0", NULL, - "name", "group8", - "width", "64", - "height", "64", - "picture", "", - "pic_alpha", "1.0", - "pic_scalemode", "0", - NULL); - HUD_Register("group9", NULL, "Group element.", - HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group9, - "0", "screen", "right", "bottom", "0", "0", ".5", "0 0 0", NULL, - "name", "group9", - "width", "64", - "height", "64", - "picture", "", - "pic_alpha", "1.0", - "pic_scalemode", "0", - NULL); - - // healthdamage - HUD_Register("healthdamage", NULL, "Shows amount of damage done to your health.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawHealthDamage, - "0", "health", "left", "before", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "3", - "duration", "0.8", - NULL); - - // armordamage - HUD_Register("armordamage", NULL, "Shows amount of damage done to your armour.", - HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawArmorDamage, - "0", "armor", "left", "before", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "3", - "duration", "0.8", - NULL); - - HUD_Register("frags", NULL, "Show list of player frags in short form.", - 0, ca_active, 0, SCR_HUD_DrawFrags, - "0", "top", "right", "bottom", "0", "0", "0", "0 0 0", NULL, - "cell_width", "32", - "cell_height", "8", - "rows", "1", - "cols", "4", - "space_x", "1", - "space_y", "1", - "teamsort", "0", - "strip", "1", - "vertical", "0", - "shownames", "0", - "showteams", "0", - "padtext", "1", - "showself_always", "1", - "extra_spec_info", "ALL", - "fliptext", "0", - "style", "0", - "bignum", "0", - "colors_alpha", "1.0", - "maxname", "16", - "notintp", "0", - NULL); - - HUD_Register("teamfrags", NULL, "Show list of team frags in short form.", - 0, ca_active, 0, SCR_HUD_DrawTeamFrags, - "1", "ibar", "center", "before", "0", "0", "0", "0 0 0", NULL, - "cell_width", "32", - "cell_height", "8", - "rows", "1", - "cols", "2", - "space_x", "1", - "space_y", "1", - "strip", "1", - "vertical", "0", - "shownames", "0", - "padtext", "1", - "fliptext", "1", - "style", "0", - "extra_spec_info", "1", - "onlytp", "0", - "bignum", "0", - "colors_alpha", "1.0", - "maxname", "16", - NULL); - - HUD_Register("teaminfo", NULL, "Show information about your team in short form.", - 0, ca_active, 0, SCR_HUD_DrawTeamInfo, - "0", "", "right", "center", "0", "0", "0.2", "20 20 20", NULL, - "layout", "%p%n $x10%l$x11 %a/%H %w", - "align_right","0", - "loc_width","5", - "name_width","6", - "low_health","25", - "armor_style","3", - "weapon_style","0", - "show_enemies","0", - "show_self","1", - "scale","1", - "powerup_style","1", - NULL); - - HUD_Register("mp3_title", NULL, "Shows current mp3 playing.", - HUD_PLUSMINUS, ca_disconnected, 0, SCR_HUD_DrawMP3_Title, - "0", "top", "right", "bottom", "0", "0", "0", "0 0 0", NULL, - "style", "2", - "width", "512", - "height", "8", - "scroll", "1", - "scroll_delay", "0.5", - "on_scoreboard", "0", - "wordwrap", "0", - NULL); - - HUD_Register("mp3_time", NULL, "Shows the time of the current mp3 playing.", - HUD_PLUSMINUS, ca_disconnected, 0, SCR_HUD_DrawMP3_Time, - "0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL, - "style", "0", - "on_scoreboard", "0", - NULL); - -#ifdef WITH_PNG - HUD_Register("radar", NULL, "Plots the players on a picture of the map. (Only when watching MVD's or QTV).", - HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawRadar, - "0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL, - "opacity", "0.5", - "width", "30%", - "height", "25%", - "autosize", "0", - "show_powerups", "1", - "show_names", "0", - "highlight_color", "yellow", - "highlight", "0", - "player_size", "10", - "show_height", "1", - "show_stats", "1", - "fade_players", "1", - "show_hold", "0", - "weaponfilter", "gl rl lg", - "itemfilter", "backpack quad pent armor mega", - "otherfilter", "projectiles gibs explosions shotgun", - "onlytp", "0", - NULL); -#endif // WITH_PNG - - HUD_Register("teamholdbar", NULL, "Shows how much of the level (in percent) that is currently being held by either team.", - HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawTeamHoldBar, - "0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL, - "opacity", "0.8", - "width", "200", - "height", "8", - "vertical", "0", - "vertical_text", "0", - "show_text", "1", - "onlytp", "0", - NULL); - - HUD_Register("teamholdinfo", NULL, "Shows which important items in the level that are being held by the teams.", - HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawTeamHoldInfo, - "0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL, - "opacity", "0.8", - "width", "200", - "height", "8", - "onlytp", "0", - "style", "1", - "itemfilter", "quad ra ya ga mega pent rl quad", - NULL); - - HUD_Register("ownfrags" /* jeez someone give me a better name please */, NULL, "Highlights your own frags", - 0, ca_active, 1, SCR_HUD_DrawOwnFrags, - "1", "screen", "center", "top", "0", "50", "0.2", "0 0 100", NULL, - /* - "color", "255 255 255", - */ - "timeout", "3", - "scale", "1.5", - NULL - ); - - HUD_Register("keys", NULL, "Shows which keys user does press at the moment", - 0, ca_active, 1, SCR_HUD_DrawKeys, - "0", "screen", "right", "center", "0", "0", "0.5", "20 20 20", NULL, - "scale", "2", - NULL - ); - - HUD_Register("itemsclock", NULL, "Displays upcoming item respawns", - 0, ca_active, 1, SCR_HUD_DrawItemsClock, - "0", "screen", "right", "center", "0", "0", "0", "0 0 0", NULL, - "timelimit", "5", - "style", "0", - NULL - ); - - HUD_Register("score_team", NULL, "Own scores or team scores.", - 0, ca_active, 0, SCR_HUD_DrawScoresTeam, - "0", "screen", "left", "bottom", "0", "0", "0.5", "4 8 32", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "0", - "colorize", "0", - NULL - ); - - HUD_Register("score_enemy", NULL, "Scores of enemy or enemy team.", - 0, ca_active, 0, SCR_HUD_DrawScoresEnemy, - "0", "score_team", "after", "bottom", "0", "0", "0.5", "32 4 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "0", - "colorize", "0", - NULL - ); - - HUD_Register("score_difference", NULL, "Difference between teamscores and enemyscores.", - 0, ca_active, 0, SCR_HUD_DrawScoresDifference, - "0", "score_enemy", "after", "bottom", "0", "0", "0.5", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "0", - "colorize", "1", - NULL - ); - - HUD_Register("score_position", NULL, "Position on scoreboard.", - 0, ca_active, 0, SCR_HUD_DrawScoresPosition, - "0", "score_difference", "after", "bottom", "0", "0", "0.5", "0 0 0", NULL, - "style", "0", - "scale", "1", - "align", "right", - "digits", "0", - "colorize", "1", - NULL - ); - - HUD_Register("score_bar", NULL, "Team, enemy, and difference scores together.", - HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawScoresBar, - "0", "screen", "center", "console", "0", "0", "0.5", "0 0 0", NULL, - "style", "0", - "scale", "1", - "format_small", "&c69f%T&r:%t &cf10%E&r:%e $[%D$]", - "format_big", "%t:%e:%Z", - - NULL - ); - - HUD_Register("bar_armor", NULL, "Armor bar.", - HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawBarArmor, - "0", "armor", "left", "center", "0", "0", "0", "0 0 0", NULL, - "height", "16", - "width", "64", - "direction", "1", - "color_noarmor", "128 128 128 64", - "color_ga", "32 128 0 128", - "color_ya", "192 128 0 128", - "color_ra", "128 0 0 128", - "color_unnatural", "255 255 255 128", - NULL - ); - - HUD_Register("bar_health", NULL, "Health bar.", - HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawBarHealth, - "0", "health", "right", "center", "0", "0", "0", "0 0 0", NULL, - "height", "16", - "width", "64", - "direction", "0", - "color_nohealth", "128 128 128 64", - "color_normal", "32 64 128 128", - "color_mega", "64 96 128 128", - "color_twomega", "128 128 255 128", - "color_unnatural", "255 255 255 128", - NULL - ); - - HUD_Register("weaponstats", NULL, "Weapon Stats", - HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawWeaponStats, - "0", "screen", "right", "center", "0", "0", "0", "0 0 0", NULL, - "scale", "1", - "fmt", "&c990sg&r:[%sg] &c099ssg&r:[%ssg] &c900rl&r:[#rl] &c009lg&r:[%lg]", - NULL - ); - -/* hexum -> FIXME? this is used only for debug purposes, I wont bother to port it (it shouldnt be too difficult if anyone cares) -#ifdef _DEBUG - HUD_Register("framegraph", NULL, "Shows different frame times for debug/profiling purposes.", - HUD_PLUSMINUS | HUD_ON_SCORES, ca_disconnected, 0, SCR_HUD_DrawFrameGraph, - "0", "top", "left", "bottom", "0", "0", "2", - "swap_x", "0", - "swap_y", "0", - "scale", "14", - "width", "256", - "height", "64", - "alpha", "1", - NULL); -#endif -*/ - -} - - +} +int Player_GetTrackId(int uid) +{ + return uid; +} +unsigned int BestWeaponFromStatItems(unsigned int items) +{ + int i; + for (i = 1<<7; i; i>>=1) + { + if (items & i) + return i; + } + return 0; +} +mpic_t * SCR_GetWeaponIconByFlag (int flag) +{ + int i, j; + for (i = 0, j = 1; i < 7; i++, j*=2) + { + if (flag == j) + return sb_weapons[0][i]; + } + return NULL; +} +static int SCR_HudDrawTeamInfoPlayer(teamplayerinfo_t *ti_cl, int x, int y, int maxname, int maxloc, qbool width_only, hud_t *hud) +{ + extern mpic_t * SCR_GetWeaponIconByFlag (int flag); + + char *s, *loc, tmp[1024], tmp2[1024], *aclr; + int x_in = x; // save x + int i; + mpic_t *pic; + float scale = HUD_FindVar(hud, "scale")->value; + + if (!ti_cl) + return 0; + + i = ti_cl->client; + + if (i < 0 || i >= MAX_CLIENTS) + { + Com_DPrintf("SCR_Draw_TeamInfoPlayer: wrong client %d\n", i); + return 0; + } + + // this limit len of string because TP_ParseFunChars() do not check overflow + strlcpy(tmp2, HUD_FindVar(hud, "layout")->string , sizeof(tmp2)); + strlcpy(tmp2, TP_ParseFunChars(tmp2, false), sizeof(tmp2)); + s = tmp2; + + // + // parse/draw string like this "%n %h:%a %l %p %w" + // + + for ( ; *s; s++) { + switch( (int) s[0] ) { + case '%': + + s++; // advance + + switch( (int) s[0] ) { + case 'n': // draw name + + if(!width_only) { + char *nick = TP_ParseFunChars(ti_cl->nick[0] ? ti_cl->nick : cl.players[i].name, false); + str_align_right(tmp, sizeof(tmp), nick, maxname); + Draw_SString (x, y, tmp, scale); + } + x += maxname * FONTWIDTH * scale; + + break; + case 'w': // draw "best" weapon icon/name + + switch (HUD_FindVar(hud, "weapon_style")->ival) { + case 1: + if(!width_only) { + if (Has_Both_RL_and_LG(ti_cl->items)) { + char *weap_str = pCvar_GetNVFDG("tp_name_rlg", "rlg", 0, NULL, NULL)->string; + char weap_white_stripped[32]; + Util_SkipChars(weap_str, "{}", weap_white_stripped, 32); + Draw_ColoredString (x, y, weap_white_stripped, false); + } + else { + char *weap_str = TP_ItemName(BestWeaponFromStatItems( ti_cl->items )); + char weap_white_stripped[32]; + Util_SkipChars(weap_str, "{}", weap_white_stripped, 32); + Draw_ColoredString (x, y, weap_white_stripped, false); + } + } + x += 3 * FONTWIDTH * scale; + + break; + default: // draw image by default + if(!width_only) + if ( (pic = SCR_GetWeaponIconByFlag(BestWeaponFromStatItems( ti_cl->items ))) ) + Draw_SPic (x, y, pic, 0.5 * scale); + x += 2 * FONTWIDTH * scale; + + break; + } + + break; + case 'h': // draw health, padding with space on left side + case 'H': // draw health, padding with space on right side + + if(!width_only) { + snprintf(tmp, sizeof(tmp), (s[0] == 'h' ? "%s%3d" : "%s%-3d"), (ti_cl->health < HUD_FindVar(hud, "low_health")->ival ? "&cf00" : ""), (int)ti_cl->health); + Draw_SString (x, y, tmp, scale); + } + x += 3 * FONTWIDTH * scale; + + break; + case 'a': // draw armor, padded with space on left side + case 'A': // draw armor, padded with space on right side + + aclr = ""; + + // + // different styles of armor + // + switch (HUD_FindVar(hud,"armor_style")->ival) { + case 1: // image prefixed armor value + if(!width_only) { + if (ti_cl->items & IT_ARMOR3) + Draw_SPic (x, y, sb_armor[2], 1.0/3 * scale); + else if (ti_cl->items & IT_ARMOR2) + Draw_SPic (x, y, sb_armor[1], 1.0/3 * scale); + else if (ti_cl->items & IT_ARMOR1) + Draw_SPic (x, y, sb_armor[0], 1.0/3 * scale); + } + x += FONTWIDTH * scale; + + break; + case 2: // colored background of armor value + /* + if(!width_only) { + byte col[4] = {255, 255, 255, 0}; + + if (ti_cl->items & IT_ARMOR3) { + col[0] = 255; col[1] = 0; col[2] = 0; col[3] = 255; + } + else if (ti_cl->items & IT_ARMOR2) { + col[0] = 255; col[1] = 255; col[2] = 0; col[3] = 255; + } + else if (ti_cl->items & IT_ARMOR1) { + col[0] = 0; col[1] = 255; col[2] = 0; col[3] = 255; + } + } + */ + + break; + case 3: // colored armor value + if(!width_only) { + if (ti_cl->items & IT_ARMOR3) + aclr = "&cf00"; + else if (ti_cl->items & IT_ARMOR2) + aclr = "&cff0"; + else if (ti_cl->items & IT_ARMOR1) + aclr = "&c0f0"; + } + + break; + case 4: // armor value prefixed with letter + if(!width_only) { + if (ti_cl->items & IT_ARMOR3) + Draw_SString (x, y, "r", scale); + else if (ti_cl->items & IT_ARMOR2) + Draw_SString (x, y, "y", scale); + else if (ti_cl->items & IT_ARMOR1) + Draw_SString (x, y, "g", scale); + } + x += FONTWIDTH * scale; + + break; + } + + if(!width_only) { // value drawed no matter which style + snprintf(tmp, sizeof(tmp), (s[0] == 'a' ? "%s%3d" : "%s%-3d"), aclr, (int)ti_cl->armor); + Draw_SString (x, y, tmp, scale); + } + x += 3 * FONTWIDTH * scale; + + break; + case 'l': // draw location + + if(!width_only) { + loc = TP_LocationName(ti_cl->org); + if (!loc[0]) + loc = "unknown"; + + str_align_right(tmp, sizeof(tmp), TP_ParseFunChars(loc, false), maxloc); + Draw_SString (x, y, tmp, scale); + } + x += maxloc * FONTWIDTH * scale; + + break; + case 'p': // draw powerups + switch (HUD_FindVar(hud, "powerup_style")->ival) { + case 1: // quad/pent/ring image + if(!width_only) { + if (ti_cl->items & IT_QUAD) + Draw_SPic (x, y, sb_items[5], 1.0/2); + x += FONTWIDTH; + if (ti_cl->items & IT_INVULNERABILITY) + Draw_SPic (x, y, sb_items[3], 1.0/2); + x += FONTWIDTH; + if (ti_cl->items & IT_INVISIBILITY) + Draw_SPic (x, y, sb_items[2], 1.0/2); + x += FONTWIDTH; + } + else { x += 3* FONTWIDTH; } + break; + + case 2: // player powerup face + if(!width_only) { + if ( sb_face_quad && (ti_cl->items & IT_QUAD)) + Draw_SPic (x, y, sb_face_quad, 1.0/3); + x += FONTWIDTH; + if ( sb_face_invuln && (ti_cl->items & IT_INVULNERABILITY)) + Draw_SPic (x, y, sb_face_invuln, 1.0/3); + x += FONTWIDTH; + if ( sb_face_invis && (ti_cl->items & IT_INVISIBILITY)) + Draw_SPic (x, y, sb_face_invis, 1.0/3); + x += FONTWIDTH; + } + else { x += 3* FONTWIDTH; } + break; + + case 3: // colored font (QPR) + if(!width_only) { + if (ti_cl->items & IT_QUAD) + Draw_ColoredString (x, y, "&c03fQ", false); + x += FONTWIDTH; + if (ti_cl->items & IT_INVULNERABILITY) + Draw_ColoredString (x, y, "&cf00P", false); + x += FONTWIDTH; + if (ti_cl->items & IT_INVISIBILITY) + Draw_ColoredString (x, y, "&cff0R", false); + x += FONTWIDTH; + } + else { x += 3* FONTWIDTH; } + break; + } + break; + + case 't': + if(!width_only) + { + sprintf(tmp, "%i", Player_GetTrackId(cl.players[ti_cl->client].userid)); + Draw_SString (x, y, tmp, scale); + } + x += FONTWIDTH * scale; // will break if tracknumber is double digits + break; + + case '%': // wow, %% result in one %, how smart + + if(!width_only) + Draw_SString (x, y, "%", scale); + x += FONTWIDTH * scale; + + break; + + default: // print %x - that mean sequence unknown + + if(!width_only) { + snprintf(tmp, sizeof(tmp), "%%%c", s[0]); + Draw_SString (x, y, tmp, scale); + } + x += (s[0] ? 2 : 1) * FONTWIDTH * scale; + + break; + } + + break; + + default: // print x + if(!width_only) { + snprintf(tmp, sizeof(tmp), "%c", s[0]); + if (s[0] != ' ') // inhuman smart optimization, do not print space! + Draw_SString (x, y, tmp, scale); + } + x += FONTWIDTH * scale; + + break; + } + } + + return (x - x_in) / (FONTWIDTH * scale); // return width +} + +#ifdef HAXX +void SCR_HUD_DrawItemsClock(hud_t *hud) +{ + extern qbool hud_editor; + int width, height; + int x, y; + static cvar_t *hud_itemsclock_timelimit = NULL, *hud_itemsclock_style; + + if (hud_itemsclock_timelimit == NULL) { + hud_itemsclock_timelimit = HUD_FindVar(hud, "timelimit"); + hud_itemsclock_style = HUD_FindVar(hud, "style"); + } + + MVD_ClockList_TopItems_DimensionsGet(hud_itemsclock_timelimit->value, hud_itemsclock_style->ival, &width, &height); + + if (hud_editor) + HUD_PrepareDraw(hud, width, LETTERHEIGHT, &x, &y); + + if (!height) + return; + + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + + MVD_ClockList_TopItems_Draw(hud_itemsclock_timelimit->value, hud_itemsclock_style->ival, x, y); +} +#endif + +// +// TODO: decide what to do in freefly mode (and how to catch it?!), now all score_* hud elements just draws "0" +// +void SCR_HUD_DrawScoresTeam(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *digits, *align, *colorize; + int value = 0; + int i; + + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + colorize = HUD_FindVar(hud, "colorize"); + } + + // + // AAS: someone please tell me how to do it in a proper way! + // + if(cl.teamplay) + { + for(i = 0; i < n_teams; i++) + { + // playing qwd demo || mvd spec/demo || playing + if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) || + ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) || + (strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ) + { + value = sorted_teams[i].frags; + break; + } + } + } + else if(cl.deathmatch) + { + for(i = 0; i < n_players; i++) + { + if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) || + ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) || + (strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ) + { + value = cl.players[sorted_players[i].playernum].frags; + break; + } + } + } + + SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); +} + +void SCR_HUD_DrawScoresEnemy(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *digits, *align, *colorize; + int value = 0; + int i; + + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + colorize = HUD_FindVar(hud, "colorize"); + } + + // + // AAS: voodoo, again + // + if(cl.teamplay) + { + for(i = 0; i < n_teams; i++) + { + + if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) || + ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) || + (strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ) + { + if(n_teams > 1) + value = sorted_teams[i == 0 ? 1 : 0].frags; + break; + } + } + } + else if(cl.deathmatch) + { + for(i = 0; i < n_players; i++) + { + if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) || + ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) || + (strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ) + { + if(n_players > 1) + value = cl.players[sorted_players[i == 0 ? 1 : 0].playernum].frags; + break; + } + } + } + + SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); +} + +void SCR_HUD_DrawScoresDifference(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *digits, *align, *colorize; + int value = 0; + int i; + + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + colorize = HUD_FindVar(hud, "colorize"); + } + + // + // AAS: more voodoo + // + if(cl.teamplay) + { + for(i = 0; i < n_teams; i++) + { + if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) || + ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) || + (strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ) + { + if(i == 0) + { + if(n_teams > 1) + value = sorted_teams[0].frags - sorted_teams[1].frags; + else + value = sorted_teams[0].frags; + } + else + { + if(n_teams > 1) + value = sorted_teams[i].frags - sorted_teams[0].frags; + } + break; + } + } + } + else if(cl.deathmatch) + { + for(i = 0; i < n_players; i++) + { + if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) || + ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) || + (strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ) + { + if(i == 0) + { + if(n_players > 1) + value = cl.players[sorted_players[0].playernum].frags - cl.players[sorted_players[1].playernum].frags; + else + value = cl.players[sorted_players[0].playernum].frags; + } + else + { + if(n_players > 1) + value = cl.players[sorted_players[i].playernum].frags - cl.players[sorted_players[0].playernum].frags; + } + break; + } + } + } + + SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); +} + +void SCR_HUD_DrawScoresPosition(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *digits, *align, *colorize; + int value = 0; + int i; + + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); + colorize = HUD_FindVar(hud, "colorize"); + } + + // + // AAS: someone, please stop me + // + if(cl.teamplay) + { + for(i = 0; i < n_teams; i++) + { + if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) || + ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) || + (strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ) + { + value = i; + break; + } + } + } + else if(cl.deathmatch) + { + for(i = 0; i < n_players; i++) + { + if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) || + ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) || + (strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ) + { + value = i; + break; + } + } + } + + SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); +} + +/* + ezQuake's analogue of +scores of KTX + ( t:x e:x [x] ) +*/ +void SCR_HUD_DrawScoresBar(hud_t *hud) +{ + static cvar_t *scale = NULL, *style, *format_big, *format_small; + int width = 0, height = 0, x, y; + int i = 0; + + int s_team = 0, s_enemy = 0, s_difference = 0; + char *n_team = "T", *n_enemy = "E"; + + char buf[256]; + char c, *out, *temp, *in; + + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + format_big = HUD_FindVar(hud, "format_big"); + format_small= HUD_FindVar(hud, "format_small"); + } + + // + // AAS: nightmare comes back + // + if(cl.teamplay) + { + for(i = 0; i < n_teams; i++) + { + if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) || + ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) || + (strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ) + { + s_team = sorted_teams[i].frags; + n_team = sorted_teams[i].name; + if(n_teams > 1) + { + s_enemy = sorted_teams[i == 0 ? 1 : 0].frags; + n_enemy = sorted_teams[i == 0 ? 1 : 0].name; + } + s_difference = s_team - s_enemy; + break; + } + } + } + else if(cl.deathmatch) + { + for(i = 0; i < n_players; i++) + { + if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) || + ((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) || + (strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ) + { + s_team = cl.players[sorted_players[i].playernum].frags; + if(n_players > 1) + { + s_enemy = cl.players[sorted_players[i == 0 ? 1 : 0].playernum].frags; + } + s_difference = s_team - s_enemy; + break; + } + } + } + + + // two pots of delicious customized copypasta from math_tools.c + switch(style->ival) + { + // Big + case 1: + in = TP_ParseFunChars(format_big->string, false); + buf[0] = 0; + out = buf; + + while((c = *in++) && (out - buf < sizeof(buf) - 1)) + { + if((c == '%') && *in) + { + switch((c = *in++)) + { + // c = colorize, r = reset + case 'd': + temp = va("%d", s_difference); + width += (s_difference >= 0) ? strlen(temp) * 24 : ((strlen(temp) - 1) * 24) + 16; + break; + case 'D': + temp = va("c%dr", s_difference); + width += (s_difference >= 0) ? (strlen(temp) - 2) * 24 : ((strlen(temp) - 3) * 24) + 16; + break; + case 'e': + temp = va("%d", s_enemy); + width += (s_enemy >= 0) ? strlen(temp) * 24 : ((strlen(temp) - 1) * 24) + 16; + break; + case 'E': + temp = va("c%dr", s_enemy); + width += (s_enemy >= 0) ? (strlen(temp) - 2) * 24 : ((strlen(temp) - 3) * 24) + 16; + break; + case 'p': + temp = va("%d", i + 1); + width += 24; + break; + case 't': + temp = va("%d", s_team); + width += (s_team >= 0) ? strlen(temp) * 24 : ((strlen(temp) - 1) * 24) + 16; + break; + case 'T': + temp = va("c%dr", s_team); + width += (s_team >= 0) ? (strlen(temp) - 2) * 24 : ((strlen(temp) - 3) * 24) + 16; + break; + case 'z': + if(s_difference >= 0) + { + temp = va("%d", s_difference); + width += strlen(temp) * 24; + } + else + { + temp = va("c%dr", -(s_difference)); + width += (strlen(temp) - 2) * 24; + } + break; + case 'Z': + if(s_difference >= 0) + { + temp = va("c%dr", s_difference); + width += (strlen(temp) - 2) * 24; + } + else + { + temp = va("%d", -(s_difference)); + width += strlen(temp) * 24; + } + break; + default: + temp = NULL; + break; + } + + if(temp != NULL) + { + strlcpy(out, temp, sizeof(buf) - (out - buf)); + out += strlen(temp); + } + } + else if (c == ':' || c == '/' || c == '-' || c == ' ') + { + width += 16; + *out++ = c; + } + } + *out = 0; + break; + + // Small + case 0: + default: + in = TP_ParseFunChars(format_small->string, false); + buf[0] = 0; + out = buf; + + while((c = *in++) && (out - buf < sizeof(buf) - 1)) + { + if((c == '%') && *in) + { + switch((c = *in++)) + { + case '%': + temp = "%"; + break; + case 't': + temp = va("%d", s_team); + break; + case 'e': + temp = va("%d", s_enemy); + break; + case 'd': + temp = va("%d", s_difference); + break; + case 'p': + temp = va("%d", i + 1); + break; + case 'T': + temp = n_team; + break; + case 'E': + temp = n_enemy; + break; + case 'D': + temp = va("%+d", s_difference); + break; + default: + temp = va("%%%c", c); + break; + } + strlcpy(out, temp, sizeof(buf) - (out - buf)); + out += strlen(temp); + } + else + { + *out++ = c; + } + } + *out = 0; + break; + } + + switch(style->ival) + { + // Big + case 1: + width *= scale->value; + height = 24 * scale->value; + + if(HUD_PrepareDraw(hud, width, height, &x, &y)) + { + SCR_DrawWadString(x, y, scale->value, buf); + } + break; + + // Small + case 0: + default: + width = 8 * strlen_color(buf) * scale->value; + height = 8 * scale->value; + + if(HUD_PrepareDraw(hud, width, height, &x, &y)) + { + Draw_SString(x, y, buf, scale->value); + } + break; + } +} + +void SCR_HUD_DrawBarArmor(hud_t *hud) +{ + static cvar_t *width = NULL, *height, *direction, *color_noarmor, *color_ga, *color_ya, *color_ra, *color_unnatural; + int x, y; + int armor = HUD_Stats(STAT_ARMOR); + qbool alive = cl.stats[STAT_HEALTH] > 0; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + direction = HUD_FindVar(hud, "direction"); + color_noarmor = HUD_FindVar(hud, "color_noarmor"); + color_ga = HUD_FindVar(hud, "color_ga"); + color_ya = HUD_FindVar(hud, "color_ya"); + color_ra = HUD_FindVar(hud, "color_ra"); + color_unnatural = HUD_FindVar(hud, "color_unnatural"); + } + + if(HUD_PrepareDraw(hud, width->ival, height->ival, &x, &y)) + { + if(!width->ival || !height->ival) + return; + + if(HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY && alive) + { + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_unnatural->vec4, x, y, width->ival, height->ival); + } + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3 && alive) + { + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); + SCR_HUD_DrawBar(direction->ival, armor, 200.0, color_ra->vec4, x, y, width->ival, height->ival); + } + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR2 && alive) + { + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); + SCR_HUD_DrawBar(direction->ival, armor, 150.0, color_ya->vec4, x, y, width->ival, height->ival); + } + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1 && alive) + { + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); + SCR_HUD_DrawBar(direction->ival, armor, 100.0, color_ga->vec4, x, y, width->ival, height->ival); + } + else + { + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); + } + } +} + +void SCR_HUD_DrawBarHealth(hud_t *hud) +{ + static cvar_t *width = NULL, *height, *direction, *color_nohealth, *color_normal, *color_mega, *color_twomega, *color_unnatural; + int x, y; + int health = cl.stats[STAT_HEALTH]; + + if (width == NULL) // first time called + { + width = HUD_FindVar(hud, "width"); + height = HUD_FindVar(hud, "height"); + direction = HUD_FindVar(hud, "direction"); + color_nohealth = HUD_FindVar(hud, "color_nohealth"); + color_normal = HUD_FindVar(hud, "color_normal"); + color_mega = HUD_FindVar(hud, "color_mega"); + color_twomega = HUD_FindVar(hud, "color_twomega"); + color_unnatural = HUD_FindVar(hud, "color_unnatural"); + } + + if(HUD_PrepareDraw(hud, width->ival, height->ival, &x, &y)) + { + if(!width->ival || !height->ival) + return; + + if(health > 250) + { + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_unnatural->vec4, x, y, width->ival, height->ival); + } + else if(health > 200) + { + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_normal->vec4, x, y, width->ival, height->ival); + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_mega->vec4, x, y, width->ival, height->ival); + SCR_HUD_DrawBar(direction->ival, health - 200, 100.0, color_twomega->vec4, x, y, width->ival, height->ival); + } + else if(health > 100) + { + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_normal->vec4, x, y, width->ival, height->ival); + SCR_HUD_DrawBar(direction->ival, health - 100, 100.0, color_mega->vec4, x, y, width->ival, height->ival); + } + else if(health > 0) + { + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_nohealth->vec4, x, y, width->ival, height->ival); + SCR_HUD_DrawBar(direction->ival, health, 100.0, color_normal->vec4, x, y, width->ival, height->ival); + } + else + { + SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_nohealth->vec4, x, y, width->ival, height->ival); + } + } +} + +void SCR_HUD_DrawOwnFrags(hud_t *hud) +{ + // not implemented yet: scale, color + // fixme: add appropriate opengl functions that will add alpha, scale and color + char ownfragtext[256]; + float age; + int width; + int height = 8; + int x, y; + double alpha; + static cvar_t + *hud_ownfrags_timeout = NULL, + *hud_ownfrags_scale = NULL; +// *hud_ownfrags_color = NULL; + extern qbool hud_editor; + + if (hud_ownfrags_timeout == NULL) // first time + { + hud_ownfrags_scale = HUD_FindVar(hud, "scale"); + // hud_ownfrags_color = HUD_FindVar(hud, "color"); + hud_ownfrags_timeout = HUD_FindVar(hud, "timeout"); + } + + if (hud_editor) + { + strcpy(ownfragtext, "Own Frags"); + age = 0; + } + else if (BUILTINISVALID(GetTrackerOwnFrags)) + age = pGetTrackerOwnFrags(0, ownfragtext, sizeof(ownfragtext)); + else + { + strcpy(ownfragtext, "Engine does not support OwnFrags"); + age = 0; + } + width = strlen(ownfragtext)*8; + + width *= hud_ownfrags_scale->value; + height *= hud_ownfrags_scale->value; + + if (age >= hud_ownfrags_timeout->value) + width = 0; + + alpha = 2 - age / hud_ownfrags_timeout->value * 2; + alpha = bound(0, alpha, 1); + + if (!width) + { + HUD_PrepareDraw(hud, width, height, NULL, NULL); + return; + } + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + + pDraw_Colour4f(1, 1, 1, alpha); + Draw_SString(x, y, ownfragtext, hud_ownfrags_scale->value); + pDraw_Colour4f(1, 1, 1, 1); +} + +static struct wstats_s *findweapon(struct wstats_s *w, size_t wc, char *wn) +{ + for (; wc>0; wc--, w++) + { + if (!strcmp(wn, w->wname)) + return w; + } + return NULL; +} +static void SCR_HUD_DrawWeaponStats(hud_t *hud) +{ + char line[1024], *o, *i; + int width; + int height = 8; + int x, y; + static cvar_t *hud_weaponstats_scale = NULL; + static cvar_t *hud_weaponstats_fmt = NULL; + extern qbool hud_editor; + + int ws; + struct wstats_s wstats[16]; + if (BUILTINISVALID(GetWeaponStats)) + ws = pGetWeaponStats(-1, wstats, countof(wstats)); + else + ws = 0; + + if (hud_editor) + { + ws = 0; + strcpy(wstats[ws].wname, "axe"); + wstats[ws].hit = 20; + wstats[ws].total = 100; + ws++; + strcpy(wstats[ws].wname, "rl"); + wstats[ws].hit = 60; + wstats[ws].total = 120; + ws++; + strcpy(wstats[ws].wname, "lg"); + wstats[ws].hit = 20; + wstats[ws].total = 100; + ws++; + } + + if (hud_weaponstats_scale == NULL) // first time + { + hud_weaponstats_scale = HUD_FindVar(hud, "scale"); + hud_weaponstats_fmt = HUD_FindVar(hud, "fmt"); +// "&c990sg&r:[%sg] &c099ssg&r:[%ssg] &c900rl&r:[#rl] &c009lg&r:[%lg]" + } + + height = 8; + for (o = line, i = hud_weaponstats_fmt->string; ws && *i && o < line+countof(line)-1; ) + { + if (i[0] == '[' && (i[1] == '%' || i[1] == '#')) + { + struct wstats_s *w; + char wname[16]; + int pct = i[1]=='%', j; + i+=2; + for (j = 0; *i && j < countof(wname)-1; j++) + { + if (*i == ']') + { + i++; + break; + } + wname[j] = *i++; + } + wname[j] = 0; + w = findweapon(wstats, ws, wname); + if (pct && w && w->total) + snprintf(wname, sizeof(wname), "%.1f", (100.0 * w->hit) / w->total); + else if (pct) + snprintf(wname, sizeof(wname), "%.1f", 0.0); + else if (w) + snprintf(wname, sizeof(wname), "%u", w->hit); + else + snprintf(wname, sizeof(wname), "%u", 0); + + for (j = 0; wname[j] && o < line+countof(line)-1; j++) + *o++ = wname[j]; + } + else if (*i == '\n') + { + height += 8; + *o++ = *i++; + } + else + *o++ = *i++; + } + *o++ = 0; + + width = 8*strlen_color(line); + + width *= hud_weaponstats_scale->value; + height *= hud_weaponstats_scale->value; + + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + + Draw_SString(x, y, line, hud_weaponstats_scale->value); +} + +void SCR_HUD_DrawKeys(hud_t *hud) +{ + char line1[32], line2[32]; + int width, height, x, y; + usercmd_t b; + static cvar_t* vscale = NULL; + float scale; + + memset(&b, 0, sizeof(b)); + if (BUILTINISVALID(GetLastInputFrame)) + pGetLastInputFrame(0, &b); + + if (!vscale) { + vscale = HUD_FindVar(hud, "scale"); + } + + scale = vscale->value; + scale = max(0, scale); + + snprintf(line1, sizeof(line1), "^{%x}^{%x}^{%x}", + 0xe000 + 'x' + ((b.buttons & 1)?0x80:0), + 0xe000 + '^' + ((b.forwardmove > 0)?0x80:0), + 0xe000 + 'J' + ((b.buttons & 2)?0x80:0)); + snprintf(line2, sizeof(line2), "^{%x}^{%x}^{%x}", + 0xe000 + '<' + ((b.sidemove < 0)?0x80:0), + 0xe000 + '_' + ((b.forwardmove < 0)?0x80:0), + 0xe000 + '>' + ((b.sidemove > 0)?0x80:0)); + + width = 8 * 3 * scale; + height = 8 * 2 * scale; + + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + + Draw_SString(x, y, line1, scale); + Draw_SString(x, y + 8*scale, line2, scale); +} + +#ifdef WITH_PNG +// What stats to draw. +#define HUD_RADAR_STATS_NONE 0 +#define HUD_RADAR_STATS_BOTH_TEAMS_HOLD 1 +#define HUD_RADAR_STATS_TEAM1_HOLD 2 +#define HUD_RADAR_STATS_TEAM2_HOLD 3 +#define HUD_RADAR_STATS_BOTH_TEAMS_DEATHS 4 +#define HUD_RADAR_STATS_TEAM1_DEATHS 5 +#define HUD_RADAR_STATS_TEAM2_DEATHS 6 + +void Radar_DrawGrid(stats_weight_grid_t *grid, int x, int y, float scale, int pic_width, int pic_height, int style) +{ + int row, col; + + // Don't try to draw anything if we got no data. + if(grid == NULL || grid->cells == NULL || style == HUD_RADAR_STATS_NONE) + { + return; + } + + // Go through all the cells and draw them based on their weight. + for(row = 0; row < grid->row_count; row++) + { + // Just to be safe if something went wrong with the allocation. + if(grid->cells[row] == NULL) + { + continue; + } + + for(col = 0; col < grid->col_count; col++) + { + float weight = 0.0; + int color = 0; + + float tl_x, tl_y; // The pixel coordinate of the top left corner of a grid cell. + float p_cell_length_x; // The pixel length of a cell. + float p_cell_length_y; // The pixel "length" on the Y-axis. We calculate this + // seperatly because we'll get errors when converting from + // quake coordinates -> pixel coordinates. + + // Calculate the pixel coordinates of the top left corner of the current cell. + // (This is times 8 because the conversion formula was calculated from a .loc-file) + tl_x = (map_x_slope * (8.0 * grid->cells[row][col].tl_x) + map_x_intercept) * scale; + tl_y = (map_y_slope * (8.0 * grid->cells[row][col].tl_y) + map_y_intercept) * scale; + + // Calculate the cell length in pixel length. + p_cell_length_x = map_x_slope*(8.0 * grid->cell_length) * scale; + p_cell_length_y = map_y_slope*(8.0 * grid->cell_length) * scale; + + // Add rounding errors (so that we don't get weird gaps in the grid). + p_cell_length_x += tl_x - Q_rint(tl_x); + p_cell_length_y += tl_y - Q_rint(tl_y); + + // Don't draw the stats stuff outside the picture. + if(tl_x + p_cell_length_x > pic_width || tl_y + p_cell_length_y > pic_height || x + tl_x < x || y + tl_y < y) + { + continue; + } + + // + // Death stats. + // + if(grid->cells[row][col].teams[STATS_TEAM1].death_weight + grid->cells[row][col].teams[STATS_TEAM2].death_weight > 0) + { + weight = 0; + + if(style == HUD_RADAR_STATS_BOTH_TEAMS_DEATHS || style == HUD_RADAR_STATS_TEAM1_DEATHS) + { + weight = grid->cells[row][col].teams[STATS_TEAM1].death_weight; + } + + if(style == HUD_RADAR_STATS_BOTH_TEAMS_DEATHS || style == HUD_RADAR_STATS_TEAM2_DEATHS) + { + weight += grid->cells[row][col].teams[STATS_TEAM2].death_weight; + } + + color = 79; + } + + // + // Team stats. + // + { + // No point in drawing if we have no weight. + if(grid->cells[row][col].teams[STATS_TEAM1].weight + grid->cells[row][col].teams[STATS_TEAM2].weight <= 0 + && (style == HUD_RADAR_STATS_BOTH_TEAMS_HOLD + || style == HUD_RADAR_STATS_TEAM1_HOLD + || style == HUD_RADAR_STATS_TEAM2_HOLD)) + { + continue; + } + + // Get the team with the highest weight for this cell. + if(grid->cells[row][col].teams[STATS_TEAM1].weight > grid->cells[row][col].teams[STATS_TEAM2].weight + && (style == HUD_RADAR_STATS_BOTH_TEAMS_HOLD + || style == HUD_RADAR_STATS_TEAM1_HOLD)) + { + weight = grid->cells[row][col].teams[STATS_TEAM1].weight; + color = stats_grid->teams[STATS_TEAM1].color; + } + else if(style == HUD_RADAR_STATS_BOTH_TEAMS_HOLD || style == HUD_RADAR_STATS_TEAM2_HOLD) + { + weight = grid->cells[row][col].teams[STATS_TEAM2].weight; + color = stats_grid->teams[STATS_TEAM2].color; + } + } + + // Draw the cell in the color of the team with the + // biggest weight for this cell. Or draw deaths. + Draw_AlphaFill( + x + Q_rint(tl_x), // X. + y + Q_rint(tl_y), // Y. + Q_rint(p_cell_length_x), // Width. + Q_rint(p_cell_length_y), // Height. + color, // Color. + weight); // Alpha. + } + } +} + +// The skinnum property in the entity_s structure is used +// for determening what type of armor to draw on the radar. +#define HUD_RADAR_GA 0 +#define HUD_RADAR_YA 1 +#define HUD_RADAR_RA 2 + +// Radar filters. +#define RADAR_SHOW_WEAPONS (radar_show_ssg || radar_show_ng || radar_show_sng || radar_show_gl || radar_show_rl || radar_show_lg) +static qbool radar_show_ssg = false; +static qbool radar_show_ng = false; +static qbool radar_show_sng = false; +static qbool radar_show_gl = false; +static qbool radar_show_rl = false; +static qbool radar_show_lg = false; + +#define RADAR_SHOW_ITEMS (radar_show_backpacks || radar_show_health || radar_show_ra || radar_show_ya || radar_show_ga || radar_show_rockets || radar_show_nails || radar_show_cells || radar_show_shells || radar_show_quad || radar_show_pent || radar_show_ring || radar_show_suit) +static qbool radar_show_backpacks = false; +static qbool radar_show_health = false; +static qbool radar_show_ra = false; +static qbool radar_show_ya = false; +static qbool radar_show_ga = false; +static qbool radar_show_rockets = false; +static qbool radar_show_nails = false; +static qbool radar_show_cells = false; +static qbool radar_show_shells = false; +static qbool radar_show_quad = false; +static qbool radar_show_pent = false; +static qbool radar_show_ring = false; +static qbool radar_show_suit = false; +static qbool radar_show_mega = false; + +#define RADAR_SHOW_OTHER (radar_show_gibs || radar_show_explosions || radar_show_nails_p || radar_show_rockets_p || radar_show_shaft_p || radar_show_teleport || radar_show_shotgun) +static qbool radar_show_nails_p = false; +static qbool radar_show_rockets_p = false; +static qbool radar_show_shaft_p = false; +static qbool radar_show_gibs = false; +static qbool radar_show_explosions = false; +static qbool radar_show_teleport = false; +static qbool radar_show_shotgun = false; + +void Radar_OnChangeWeaponFilter(cvar_t *var, char *oldval) +{ + // Parse the weapon filter. + radar_show_ssg = Utils_RegExpMatch("SSG|SUPERSHOTGUN|ALL", var->string); + radar_show_ng = Utils_RegExpMatch("([^S]|^)NG|NAILGUN|ALL", var->string); // Yes very ugly, but we don't want to match SNG. + radar_show_sng = Utils_RegExpMatch("SNG|SUPERNAILGUN|ALL", var->string); + radar_show_rl = Utils_RegExpMatch("RL|ROCKETLAUNCHER|ALL", var->string); + radar_show_gl = Utils_RegExpMatch("GL|GRENADELAUNCHER|ALL", var->string); + radar_show_lg = Utils_RegExpMatch("LG|SHAFT|LIGHTNING|ALL", var->string); +} + +void Radar_OnChangeItemFilter(cvar_t *var, char *oldval) +{ + // Parse the item filter. + radar_show_backpacks = Utils_RegExpMatch("BP|BACKPACK|ALL", var->string); + radar_show_health = Utils_RegExpMatch("HP|HEALTH|ALL", var->string); + radar_show_ra = Utils_RegExpMatch("RA|REDARMOR|ARMOR|ALL", var->string); + radar_show_ya = Utils_RegExpMatch("YA|YELLOWARMOR|ARMOR|ALL", var->string); + radar_show_ga = Utils_RegExpMatch("GA|GREENARMOR|ARMOR|ALL", var->string); + radar_show_rockets = Utils_RegExpMatch("ROCKETS|ROCKS|AMMO|ALL", var->string); + radar_show_nails = Utils_RegExpMatch("NAILS|SPIKES|AMMO|ALL", var->string); + radar_show_cells = Utils_RegExpMatch("CELLS|BATTERY|AMMO|ALL", var->string); + radar_show_shells = Utils_RegExpMatch("SHELLS|AMMO|ALL", var->string); + radar_show_quad = Utils_RegExpMatch("QUAD|POWERUPS|ALL", var->string); + radar_show_pent = Utils_RegExpMatch("PENT|PENTAGRAM|666|POWERUPS|ALL", var->string); + radar_show_ring = Utils_RegExpMatch("RING|INVISIBLE|EYES|POWERUPS|ALL", var->string); + radar_show_suit = Utils_RegExpMatch("SUIT|POWERUPS|ALL", var->string); + radar_show_mega = Utils_RegExpMatch("MH|MEGA|MEGAHEALTH|100\\+|ALL", var->string); +} + +void Radar_OnChangeOtherFilter(cvar_t *var, char *oldval) +{ + // Parse the "other" filter. + radar_show_nails_p = Utils_RegExpMatch("NAILS|PROJECTILES|ALL", var->string); + radar_show_rockets_p = Utils_RegExpMatch("ROCKETS|PROJECTILES|ALL", var->string); + radar_show_shaft_p = Utils_RegExpMatch("SHAFT|PROJECTILES|ALL", var->string); + radar_show_gibs = Utils_RegExpMatch("GIBS|ALL", var->string); + radar_show_explosions = Utils_RegExpMatch("EXPLOSIONS|ALL", var->string); + radar_show_teleport = Utils_RegExpMatch("TELE|ALL", var->string); + radar_show_shotgun = Utils_RegExpMatch("SHOTGUN|SG|BUCK|ALL", var->string); +} + + +#define HUD_COLOR_DEFAULT_TRANSPARENCY 75 + +byte hud_radar_highlight_color[4] = {255, 255, 0, HUD_COLOR_DEFAULT_TRANSPARENCY}; + +void Radar_OnChangeHighlightColor(cvar_t *var, char *newval, qbool *cancel) +{ + char *new_color; + char buf[MAX_COM_TOKEN]; + + // Translate a colors name to RGB values. + new_color = ColorNameToRGBString(newval); + + // Parse the colors. + //color = StringToRGB(new_color); + strlcpy(buf,new_color,sizeof(buf)); + memcpy(hud_radar_highlight_color, StringToRGB(buf), sizeof(byte) * 4); + + // Set the cvar to contain the new color string + // (if the user entered "red" it will be "255 0 0"). + Cvar_Set(var, new_color); +} + +void Radar_DrawEntities(int x, int y, float scale, float player_size, int show_hold_areas) +{ + int i; + + // Entities (weapons and such). cl_main.c + extern visentlist_t cl_visents; + + // Go through all the entities and draw the ones we're supposed to. + for (i = 0; i < cl_visents.count; i++) + { + int entity_q_x = 0; + int entity_q_y = 0; + int entity_p_x = 0; + int entity_p_y = 0; + + // Get quake coordinates (times 8 to get them in the same format as .locs). + entity_q_x = cl_visents.list[i].origin[0]*8; + entity_q_y = cl_visents.list[i].origin[1]*8; + + // Convert from quake coordiantes -> pixel coordinates. + entity_p_x = x + Q_rint((map_x_slope*entity_q_x + map_x_intercept) * scale); + entity_p_y = y + Q_rint((map_y_slope*entity_q_y + map_y_intercept) * scale); + + // TODO: Replace all model name comparison below with MOD_HINT's instead for less comparisons (create new ones in Mod_LoadAliasModel() in r_model.c and gl_model.c/.h for the ones that don't have one already). + + // + // Powerups. + // + + if(radar_show_pent && !strcmp(cl_visents.list[i].model->name, "progs/invulner.mdl")) + { + // Pentagram. + Draw_ColoredString(entity_p_x, entity_p_y, "&cf00P", 0); + } + else if(radar_show_quad && !strcmp(cl_visents.list[i].model->name, "progs/quaddama.mdl")) + { + // Quad. + Draw_ColoredString(entity_p_x, entity_p_y, "&c0ffQ", 0); + } + else if(radar_show_ring && !strcmp(cl_visents.list[i].model->name, "progs/invisibl.mdl")) + { + // Ring. + Draw_ColoredString(entity_p_x, entity_p_y, "&cff0R", 0); + } + else if(radar_show_suit && !strcmp(cl_visents.list[i].model->name, "progs/suit.mdl")) + { + // Suit. + Draw_ColoredString(entity_p_x, entity_p_y, "&c0f0S", 0); + } + + // + // Show RL, LG and backpacks. + // + if(radar_show_rl && !strcmp(cl_visents.list[i].model->name, "progs/g_rock2.mdl")) + { + // RL. + Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "RL"); + } + else if(radar_show_lg && !strcmp(cl_visents.list[i].model->name, "progs/g_light.mdl")) + { + // LG. + Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "LG"); + } + else if(radar_show_backpacks && cl_visents.list[i].model->modhint == MOD_BACKPACK) + { + // Back packs. + float back_pack_size = 0; + + back_pack_size = max(player_size * 0.5, 0.05); + + Draw_AlphaCircleFill (entity_p_x, entity_p_y, back_pack_size, 114, 1); + Draw_AlphaCircleOutline (entity_p_x, entity_p_y, back_pack_size, 1.0, 0, 1); + } + + if(!strcmp(cl_visents.list[i].model->name, "progs/armor.mdl")) + { + // + // Show armors. + // + + if(radar_show_ga && cl_visents.list[i].skinnum == HUD_RADAR_GA) + { + // GA. + Draw_AlphaCircleFill (entity_p_x, entity_p_y, 3.0, 178, 1.0); + } + else if(radar_show_ya && cl_visents.list[i].skinnum == HUD_RADAR_YA) + { + // YA. + Draw_AlphaCircleFill (entity_p_x, entity_p_y, 3.0, 192, 1.0); + } + else if(radar_show_ra && cl_visents.list[i].skinnum == HUD_RADAR_RA) + { + // RA. + Draw_AlphaCircleFill (entity_p_x, entity_p_y, 3.0, 251, 1.0); + } + + Draw_AlphaCircleOutline (entity_p_x, entity_p_y, 3.0, 1.0, 0, 1.0); + } + + if(radar_show_mega && !strcmp(cl_visents.list[i].model->name, "maps/b_bh100.bsp")) + { + // + // Show megahealth. + // + + // Draw a red border around the cross. + Draw_AlphaRectangleRGB(entity_p_x - 3, entity_p_y - 3, 8, 8, 1, false, RGBA_TO_COLOR(200, 0, 0, 200)); + + // Draw a black outline cross. + Draw_AlphaFill(entity_p_x - 3, entity_p_y - 1, 8, 4, 0, 1); + Draw_AlphaFill(entity_p_x - 1, entity_p_y - 3, 4, 8, 0, 1); + + // Draw a 2 pixel cross. + Draw_AlphaFill(entity_p_x - 2, entity_p_y, 6, 2, 79, 1); + Draw_AlphaFill(entity_p_x, entity_p_y - 2, 2, 6, 79, 1); + } + + if(radar_show_ssg && !strcmp(cl_visents.list[i].model->name, "progs/g_shot.mdl")) + { + // SSG. + Draw_String(entity_p_x - (3*8)/2, entity_p_y - 4, "SSG"); + } + else if(radar_show_ng && !strcmp(cl_visents.list[i].model->name, "progs/g_nail.mdl")) + { + // NG. + Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "NG"); + } + else if(radar_show_sng && !strcmp(cl_visents.list[i].model->name, "progs/g_nail2.mdl")) + { + // SNG. + Draw_String(entity_p_x - (3*8)/2, entity_p_y - 4, "SNG"); + } + else if(radar_show_gl && !strcmp(cl_visents.list[i].model->name, "progs/g_rock.mdl")) + { + // GL. + Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "GL"); + } + + if(radar_show_gibs + &&(!strcmp(cl_visents.list[i].model->name, "progs/gib1.mdl") + || !strcmp(cl_visents.list[i].model->name, "progs/gib2.mdl") + || !strcmp(cl_visents.list[i].model->name, "progs/gib3.mdl"))) + { + // + // Gibs. + // + + Draw_AlphaCircleFill(entity_p_x, entity_p_y, 2.0, 251, 1); + } + + if(radar_show_health + &&(!strcmp(cl_visents.list[i].model->name, "maps/b_bh25.bsp") + || !strcmp(cl_visents.list[i].model->name, "maps/b_bh10.bsp"))) + { + // + // Health. + // + + // Draw a black outline cross. + Draw_AlphaFill (entity_p_x - 3, entity_p_y - 1, 7, 3, 0, 1); + Draw_AlphaFill (entity_p_x - 1, entity_p_y - 3, 3, 7, 0, 1); + + // Draw a cross. + Draw_AlphaFill (entity_p_x - 2, entity_p_y, 5, 1, 79, 1); + Draw_AlphaFill (entity_p_x, entity_p_y - 2, 1, 5, 79, 1); + } + + // + // Ammo. + // + if(radar_show_rockets + &&(!strcmp(cl_visents.list[i].model->name, "maps/b_rock0.bsp") + || !strcmp(cl_visents.list[i].model->name, "maps/b_rock1.bsp"))) + { + // + // Rockets. + // + + // Draw a black outline. + Draw_AlphaFill (entity_p_x - 1, entity_p_y - 6, 3, 5, 0, 1); + Draw_AlphaFill (entity_p_x - 2, entity_p_y - 1, 5, 5, 0, 1); + + // The brown rocket. + Draw_AlphaFill (entity_p_x, entity_p_y - 5, 1, 5, 120, 1); + Draw_AlphaFill (entity_p_x - 1, entity_p_y, 1, 3, 120, 1); + Draw_AlphaFill (entity_p_x + 1, entity_p_y, 1, 3, 120, 1); + } + + if(radar_show_cells + &&(!strcmp(cl_visents.list[i].model->name, "maps/b_batt0.bsp") + || !strcmp(cl_visents.list[i].model->name, "maps/b_batt1.bsp"))) + { + // + // Cells. + // + + // Draw a black outline. + Draw_AlphaLine(entity_p_x - 3, entity_p_y, entity_p_x + 4, entity_p_y - 5, 3, 0, 1); + Draw_AlphaLine(entity_p_x - 3, entity_p_y, entity_p_x + 3 , entity_p_y, 3, 0, 1); + Draw_AlphaLine(entity_p_x + 3, entity_p_y, entity_p_x - 3, entity_p_y + 4, 3, 0, 1); + + // Draw a yellow lightning! + Draw_AlphaLine(entity_p_x - 2, entity_p_y, entity_p_x + 3, entity_p_y - 4, 1, 111, 1); + Draw_AlphaLine(entity_p_x - 2, entity_p_y, entity_p_x + 2 , entity_p_y, 1, 111, 1); + Draw_AlphaLine(entity_p_x + 2, entity_p_y, entity_p_x - 2, entity_p_y + 3, 1, 111, 1); + } + + if(radar_show_nails + &&(!strcmp(cl_visents.list[i].model->name, "maps/b_nail0.bsp") + || !strcmp(cl_visents.list[i].model->name, "maps/b_nail1.bsp"))) + { + // + // Nails. + // + + // Draw a black outline. + Draw_AlphaFill (entity_p_x - 3, entity_p_y - 3, 7, 3, 0, 1); + Draw_AlphaFill (entity_p_x - 2, entity_p_y - 2, 5, 3, 0, 0.5); + Draw_AlphaFill (entity_p_x - 1, entity_p_y, 3, 3, 0, 1); + Draw_AlphaFill (entity_p_x - 1, entity_p_y + 3, 1, 1, 0, 0.5); + Draw_AlphaFill (entity_p_x + 1, entity_p_y + 3, 1, 1, 0, 0.5); + Draw_AlphaFill (entity_p_x, entity_p_y + 4, 1, 1, 0, 1); + + Draw_AlphaFill (entity_p_x - 2, entity_p_y - 2, 5, 1, 6, 1); + Draw_AlphaFill (entity_p_x - 1, entity_p_y - 1, 3, 1, 6, 0.5); + Draw_AlphaFill (entity_p_x, entity_p_y, 1, 4, 6, 1); + } + + if(radar_show_shells + &&(!strcmp(cl_visents.list[i].model->name, "maps/b_shell0.bsp") + || !strcmp(cl_visents.list[i].model->name, "maps/b_shell1.bsp"))) + { + // + // Shells. + // + + // Draw a black outline. + Draw_AlphaFill (entity_p_x - 2, entity_p_y - 3, 5, 9, 0, 1); + + // Draw 2 shotgun shells. + Draw_AlphaFill (entity_p_x - 1, entity_p_y - 2, 1, 4, 73, 1); + Draw_AlphaFill (entity_p_x - 1, entity_p_y - 2 + 5, 1, 2, 104, 1); + + Draw_AlphaFill (entity_p_x + 1, entity_p_y - 2, 1, 4, 73, 1); + Draw_AlphaFill (entity_p_x + 1, entity_p_y - 2 + 5, 1, 2, 104, 1); + } + + // + // Show projectiles (rockets, grenades, nails, shaft). + // + + if(radar_show_nails_p + && (!strcmp(cl_visents.list[i].model->name, "progs/s_spike.mdl") + || !strcmp(cl_visents.list[i].model->name, "progs/spike.mdl"))) + { + // + // Spikes from SNG and NG. + // + + Draw_AlphaFill(entity_p_x, entity_p_y, 1, 1, 254, 1); + } + else if(radar_show_rockets_p + && (!strcmp(cl_visents.list[i].model->name, "progs/missile.mdl") + || !strcmp(cl_visents.list[i].model->name, "progs/grenade.mdl"))) + { + // + // Rockets and grenades. + // + + float entity_angle = 0; + int x_line_end = 0; + int y_line_end = 0; + + // Get the entity angle in radians. + entity_angle = DEG2RAD(cl_visents.list[i].angles[1]); + + x_line_end = entity_p_x + 5 * cos(entity_angle) * scale; + y_line_end = entity_p_y - 5 * sin(entity_angle) * scale; + + // Draw the rocket/grenade showing it's angle also. + Draw_AlphaLine (entity_p_x, entity_p_y, x_line_end, y_line_end, 1.0, 254, 1); + } + else if(radar_show_shaft_p + && (!strcmp(cl_visents.list[i].model->name, "progs/bolt.mdl") + || !strcmp(cl_visents.list[i].model->name, "progs/bolt2.mdl") + || !strcmp(cl_visents.list[i].model->name, "progs/bolt3.mdl"))) + { + // + // Shaft beam. + // + + float entity_angle = 0; + float shaft_length = 0; + float x_line_end = 0; + float y_line_end = 0; + + // Get the length and angle of the shaft. + shaft_length = cl_visents.list[i].model->maxs[1]; + entity_angle = (cl_visents.list[i].angles[1]*M_PI)/180; + + // Calculate where the shaft beam's ending point. + x_line_end = entity_p_x + shaft_length * cos(entity_angle); + y_line_end = entity_p_y - shaft_length * sin(entity_angle); + + // Draw the shaft beam. + Draw_AlphaLine (entity_p_x, entity_p_y, x_line_end, y_line_end, 1.0, 254, 1); + } + } + + // Draw a circle around "hold areas", the grid cells within this circle + // are the ones that are counted for that particular hold area. The team + // that has the most percentage of these cells is considered to hold that area. + if(show_hold_areas && stats_important_ents != NULL && stats_important_ents->list != NULL) + { + int entity_p_x = 0; + int entity_p_y = 0; + + for(i = 0; i < stats_important_ents->count; i++) + { + entity_p_x = x + Q_rint((map_x_slope*8*stats_important_ents->list[i].origin[0] + map_x_intercept) * scale); + entity_p_y = y + Q_rint((map_y_slope*8*stats_important_ents->list[i].origin[1] + map_y_intercept) * scale); + + Draw_ColoredString(entity_p_x - (8 * strlen(stats_important_ents->list[i].name)) / 2.0, entity_p_y - 4, + va("&c55f%s", stats_important_ents->list[i].name), 0); + + Draw_AlphaCircleOutline(entity_p_x , entity_p_y, map_x_slope * 8 * stats_important_ents->hold_radius * scale, 1.0, 15, 0.2); + } + } + + // + // Draw temp entities (explosions, blood, teleport effects). + // + for(i = 0; i < MAX_TEMP_ENTITIES; i++) + { + float time_diff = 0.0; + + int entity_q_x = 0; + int entity_q_y = 0; + int entity_p_x = 0; + int entity_p_y = 0; + + // Get the time since the entity spawned. + if(cls.demoplayback) + { + time_diff = cls.demotime - temp_entities.list[i].time; + } + else + { + time_diff = cls.realtime - temp_entities.list[i].time; + } + + // Don't show temp entities for long. + if(time_diff < 0.25) + { + float radius = 0.0; + radius = (time_diff < 0.125) ? (time_diff * 32.0) : (time_diff * 32.0) - time_diff; + radius *= scale; + radius = min(max(radius, 0), 200); + + // Get quake coordinates (times 8 to get them in the same format as .locs). + entity_q_x = temp_entities.list[i].pos[0]*8; + entity_q_y = temp_entities.list[i].pos[1]*8; + + entity_p_x = x + Q_rint((map_x_slope*entity_q_x + map_x_intercept) * scale); + entity_p_y = y + Q_rint((map_y_slope*entity_q_y + map_y_intercept) * scale); + + if(radar_show_explosions + && (temp_entities.list[i].type == TE_EXPLOSION + || temp_entities.list[i].type == TE_TAREXPLOSION)) + { + // + // Explosions. + // + + Draw_AlphaCircleFill (entity_p_x, entity_p_y, radius, 235, 0.8); + } + else if(radar_show_teleport && temp_entities.list[i].type == TE_TELEPORT) + { + // + // Teleport effect. + // + + radius *= 1.5; + Draw_AlphaCircleFill (entity_p_x, entity_p_y, radius, 244, 0.8); + } + else if(radar_show_shotgun && temp_entities.list[i].type == TE_GUNSHOT) + { + // + // Shotgun fire. + // + + #define SHOTGUN_SPREAD 10 + int spread_x = 0; + int spread_y = 0; + int n = 0; + + for(n = 0; n < 10; n++) + { + spread_x = (int)(rand() / (((double)RAND_MAX + 1) / SHOTGUN_SPREAD)); + spread_y = (int)(rand() / (((double)RAND_MAX + 1) / SHOTGUN_SPREAD)); + + Draw_AlphaFill (entity_p_x + spread_x - (SHOTGUN_SPREAD/2), entity_p_y + spread_y - (SHOTGUN_SPREAD/2), 1, 1, 8, 0.9); + } + } + } + } +} + +void Radar_DrawPlayers(int x, int y, int width, int height, float scale, + float show_height, float show_powerups, + float player_size, float show_names, + float fade_players, float highlight, + char *highlight_color) +{ + int i; + player_state_t *state; + player_info_t *info; + + // Get player state so we can know where he is (or on rare occassions, she). + state = cl.frames[cl.oldparsecount & UPDATE_MASK].playerstate; + + // Get the info for the player. + info = cl.players; + + // + // Draw the players. + // + for (i = 0; i < MAX_CLIENTS; i++, info++, state++) + { + // Players quake coordinates + // (these are multiplied by 8, since the conversion formula was + // calculated using the coordinates in a .loc-file, which are in + // the format quake-coordainte*8). + int player_q_x = 0; + int player_q_y = 0; + + // The height of the player. + float player_z = 1.0; + float player_z_relative = 1.0; + + // Players pixel coordinates. + int player_p_x = 0; + int player_p_y = 0; + + // Used for drawing the the direction the + // player is looking at. + float player_angle = 0; + int x_line_start = 0; + int y_line_start = 0; + int x_line_end = 0; + int y_line_end = 0; + + // Color and opacity of the player. + int player_color = 0; + float player_alpha = 1.0; + + // Make sure we're not drawing any ghosts. + if(!info->name[0]) + { + continue; + } + + if (state->messagenum == cl.oldparsecount) + { + // TODO: Implement lerping to get smoother drawing. + + // Get the quake coordinates. Multiply by 8 since + // the conversion formula has been calculated using + // a .loc-file which is in that format. + player_q_x = state->origin[0]*8; + player_q_y = state->origin[1]*8; + + // Get the players view angle. + player_angle = cls.demoplayback ? state->viewangles[1] : cl.simangles[1]; + + // Convert from quake coordiantes -> pixel coordinates. + player_p_x = Q_rint((map_x_slope*player_q_x + map_x_intercept) * scale); + player_p_y = Q_rint((map_y_slope*player_q_y + map_y_intercept) * scale); + + player_color = Sbar_BottomColor(info); + + // Calculate the height of the player. + if(show_height) + { + player_z = state->origin[2]; + player_z += (player_z >= 0) ? fabs(cl.worldmodel->mins[2]) : fabs(cl.worldmodel->maxs[2]); + player_z_relative = min(fabs(player_z / map_height_diff), 1.0); + player_z_relative = max(player_z_relative, 0.2); + } + + // Make the players fade out as they get less armor/health. + if(fade_players) + { + int armor_strength = 0; + armor_strength = (info->stats[STAT_ITEMS] & IT_ARMOR1) ? 100 : + ((info->stats[STAT_ITEMS] & IT_ARMOR2) ? 150 : + ((info->stats[STAT_ITEMS] & IT_ARMOR3) ? 200 : 0)); + + // Don't let the players get completly transparent so add 0.2 to the final value. + player_alpha = ((info->stats[STAT_HEALTH] + (info->stats[STAT_ARMOR] * armor_strength)) / 100.0) + 0.2; + } + + // Turn dead people red. + if(info->stats[STAT_HEALTH] <= 0) + { + player_alpha = 1.0; + player_color = 79; + } + + // Draw a ring around players with powerups if it's enabled. + if(show_powerups) + { + if(info->stats[STAT_ITEMS] & IT_INVISIBILITY) + { + Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size*2*player_z_relative, 161, 0.2); + } + + if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY) + { + Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size*2*player_z_relative, 79, 0.5); + } + + if(info->stats[STAT_ITEMS] & IT_QUAD) + { + Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size*2*player_z_relative, 244, 0.2); + } + } + + #define HUD_RADAR_HIGHLIGHT_NONE 0 + #define HUD_RADAR_HIGHLIGHT_TEXT_ONLY 1 + #define HUD_RADAR_HIGHLIGHT_OUTLINE 2 + #define HUD_RADAR_HIGHLIGHT_FIXED_OUTLINE 3 + #define HUD_RADAR_HIGHLIGHT_CIRCLE 4 + #define HUD_RADAR_HIGHLIGHT_FIXED_CIRCLE 5 + #define HUD_RADAR_HIGHLIGHT_ARROW_BOTTOM 6 + #define HUD_RADAR_HIGHLIGHT_ARROW_CENTER 7 + #define HUD_RADAR_HIGHLIGHT_ARROW_TOP 8 + #define HUD_RADAR_HIGHLIGHT_CROSS_CORNERS 9 + + // Draw a circle around the tracked player. + if (highlight != HUD_RADAR_HIGHLIGHT_NONE && Cam_TrackNum() >= 0 && info->userid == cl.players[Cam_TrackNum()].userid) + { + color_t higlight_color = RGBAVECT_TO_COLOR(hud_radar_highlight_color); + + // Draw the highlight. + switch ((int)highlight) + { + case HUD_RADAR_HIGHLIGHT_CROSS_CORNERS : + { + // Top left + Draw_AlphaLineRGB (x, y, x + player_p_x, y + player_p_y, 2, higlight_color); + + // Top right. + Draw_AlphaLineRGB (x + width, y, x + player_p_x, y + player_p_y, 2, higlight_color); + + // Bottom left. + Draw_AlphaLineRGB (x, y + height, x + player_p_x, y + player_p_y, 2, higlight_color); + + // Bottom right. + Draw_AlphaLineRGB (x + width, y + height, x + player_p_x, y + player_p_y, 2, higlight_color); + break; + } + case HUD_RADAR_HIGHLIGHT_ARROW_TOP : + { + // Top center. + Draw_AlphaLineRGB (x + width / 2, y, x + player_p_x, y + player_p_y, 2, higlight_color); + break; + } + case HUD_RADAR_HIGHLIGHT_ARROW_CENTER : + { + // Center. + Draw_AlphaLineRGB (x + width / 2, y + height / 2, x + player_p_x, y + player_p_y, 2, higlight_color); + break; + } + case HUD_RADAR_HIGHLIGHT_ARROW_BOTTOM : + { + // Bottom center. + Draw_AlphaLineRGB (x + width / 2, y + height, x + player_p_x, y + player_p_y, 2, higlight_color); + break; + } + case HUD_RADAR_HIGHLIGHT_FIXED_CIRCLE : + { + Draw_AlphaCircleRGB (x + player_p_x, y + player_p_y, player_size * 1.5, 1.0, true, higlight_color); + break; + } + case HUD_RADAR_HIGHLIGHT_CIRCLE : + { + Draw_AlphaCircleRGB (x + player_p_x, y + player_p_y, player_size * player_z_relative * 2.0, 1.0, true, higlight_color); + break; + } + case HUD_RADAR_HIGHLIGHT_FIXED_OUTLINE : + { + Draw_AlphaCircleOutlineRGB (x + player_p_x, y + player_p_y, player_size * 1.5, 1.0, higlight_color); + break; + } + case HUD_RADAR_HIGHLIGHT_OUTLINE : + { + Draw_AlphaCircleOutlineRGB (x + player_p_x, y + player_p_y, player_size * player_z_relative * 2.0, 1.0, higlight_color); + break; + } + case HUD_RADAR_HIGHLIGHT_TEXT_ONLY : + default : + { + break; + } + } + } + + // Draw the actual player and a line showing what direction the player is looking in. + { + float relative_x = 0; + float relative_y = 0; + + x_line_start = x + player_p_x; + y_line_start = y + player_p_y; + + // Translate the angle into radians. + player_angle = DEG2RAD(player_angle); + + relative_x = cos(player_angle); + relative_y = sin(player_angle); + + // Draw a slightly larger line behind the colored one + // so that it get's an outline. + x_line_end = x_line_start + (player_size * 2 * player_z_relative + 1) * relative_x; + y_line_end = y_line_start - (player_size * 2 * player_z_relative + 1) * relative_y; + Draw_AlphaLine (x_line_start, y_line_start, x_line_end, y_line_end, 4.0, 0, 1.0); + + // Draw the colored line. + x_line_end = x_line_start + (player_size * 2 * player_z_relative) * relative_x; + y_line_end = y_line_start - (player_size * 2 * player_z_relative) * relative_y; + Draw_AlphaLine (x_line_start, y_line_start, x_line_end, y_line_end, 2.0, player_color, player_alpha); + + // Draw the player on the map. + Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size * player_z_relative, player_color, player_alpha); + Draw_AlphaCircleOutline (x + player_p_x, y + player_p_y, player_size * player_z_relative, 1.0, 0, 1.0); + } + + // Draw the players name. + if(show_names) + { + int name_x = 0; + int name_y = 0; + + name_x = x + player_p_x; + name_y = y + player_p_y; + + // Make sure we're not too far right. + while(name_x + 8 * strlen(info->name) > x + width) + { + name_x--; + } + + // Make sure we're not outside the radar to the left. + name_x = max(name_x, x); + + // Draw the name. + if (highlight >= HUD_RADAR_HIGHLIGHT_TEXT_ONLY + && info->userid == cl.players[Cam_TrackNum()].userid) + { + // Draw the tracked players name in the user specified color. + Draw_ColoredString (name_x, name_y, + va("&c%x%x%x%s", + (unsigned int)(hud_radar_highlight_color[0] * 15), + (unsigned int)(hud_radar_highlight_color[1] * 15), + (unsigned int)(hud_radar_highlight_color[2] * 15), info->name), 0); + } + else + { + // Draw other players in normal character color. + Draw_String (name_x, name_y, info->name); + } + } + + // Show if a person lost an RL-pack. + if(info->stats[STAT_HEALTH] <= 0 && info->stats[STAT_ACTIVEWEAPON] == IT_ROCKET_LAUNCHER) + { + Draw_AlphaCircleOutline (x + player_p_x, y + player_p_y, player_size*player_z_relative*2, 1.0, 254, player_alpha); + Draw_ColoredString (x + player_p_x, y + player_p_y, va("&cf00PACK!"), 1); + } + } + } +} + +// +// Draws a map of the current level and plots player movements on it. +// +void SCR_HUD_DrawRadar(hud_t *hud) +{ + int width, height, x, y; + float width_limit, height_limit; + float scale; + float x_scale; + float y_scale; + + static cvar_t + *hud_radar_opacity = NULL, + *hud_radar_width, + *hud_radar_height, + *hud_radar_autosize, + *hud_radar_fade_players, + *hud_radar_show_powerups, + *hud_radar_show_names, + *hud_radar_highlight, + *hud_radar_highlight_color, + *hud_radar_player_size, + *hud_radar_show_height, + *hud_radar_show_stats, + *hud_radar_show_hold, + *hud_radar_weaponfilter, + *hud_radar_itemfilter, + *hud_radar_onlytp, + *hud_radar_otherfilter; + + if (hud_radar_opacity == NULL) // first time + { + char checkval[256]; + + hud_radar_opacity = HUD_FindVar(hud, "opacity"); + hud_radar_width = HUD_FindVar(hud, "width"); + hud_radar_height = HUD_FindVar(hud, "height"); + hud_radar_autosize = HUD_FindVar(hud, "autosize"); + hud_radar_fade_players = HUD_FindVar(hud, "fade_players"); + hud_radar_show_powerups = HUD_FindVar(hud, "show_powerups"); + hud_radar_show_names = HUD_FindVar(hud, "show_names"); + hud_radar_player_size = HUD_FindVar(hud, "player_size"); + hud_radar_show_height = HUD_FindVar(hud, "show_height"); + hud_radar_show_stats = HUD_FindVar(hud, "show_stats"); + hud_radar_show_hold = HUD_FindVar(hud, "show_hold"); + hud_radar_weaponfilter = HUD_FindVar(hud, "weaponfilter"); + hud_radar_itemfilter = HUD_FindVar(hud, "itemfilter"); + hud_radar_otherfilter = HUD_FindVar(hud, "otherfilter"); + hud_radar_onlytp = HUD_FindVar(hud, "onlytp"); + hud_radar_highlight = HUD_FindVar(hud, "highlight"); + hud_radar_highlight_color = HUD_FindVar(hud, "highlight_color"); + + // + // Only parse the the filters when they change, not on each frame. + // + + // Weapon filter. + hud_radar_weaponfilter->OnChange = Radar_OnChangeWeaponFilter; + strlcpy(checkval, hud_radar_weaponfilter->string, sizeof(checkval)); + Cvar_Set(hud_radar_weaponfilter, checkval); + + // Item filter. + hud_radar_itemfilter->OnChange = Radar_OnChangeItemFilter; + strlcpy(checkval, hud_radar_itemfilter->string, sizeof(checkval)); + Cvar_Set(hud_radar_itemfilter, checkval); + + // Other filter. + hud_radar_otherfilter->OnChange = Radar_OnChangeOtherFilter; + strlcpy(checkval, hud_radar_otherfilter->string, sizeof(checkval)); + Cvar_Set(hud_radar_otherfilter, checkval); + + // Highlight color. + hud_radar_highlight_color->OnChange = Radar_OnChangeHighlightColor; + strlcpy(checkval, hud_radar_highlight_color->string, sizeof(checkval)); + Cvar_Set(hud_radar_highlight_color, checkval); + } + + // Don't show anything if it's a normal player. + if(!(cls.demoplayback || cl.spectator)) + { + HUD_PrepareDraw(hud, hud_radar_width->value, hud_radar_height->value, &x, &y); + return; + } + + // Don't show when not in teamplay/demoplayback. + if(!HUD_ShowInDemoplayback(hud_radar_onlytp->value)) + { + HUD_PrepareDraw(hud, hud_radar_width->value, hud_radar_height->value, &x, &y); + return; + } + + // Save the width and height of the HUD. We're using these because + // if autosize is on these will be altered and we don't want to change + // the settings that the user set, if we try, and the user turns off + // autosize again the size of the HUD will remain "autosized" until the user + // resets it by hand again. + width_limit = hud_radar_width->value; + height_limit = hud_radar_height->value; + + // we support also sizes specified as a percentage of total screen width/height + if (strchr(hud_radar_width->string, '%')) + width_limit = width_limit * vid.conwidth / 100.0; + if (strchr(hud_radar_height->string, '%')) + height_limit = hud_radar_height->value * vid.conheight / 100.0; + + // This map doesn't have a map pic. + if(!radar_pic_found) + { + if(HUD_PrepareDraw(hud, Q_rint(width_limit), Q_rint(height_limit), &x, &y)) + { + Draw_String(x, y, "No radar picture found!"); + } + return; + } + + // Make sure we can translate the coordinates. + if(!conversion_formula_found) + { + if(HUD_PrepareDraw(hud, Q_rint(width_limit), Q_rint(height_limit), &x, &y)) + { + Draw_String(x, y, "No conversion formula found!"); + } + return; + } + + x = 0; + y = 0; + + scale = 1; + + if(hud_radar_autosize->value) + { + // + // Autosize the hud element based on the size of the radar picture. + // + + width = width_limit = radar_pic.width; + height = height_limit = radar_pic.height; + } + else + { + // + // Size the picture so that it fits inside the hud element. + // + + // Set the scaling based on the picture dimensions. + x_scale = (width_limit / radar_pic.width); + y_scale = (height_limit / radar_pic.height); + + scale = (x_scale < y_scale) ? x_scale : y_scale; + + width = radar_pic.width * scale; + height = radar_pic.height * scale; + } + + if (HUD_PrepareDraw(hud, Q_rint(width_limit), Q_rint(height_limit), &x, &y)) + { + float player_size = 1.0; + static int lastframecount = -1; + + // Place the map picture in the center of the HUD element. + x += Q_rint((width_limit / 2.0) - (width / 2.0)); + x = max(0, x); + x = min(x + width, x); + + y += Q_rint((height_limit / 2.0) - (height / 2.0)); + y = max(0, y); + y = min(y + height, y); + + // Draw the radar background. + Draw_SAlphaPic (x, y, &radar_pic, hud_radar_opacity->value, scale); + + // Only draw once per frame. + if (cls.framecount == lastframecount) + { + return; + } + lastframecount = cls.framecount; + + if (!cl.oldparsecount || !cl.parsecount || cls.state < ca_active) + { + return; + } + + // Scale the player size after the size of the radar. + player_size = hud_radar_player_size->value * scale; + + // Draw team stats. + if(hud_radar_show_stats->value) + { + Radar_DrawGrid(stats_grid, x, y, scale, width, height, hud_radar_show_stats->value); + } + + // Draw entities such as powerups, weapons and backpacks. + if(RADAR_SHOW_WEAPONS || RADAR_SHOW_ITEMS || RADAR_SHOW_OTHER) + { + Radar_DrawEntities(x, y, scale, + player_size, + hud_radar_show_hold->value); + } + + // Draw the players. + Radar_DrawPlayers(x, y, width, height, scale, + hud_radar_show_height->value, + hud_radar_show_powerups->value, + player_size, + hud_radar_show_names->value, + hud_radar_fade_players->value, + hud_radar_highlight->value, + hud_radar_highlight_color->string); + } +} + +#endif // WITH_PNG + +// +// Run before HUD elements are drawn. +// Place stuff that is common for HUD elements here. +// +void HUD_BeforeDraw() +{ + // Only sort once per draw. + HUD_Sort_Scoreboard (HUD_SCOREBOARD_ALL); +} + +// +// Run after HUD elements are drawn. +// Place stuff that is common for HUD elements here. +// +void HUD_AfterDraw() +{ +} + + +#ifndef HAXX +static void SCR_HUD_DrawNotImplemented(hud_t *hud) +{ + char line1[64]; + int width, height, x, y; + + snprintf(line1, sizeof(line1), "%s not implemented", hud->name); + + width = 8 * strlen(line1); + height = 8; + + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + + Draw_SString(x, y, line1, 1); +} +#define SCR_HUD_DrawSpeed SCR_HUD_DrawNotImplemented +#define SCR_HUD_DrawTeamHoldBar SCR_HUD_DrawNotImplemented +#define SCR_HUD_DrawTeamHoldInfo SCR_HUD_DrawNotImplemented +#define SCR_HUD_DrawItemsClock SCR_HUD_DrawNotImplemented +#endif + + +// ---------------- +// Init +// and add some common elements to hud (clock etc) +// + +void CommonDraw_Init(void) +{ + int i; + + HUD_InitSbarImages(); + + // variables + hud_planmode = pCvar_GetNVFDG("hud_planmode", "0", 0, NULL, "ezhud"); + hud_tp_need = pCvar_GetNVFDG("hud_tp_need", "0", 0, NULL, "ezhud"); + hud_digits_trim = pCvar_GetNVFDG("hud_digits_trim", "1", 0, NULL, "ezhud"); + mvd_autohud = pCvar_GetNVFDG("mvd_autohud", "0", 0, NULL, "ezhud"); + cl_weaponpreselect = pCvar_GetNVFDG("cl_weaponpreselect", "0", 0, NULL, "ezhud"); + cl_multiview = pCvar_GetNVFDG("cl_multiview", "0", 0, NULL, "ezhud"); + + + tp_need_health = pCvar_GetNVFDG("tp_need_health", "50", 0, NULL, "ezhud"); + tp_need_ra = pCvar_GetNVFDG("tp_need_ra", "50", 0, NULL, "ezhud"); + tp_need_ya = pCvar_GetNVFDG("tp_need_ya", "50", 0, NULL, "ezhud"); + tp_need_ga = pCvar_GetNVFDG("tp_need_ga", "50", 0, NULL, "ezhud"); + tp_weapon_order = pCvar_GetNVFDG("tp_weapon_order", "78654321", 0, NULL, "ezhud"); + tp_need_weapon = pCvar_GetNVFDG("tp_need_weapon", "35687", 0, NULL, "ezhud"); + tp_need_shells = pCvar_GetNVFDG("tp_need_shells", "10", 0, NULL, "ezhud"); + tp_need_nails = pCvar_GetNVFDG("tp_need_nails", "40", 0, NULL, "ezhud"); + tp_need_rockets = pCvar_GetNVFDG("tp_need_rockets", "5", 0, NULL, "ezhud"); + tp_need_cells = pCvar_GetNVFDG("tp_need_cells", "20", 0, NULL, "ezhud"); + + // init HUD STAT table + for (i=0; i < MAX_CL_STATS; i++) + hud_stats[i] = 0; + hud_stats[STAT_HEALTH] = 200; + hud_stats[STAT_AMMO] = 100; + hud_stats[STAT_ARMOR] = 200; + hud_stats[STAT_SHELLS] = 100; + hud_stats[STAT_NAILS] = 200; + hud_stats[STAT_ROCKETS] = 100; + hud_stats[STAT_CELLS] = 100; + hud_stats[STAT_ACTIVEWEAPON] = 32; + hud_stats[STAT_ITEMS] = 0xffffffff - IT_ARMOR2 - IT_ARMOR1; + + autohud.active = 0; + + // init gameclock + HUD_Register("gameclock", NULL, "Shows current game time (hh:mm:ss).", + HUD_PLUSMINUS, ca_disconnected, 8, SCR_HUD_DrawGameClock, + "1", "top", "right", "console", "0", "0", "0", "0 0 0", NULL, + "big", "1", + "style", "0", + "scale", "1", + "blink", "1", + "countdown","0", + "offset","0", + NULL); + + HUD_Register("notify", NULL, "Shows last console lines", + HUD_PLUSMINUS, ca_disconnected, 8, SCR_HUD_DrawNotify, + "0", "top", "left", "top", "0", "0", "0", "0 0 0", NULL, + "rows", "4", + "cols", "30", + "scale", "1", + "time", "4", + NULL); + + // fps + HUD_Register("fps", NULL, + "Shows your current framerate in frames per second (fps)." + "This can also show the minimum framerate that occured in the last measured period.", + HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawFPS, + "1", "gameclock", "center", "after", "0", "0", "0", "0 0 0", NULL, + "show_min", "0", + "style", "0", + "title", "1", + "drop", "70", + NULL); + + HUD_Register("vidlag", NULL, + "Shows the delay between the time a frame is rendered and the time it's displayed.", + HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawVidLag, + "0", "top", "right", "top", "0", "0", "0", "0 0 0", NULL, + "style", "0", + NULL); + + HUD_Register("mouserate", NULL, "Show your current mouse input rate", HUD_PLUSMINUS, ca_active, 9, + SCR_HUD_DrawMouserate, + "0", "screen", "left", "bottom", "0", "0", "0", "0 0 0", NULL, + "title", "1", + "interval", "1", + "style", "0", + NULL); + + // init clock + HUD_Register("clock", NULL, "Shows current local time (hh:mm:ss).", + HUD_PLUSMINUS, ca_disconnected, 8, SCR_HUD_DrawClock, + "0", "top", "right", "console", "0", "0", "0", "0 0 0", NULL, + "big", "1", + "style", "0", + "scale", "1", + "blink", "1", + "format", "0", + NULL); + + // init democlock + HUD_Register("democlock", NULL, "Shows current demo time (hh:mm:ss).", + HUD_PLUSMINUS, ca_disconnected, 7, SCR_HUD_DrawDemoClock, + "1", "top", "right", "console", "0", "8", "0", "0 0 0", NULL, + "big", "0", + "style", "0", + "scale", "1", + "blink", "0", + NULL); + + // init ping + HUD_Register("ping", NULL, "Shows most important net conditions, like ping and pl. Shown only when you are connected to a server.", + HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawPing, + "0", "screen", "left", "bottom", "0", "0", "0", "0 0 0", NULL, + "period", "1", + "show_pl", "1", + "show_min", "0", + "show_max", "0", + "show_dev", "0", + "style", "0", + "blink", "1", + NULL); + + // init net + HUD_Register("net", NULL, "Shows network statistics, like latency, packet loss, average packet sizes and bandwidth. Shown only when you are connected to a server.", + HUD_PLUSMINUS, ca_active, 7, SCR_HUD_DrawNetStats, + "0", "top", "left", "center", "0", "0", "0.2", "0 0 0", NULL, + "period", "1", + NULL); + + // init speed + HUD_Register("speed", NULL, "Shows your current running speed. It is measured over XY or XYZ axis depending on \'xyz\' property.", + HUD_PLUSMINUS, ca_active, 7, SCR_HUD_DrawSpeed, + "0", "top", "center", "bottom", "0", "-5", "0", "0 0 0", NULL, + "xyz", "0", + "width", "160", + "height", "15", + "opacity", "1.0", + "tick_spacing", "0.2", + "color_stopped", SPEED_STOPPED, + "color_normal", SPEED_NORMAL, + "color_fast", SPEED_FAST, + "color_fastest", SPEED_FASTEST, + "color_insane", SPEED_INSANE, + "vertical", "0", + "vertical_text", "1", + "text_align", "1", + "style", "0", + NULL); + + // Init speed2 (half circle thingie). + HUD_Register("speed2", NULL, "Shows your current running speed. It is measured over XY or XYZ axis depending on \'xyz\' property.", + HUD_PLUSMINUS, ca_active, 7, SCR_HUD_DrawSpeed2, + "0", "top", "center", "bottom", "0", "0", "0", "0 0 0", NULL, + "xyz", "0", + "opacity", "1.0", + "color_stopped", SPEED_STOPPED, + "color_normal", SPEED_NORMAL, + "color_fast", SPEED_FAST, + "color_fastest", SPEED_FASTEST, + "color_insane", SPEED_INSANE, + "radius", "50.0", + "wrapspeed", "500", + "orientation", "0", + NULL); + + // init guns + HUD_Register("gun", NULL, "Part of your inventory - current weapon.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGunCurrent, + "0", "ibar", "center", "bottom", "0", "0", "0", "0 0 0", NULL, + "wide", "0", + "style", "0", + "scale", "1", + NULL); + HUD_Register("gun2", NULL, "Part of your inventory - shotgun.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun2, + "1", "ibar", "left", "bottom", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("gun3", NULL, "Part of your inventory - super shotgun.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun3, + "1", "gun2", "after", "center", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("gun4", NULL, "Part of your inventory - nailgun.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun4, + "1", "gun3", "after", "center", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("gun5", NULL, "Part of your inventory - super nailgun.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun5, + "1", "gun4", "after", "center", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("gun6", NULL, "Part of your inventory - grenade launcher.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun6, + "1", "gun5", "after", "center", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("gun7", NULL, "Part of your inventory - rocket launcher.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun7, + "1", "gun6", "after", "center", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("gun8", NULL, "Part of your inventory - thunderbolt.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun8, + "1", "gun7", "after", "center", "0", "0", "0", "0 0 0", NULL, + "wide", "0", + "style", "0", + "scale", "1", + NULL); + + // init powerzz + HUD_Register("key1", NULL, "Part of your inventory - silver key.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawKey1, + "1", "ibar", "top", "left", "0", "64", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("key2", NULL, "Part of your inventory - gold key.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawKey2, + "1", "key1", "left", "after", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("ring", NULL, "Part of your inventory - invisibility.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawRing, + "1", "key2", "left", "after", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("pent", NULL, "Part of your inventory - invulnerability.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawPent, + "1", "ring", "left", "after", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("suit", NULL, "Part of your inventory - biosuit.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSuit, + "1", "pent", "left", "after", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("quad", NULL, "Part of your inventory - quad damage.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawQuad, + "1", "suit", "left", "after", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + + // netproblem icon + HUD_Register("netproblem", NULL, "Shows an icon if you are experiencing network problems", + HUD_NO_FRAME, ca_active, 0, SCR_HUD_NetProblem, + "1", "top", "left", "top", "0", "0", "0", "0 0 0", NULL, + "scale", "1", + NULL); + + // sigilzz + HUD_Register("sigil1", NULL, "Part of your inventory - sigil 1.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil1, + "0", "ibar", "left", "top", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("sigil2", NULL, "Part of your inventory - sigil 2.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil2, + "0", "sigil1", "after", "top", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("sigil3", NULL, "Part of your inventory - sigil 3.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil3, + "0", "sigil2", "after", "top", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("sigil4", NULL, "Part of your inventory - sigil 4.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil4, + "0", "sigil3", "after", "top", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + + // player face (health indicator) + HUD_Register("face", NULL, "Your bloody face.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawFace, + "1", "screen", "center", "bottom", "0", "0", "0", "0 0 0", NULL, + "scale", "1", + NULL); + + // health + HUD_Register("health", NULL, "Part of your status - health level.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawHealth, + "1", "face", "after", "center", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "3", + NULL); + + // ammo/s + HUD_Register("ammo", NULL, "Part of your inventory - ammo for active weapon.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoCurrent, + "1", "health", "after", "center", "32", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "3", + NULL); + HUD_Register("ammo1", NULL, "Part of your inventory - ammo - shells.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo1, + "0", "ibar", "left", "top", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "3", + NULL); + HUD_Register("ammo2", NULL, "Part of your inventory - ammo - nails.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo2, + "0", "ammo1", "after", "top", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "3", + NULL); + HUD_Register("ammo3", NULL, "Part of your inventory - ammo - rockets.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo3, + "0", "ammo2", "after", "top", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "3", + NULL); + HUD_Register("ammo4", NULL, "Part of your inventory - ammo - cells.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo4, + "0", "ammo3", "after", "top", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "3", + NULL); + + // ammo icon/s + HUD_Register("iammo", NULL, "Part of your inventory - ammo icon.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIconCurrent, + "1", "ammo", "before", "center", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + HUD_Register("iammo1", NULL, "Part of your inventory - ammo icon.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon1, + "0", "ibar", "left", "top", "0", "0", "0", "0 0 0", NULL, + "style", "2", + "scale", "1", + NULL); + HUD_Register("iammo2", NULL, "Part of your inventory - ammo icon.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon2, + "0", "iammo1", "after", "top", "0", "0", "0", "0 0 0", NULL, + "style", "2", + "scale", "1", + NULL); + HUD_Register("iammo3", NULL, "Part of your inventory - ammo icon.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon3, + "0", "iammo2", "after", "top", "0", "0", "0", "0 0 0", NULL, + "style", "2", + "scale", "1", + NULL); + HUD_Register("iammo4", NULL, "Part of your inventory - ammo icon.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon4, + "0", "iammo3", "after", "top", "0", "0", "0", "0 0 0", NULL, + "style", "2", + "scale", "1", + NULL); + + // armor count + HUD_Register("armor", NULL, "Part of your inventory - armor level.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawArmor, + "1", "face", "before", "center", "-32", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "3", + "pent_666", "1", // Show 666 instead of armor value + NULL); + + // armor icon + HUD_Register("iarmor", NULL, "Part of your inventory - armor icon.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawArmorIcon, + "1", "armor", "before", "center", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + NULL); + + // Tracking JohnNy_cz (Contains name of the player who's player we're watching at the moment) + HUD_Register("tracking", NULL, "Shows the name of tracked player.", + HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawTracking, + "1", "face", "center", "before", "0", "0", "0", "0 0 0", NULL, + "format", "^mTracking:^m %t %n"/*, ^mJUMP^m for next"*/, //"Tracking: team name, JUMP for next", "Tracking:" and "JUMP" are brown. default: "Tracking %t %n, [JUMP] for next" + "scale", "1", + NULL); + + // groups + HUD_Register("group1", NULL, "Group element.", + HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group1, + "0", "screen", "left", "top", "0", "0", ".5", "0 0 0", NULL, + "name", "group1", + "width", "64", + "height", "64", + "picture", "", + "pic_alpha", "1.0", + "pic_scalemode", "0", + NULL); + HUD_Register("group2", NULL, "Group element.", + HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group2, + "0", "screen", "center", "top", "0", "0", ".5", "0 0 0", NULL, + "name", "group2", + "width", "64", + "height", "64", + "picture", "", + "pic_alpha", "1.0", + "pic_scalemode", "0", + NULL); + HUD_Register("group3", NULL, "Group element.", + HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group3, + "0", "screen", "right", "top", "0", "0", ".5", "0 0 0", NULL, + "name", "group3", + "width", "64", + "height", "64", + "picture", "", + "pic_alpha", "1.0", + "pic_scalemode", "0", + NULL); + HUD_Register("group4", NULL, "Group element.", + HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group4, + "0", "screen", "left", "center", "0", "0", ".5", "0 0 0", NULL, + "name", "group4", + "width", "64", + "height", "64", + "picture", "", + "pic_alpha", "1.0", + "pic_scalemode", "0", + NULL); + HUD_Register("group5", NULL, "Group element.", + HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group5, + "0", "screen", "center", "center", "0", "0", ".5", "0 0 0", NULL, + "name", "group5", + "width", "64", + "height", "64", + "picture", "", + "pic_alpha", "1.0", + "pic_scalemode", "0", + NULL); + HUD_Register("group6", NULL, "Group element.", + HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group6, + "0", "screen", "right", "center", "0", "0", ".5", "0 0 0", NULL, + "name", "group6", + "width", "64", + "height", "64", + "picture", "", + "pic_alpha", "1.0", + "pic_scalemode", "0", + NULL); + HUD_Register("group7", NULL, "Group element.", + HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group7, + "0", "screen", "left", "bottom", "0", "0", ".5", "0 0 0", NULL, + "name", "group7", + "width", "64", + "height", "64", + "picture", "", + "pic_alpha", "1.0", + "pic_scalemode", "0", + NULL); + HUD_Register("group8", NULL, "Group element.", + HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group8, + "0", "screen", "center", "bottom", "0", "0", ".5", "0 0 0", NULL, + "name", "group8", + "width", "64", + "height", "64", + "picture", "", + "pic_alpha", "1.0", + "pic_scalemode", "0", + NULL); + HUD_Register("group9", NULL, "Group element.", + HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group9, + "0", "screen", "right", "bottom", "0", "0", ".5", "0 0 0", NULL, + "name", "group9", + "width", "64", + "height", "64", + "picture", "", + "pic_alpha", "1.0", + "pic_scalemode", "0", + NULL); + + // healthdamage + HUD_Register("healthdamage", NULL, "Shows amount of damage done to your health.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawHealthDamage, + "0", "health", "left", "before", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "3", + "duration", "0.8", + NULL); + + // armordamage + HUD_Register("armordamage", NULL, "Shows amount of damage done to your armour.", + HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawArmorDamage, + "0", "armor", "left", "before", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "3", + "duration", "0.8", + NULL); + + HUD_Register("frags", NULL, "Show list of player frags in short form.", + 0, ca_active, 0, SCR_HUD_DrawFrags, + "0", "top", "right", "bottom", "0", "0", "0", "0 0 0", NULL, + "cell_width", "32", + "cell_height", "8", + "rows", "1", + "cols", "4", + "space_x", "1", + "space_y", "1", + "teamsort", "0", + "strip", "1", + "vertical", "0", + "shownames", "0", + "showteams", "0", + "padtext", "1", + "showself_always", "1", + "extra_spec_info", "ALL", + "fliptext", "0", + "style", "0", + "bignum", "0", + "colors_alpha", "1.0", + "maxname", "16", + "notintp", "0", + NULL); + + HUD_Register("teamfrags", NULL, "Show list of team frags in short form.", + 0, ca_active, 0, SCR_HUD_DrawTeamFrags, + "1", "ibar", "center", "before", "0", "0", "0", "0 0 0", NULL, + "cell_width", "32", + "cell_height", "8", + "rows", "1", + "cols", "2", + "space_x", "1", + "space_y", "1", + "strip", "1", + "vertical", "0", + "shownames", "0", + "padtext", "1", + "fliptext", "1", + "style", "0", + "extra_spec_info", "1", + "onlytp", "0", + "bignum", "0", + "colors_alpha", "1.0", + "maxname", "16", + NULL); + + HUD_Register("teaminfo", NULL, "Show information about your team in short form.", + 0, ca_active, 0, SCR_HUD_DrawTeamInfo, + "0", "", "right", "center", "0", "0", "0.2", "20 20 20", NULL, + "layout", "%p%n $x10%l$x11 %a/%H %w", + "align_right","0", + "loc_width","5", + "name_width","6", + "low_health","25", + "armor_style","3", + "weapon_style","0", + "show_enemies","0", + "show_self","1", + "scale","1", + "powerup_style","1", + NULL); + + HUD_Register("mp3_title", NULL, "Shows current mp3 playing.", + HUD_PLUSMINUS, ca_disconnected, 0, SCR_HUD_DrawMP3_Title, + "0", "top", "right", "bottom", "0", "0", "0", "0 0 0", NULL, + "style", "2", + "width", "512", + "height", "8", + "scroll", "1", + "scroll_delay", "0.5", + "on_scoreboard", "0", + "wordwrap", "0", + NULL); + + HUD_Register("mp3_time", NULL, "Shows the time of the current mp3 playing.", + HUD_PLUSMINUS, ca_disconnected, 0, SCR_HUD_DrawMP3_Time, + "0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL, + "style", "0", + "on_scoreboard", "0", + NULL); + +#ifdef WITH_PNG + HUD_Register("radar", NULL, "Plots the players on a picture of the map. (Only when watching MVD's or QTV).", + HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawRadar, + "0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL, + "opacity", "0.5", + "width", "30%", + "height", "25%", + "autosize", "0", + "show_powerups", "1", + "show_names", "0", + "highlight_color", "yellow", + "highlight", "0", + "player_size", "10", + "show_height", "1", + "show_stats", "1", + "fade_players", "1", + "show_hold", "0", + "weaponfilter", "gl rl lg", + "itemfilter", "backpack quad pent armor mega", + "otherfilter", "projectiles gibs explosions shotgun", + "onlytp", "0", + NULL); +#endif // WITH_PNG + + HUD_Register("teamholdbar", NULL, "Shows how much of the level (in percent) that is currently being held by either team.", + HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawTeamHoldBar, + "0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL, + "opacity", "0.8", + "width", "200", + "height", "8", + "vertical", "0", + "vertical_text", "0", + "show_text", "1", + "onlytp", "0", + NULL); + + HUD_Register("teamholdinfo", NULL, "Shows which important items in the level that are being held by the teams.", + HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawTeamHoldInfo, + "0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL, + "opacity", "0.8", + "width", "200", + "height", "8", + "onlytp", "0", + "style", "1", + "itemfilter", "quad ra ya ga mega pent rl quad", + NULL); + + HUD_Register("ownfrags" /* jeez someone give me a better name please */, NULL, "Highlights your own frags", + 0, ca_active, 1, SCR_HUD_DrawOwnFrags, + "1", "screen", "center", "top", "0", "50", "0.2", "0 0 100", NULL, + /* + "color", "255 255 255", + */ + "timeout", "3", + "scale", "1.5", + NULL + ); + + HUD_Register("keys", NULL, "Shows which keys user does press at the moment", + 0, ca_active, 1, SCR_HUD_DrawKeys, + "0", "screen", "right", "center", "0", "0", "0.5", "20 20 20", NULL, + "scale", "2", + NULL + ); + + HUD_Register("itemsclock", NULL, "Displays upcoming item respawns", + 0, ca_active, 1, SCR_HUD_DrawItemsClock, + "0", "screen", "right", "center", "0", "0", "0", "0 0 0", NULL, + "timelimit", "5", + "style", "0", + NULL + ); + + HUD_Register("score_team", NULL, "Own scores or team scores.", + 0, ca_active, 0, SCR_HUD_DrawScoresTeam, + "0", "screen", "left", "bottom", "0", "0", "0.5", "4 8 32", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "0", + "colorize", "0", + NULL + ); + + HUD_Register("score_enemy", NULL, "Scores of enemy or enemy team.", + 0, ca_active, 0, SCR_HUD_DrawScoresEnemy, + "0", "score_team", "after", "bottom", "0", "0", "0.5", "32 4 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "0", + "colorize", "0", + NULL + ); + + HUD_Register("score_difference", NULL, "Difference between teamscores and enemyscores.", + 0, ca_active, 0, SCR_HUD_DrawScoresDifference, + "0", "score_enemy", "after", "bottom", "0", "0", "0.5", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "0", + "colorize", "1", + NULL + ); + + HUD_Register("score_position", NULL, "Position on scoreboard.", + 0, ca_active, 0, SCR_HUD_DrawScoresPosition, + "0", "score_difference", "after", "bottom", "0", "0", "0.5", "0 0 0", NULL, + "style", "0", + "scale", "1", + "align", "right", + "digits", "0", + "colorize", "1", + NULL + ); + + HUD_Register("score_bar", NULL, "Team, enemy, and difference scores together.", + HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawScoresBar, + "0", "screen", "center", "console", "0", "0", "0.5", "0 0 0", NULL, + "style", "0", + "scale", "1", + "format_small", "&c69f%T&r:%t &cf10%E&r:%e $[%D$]", + "format_big", "%t:%e:%Z", + + NULL + ); + + HUD_Register("bar_armor", NULL, "Armor bar.", + HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawBarArmor, + "0", "armor", "left", "center", "0", "0", "0", "0 0 0", NULL, + "height", "16", + "width", "64", + "direction", "1", + "color_noarmor", "128 128 128 64", + "color_ga", "32 128 0 128", + "color_ya", "192 128 0 128", + "color_ra", "128 0 0 128", + "color_unnatural", "255 255 255 128", + NULL + ); + + HUD_Register("bar_health", NULL, "Health bar.", + HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawBarHealth, + "0", "health", "right", "center", "0", "0", "0", "0 0 0", NULL, + "height", "16", + "width", "64", + "direction", "0", + "color_nohealth", "128 128 128 64", + "color_normal", "32 64 128 128", + "color_mega", "64 96 128 128", + "color_twomega", "128 128 255 128", + "color_unnatural", "255 255 255 128", + NULL + ); + + HUD_Register("weaponstats", NULL, "Weapon Stats", + HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawWeaponStats, + "0", "screen", "right", "center", "0", "0", "0", "0 0 0", NULL, + "scale", "1", + "fmt", "&c990sg&r:[%sg] &c099ssg&r:[%ssg] &c900rl&r:[#rl] &c009lg&r:[%lg]", + NULL + ); + +/* hexum -> FIXME? this is used only for debug purposes, I wont bother to port it (it shouldnt be too difficult if anyone cares) +#ifdef _DEBUG + HUD_Register("framegraph", NULL, "Shows different frame times for debug/profiling purposes.", + HUD_PLUSMINUS | HUD_ON_SCORES, ca_disconnected, 0, SCR_HUD_DrawFrameGraph, + "0", "top", "left", "bottom", "0", "0", "2", + "swap_x", "0", + "swap_y", "0", + "scale", "14", + "width", "256", + "height", "64", + "alpha", "1", + NULL); +#endif +*/ + +} + +