diff --git a/doc/client.asciidoc b/doc/client.asciidoc index a68376f7b..8e0046971 100644 --- a/doc/client.asciidoc +++ b/doc/client.asciidoc @@ -697,6 +697,9 @@ gl_bilerp_pics:: - 1 — enabled for large pictures that don't fit into the scrap - 2 — enabled for all pictures, including the scrap texture itself +gl_bilerp_skies:: + Enables bilinear filtering of skybox textures. Default value is 1 (enabled). + gl_upscale_pcx:: Enables upscaling of PCX images using HQ2x and HQ4x filters. This improves rendering quality when screen scaling is used. Default value is 0. @@ -727,6 +730,18 @@ gl_fog:: Enable re-release fog effect. Only effective when using GLSL backend. Default value is 1 (enabled). +gl_bloom:: + Enable re-release bloom effect. Only effective when using GLSL backend. + Default value is 0 (disabled). Higher values specify number of blurring + filter iterations (typical value is 1). + +gl_bloom_sigma:: + Specifies strength parameter of gaussian blur filter used for the bloom + effect. Default value is 4. + +NOTE: Bloom only works with glowmaps. Enabling it with non-remastered content +(or glowmaps disabled) is a waste of resources. + gl_flarespeed:: Specifies flare fading effect speed. Default value is 8. Set this to 0 to disable fading. @@ -764,6 +779,12 @@ gl_dotshading:: truly 3D-ish by simulating diffuse lighting from a fake light source. Default value is 1 (enabled). +gl_shadows:: + Enables drawing stencil shadows underneath 3D models. Default value is 0. + - 0 — disabled + - 1 — enabled, constant alpha + - 2 — enabled, alpha fade with distance + gl_saturation:: Enables grayscaling of world textures. 1 keeps original colors, 0 converts textures to grayscale format (this may save some video memory and speed up diff --git a/inc/client/client.h b/inc/client/client.h index d36af72b7..c8d980085 100644 --- a/inc/client/client.h +++ b/inc/client/client.h @@ -26,8 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "shared/ghud.h" #endif -#define CHAR_WIDTH 8 -#define CHAR_HEIGHT 8 +#define CONCHAR_WIDTH 8 +#define CONCHAR_HEIGHT 8 // only begin attenuating sound volumes when outside the FULLVOLUME range #define SOUND_FULLVOLUME 80 @@ -38,6 +38,8 @@ with this program; if not, write to the Free Software Foundation, Inc., void CL_PreInit(void); +void SCR_DebugGraph(float value, int color); + #if USE_CLIENT #define MAX_LOCAL_SERVERS 16 diff --git a/inc/common/bsp.h b/inc/common/bsp.h index da55afe94..1cac1821a 100644 --- a/inc/common/bsp.h +++ b/inc/common/bsp.h @@ -75,7 +75,7 @@ typedef struct { #define SURF_COLOR_MASK (SURF_TRANS_MASK | SURF_WARP) #define SURF_NOLM_MASK_REMASTER (SURF_SKY | SURF_NODRAW) -#define SURF_NOLM_MASK_DEFAULT (SURF_COLOR_MASK | SURF_FLOWING | SURF_NOLM_MASK_REMASTER) +#define SURF_NOLM_MASK_DEFAULT (SURF_COLOR_MASK | SURF_NOLM_MASK_REMASTER) #define DSURF_PLANEBACK 1 @@ -115,21 +115,21 @@ typedef struct mface_s { typedef struct mnode_s { /* ======> */ cplane_t *plane; // never NULL to differentiate from leafs + struct mnode_s *parent; + #if USE_REF vec3_t mins; vec3_t maxs; - unsigned visframe; #endif - struct mnode_s *parent; /* <====== */ - struct mnode_s *children[2]; - #if USE_REF int numfaces; mface_t *firstface; #endif + + struct mnode_s *children[2]; } mnode_t; typedef struct { @@ -147,16 +147,16 @@ typedef struct { typedef struct { /* ======> */ cplane_t *plane; // always NULL to differentiate from nodes + struct mnode_s *parent; + #if USE_REF vec3_t mins; vec3_t maxs; - unsigned visframe; #endif - struct mnode_s *parent; /* <====== */ - int contents; + int contents[2]; // 0 - original, 1 - merged int cluster; int area; int numleafbrushes; @@ -572,9 +572,9 @@ typedef struct { //#if USE_REF lightgrid_t lightgrid; - qboolean lm_decoupled; -//#endif - qboolean extended; + bool lm_decoupled; + bool extended; // QBSP extended format + bool has_bspx; // has BSPX header char name[1]; } bsp_t; @@ -593,6 +593,7 @@ typedef struct { cplane_t plane; float s, t; float fraction; + vec3_t pos; } lightpoint_t; void BSP_LightPoint(lightpoint_t *point, const vec3_t start, const vec3_t end, const mnode_t *headnode, int nolm_mask); diff --git a/inc/common/cmodel.h b/inc/common/cmodel.h index 6f7359de4..5ac6d9e6f 100644 --- a/inc/common/cmodel.h +++ b/inc/common/cmodel.h @@ -46,7 +46,7 @@ void CM_Init(void); void CM_FreeMap(cm_t *cm); int CM_LoadMap(cm_t *cm, const char *name); -void CM_LoadOverrides(cm_t *cm, char *server, size_t server_size); +void CM_LoadOverride(cm_t *cm, char *server, size_t server_size); const mnode_t *CM_NodeNum(const cm_t *cm, int number); const mleaf_t *CM_LeafNum(const cm_t *cm, int number); @@ -60,25 +60,28 @@ const mleaf_t *CM_LeafNum(const cm_t *cm, int number); const mnode_t *CM_HeadnodeForBox(const vec3_t mins, const vec3_t maxs); // returns an ORed contents mask -static inline int CM_PointContents(const vec3_t p, const mnode_t *headnode) +static inline int CM_PointContents(const vec3_t p, const mnode_t *headnode, bool extended) { if (!headnode) return 0; // map not loaded - return BSP_PointLeaf(headnode, p)->contents; + return BSP_PointLeaf(headnode, p)->contents[extended]; } int CM_TransformedPointContents(const vec3_t p, const mnode_t *headnode, - const vec3_t origin, const vec3_t angles); + const vec3_t origin, const vec3_t angles, + bool extended); void CM_BoxTrace(trace_t *trace, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, - const mnode_t *headnode, int brushmask); + const mnode_t *headnode, int brushmask, + bool extended); void CM_TransformedBoxTrace(trace_t *trace, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, const mnode_t *headnode, int brushmask, - const vec3_t origin, const vec3_t angles); + const vec3_t origin, const vec3_t angles, + bool extended); void CM_ClipEntity(trace_t *dst, const trace_t *src, struct edict_s *ent); // call with topnode set to the headnode, returns with topnode diff --git a/inc/common/common.h b/inc/common/common.h index ffa01ac63..22a3931a2 100644 --- a/inc/common/common.h +++ b/inc/common/common.h @@ -133,23 +133,29 @@ void G_InitializeExtensions(void); #endif #if USE_DEBUG +#define COM_DEVELOPER (developer->integer) #define Com_DPrintf(...) \ - do { if (developer && developer->integer > 0) \ + do { if (developer && developer->integer >= 1) \ Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define Com_DDPrintf(...) \ - do { if (developer && developer->integer > 1) \ + do { if (developer && developer->integer >= 2) \ Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define Com_DDDPrintf(...) \ - do { if (developer && developer->integer > 2) \ + do { if (developer && developer->integer >= 3) \ Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define Com_DDDDPrintf(...) \ - do { if (developer && developer->integer > 3) \ + do { if (developer && developer->integer >= 4) \ Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) +#define Com_DWPrintf(...) \ + do { if (developer && developer->integer >= 1) \ + Com_LPrintf(PRINT_WARNING, __VA_ARGS__); } while (0) #else +#define COM_DEVELOPER 0 #define Com_DPrintf(...) ((void)0) #define Com_DDPrintf(...) ((void)0) #define Com_DDDPrintf(...) ((void)0) #define Com_DDDDPrintf(...) ((void)0) +#define Com_DWPrintf(...) ((void)0) #endif #if USE_TESTS diff --git a/inc/common/crc.h b/inc/common/crc.h new file mode 100644 index 000000000..453796277 --- /dev/null +++ b/inc/common/crc.h @@ -0,0 +1,25 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +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, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once + +uint16_t CRC_Block(const byte *start, size_t count); + +#if USE_CLIENT +byte COM_BlockSequenceCRCByte(const byte *base, size_t length, int sequence); +#endif diff --git a/inc/refresh/refresh.h b/inc/refresh/refresh.h index d8215ddb5..b668cdcdd 100644 --- a/inc/refresh/refresh.h +++ b/inc/refresh/refresh.h @@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #define POWERSUIT_SCALE 4.0f #define WEAPONSHELL_SCALE 0.5f +#define RF_TRACKER BIT_ULL(32) + #define RF_SHELL_MASK (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | \ RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM | RF_SHELL_LITE_GREEN) @@ -60,9 +62,9 @@ typedef struct entity_s { float alpha; // ignore if RF_TRANSLUCENT isn't set color_t rgba; - qhandle_t skin; // NULL for inline skin - int flags; + uint64_t flags; + qhandle_t skin; // NULL for inline skin float scale; } entity_t; @@ -76,6 +78,7 @@ typedef struct { typedef struct { vec3_t origin; int color; // -1 => use rgba + float scale; float alpha; color_t rgba; } particle_t; diff --git a/inc/shared/game.h b/inc/shared/game.h index 6fe4f6b22..9b490be0b 100644 --- a/inc/shared/game.h +++ b/inc/shared/game.h @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define GAME_API_VERSION_OLD 3 // game uses gclient_old_t #define GAME_API_VERSION_AQTION 4 // game uses gclient_t with AQtion extension (aliased to gclient_old_t) -#define GAME_API_VERSION_NEW 3301 // game uses gclient_new_t +#define GAME_API_VERSION_NEW 3302 // game uses gclient_new_t #if USE_NEW_GAME_API #define GAME_API_VERSION GAME_API_VERSION_NEW diff --git a/inc/shared/shared.h b/inc/shared/shared.h index 51a0b7bd5..ec922c368 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -1202,11 +1202,12 @@ typedef struct { vec3_t mins, maxs; // bounding box size struct edict_s *groundentity; + cplane_t groundplane; int watertype; int waterlevel; // callbacks to test the world - trace_t (* q_gameabi trace)(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end); + trace_t (* q_gameabi trace)(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int contentmask); int (*pointcontents)(const vec3_t point); } pmove_new_t; #endif @@ -1453,6 +1454,7 @@ enum { SPLASH_SLIME, SPLASH_LAVA, SPLASH_BLOOD, + SPLASH_ELECTRIC_N64, // KEX }; // sound channels diff --git a/inc/system/pthread.h b/inc/system/pthread.h index bb6fc18e7..5547414e7 100644 --- a/inc/system/pthread.h +++ b/inc/system/pthread.h @@ -44,11 +44,11 @@ typedef struct { void *(*func)(void *); void *arg, *ret; HANDLE handle; -} pthread_t; +} *pthread_t; static unsigned __stdcall thread_func(void *arg) { - pthread_t *t = arg; + pthread_t t = arg; t->ret = t->func(t->arg); return 0; } @@ -56,18 +56,27 @@ static unsigned __stdcall thread_func(void *arg) static inline int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { - thread->func = start_routine; - thread->arg = arg; - thread->handle = (HANDLE)_beginthreadex(NULL, 0, thread_func, thread, 0, NULL); - return thread->handle ? 0 : EAGAIN; + pthread_t t = calloc(1, sizeof(*t)); + if (!t) + return EAGAIN; + t->func = start_routine; + t->arg = arg; + t->handle = (HANDLE)_beginthreadex(NULL, 0, thread_func, t, 0, NULL); + if (!t->handle) { + free(t); + return EAGAIN; + } + *thread = t; + return 0; } static inline int pthread_join(pthread_t thread, void **retval) { - int ret = WaitForSingleObject(thread.handle, INFINITE); - CloseHandle(thread.handle); + int ret = WaitForSingleObject(thread->handle, INFINITE); + CloseHandle(thread->handle); if (retval) - *retval = thread.ret; + *retval = thread->ret; + free(thread); return ret ? EINVAL : 0; } diff --git a/meson.build b/meson.build index 3fd39b7bc..f8cd0e29f 100644 --- a/meson.build +++ b/meson.build @@ -13,6 +13,7 @@ common_src = [ 'src/common/cmd.c', 'src/common/cmodel.c', 'src/common/common.c', + 'src/common/crc.c', 'src/common/cvar.c', 'src/common/error.c', 'src/common/field.c', @@ -37,7 +38,6 @@ common_src = [ client_src = [ 'src/client/ascii.c', 'src/client/console.c', - 'src/client/crc.c', 'src/client/demo.c', 'src/client/download.c', 'src/client/effects.c', diff --git a/src/client/ascii.c b/src/client/ascii.c index 566222894..0a058bc89 100644 --- a/src/client/ascii.c +++ b/src/client/ascii.c @@ -233,7 +233,7 @@ static void TH_DrawLayoutString(char *dst, const char *s) width = Q_atoi(token); token = COM_Parse(&s); value = Q_atoi(token); - if (value < 0 || value >= MAX_STATS) { + if (value < 0 || value >= cl.max_stats) { Com_Error(ERR_DROP, "%s: invalid stat index for num: %i", __func__, value); } value = cl.frame.ps.stats[value]; @@ -244,7 +244,7 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (!strcmp(token, "stat_string")) { token = COM_Parse(&s); index = Q_atoi(token); - if (index < 0 || index >= MAX_STATS) { + if (index < 0 || index >= cl.max_stats) { Com_Error(ERR_DROP, "%s: invalid string index for stat_string: %i", __func__, index); } index = cl.frame.ps.stats[index]; @@ -273,7 +273,7 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (!strcmp(token, "if")) { token = COM_Parse(&s); value = Q_atoi(token); - if (value < 0 || value >= MAX_STATS) { + if (value < 0 || value >= cl.max_stats) { Com_Error(ERR_DROP, "%s: invalid stat index for if: %i", __func__, value); } value = cl.frame.ps.stats[value]; diff --git a/src/client/client.h b/src/client/client.h index d18a3039c..11926aa4f 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -200,6 +200,7 @@ typedef struct { server_frame_t frames[UPDATE_BACKUP]; unsigned frameflags; + int suppress_count; server_frame_t frame; // received from server server_frame_t oldframe; @@ -270,6 +271,7 @@ typedef struct { char gamedir[MAX_QPATH]; int clientNum; // never changed during gameplay, set by serverdata packet int maxclients; + int max_stats; pmoveParams_t pmp; #if USE_FPS @@ -324,6 +326,8 @@ typedef struct { unsigned hit_marker_time; int hit_marker_count; + + player_fog_t custom_fog; } client_state_t; extern client_state_t cl; @@ -557,10 +561,10 @@ extern cvar_t *cl_enhanced_footsteps; #if USE_DEBUG #define SHOWNET(level, ...) \ - do { if (cl_shownet->integer > level) \ + do { if (cl_shownet->integer >= level) \ Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define SHOWCLAMP(level, ...) \ - do { if (cl_showclamp->integer > level) \ + do { if (cl_showclamp->integer >= level) \ Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define SHOWMISS(...) \ do { if (cl_showmiss->integer) \ @@ -776,6 +780,9 @@ bool CL_SeekDemoMessage(void); EF_TRACKERTRAIL | EF_TRACKER | EF_GREENGIB | EF_IONRIPPER | \ EF_BLUEHYPERBLASTER | EF_PLASMA) +#define IS_TRACKER(effects) \ + (((effects) & (EF_TRACKERTRAIL | EF_TRACKER)) == EF_TRACKERTRAIL) + void CL_DeltaFrame(void); void CL_AddEntities(void); void CL_CalcViewValues(void); @@ -877,6 +884,7 @@ typedef struct cparticle_s { vec3_t vel; vec3_t accel; int color; // -1 => use rgba + float scale; float alpha; float alphavel; color_t rgba; @@ -1035,6 +1043,7 @@ void SCR_LagSample(void); void SCR_LagClear(void); void init_lag_graph_dimensions(void); void SCR_SetCrosshairColor(void); +void SCR_AddNetgraph(void); float SCR_FadeAlpha(unsigned startTime, unsigned visTime, unsigned fadeTime); int SCR_DrawStringEx(int x, int y, int flags, size_t maxlen, const char *s, qhandle_t font); diff --git a/src/client/console.c b/src/client/console.c index 4a07da351..c72143ec2 100644 --- a/src/client/console.c +++ b/src/client/console.c @@ -372,7 +372,7 @@ void Con_CheckResize(void) con.vidWidth = Q_rint(r_config.width * con.scale); con.vidHeight = Q_rint(r_config.height * con.scale); - con.linewidth = Q_clip(con.vidWidth / CHAR_WIDTH - 2, 0, CON_LINEWIDTH); + con.linewidth = Q_clip(con.vidWidth / CONCHAR_WIDTH - 2, 0, CON_LINEWIDTH); con.prompt.inputLine.visibleChars = con.linewidth; con.prompt.widthInChars = con.linewidth; con.chatPrompt.inputLine.visibleChars = con.linewidth; @@ -693,7 +693,7 @@ static int Con_DrawLine(int v, int row, float alpha, bool notify) const consoleLine_t *line = &con.text[row & CON_TOTALLINES_MASK]; const char *s = line->text; int flags = 0; - int x = CHAR_WIDTH; + int x = CONCHAR_WIDTH; int w = con.linewidth; if (notify) { @@ -724,7 +724,7 @@ static int Con_DrawLine(int v, int row, float alpha, bool notify) return R_DrawString(x, v, flags, w, s, con.charsetImage); } -#define CON_PRESTEP (CHAR_HEIGHT * 3 + CHAR_HEIGHT / 4) +#define CON_PRESTEP (CONCHAR_HEIGHT * 3 + CONCHAR_HEIGHT / 4) /* ================ @@ -775,7 +775,7 @@ static void Con_DrawNotify(void) Con_DrawLine(v, i, alpha, true); - v += CHAR_HEIGHT; + v += CONCHAR_HEIGHT; } R_ClearColor(); @@ -789,10 +789,10 @@ static void Con_DrawNotify(void) skip = 5; } - R_DrawString(CHAR_WIDTH, v, 0, MAX_STRING_CHARS, text, + R_DrawString(CONCHAR_WIDTH, v, 0, MAX_STRING_CHARS, text, con.charsetImage); con.chatPrompt.inputLine.visibleChars = con.linewidth - skip + 1; - IF_Draw(&con.chatPrompt.inputLine, skip * CHAR_WIDTH, v, + IF_Draw(&con.chatPrompt.inputLine, skip * CONCHAR_WIDTH, v, UI_DRAWCURSOR, con.charsetImage); } } @@ -836,16 +836,16 @@ static void Con_DrawSolidConsole(void) // draw the text y = vislines - CON_PRESTEP; - rows = y / CHAR_HEIGHT + 1; // rows of text to draw + rows = y / CONCHAR_HEIGHT + 1; // rows of text to draw // draw arrows to show the buffer is backscrolled if (con.display != con.current) { R_SetColor(U32_RED); for (i = 1; i < con.linewidth / 2; i += 4) { - R_DrawChar(i * CHAR_WIDTH, y, 0, '^', con.charsetImage); + R_DrawChar(i * CONCHAR_WIDTH, y, 0, '^', con.charsetImage); } - y -= CHAR_HEIGHT; + y -= CONCHAR_HEIGHT; rows--; } @@ -864,7 +864,7 @@ static void Con_DrawSolidConsole(void) widths[i] = x; } - y -= CHAR_HEIGHT; + y -= CONCHAR_HEIGHT; row--; } @@ -913,8 +913,8 @@ static void Con_DrawSolidConsole(void) Q_strlcat(buffer, suf, sizeof(buffer)); // draw it - y = vislines - CON_PRESTEP + CHAR_HEIGHT * 2; - R_DrawString(CHAR_WIDTH, y, 0, con.linewidth, buffer, con.charsetImage); + y = vislines - CON_PRESTEP + CONCHAR_HEIGHT * 2; + R_DrawString(CONCHAR_WIDTH, y, 0, con.linewidth, buffer, con.charsetImage); } else if (cls.state == ca_loading) { // draw loading state switch (con.loadstate) { @@ -942,35 +942,35 @@ static void Con_DrawSolidConsole(void) Q_snprintf(buffer, sizeof(buffer), "Loading %s...", text); // draw it - y = vislines - CON_PRESTEP + CHAR_HEIGHT * 2; - R_DrawString(CHAR_WIDTH, y, 0, con.linewidth, buffer, con.charsetImage); + y = vislines - CON_PRESTEP + CONCHAR_HEIGHT * 2; + R_DrawString(CONCHAR_WIDTH, y, 0, con.linewidth, buffer, con.charsetImage); } } // draw the input prompt, user text, and cursor if desired x = 0; if (cls.key_dest & KEY_CONSOLE) { - y = vislines - CON_PRESTEP + CHAR_HEIGHT; + y = vislines - CON_PRESTEP + CONCHAR_HEIGHT; // draw command prompt i = con.mode == CON_REMOTE ? '#' : 17; R_SetColor(U32_YELLOW); - R_DrawChar(CHAR_WIDTH, y, 0, i, con.charsetImage); + R_DrawChar(CONCHAR_WIDTH, y, 0, i, con.charsetImage); R_ClearColor(); // draw input line - x = IF_Draw(&con.prompt.inputLine, 2 * CHAR_WIDTH, y, + x = IF_Draw(&con.prompt.inputLine, 2 * CONCHAR_WIDTH, y, UI_DRAWCURSOR, con.charsetImage); } #define APP_VERSION APPLICATION " " VERSION -#define VER_WIDTH ((int)(sizeof(APP_VERSION) + 1) * CHAR_WIDTH) +#define VER_WIDTH ((int)(sizeof(APP_VERSION) + 1) * CONCHAR_WIDTH) - y = vislines - CON_PRESTEP + CHAR_HEIGHT; + y = vislines - CON_PRESTEP + CONCHAR_HEIGHT; row = 0; // shift version upwards to prevent overdraw if (x > con.vidWidth - VER_WIDTH) { - y -= CHAR_HEIGHT; + y -= CONCHAR_HEIGHT; row++; } @@ -978,17 +978,17 @@ static void Con_DrawSolidConsole(void) // draw clock if (con_clock->integer) { - x = Com_Time_m(buffer, sizeof(buffer)) * CHAR_WIDTH; - if (widths[row] + x + CHAR_WIDTH <= con.vidWidth) { - R_DrawString(con.vidWidth - CHAR_WIDTH - x, y - CHAR_HEIGHT, + x = Com_Time_m(buffer, sizeof(buffer)) * CONCHAR_WIDTH; + if (widths[row] + x + CONCHAR_WIDTH <= con.vidWidth) { + R_DrawString(con.vidWidth - CONCHAR_WIDTH - x, y - CONCHAR_HEIGHT, UI_RIGHT, MAX_STRING_CHARS, buffer, con.charsetImage); } } // draw version if (!row || widths[0] + VER_WIDTH <= con.vidWidth) { - SCR_DrawStringEx(con.vidWidth - CHAR_WIDTH, y, UI_RIGHT, - MAX_STRING_CHARS, VERSION, con.charsetImage); + SCR_DrawStringEx(con.vidWidth - CONCHAR_WIDTH, y, UI_RIGHT, + MAX_STRING_CHARS, APP_VERSION, con.charsetImage); } // restore rendering parameters diff --git a/src/client/demo.c b/src/client/demo.c index 317b07334..e04907452 100644 --- a/src/client/demo.c +++ b/src/client/demo.c @@ -166,7 +166,7 @@ static void emit_delta_frame(const server_frame_t *from, const server_frame_t *t MSG_WriteLong(tonum); MSG_WriteLong(fromnum); // what we are delta'ing from if (cls.serverProtocol != PROTOCOL_VERSION_OLD) - MSG_WriteByte(0); // rate dropped packets + MSG_WriteByte(cl.suppress_count); // rate dropped packets // send over the areabits MSG_WriteByte(to->areabytes); @@ -756,6 +756,7 @@ static void CL_PlayDemo_f(void) Q_strlcpy(cls.servername, COM_SkipPath(name), sizeof(cls.servername)); cls.serverAddress.type = NA_LOOPBACK; cl.csr = cs_remap_old; + cl.max_stats = MAX_STATS_OLD; Con_Popup(true); SCR_UpdateScreen(); diff --git a/src/client/download.c b/src/client/download.c index b18a2934a..a4dfe5670 100644 --- a/src/client/download.c +++ b/src/client/download.c @@ -826,7 +826,7 @@ void CL_RequestNextDownload(void) if (allow_download_textures->integer) { for (i = 0; i < cl.bsp->numtexinfo; i++) { - if (cl.bsp->texinfo[i].c.flags & SURF_NODRAW) + if (cl.bsp->texinfo[i].c.flags & SURF_NODRAW && cl.bsp->has_bspx) continue; if (r_override_textures->integer == 2 || (r_texture_overrides->integer & 16)) { len = Q_concat(fn, sizeof(fn), "textures/", cl.bsp->texinfo[i].name, ".jpg"); diff --git a/src/client/effects.c b/src/client/effects.c index 945fc256f..090d277fd 100644 --- a/src/client/effects.c +++ b/src/client/effects.c @@ -847,6 +847,7 @@ cparticle_t *CL_AllocParticle(void) p->next = active_particles; active_particles = p; + p->scale = 1.0f; return p; } @@ -1708,6 +1709,7 @@ void CL_AddParticles(void) part->rgba = p->rgba; part->color = p->color; part->alpha = min(alpha, 1.0f); + part->scale = p->scale; if (p->alphavel == INSTANT_PARTICLE) { p->alphavel = 0.0f; diff --git a/src/client/entities.c b/src/client/entities.c index 9691c8cb2..cb6a54369 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -826,6 +826,9 @@ static void CL_AddPacketEntities(void) ent.scale = s1->scale; + if (IS_TRACKER(effects)) + ent.flags |= RF_TRACKER; + // add to refresh list V_AddEntity(&ent); @@ -876,12 +879,17 @@ static void CL_AddPacketEntities(void) ent.alpha = s1->alpha; } + if (IS_TRACKER(effects)) + ent.flags |= RF_TRACKER; + // duplicate for linked models if (s1->modelindex2) { if (s1->modelindex2 == MODELINDEX_PLAYER) { // custom weapon ci = &cl.clientinfo[s1->skinnum & 0xff]; i = (s1->skinnum >> 8); // 0 is default weapon model + if (cl.csr.extended) + i &= 0xff; if (i < 0 || i > cl.numWeaponModels - 1) i = 0; ent.model = ci->weaponmodel[i]; @@ -913,6 +921,9 @@ static void CL_AddPacketEntities(void) ent.alpha = s1->alpha; } + if (IS_TRACKER(effects)) + ent.flags |= RF_TRACKER; + if (s1->modelindex3) { ent.model = cl.model_draw[s1->modelindex3]; V_AddEntity(&ent); @@ -992,11 +1003,14 @@ static void CL_AddPacketEntities(void) } else if (effects & EF_FLIES) { CL_FlyEffect(cent, ent.origin); } else if (effects & EF_BFG) { + static const uint16_t bfg_lightramp[6] = {300, 400, 600, 300, 150, 75}; if (effects & EF_ANIM_ALLFAST) { CL_BfgParticles(&ent); i = 200; + } else if (cl.csr.extended) { + i = bfg_lightramp[Q_clip(ent.oldframe, 0, 5)] * ent.backlerp + + bfg_lightramp[Q_clip(ent.frame, 0, 5)] * (1.0f - ent.backlerp); } else { - static const uint16_t bfg_lightramp[6] = {300, 400, 600, 300, 150, 75}; i = bfg_lightramp[Q_clip(s1->frame, 0, 5)]; } V_AddLight(ent.origin, i, 0, 1, 0); @@ -1086,8 +1100,13 @@ static int shell_effect_hack(void) flags |= RF_SHELL_DOUBLE; if (ent->current.effects & EF_HALF_DAMAGE) flags |= RF_SHELL_HALF_DAM; - if (ent->current.morefx & EFX_DUALFIRE) - flags |= RF_SHELL_LITE_GREEN; + + if (cl.csr.extended) { + if (ent->current.morefx & EFX_DUALFIRE) + flags |= RF_SHELL_LITE_GREEN; + if (ent->current.effects & EF_COLOR_SHELL) + flags |= ent->current.renderfx & RF_SHELL_MASK; + } return flags; } @@ -1270,7 +1289,7 @@ static void CL_SetupThirdPersionView(void) VectorMA(cl.refdef.vieworg, -range * rscale, cl.v_right, cl.refdef.vieworg); CM_BoxTrace(&trace, cl.playerEntityOrigin, cl.refdef.vieworg, - mins, maxs, cl.bsp->nodes, MASK_SOLID); + mins, maxs, cl.bsp->nodes, MASK_SOLID, cl.csr.extended); if (trace.fraction != 1.0f) { VectorCopy(trace.endpos, cl.refdef.vieworg); } @@ -1377,9 +1396,6 @@ void CL_CalcViewValues(void) LerpVector(ops->viewoffset, ps->viewoffset, lerp, viewoffset); // smooth out stair climbing - if (cl.predicted_step < 127 * 0.125f) { - delta <<= 1; // small steps - } if (delta < 100) { cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01f; } @@ -1438,9 +1454,16 @@ void CL_CalcViewValues(void) LerpAngles(ops->viewangles, ps->viewangles, lerp, cl.refdef.viewangles); } - // don't interpolate blend color - Vector4Copy(ps->blend, cl.refdef.screen_blend); - Vector4Copy(ps->damage_blend, cl.refdef.damage_blend); + // interpolate blend + if (cl.csr.extended && ops->blend[3]) + lerp_values(ops->blend, ps->blend, lerp, cl.refdef.screen_blend, 4); + else + Vector4Copy(ps->blend, cl.refdef.screen_blend); + + if (cl.csr.extended && ops->damage_blend[3]) + lerp_values(ops->damage_blend, ps->damage_blend, lerp, cl.refdef.damage_blend, 4); + else + Vector4Copy(ps->damage_blend, cl.refdef.damage_blend); // interpolate fog if (cl.psFlags & MSG_PS_MOREBITS) { diff --git a/src/client/input.c b/src/client/input.c index 4a4fdc5c0..8bbc187b9 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., // cl.input.c -- builds an intended movement command to send to the server #include "client.h" +#include "common/crc.h" static cvar_t *cl_nodelta; static cvar_t *cl_maxpackets; @@ -958,10 +959,8 @@ CL_SendBatchedCmd */ static void CL_SendBatchedCmd(void) { - int i, j, seq, bits q_unused; - int numCmds, numDups; - int totalCmds, totalMsec; - int cursize q_unused; + int i, j, seq, numCmds, numDups; + q_unused int totalCmds, totalMsec, cursize, bits; usercmd_t *cmd, *oldcmd; client_history_t *history, *oldest; byte *patch; diff --git a/src/client/locs.c b/src/client/locs.c index c5f1c9e97..bfeba459e 100644 --- a/src/client/locs.c +++ b/src/client/locs.c @@ -151,7 +151,7 @@ static location_t *LOC_FindClosest(const vec3_t pos) if (loc_trace->integer) { CM_BoxTrace(&trace, pos, loc->origin, vec3_origin, vec3_origin, - cl.bsp->nodes, MASK_SOLID); + cl.bsp->nodes, MASK_SOLID, cl.csr.extended); if (trace.fraction != 1.0f) { continue; } @@ -239,7 +239,7 @@ static size_t LOC_There_m(char *buffer, size_t size) VectorMA(cl.playerEntityOrigin, 8192, cl.v_forward, pos); CM_BoxTrace(&trace, cl.playerEntityOrigin, pos, vec3_origin, - vec3_origin, cl.bsp->nodes, MASK_SOLID); + vec3_origin, cl.bsp->nodes, MASK_SOLID, cl.csr.extended); loc = LOC_FindClosest(trace.endpos); } diff --git a/src/client/main.c b/src/client/main.c index f31727059..d1ae3dd0c 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -1440,6 +1440,7 @@ static void CL_ConnectionlessPacket(void) cls.connect_count = 0; Q_strlcpy(cl.mapname, mapname, sizeof(cl.mapname)); // for levelshot screen cl.csr = cs_remap_old; + cl.max_stats = MAX_STATS_OLD; return; } @@ -1529,8 +1530,12 @@ static void CL_PacketEvent(void) cls.errorReceived = false; // don't drop #endif + cl.suppress_count = 0; + CL_ParseServerMessage(); + SCR_AddNetgraph(); + SCR_LagSample(); // if recording demo, write the message out @@ -1788,7 +1793,7 @@ void CL_LoadFilterList(string_entry_t **list, const char *name, const char *comm { string_entry_t *entry, *next; char *raw, *data, *p; - int len, count, line; + int len, count q_unused, line; // free previous entries for (entry = *list; entry; entry = next) { @@ -2339,7 +2344,7 @@ static size_t CL_Surface_m(char *buffer, size_t size) VectorMA(cl.refdef.vieworg, 8192, cl.v_forward, end); CL_Trace(&trace, cl.refdef.vieworg, end, vec3_origin, vec3_origin, MASK_SOLID | MASK_WATER); - return Q_strlcpy(buffer, trace.surface->name, size); + return Q_snprintf(buffer, size, "%s %#x", trace.surface->name, trace.surface->flags); } /* @@ -3005,35 +3010,35 @@ static void CL_SetClientTime(void) prevtime = cl.servertime - CL_FRAMETIME; if (cl.time > cl.servertime) { - SHOWCLAMP(1, "high clamp %i\n", cl.time - cl.servertime); + SHOWCLAMP(2, "high clamp %i\n", cl.time - cl.servertime); cl.time = cl.servertime; cl.lerpfrac = 1.0f; } else if (cl.time < prevtime) { - SHOWCLAMP(1, "low clamp %i\n", prevtime - cl.time); + SHOWCLAMP(2, "low clamp %i\n", prevtime - cl.time); cl.time = prevtime; cl.lerpfrac = 0; } else { cl.lerpfrac = (cl.time - prevtime) * CL_1_FRAMETIME; } - SHOWCLAMP(2, "time %d %d, lerpfrac %.3f\n", + SHOWCLAMP(3, "time %d %d, lerpfrac %.3f\n", cl.time, cl.servertime, cl.lerpfrac); #if USE_FPS prevtime = cl.keyservertime - BASE_FRAMETIME; if (cl.keytime > cl.keyservertime) { - SHOWCLAMP(1, "high keyclamp %i\n", cl.keytime - cl.keyservertime); + SHOWCLAMP(2, "high keyclamp %i\n", cl.keytime - cl.keyservertime); cl.keytime = cl.keyservertime; cl.keylerpfrac = 1.0f; } else if (cl.keytime < prevtime) { - SHOWCLAMP(1, "low keyclamp %i\n", prevtime - cl.keytime); + SHOWCLAMP(2, "low keyclamp %i\n", prevtime - cl.keytime); cl.keytime = prevtime; cl.keylerpfrac = 0; } else { cl.keylerpfrac = (cl.keytime - prevtime) * BASE_1_FRAMETIME; } - SHOWCLAMP(2, "keytime %d %d keylerpfrac %.3f\n", + SHOWCLAMP(3, "keytime %d %d keylerpfrac %.3f\n", cl.keytime, cl.keyservertime, cl.keylerpfrac); #endif } diff --git a/src/client/newfx.c b/src/client/newfx.c index 70650217d..d8eade9b7 100644 --- a/src/client/newfx.c +++ b/src/client/newfx.c @@ -338,31 +338,44 @@ void CL_TrackerTrail(centity_t *ent, const vec3_t end) VectorCopy(move, ent->lerp_origin); } +// Marsaglia 1972 rejection method static void RandomDir(vec3_t dir) { - dir[0] = crand(); - dir[1] = crand(); - dir[2] = crand(); - VectorNormalize(dir); + float x, y, s, a; + + do { + x = crand(); + y = crand(); + s = x * x + y * y; + } while (s > 1); + + a = 2 * sqrtf(1 - s); + dir[0] = x * a; + dir[1] = y * a; + dir[2] = -1 + 2 * s; } void CL_Tracker_Shell(const centity_t *ent, const vec3_t origin) { vec3_t org, dir, mid; - int i; + int i, count; cparticle_t *p; - float radius; + float radius, scale; if (cl.csr.extended) { VectorAvg(ent->mins, ent->maxs, mid); VectorAdd(origin, mid, org); radius = ent->radius; + scale = Q_clipf(ent->radius / 40.0f, 1, 2); + count = 300 * scale; } else { VectorCopy(origin, org); radius = 40.0f; + scale = 1.0f; + count = 300; } - for (i = 0; i < 300; i++) { + for (i = 0; i < count; i++) { p = CL_AllocParticle(); if (!p) return; @@ -373,6 +386,7 @@ void CL_Tracker_Shell(const centity_t *ent, const vec3_t origin) p->alpha = 1.0f; p->alphavel = INSTANT_PARTICLE; p->color = 0; + p->scale = scale; RandomDir(dir); VectorMA(org, radius, dir, p->org); diff --git a/src/client/null.c b/src/client/null.c index 81c2f1705..db3f319a0 100644 --- a/src/client/null.c +++ b/src/client/null.c @@ -33,3 +33,7 @@ void CL_PreInit(void) for (int i = 0; i < q_countof(nullcmds); i++) Cmd_AddCommand(nullcmds[i], NULL); } + +void SCR_DebugGraph(float value, int color) +{ +} diff --git a/src/client/parse.c b/src/client/parse.c index 3d75ebf10..9ecdb8f47 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -45,7 +45,7 @@ static void CL_ParseDeltaEntity(server_frame_t *frame, frame->numEntities++; #if USE_DEBUG - if (cl_shownet->integer > 2 && bits) { + if (cl_shownet->integer >= 3 && bits) { MSG_ShowDeltaEntityBits(bits); Com_LPrintf(PRINT_DEVELOPER, "\n"); } @@ -112,7 +112,7 @@ static void CL_ParsePacketEntities(const server_frame_t *oldframe, server_frame_ while (oldnum < newnum) { // one or more entities from the old packet are unchanged - SHOWNET(3, " unchanged:%i\n", oldnum); + SHOWNET(4, " unchanged:%i\n", oldnum); CL_ParseDeltaEntity(frame, oldnum, oldstate, 0); oldindex++; @@ -128,7 +128,7 @@ static void CL_ParsePacketEntities(const server_frame_t *oldframe, server_frame_ if (bits & U_REMOVE) { // the entity present in oldframe is not in the current frame - SHOWNET(2, "%3u:remove:%i\n", readcount, newnum); + SHOWNET(3, "%3u:remove:%i\n", readcount, newnum); if (oldnum != newnum) { Com_DPrintf("U_REMOVE: oldnum != newnum\n"); } @@ -150,10 +150,10 @@ static void CL_ParsePacketEntities(const server_frame_t *oldframe, server_frame_ if (oldnum == newnum) { // delta from previous state - SHOWNET(2, "%3u:delta:%i ", readcount, newnum); + SHOWNET(3, "%3u:delta:%i ", readcount, newnum); CL_ParseDeltaEntity(frame, newnum, oldstate, bits); if (!bits) { - SHOWNET(2, "\n"); + SHOWNET(3, "\n"); } oldindex++; @@ -170,10 +170,10 @@ static void CL_ParsePacketEntities(const server_frame_t *oldframe, server_frame_ if (oldnum > newnum) { // delta from baseline - SHOWNET(2, "%3u:baseline:%i ", readcount, newnum); + SHOWNET(3, "%3u:baseline:%i ", readcount, newnum); CL_ParseDeltaEntity(frame, newnum, &cl.baselines[newnum], bits); if (!bits) { - SHOWNET(2, "\n"); + SHOWNET(3, "\n"); } continue; } @@ -182,7 +182,7 @@ static void CL_ParsePacketEntities(const server_frame_t *oldframe, server_frame_ // any remaining entities in the old frame are copied over while (oldnum != MAX_EDICTS) { // one or more entities from the old packet are unchanged - SHOWNET(3, " unchanged:%i\n", oldnum); + SHOWNET(4, " unchanged:%i\n", oldnum); CL_ParseDeltaEntity(frame, oldnum, oldstate, 0); oldindex++; @@ -253,9 +253,15 @@ static void CL_ParseFrame(int extrabits) // CLIENTDROP is implied, don't draw both suppressed &= ~FF_CLIENTDROP; } + if (suppressed & FF_SUPPRESSED) { + cl.suppress_count = 1; + } cl.frameflags |= suppressed; - } else if (suppressed) { - cl.frameflags |= FF_SUPPRESSED; + } else { + if (suppressed) { + cl.frameflags |= FF_SUPPRESSED; + } + cl.suppress_count = suppressed; } extraflags = (extrabits << 4) | (bits >> SUPPRESSCOUNT_BITS); } else { @@ -268,7 +274,7 @@ static void CL_ParseFrame(int extrabits) // BIG HACK to let old demos continue to work if (cls.serverProtocol != PROTOCOL_VERSION_OLD) { - suppressed = MSG_ReadByte(); + cl.suppress_count = suppressed = MSG_ReadByte(); if (suppressed) { cl.frameflags |= FF_SUPPRESSED; } @@ -333,7 +339,7 @@ static void CL_ParseFrame(int extrabits) frame.areabytes = 0; } - SHOWNET(2, "%3u:playerinfo\n", msg_read.readcount); + SHOWNET(3, "%3u:playerinfo\n", msg_read.readcount); if (cls.serverProtocol <= PROTOCOL_VERSION_DEFAULT || cls.serverProtocol == PROTOCOL_VERSION_AQTION) { if (MSG_ReadByte() != svc_playerinfo) { @@ -369,7 +375,7 @@ static void CL_ParseFrame(int extrabits) } else if (cls.serverProtocol > PROTOCOL_VERSION_DEFAULT) { MSG_ParseDeltaPlayerstate_Enhanced(from, &frame.ps, bits, extraflags, cl.psFlags); #if USE_DEBUG - if (cl_shownet->integer > 2 && (bits || extraflags)) { + if (cl_shownet->integer >= 3 && (bits || extraflags)) { Com_LPrintf(PRINT_DEVELOPER, " "); MSG_ShowDeltaPlayerstateBits_Enhanced(bits, extraflags); Com_LPrintf(PRINT_DEVELOPER, "\n"); @@ -395,7 +401,7 @@ static void CL_ParseFrame(int extrabits) } else { MSG_ParseDeltaPlayerstate_Default(from, &frame.ps, bits, cl.psFlags); #if USE_DEBUG - if (cl_shownet->integer > 2 && bits) { + if (cl_shownet->integer >= 3 && bits) { Com_LPrintf(PRINT_DEVELOPER, " "); MSG_ShowDeltaPlayerstateBits_Default(bits); Com_LPrintf(PRINT_DEVELOPER, "\n"); @@ -404,7 +410,7 @@ static void CL_ParseFrame(int extrabits) frame.clientNum = cl.clientNum; } - SHOWNET(2, "%3u:packetentities\n", msg_read.readcount); + SHOWNET(3, "%3u:packetentities\n", msg_read.readcount); // parse packetentities if (cls.serverProtocol <= PROTOCOL_VERSION_DEFAULT || cls.serverProtocol == PROTOCOL_VERSION_AQTION) { @@ -419,7 +425,7 @@ static void CL_ParseFrame(int extrabits) cl.frames[currentframe & UPDATE_MASK] = frame; #if USE_DEBUG - if (cl_shownet->integer > 2) { + if (cl_shownet->integer >= 3) { int seq = cls.netchan.incoming_acknowledged & CMD_MASK; int rtt = cls.demo.playback ? 0 : cls.realtime - cl.history[seq].sent; Com_LPrintf(PRINT_DEVELOPER, "%3u:frame:%d delta:%d rtt:%d\n", @@ -480,7 +486,7 @@ static void CL_ParseConfigstring(int index) maxlen = Com_ConfigstringSize(&cl.csr, index); len = MSG_ReadString(s, maxlen); - SHOWNET(2, " %d \"%s\"\n", index, Com_MakePrintable(s)); + SHOWNET(3, " %d \"%s\"\n", index, Com_MakePrintable(s)); if (len >= maxlen) { Com_WPrintf( @@ -510,7 +516,7 @@ static void CL_ParseBaseline(int index, uint64_t bits) } #if USE_DEBUG - if (cl_shownet->integer > 2) { + if (cl_shownet->integer >= 3) { Com_LPrintf(PRINT_DEVELOPER, " baseline:%i ", index); MSG_ShowDeltaEntityBits(bits); Com_LPrintf(PRINT_DEVELOPER, "\n"); @@ -802,6 +808,8 @@ static void CL_ParseServerData(void) } } + cl.max_stats = (cl.psFlags & MSG_PS_EXTENSIONS_2) ? MAX_STATS_NEW : MAX_STATS_OLD; + // use full extended flags unless writing backward compatible demo cls.demo.esFlags = cl.csr.extended ? CL_ES_EXTENDED_MASK_2 : 0; cls.demo.psFlags = cl.csr.extended ? CL_PS_EXTENDED_MASK_2 : 0; @@ -1054,7 +1062,7 @@ static void CL_ParseStartSoundPacket(void) if (flags & SND_POS) CL_ReadPos(snd.pos); - SHOWNET(2, " %s\n", cl.configstrings[cl.csr.sounds + snd.index]); + SHOWNET(3, " %s\n", cl.configstrings[cl.csr.sounds + snd.index]); } static void CL_ParseReconnect(void) @@ -1143,7 +1151,7 @@ static void CL_ParsePrint(void) level = MSG_ReadByte(); MSG_ReadString(s, sizeof(s)); - SHOWNET(2, " %i \"%s\"\n", level, Com_MakePrintable(s)); + SHOWNET(3, " %i \"%s\"\n", level, Com_MakePrintable(s)); if (level != PRINT_CHAT) { if (cl.csr.extended && (level == PRINT_TYPEWRITER || level == PRINT_CENTER)) @@ -1204,7 +1212,7 @@ static void CL_ParseCenterPrint(void) char s[MAX_STRING_CHARS]; MSG_ReadString(s, sizeof(s)); - SHOWNET(2, " \"%s\"\n", Com_MakePrintable(s)); + SHOWNET(3, " \"%s\"\n", Com_MakePrintable(s)); SCR_CenterPrint(s, false); if (!cls.demo.playback && cl.serverstate != ss_broadcast) { @@ -1218,14 +1226,14 @@ static void CL_ParseStuffText(void) char s[MAX_STRING_CHARS]; MSG_ReadString(s, sizeof(s)); - SHOWNET(2, " \"%s\"\n", Com_MakePrintable(s)); + SHOWNET(3, " \"%s\"\n", Com_MakePrintable(s)); Cbuf_AddText(&cl_cmdbuf, s); } static void CL_ParseLayout(void) { MSG_ReadString(cl.layout, sizeof(cl.layout)); - SHOWNET(2, " \"%s\"\n", Com_MakePrintable(cl.layout)); + SHOWNET(3, " \"%s\"\n", Com_MakePrintable(cl.layout)); } static void CL_ParseInventory(void) @@ -1446,7 +1454,7 @@ void CL_ParseServerMessage(void) #if USE_DEBUG if (cl_shownet->integer == 1) { Com_LPrintf(PRINT_DEVELOPER, "%u ", msg_read.cursize); - } else if (cl_shownet->integer > 1) { + } else if (cl_shownet->integer >= 2) { Com_LPrintf(PRINT_DEVELOPER, "------------------\n"); } #endif @@ -1459,7 +1467,7 @@ void CL_ParseServerMessage(void) while (1) { readcount = msg_read.readcount; if (readcount == msg_read.cursize) { - SHOWNET(1, "%3u:END OF MESSAGE\n", readcount); + SHOWNET(2, "%3u:END OF MESSAGE\n", readcount); break; } @@ -1470,10 +1478,7 @@ void CL_ParseServerMessage(void) extrabits = cmd >> SVCMD_BITS; cmd &= SVCMD_MASK; - if (cmd == svc_extend) - cmd = MSG_ReadByte(); - - SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); + SHOWNET(2, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); // other commands switch (cmd) { @@ -1669,7 +1674,7 @@ bool CL_SeekDemoMessage(void) #if USE_DEBUG if (cl_shownet->integer == 1) { Com_LPrintf(PRINT_DEVELOPER, "%u ", msg_read.cursize); - } else if (cl_shownet->integer > 1) { + } else if (cl_shownet->integer >= 2) { Com_LPrintf(PRINT_DEVELOPER, "------------------\n"); } #endif @@ -1681,12 +1686,12 @@ bool CL_SeekDemoMessage(void) // while (1) { if (msg_read.readcount == msg_read.cursize) { - SHOWNET(1, "%3u:END OF MESSAGE\n", msg_read.readcount); + SHOWNET(2, "%3u:END OF MESSAGE\n", msg_read.readcount); break; } cmd = MSG_ReadByte(); - SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); + SHOWNET(2, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); // other commands switch (cmd) { diff --git a/src/client/precache.c b/src/client/precache.c index b9d31c1df..0669fe068 100644 --- a/src/client/precache.c +++ b/src/client/precache.c @@ -331,8 +331,12 @@ static qhandle_t CL_RegisterImage(const char *s) // if it's in a subdir and has an extension, it's either a sprite or a skin // allow /some/pic.pcx escape syntax if (cl.csr.extended && *s != '/' && *s != '\\' && *COM_FileExtension(s)) { + if (!FS_pathcmpn(s, CONST_STR_LEN("sprites/psx_flare"))) + return R_RegisterImage(s, IT_SPRITE, IF_DEFAULT_FLARE); + if (!FS_pathcmpn(s, CONST_STR_LEN("sprites/"))) return R_RegisterSprite(s); + if (strchr(s, '/')) return R_RegisterSkin(s); } diff --git a/src/client/predict.c b/src/client/predict.c index 5a32feaa8..5555fcf05 100644 --- a/src/client/predict.c +++ b/src/client/predict.c @@ -51,7 +51,7 @@ void CL_CheckPredictionError(void) // save the prediction error for interpolation len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]); - if (len < 1 || len > 640) { + if (len <= 1 || len > 640) { // > 80 world units is a teleport or something VectorClear(cl.prediction_error); return; @@ -104,7 +104,8 @@ static void CL_ClipMoveToEntities(trace_t *tr, const vec3_t start, const vec3_t CM_TransformedBoxTrace(&trace, start, end, mins, maxs, headnode, contentmask, - ent->current.origin, ent->current.angles); + ent->current.origin, ent->current.angles, + cl.csr.extended); CM_ClipEntity(tr, &trace, (struct edict_s *)ent); } @@ -118,7 +119,7 @@ CL_Trace void CL_Trace(trace_t *tr, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, int contentmask) { // check against world - CM_BoxTrace(tr, start, end, mins, maxs, cl.bsp->nodes, contentmask); + CM_BoxTrace(tr, start, end, mins, maxs, cl.bsp->nodes, contentmask, cl.csr.extended); tr->ent = (struct edict_s *)cl_entities; if (tr->fraction == 0) return; // blocked by the world @@ -129,10 +130,10 @@ void CL_Trace(trace_t *tr, const vec3_t start, const vec3_t end, const vec3_t mi static int pm_clipmask; -static trace_t q_gameabi CL_PMTrace(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end) +static trace_t q_gameabi CL_PMTrace(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int contentmask) { trace_t t; - CL_Trace(&t, start, end, mins, maxs, pm_clipmask); + CL_Trace(&t, start, end, mins, maxs, (cl.csr.extended && contentmask) ? contentmask : pm_clipmask); return t; } @@ -142,7 +143,7 @@ static int CL_PointContents(const vec3_t point) const mmodel_t *cmodel; int i, contents; - contents = CM_PointContents(point, cl.bsp->nodes); + contents = CM_PointContents(point, cl.bsp->nodes, cl.csr.extended); for (i = 0; i < cl.numSolidEntities; i++) { ent = cl.solidEntities[i]; @@ -154,10 +155,8 @@ static int CL_PointContents(const vec3_t point) if (!cmodel) continue; - contents |= CM_TransformedPointContents( - point, cmodel->headnode, - ent->current.origin, - ent->current.angles); + contents |= CM_TransformedPointContents(point, cmodel->headnode, ent->current.origin, + ent->current.angles, cl.csr.extended); } return contents; @@ -261,8 +260,14 @@ void CL_PredictMovement(void) if (pm.s.pm_type != PM_SPECTATOR && (pm.s.pm_flags & PMF_ON_GROUND)) { oldz = cl.predicted_origins[cl.predicted_step_frame & CMD_MASK][2]; step = pm.s.origin[2] - oldz; - if (step > 63 && step < 160) { - cl.predicted_step = step * 0.125f; + if (step >= 63 && step < 160) { + // check for stepping up before a previous step is completed + unsigned delta = cls.realtime - cl.predicted_step_time; + float prev_step = 0; + if (delta < 100) + prev_step = cl.predicted_step * (100 - delta) * 0.01f; + + cl.predicted_step = min(prev_step + step * 0.125f, 32); cl.predicted_step_time = cls.realtime; cl.predicted_step_frame = frame + 1; // don't double step } diff --git a/src/client/screen.c b/src/client/screen.c index 48273855e..2d8751d44 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -74,6 +74,13 @@ static cvar_t *scr_showpmove; #endif static cvar_t *scr_showturtle; +static cvar_t *scr_netgraph; +static cvar_t *scr_timegraph; +static cvar_t *scr_debuggraph; +static cvar_t *scr_graphheight; +static cvar_t *scr_graphscale; +static cvar_t *scr_graphshift; + static cvar_t *scr_draw2d; static cvar_t *scr_lag_x; static cvar_t *scr_lag_y; @@ -166,9 +173,9 @@ int SCR_DrawStringEx(int x, int y, int flags, size_t maxlen, } if ((flags & UI_CENTER) == UI_CENTER) { - x -= len * CHAR_WIDTH / 2; + x -= len * CONCHAR_WIDTH / 2; } else if (flags & UI_RIGHT) { - x -= len * CHAR_WIDTH; + x -= len * CONCHAR_WIDTH; } return R_DrawString(x, y, flags, maxlen, s, font); @@ -185,21 +192,28 @@ void SCR_DrawStringMulti(int x, int y, int flags, size_t maxlen, { char *p; size_t len; + int last_x = x; + int last_y = y; while (*s && maxlen) { p = strchr(s, '\n'); if (!p) { - SCR_DrawStringEx(x, y, flags, maxlen, s, font); + last_x = SCR_DrawStringEx(x, y, flags, maxlen, s, font); + last_y = y; break; } len = min(p - s, maxlen); - SCR_DrawStringEx(x, y, flags, len, s, font); + last_x = SCR_DrawStringEx(x, y, flags, len, s, font); + last_y = y; maxlen -= len; - y += CHAR_HEIGHT; + y += CONCHAR_HEIGHT; s = p + 1; } + + if (flags & UI_DRAWCURSOR && com_localTime & BIT(8)) + R_DrawChar(last_x, last_y, flags, 11, font); } @@ -308,6 +322,112 @@ BAR GRAPHS =============================================================================== */ +/* +============== +SCR_AddNetgraph + +A new packet was just parsed +============== +*/ +void SCR_AddNetgraph(void) +{ + int i, color; + unsigned ping; + + // if using the debuggraph for something else, don't + // add the net lines + if (scr_debuggraph->integer || scr_timegraph->integer) + return; + + for (i = 0; i < cls.netchan.dropped; i++) + SCR_DebugGraph(30, 0x40); + + for (i = 0; i < cl.suppress_count; i++) + SCR_DebugGraph(30, 0xdf); + + if (scr_netgraph->integer > 1) { + ping = msg_read.cursize; + if (ping < 200) + color = 61; + else if (ping < 500) + color = 59; + else if (ping < 800) + color = 57; + else if (ping < 1200) + color = 224; + else + color = 242; + ping /= 40; + } else { + // see what the latency was on this packet + i = cls.netchan.incoming_acknowledged & CMD_MASK; + ping = (cls.realtime - cl.history[i].sent) / 30; + color = 0xd0; + } + + SCR_DebugGraph(min(ping, 30), color); +} + +#define GRAPH_SAMPLES 4096 +#define GRAPH_MASK (GRAPH_SAMPLES - 1) + +static struct { + float values[GRAPH_SAMPLES]; + byte colors[GRAPH_SAMPLES]; + unsigned current; +} graph; + +/* +============== +SCR_DebugGraph +============== +*/ +void SCR_DebugGraph(float value, int color) +{ + graph.values[graph.current & GRAPH_MASK] = value; + graph.colors[graph.current & GRAPH_MASK] = color; + graph.current++; +} + +/* +============== +SCR_DrawDebugGraph +============== +*/ +static void SCR_DrawDebugGraph(void) +{ + int a, y, w, i, h, height; + float v, scale, shift; + + scale = scr_graphscale->value; + shift = scr_graphshift->value; + height = scr_graphheight->integer; + if (height < 1) + return; + + w = scr.hud_width; + y = scr.hud_height; + + for (a = 0; a < w; a++) { + i = (graph.current - 1 - a) & GRAPH_MASK; + v = graph.values[i] * scale + shift; + + if (v < 0) + v += height * (1 + (int)(-v / height)); + + h = (int)v % height; + R_DrawFill8(w - 1 - a, y - h, 1, h, graph.colors[i]); + } +} + +/* +=============================================================================== + +DEMO BAR + +=============================================================================== +*/ + static void draw_progress_bar(float progress, bool paused, int framenum) { char buffer[16]; @@ -315,7 +435,7 @@ static void draw_progress_bar(float progress, bool paused, int framenum) size_t len; w = Q_rint(scr.hud_width * progress); - h = Q_rint(CHAR_HEIGHT / scr.hud_scale); + h = Q_rint(CONCHAR_HEIGHT / scr.hud_scale); scr.hud_height -= h; @@ -328,7 +448,7 @@ static void draw_progress_bar(float progress, bool paused, int framenum) h = Q_rint(scr.hud_height * scr.hud_scale); len = Q_scnprintf(buffer, sizeof(buffer), "%.f%%", progress * 100); - x = (w - len * CHAR_WIDTH) / 2; + x = (w - len * CONCHAR_WIDTH) / 2; R_DrawString(x, h, 0, MAX_STRING_CHARS, buffer, scr.font_pic); if (scr_demobar->integer > 1) { @@ -471,7 +591,7 @@ void SCR_CenterPrint(const char *str, bool typewrite) static void SCR_DrawCenterString(void) { centerprint_t *cp; - int y; + int y, flags; float alpha; size_t maxlen; @@ -494,14 +614,17 @@ static void SCR_DrawCenterString(void) R_SetAlpha(alpha * scr_alpha->value); - y = scr.hud_height / 4 - cp->lines * CHAR_HEIGHT / 2; + y = scr.hud_height / 4 - cp->lines * CONCHAR_HEIGHT / 2; + flags = UI_CENTER; - if (cp->typewrite) + if (cp->typewrite) { maxlen = scr_printspeed->value * 0.001f * (cls.realtime - cp->start); - else + flags |= UI_DROPSHADOW | UI_DRAWCURSOR; + } else { maxlen = MAX_STRING_CHARS; + } - SCR_DrawStringMulti(scr.hud_width / 2, y, UI_CENTER, + SCR_DrawStringMulti(scr.hud_width / 2, y, flags, maxlen, cp->string, scr.font_pic); R_SetAlpha(scr_alpha->value); @@ -843,8 +966,8 @@ static void SCR_DrawObjects(void) if (obj->x < 0) { x += scr.hud_width + 1; } - if (obj->y < 0) { - y += scr.hud_height - CHAR_HEIGHT + 1; + if (y < 0) { + y += scr.hud_height - CONCHAR_HEIGHT + 1; } if (!(obj->flags & UI_IGNORECOLOR)) { R_SetColor(obj->color.u32); @@ -926,11 +1049,11 @@ static void SCR_DrawChatHUD(void) flags |= UI_LEFT; } - if (scr_chathud_y->integer < 0) { - y += scr.hud_height - CHAR_HEIGHT + 1; - step = -CHAR_HEIGHT; + if (y < 0) { + y += scr.hud_height - CONCHAR_HEIGHT + 1; + step = -CONCHAR_HEIGHT; } else { - step = CHAR_HEIGHT; + step = CONCHAR_HEIGHT; } lines = scr_chathud_lines->integer; @@ -974,13 +1097,13 @@ static void SCR_DrawTurtle(void) if (!cl.frameflags) return; - x = CHAR_WIDTH; - y = scr.hud_height - 11 * CHAR_HEIGHT; + x = CONCHAR_WIDTH; + y = scr.hud_height - 11 * CONCHAR_HEIGHT; #define DF(f) \ if (cl.frameflags & FF_##f) { \ SCR_DrawString(x, y, UI_ALTCOLOR, #f); \ - y += CHAR_HEIGHT; \ + y += CONCHAR_HEIGHT; \ } if (scr_showturtle->integer > 1) { @@ -1011,11 +1134,11 @@ static void SCR_DrawDebugStats(void) if (j <= 0) return; - if (j > MAX_STATS) - j = MAX_STATS; + if (j > cl.max_stats) + j = cl.max_stats; - x = CHAR_WIDTH; - y = (scr.hud_height - j * CHAR_HEIGHT) / 2; + x = CONCHAR_WIDTH; + y = (scr.hud_height - j * CONCHAR_HEIGHT) / 2; for (i = 0; i < j; i++) { Q_snprintf(buffer, sizeof(buffer), "%2d: %d", i, cl.frame.ps.stats[i]); if (cl.oldframe.ps.stats[i] != cl.frame.ps.stats[i]) { @@ -1023,7 +1146,7 @@ static void SCR_DrawDebugStats(void) } R_DrawString(x, y, 0, MAX_STRING_CHARS, buffer, scr.font_pic); R_ClearColor(); - y += CHAR_HEIGHT; + y += CONCHAR_HEIGHT; } } @@ -1043,21 +1166,21 @@ static void SCR_DrawDebugPmove(void) if (!scr_showpmove->integer) return; - x = CHAR_WIDTH; - y = (scr.hud_height - 2 * CHAR_HEIGHT) / 2; + x = CONCHAR_WIDTH; + y = (scr.hud_height - 2 * CONCHAR_HEIGHT) / 2; i = cl.frame.ps.pmove.pm_type; if (i > PM_FREEZE) i = PM_FREEZE; R_DrawString(x, y, 0, MAX_STRING_CHARS, types[i], scr.font_pic); - y += CHAR_HEIGHT; + y += CONCHAR_HEIGHT; j = cl.frame.ps.pmove.pm_flags; for (i = 0; i < 8; i++) { if (j & (1 << i)) { x = R_DrawString(x, y, 0, MAX_STRING_CHARS, flags[i], scr.font_pic); - x += CHAR_WIDTH; + x += CONCHAR_WIDTH; } } } @@ -1375,6 +1498,13 @@ void SCR_Init(void) scr_crosshair = Cvar_Get("crosshair", "0", CVAR_ARCHIVE); scr_crosshair->changed = scr_crosshair_changed; + scr_netgraph = Cvar_Get("netgraph", "0", 0); + scr_timegraph = Cvar_Get("timegraph", "0", 0); + scr_debuggraph = Cvar_Get("debuggraph", "0", 0); + scr_graphheight = Cvar_Get("graphheight", "32", 0); + scr_graphscale = Cvar_Get("graphscale", "1", 0); + scr_graphshift = Cvar_Get("graphshift", "0", 0); + scr_chathud = Cvar_Get("scr_chathud", "0", 0); scr_chathud_lines = Cvar_Get("scr_chathud_lines", "4", 0); scr_chathud_time = Cvar_Get("scr_chathud_time", "0", 0); @@ -1642,10 +1772,10 @@ static void SCR_DrawInventory(void) x += 24; HUD_DrawString(x, y, "hotkey ### item"); - y += CHAR_HEIGHT; + y += CONCHAR_HEIGHT; HUD_DrawString(x, y, "------ --- ----"); - y += CHAR_HEIGHT; + y += CONCHAR_HEIGHT; for (i = top; i < num && i < top + DISPLAY_ITEMS; i++) { item = index[i]; @@ -1661,11 +1791,11 @@ static void SCR_DrawInventory(void) } else { // draw a blinky cursor by the selected item HUD_DrawString(x, y, string); if ((cls.realtime >> 8) & 1) { - R_DrawChar(x - CHAR_WIDTH, y, 0, 15, scr.font_pic); + R_DrawChar(x - CONCHAR_WIDTH, y, 0, 15, scr.font_pic); } } - y += CHAR_HEIGHT; + y += CONCHAR_HEIGHT; } } @@ -1728,7 +1858,7 @@ static void SCR_DrawHealthBar(int x, int y, int value) int bar_width = scr.hud_width / 3; float percent = (value - 1) / 254.0f; int w = bar_width * percent + 0.5f; - int h = CHAR_HEIGHT / 2; + int h = CONCHAR_HEIGHT / 2; x -= bar_width / 2; R_DrawFill8(x, y, w, h, 240); @@ -1800,7 +1930,7 @@ static void SCR_ExecuteLayoutString(const char *s) // draw a pic from a stat number token = COM_Parse(&s); value = Q_atoi(token); - if (value < 0 || value >= MAX_STATS) { + if (value < 0 || value >= cl.max_stats) { Com_Error(ERR_DROP, "%s: invalid stat index for pic: %i", __func__, value); } value = cl.frame.ps.stats[value]; @@ -1855,13 +1985,13 @@ static void SCR_ExecuteLayoutString(const char *s) time = Q_atoi(token); HUD_DrawAltString(x + 32, y, ci->name); - HUD_DrawString(x + 32, y + CHAR_HEIGHT, "Score: "); + HUD_DrawString(x + 32, y + CONCHAR_HEIGHT, "Score: "); Q_snprintf(buffer, sizeof(buffer), "%i", score); - HUD_DrawAltString(x + 32 + 7 * CHAR_WIDTH, y + CHAR_HEIGHT, buffer); + HUD_DrawAltString(x + 32 + 7 * CONCHAR_WIDTH, y + CONCHAR_HEIGHT, buffer); Q_snprintf(buffer, sizeof(buffer), "Ping: %i", ping); - HUD_DrawString(x + 32, y + 2 * CHAR_HEIGHT, buffer); + HUD_DrawString(x + 32, y + 2 * CONCHAR_HEIGHT, buffer); Q_snprintf(buffer, sizeof(buffer), "Time: %i", time); - HUD_DrawString(x + 32, y + 3 * CHAR_HEIGHT, buffer); + HUD_DrawString(x + 32, y + 3 * CONCHAR_HEIGHT, buffer); if (!ci->icon) { ci = &cl.baseclientinfo; @@ -1917,7 +2047,7 @@ static void SCR_ExecuteLayoutString(const char *s) width = Q_atoi(token); token = COM_Parse(&s); value = Q_atoi(token); - if (value < 0 || value >= MAX_STATS) { + if (value < 0 || value >= cl.max_stats) { Com_Error(ERR_DROP, "%s: invalid stat index for num: %i", __func__, value); } value = cl.frame.ps.stats[value]; @@ -1987,7 +2117,7 @@ static void SCR_ExecuteLayoutString(const char *s) char *cmd = token + 5; token = COM_Parse(&s); index = Q_atoi(token); - if (index < 0 || index >= MAX_STATS) { + if (index < 0 || index >= cl.max_stats) { Com_Error(ERR_DROP, "%s: invalid stat index for stat_: %i", __func__, index); } index = cl.frame.ps.stats[index]; @@ -2049,7 +2179,7 @@ static void SCR_ExecuteLayoutString(const char *s) if (!strcmp(token, "if")) { token = COM_Parse(&s); value = Q_atoi(token); - if (value < 0 || value >= MAX_STATS) { + if (value < 0 || value >= cl.max_stats) { Com_Error(ERR_DROP, "%s: invalid stat index for if: %i", __func__, value); } value = cl.frame.ps.stats[value]; @@ -2081,7 +2211,7 @@ static void SCR_ExecuteLayoutString(const char *s) if (!strcmp(token, "health_bars")) { token = COM_Parse(&s); value = Q_atoi(token); - if (value < 0 || value >= MAX_STATS) { + if (value < 0 || value >= cl.max_stats) { Com_Error(ERR_DROP, "%s: invalid stat index", __func__); } value = cl.frame.ps.stats[value]; @@ -2093,8 +2223,8 @@ static void SCR_ExecuteLayoutString(const char *s) } HUD_DrawCenterString(x + 320 / 2, y, cl.configstrings[index]); - SCR_DrawHealthBar(x + 320 / 2, y + CHAR_HEIGHT + 4, value & 0xff); - SCR_DrawHealthBar(x + 320 / 2, y + CHAR_HEIGHT + 12, (value >> 8) & 0xff); + SCR_DrawHealthBar(x + 320 / 2, y + CONCHAR_HEIGHT + 4, value & 0xff); + SCR_DrawHealthBar(x + 320 / 2, y + CONCHAR_HEIGHT + 12, (value >> 8) & 0xff); continue; } } @@ -2419,14 +2549,14 @@ static void SCR_DrawGhudElement(ghud_element_t *element, float alpha_base, color int length = strlen(element->text); int uiflags = element->size[0] | (element->size[1] << 16); if ((uiflags & UI_CENTER) == UI_CENTER) - x -= (length * CHAR_WIDTH * 0.5); + x -= (length * CONCHAR_WIDTH * 0.5); else if (uiflags & UI_RIGHT) - x -= (length * CHAR_WIDTH); + x -= (length * CONCHAR_WIDTH); if ((uiflags & UI_MIDDLE) == UI_MIDDLE) - y -= (length * CHAR_HEIGHT * 0.5); + y -= (length * CONCHAR_HEIGHT * 0.5); else if (uiflags & UI_BOTTOM) - y -= (length * CHAR_HEIGHT); + y -= (length * CONCHAR_HEIGHT); uiflags &= ~(UI_LEFT | UI_RIGHT | UI_TOP | UI_BOTTOM); @@ -2655,6 +2785,12 @@ static void SCR_Draw2D(void) R_ClearColor(); R_SetAlpha(Cvar_ClampValue(scr_alpha, 0, 1)); + if (scr_timegraph->integer) + SCR_DebugGraph(cls.frametime * 300, 0xdc); + + if (scr_debuggraph->integer || scr_timegraph->integer || scr_netgraph->integer) + SCR_DrawDebugGraph(); + SCR_DrawStats(); SCR_DrawLayout(); diff --git a/src/client/tent.c b/src/client/tent.c index 3b241865b..a7c991405 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -971,7 +971,7 @@ static void CL_AddPlayerBeams(void) vectoangles2(dist, angles); // if it's the heatbeam, draw the particle effect - if (cl_mod_heatbeam && b->model == cl_mod_heatbeam) + if (cl_mod_heatbeam && b->model == cl_mod_heatbeam && !sv_paused->integer) CL_Heatbeam(org, dist); framenum = 1; @@ -1342,11 +1342,17 @@ void CL_ParseTEnt(void) break; case TE_SPLASH: // bullet hitting water - if (te.color < 0 || te.color > 6) - r = 0x00; - else - r = splash_color[te.color]; - CL_ParticleEffect(te.pos1, te.dir, r, te.count); + if (cl.csr.extended && te.color == SPLASH_ELECTRIC_N64) { + CL_ParticleEffect(te.pos1, te.dir, 0x6c, te.count / 2); + CL_ParticleEffect(te.pos1, te.dir, 0xb0, (te.count + 1) / 2); + te.color = SPLASH_SPARKS; + } else { + if (te.color >= q_countof(splash_color)) + r = 0x00; + else + r = splash_color[te.color]; + CL_ParticleEffect(te.pos1, te.dir, r, te.count); + } if (te.color == SPLASH_SPARKS) { r = Q_rand() & 3; diff --git a/src/client/ui/demos.c b/src/client/ui/demos.c index 0d26d0b7b..49c4b45d6 100644 --- a/src/client/ui/demos.c +++ b/src/client/ui/demos.c @@ -539,26 +539,26 @@ static void Size(menuFrameWork_t *self) int w1, w2; m_demos.list.generic.x = 0; - m_demos.list.generic.y = CHAR_HEIGHT; + m_demos.list.generic.y = CONCHAR_HEIGHT; m_demos.list.generic.width = 0; - m_demos.list.generic.height = uis.height - CHAR_HEIGHT * 2 - 1; + m_demos.list.generic.height = uis.height - CONCHAR_HEIGHT * 2 - 1; w1 = 17 + m_demos.widest_map + m_demos.widest_pov; - w2 = uis.width - w1 * CHAR_WIDTH - MLIST_PADDING * 4 - MLIST_SCROLLBAR_WIDTH; - if (w2 > 8 * CHAR_WIDTH) { + w2 = uis.width - w1 * CONCHAR_WIDTH - MLIST_PADDING * 4 - MLIST_SCROLLBAR_WIDTH; + if (w2 > 8 * CONCHAR_WIDTH) { // everything fits m_demos.list.columns[0].width = w2; - m_demos.list.columns[1].width = 12 * CHAR_WIDTH + MLIST_PADDING; - m_demos.list.columns[2].width = 5 * CHAR_WIDTH + MLIST_PADDING; - m_demos.list.columns[3].width = m_demos.widest_map * CHAR_WIDTH + MLIST_PADDING; - m_demos.list.columns[4].width = m_demos.widest_pov * CHAR_WIDTH + MLIST_PADDING; + m_demos.list.columns[1].width = 12 * CONCHAR_WIDTH + MLIST_PADDING; + m_demos.list.columns[2].width = 5 * CONCHAR_WIDTH + MLIST_PADDING; + m_demos.list.columns[3].width = m_demos.widest_map * CONCHAR_WIDTH + MLIST_PADDING; + m_demos.list.columns[4].width = m_demos.widest_pov * CONCHAR_WIDTH + MLIST_PADDING; m_demos.list.numcolumns = COL_MAX; } else { // map and pov don't fit - w2 = uis.width - 17 * CHAR_WIDTH - MLIST_PADDING * 2 - MLIST_SCROLLBAR_WIDTH; + w2 = uis.width - 17 * CONCHAR_WIDTH - MLIST_PADDING * 2 - MLIST_SCROLLBAR_WIDTH; m_demos.list.columns[0].width = w2; - m_demos.list.columns[1].width = 12 * CHAR_WIDTH + MLIST_PADDING; - m_demos.list.columns[2].width = 5 * CHAR_WIDTH + MLIST_PADDING; + m_demos.list.columns[1].width = 12 * CONCHAR_WIDTH + MLIST_PADDING; + m_demos.list.columns[2].width = 5 * CONCHAR_WIDTH + MLIST_PADDING; m_demos.list.columns[3].width = 0; m_demos.list.columns[4].width = 0; m_demos.list.numcolumns = COL_MAX - 2; @@ -579,7 +579,7 @@ static void Draw(menuFrameWork_t *self) { Menu_Draw(self); if (uis.width >= 640) { - UI_DrawString(uis.width, uis.height - CHAR_HEIGHT, + UI_DrawString(uis.width, uis.height - CONCHAR_HEIGHT, UI_RIGHT, m_demos.status); } } diff --git a/src/client/ui/menu.c b/src/client/ui/menu.c index ef34cc16a..9c140a011 100644 --- a/src/client/ui/menu.c +++ b/src/client/ui/menu.c @@ -72,7 +72,7 @@ static void Action_Draw(menuAction_t *a) } else { flags |= UI_ALTCOLOR; if ((uis.realtime >> 8) & 1) { - UI_DrawChar(a->generic.x - strlen(a->generic.name) * CHAR_WIDTH / 2 - CHAR_WIDTH, a->generic.y, flags, 13); + UI_DrawChar(a->generic.x - strlen(a->generic.name) * CONCHAR_WIDTH / 2 - CONCHAR_WIDTH, a->generic.y, flags, 13); } } } @@ -208,7 +208,7 @@ static void Keybind_Init(menuKeybind_t *k) len = 3; } - k->generic.rect.width += (RCOLUMN_OFFSET - LCOLUMN_OFFSET) + len * CHAR_WIDTH; + k->generic.rect.width += (RCOLUMN_OFFSET - LCOLUMN_OFFSET) + len * CONCHAR_WIDTH; } /* @@ -390,7 +390,7 @@ Field_Init */ static void Field_Init(menuField_t *f) { - int w = f->width * CHAR_WIDTH; + int w = f->width * CONCHAR_WIDTH; f->generic.uiFlags &= ~(UI_LEFT | UI_RIGHT); @@ -404,7 +404,7 @@ static void Field_Init(menuField_t *f) f->generic.rect.x = f->generic.x - w / 2; f->generic.rect.y = f->generic.y; f->generic.rect.width = w; - f->generic.rect.height = CHAR_HEIGHT; + f->generic.rect.height = CONCHAR_HEIGHT; } } @@ -429,13 +429,13 @@ static void Field_Draw(menuField_t *f) f->generic.uiFlags | UI_RIGHT | UI_ALTCOLOR, f->generic.name); R_DrawFill32(f->generic.x + RCOLUMN_OFFSET, f->generic.y - 1, - f->field.visibleChars * CHAR_WIDTH, CHAR_HEIGHT + 2, color); + f->field.visibleChars * CONCHAR_WIDTH, CONCHAR_HEIGHT + 2, color); IF_Draw(&f->field, f->generic.x + RCOLUMN_OFFSET, f->generic.y, flags, uis.fontHandle); } else { R_DrawFill32(f->generic.rect.x, f->generic.rect.y - 1, - f->generic.rect.width, CHAR_HEIGHT + 2, color); + f->generic.rect.width, CONCHAR_HEIGHT + 2, color); IF_Draw(&f->field, f->generic.rect.x, f->generic.rect.y, flags, uis.fontHandle); @@ -560,7 +560,7 @@ void SpinControl_Init(menuSpinControl_t *s) } s->generic.rect.width += (RCOLUMN_OFFSET - LCOLUMN_OFFSET) + - maxLength * CHAR_WIDTH; + maxLength * CONCHAR_WIDTH; } /* @@ -1304,7 +1304,7 @@ static void MenuList_DrawString(int x, int y, int flags, rc.left = x; rc.right = x + column->width - 1; rc.top = y + 1; - rc.bottom = y + CHAR_HEIGHT + 1; + rc.bottom = y + CONCHAR_HEIGHT + 1; if ((column->uiFlags & UI_CENTER) == UI_CENTER) { x += column->width / 2 - 1; @@ -1518,14 +1518,14 @@ static void Slider_Free(menuSlider_t *s) static void Slider_Init(menuSlider_t *s) { - int len = strlen(s->generic.name) * CHAR_WIDTH; + int len = strlen(s->generic.name) * CONCHAR_WIDTH; s->generic.rect.x = s->generic.x + LCOLUMN_OFFSET - len; s->generic.rect.y = s->generic.y; s->generic.rect.width = (RCOLUMN_OFFSET - LCOLUMN_OFFSET) + - len + (SLIDER_RANGE + 2) * CHAR_WIDTH; - s->generic.rect.height = CHAR_HEIGHT; + len + (SLIDER_RANGE + 2) * CONCHAR_WIDTH; + s->generic.rect.height = CONCHAR_HEIGHT; } static menuSound_t Slider_Click(menuSlider_t *s) @@ -1536,31 +1536,31 @@ static menuSound_t Slider_Click(menuSlider_t *s) pos = Q_clipf((s->curvalue - s->minvalue) / (s->maxvalue - s->minvalue), 0, 1); - x = CHAR_WIDTH + (SLIDER_RANGE - 1) * CHAR_WIDTH * pos; + x = CONCHAR_WIDTH + (SLIDER_RANGE - 1) * CONCHAR_WIDTH * pos; // click left of thumb rect.x = s->generic.x + RCOLUMN_OFFSET; rect.y = s->generic.y; rect.width = x; - rect.height = CHAR_HEIGHT; + rect.height = CONCHAR_HEIGHT; if (UI_CursorInRect(&rect)) return Slider_DoSlide(s, -1); // click on thumb rect.x = s->generic.x + RCOLUMN_OFFSET + x; rect.y = s->generic.y; - rect.width = CHAR_WIDTH; - rect.height = CHAR_HEIGHT; + rect.width = CONCHAR_WIDTH; + rect.height = CONCHAR_HEIGHT; if (UI_CursorInRect(&rect)) { uis.mouseTracker = &s->generic; return QMS_SILENT; } // click right of thumb - rect.x = s->generic.x + RCOLUMN_OFFSET + x + CHAR_WIDTH; + rect.x = s->generic.x + RCOLUMN_OFFSET + x + CONCHAR_WIDTH; rect.y = s->generic.y; - rect.width = (SLIDER_RANGE + 1) * CHAR_WIDTH - x; - rect.height = CHAR_HEIGHT; + rect.width = (SLIDER_RANGE + 1) * CONCHAR_WIDTH - x; + rect.height = CONCHAR_HEIGHT; if (UI_CursorInRect(&rect)) return Slider_DoSlide(s, 1); @@ -1575,7 +1575,7 @@ static menuSound_t Slider_MouseMove(menuSlider_t *s) if (uis.mouseTracker != &s->generic) return QMS_NOTHANDLED; - pos = (uis.mouseCoords[0] - (s->generic.x + RCOLUMN_OFFSET + CHAR_WIDTH)) * (1.0f / (SLIDER_RANGE * CHAR_WIDTH)); + pos = (uis.mouseCoords[0] - (s->generic.x + RCOLUMN_OFFSET + CONCHAR_WIDTH)) * (1.0f / (SLIDER_RANGE * CONCHAR_WIDTH)); value = Q_clipf(pos, 0, 1) * (s->maxvalue - s->minvalue); steps = Q_rint(value / s->step); @@ -1648,13 +1648,13 @@ static void Slider_Draw(menuSlider_t *s) UI_DrawChar(s->generic.x + RCOLUMN_OFFSET, s->generic.y, flags | UI_LEFT, 128); for (i = 0; i < SLIDER_RANGE; i++) - UI_DrawChar(RCOLUMN_OFFSET + s->generic.x + i * CHAR_WIDTH + CHAR_WIDTH, s->generic.y, flags | UI_LEFT, 129); + UI_DrawChar(RCOLUMN_OFFSET + s->generic.x + i * CONCHAR_WIDTH + CONCHAR_WIDTH, s->generic.y, flags | UI_LEFT, 129); - UI_DrawChar(RCOLUMN_OFFSET + s->generic.x + i * CHAR_WIDTH + CHAR_WIDTH, s->generic.y, flags | UI_LEFT, 130); + UI_DrawChar(RCOLUMN_OFFSET + s->generic.x + i * CONCHAR_WIDTH + CONCHAR_WIDTH, s->generic.y, flags | UI_LEFT, 130); pos = Q_clipf((s->curvalue - s->minvalue) / (s->maxvalue - s->minvalue), 0, 1); - UI_DrawChar(CHAR_WIDTH + RCOLUMN_OFFSET + s->generic.x + (SLIDER_RANGE - 1) * CHAR_WIDTH * pos, s->generic.y, flags | UI_LEFT, 131); + UI_DrawChar(CONCHAR_WIDTH + RCOLUMN_OFFSET + s->generic.x + (SLIDER_RANGE - 1) * CONCHAR_WIDTH * pos, s->generic.y, flags | UI_LEFT, 131); } /* @@ -2082,7 +2082,7 @@ menuSound_t Menu_AdjustCursor(menuFrameWork_t *m, int dir) static void Menu_DrawStatus(menuFrameWork_t *menu) { - int linewidth = uis.width / CHAR_WIDTH; + int linewidth = uis.width / CONCHAR_WIDTH; int x, y, l, count; char *txt, *p; int lens[8]; @@ -2116,11 +2116,11 @@ static void Menu_DrawStatus(menuFrameWork_t *menu) lens[count++] = x; - R_DrawFill8(0, menu->y2 - count * CHAR_HEIGHT, uis.width, count * CHAR_HEIGHT, 4); + R_DrawFill8(0, menu->y2 - count * CONCHAR_HEIGHT, uis.width, count * CONCHAR_HEIGHT, 4); for (l = 0; l < count; l++) { - x = (uis.width - lens[l] * CHAR_WIDTH) / 2; - y = menu->y2 - (count - l) * CHAR_HEIGHT; + x = (uis.width - lens[l] * CONCHAR_WIDTH) / 2; + y = menu->y2 - (count - l) * CONCHAR_HEIGHT; R_DrawString(x, y, 0, lens[l], ptrs[l], uis.fontHandle); } } diff --git a/src/client/ui/playerconfig.c b/src/client/ui/playerconfig.c index a5867c141..bda423565 100644 --- a/src/client/ui/playerconfig.c +++ b/src/client/ui/playerconfig.c @@ -150,7 +150,7 @@ static void Size(menuFrameWork_t *self) m_player.refdef.width, m_player.refdef.height); if (uis.width < 800 && uis.width >= 640) { - x -= CHAR_WIDTH * 10; + x -= CONCHAR_WIDTH * 10; } if (m_player.menu.banner) { @@ -161,7 +161,7 @@ static void Size(menuFrameWork_t *self) } if (uis.width < 640) { - x -= CHAR_WIDTH * 10; + x -= CONCHAR_WIDTH * 10; m_player.hand.generic.name = "hand"; } else { m_player.hand.generic.name = "handedness"; diff --git a/src/client/ui/q2pro.menu b/src/client/ui/q2pro.menu index 1a9d2c8a6..78ea98301 100644 --- a/src/client/ui/q2pro.menu +++ b/src/client/ui/q2pro.menu @@ -133,7 +133,7 @@ begin effects values "dynamic lighting" gl_dynamic "no" "yes" "only switchable" values "entity cel-shading" gl_celshading no 1x 2x 3x toggle "entity glowing" cl_noglow ~ - toggle "ground shadows" gl_shadows + values "ground shadows" gl_shadows no yes fade toggle "screen blending" gl_polyblend toggle "screen warping" gl_waterwarp toggle "grenade explosions" cl_disable_explosions ~0 diff --git a/src/client/ui/servers.c b/src/client/ui/servers.c index 795f8547c..e97c27ed7 100644 --- a/src/client/ui/servers.c +++ b/src/client/ui/servers.c @@ -929,52 +929,52 @@ static void SizeCompact(void) // server list // m_servers.list.generic.x = 0; - m_servers.list.generic.y = CHAR_HEIGHT; - m_servers.list.generic.height = uis.height / 2 - CHAR_HEIGHT; + m_servers.list.generic.y = CONCHAR_HEIGHT; + m_servers.list.generic.height = uis.height / 2 - CONCHAR_HEIGHT; - m_servers.list.columns[0].width = w - 10 * CHAR_WIDTH - MLIST_PADDING * 2; + m_servers.list.columns[0].width = w - 10 * CONCHAR_WIDTH - MLIST_PADDING * 2; m_servers.list.columns[1].width = 0; m_servers.list.columns[2].width = 0; - m_servers.list.columns[3].width = 7 * CHAR_WIDTH + MLIST_PADDING; - m_servers.list.columns[4].width = 3 * CHAR_WIDTH + MLIST_PADDING; + m_servers.list.columns[3].width = 7 * CONCHAR_WIDTH + MLIST_PADDING; + m_servers.list.columns[4].width = 3 * CONCHAR_WIDTH + MLIST_PADDING; // // player list // m_servers.players.generic.x = 0; m_servers.players.generic.y = uis.height / 2 + 1; - m_servers.players.generic.height = (uis.height + 1) / 2 - CHAR_HEIGHT - 2; + m_servers.players.generic.height = (uis.height + 1) / 2 - CONCHAR_HEIGHT - 2; - m_servers.players.columns[0].width = 3 * CHAR_WIDTH + MLIST_PADDING; - m_servers.players.columns[1].width = 3 * CHAR_WIDTH + MLIST_PADDING; - m_servers.players.columns[2].width = w - 6 * CHAR_WIDTH - MLIST_PADDING * 2; + m_servers.players.columns[0].width = 3 * CONCHAR_WIDTH + MLIST_PADDING; + m_servers.players.columns[1].width = 3 * CONCHAR_WIDTH + MLIST_PADDING; + m_servers.players.columns[2].width = w - 6 * CONCHAR_WIDTH - MLIST_PADDING * 2; m_servers.players.mlFlags |= MLF_SCROLLBAR; } static void SizeFull(void) { - int w = uis.width - MLIST_SCROLLBAR_WIDTH - 21 * CHAR_WIDTH - MLIST_PADDING * 3; + int w = uis.width - MLIST_SCROLLBAR_WIDTH - 21 * CONCHAR_WIDTH - MLIST_PADDING * 3; // // server list // m_servers.list.generic.x = 0; - m_servers.list.generic.y = CHAR_HEIGHT; - m_servers.list.generic.height = uis.height / 2 - CHAR_HEIGHT; + m_servers.list.generic.y = CONCHAR_HEIGHT; + m_servers.list.generic.height = uis.height / 2 - CONCHAR_HEIGHT; - m_servers.list.columns[0].width = w - 26 * CHAR_WIDTH - MLIST_PADDING * 4; - m_servers.list.columns[1].width = 4 * CHAR_WIDTH + MLIST_PADDING; - m_servers.list.columns[2].width = 12 * CHAR_WIDTH + MLIST_PADDING; - m_servers.list.columns[3].width = 7 * CHAR_WIDTH + MLIST_PADDING; - m_servers.list.columns[4].width = 3 * CHAR_WIDTH + MLIST_PADDING; + m_servers.list.columns[0].width = w - 26 * CONCHAR_WIDTH - MLIST_PADDING * 4; + m_servers.list.columns[1].width = 8 * CONCHAR_WIDTH + MLIST_PADDING; + m_servers.list.columns[2].width = 8 * CONCHAR_WIDTH + MLIST_PADDING; + m_servers.list.columns[3].width = 7 * CONCHAR_WIDTH + MLIST_PADDING; + m_servers.list.columns[4].width = 3 * CONCHAR_WIDTH + MLIST_PADDING; // // server info // m_servers.info.generic.x = 0; m_servers.info.generic.y = uis.height / 2 + 1; - m_servers.info.generic.height = (uis.height + 1) / 2 - CHAR_HEIGHT - 2; + m_servers.info.generic.height = (uis.height + 1) / 2 - CONCHAR_HEIGHT - 2; m_servers.info.columns[0].width = w / 3; m_servers.info.columns[1].width = w - w / 3; @@ -983,12 +983,12 @@ static void SizeFull(void) // player list // m_servers.players.generic.x = w + MLIST_SCROLLBAR_WIDTH; - m_servers.players.generic.y = CHAR_HEIGHT; - m_servers.players.generic.height = uis.height - CHAR_HEIGHT * 2 - 1; + m_servers.players.generic.y = CONCHAR_HEIGHT; + m_servers.players.generic.height = uis.height - CONCHAR_HEIGHT * 2 - 1; - m_servers.players.columns[0].width = 3 * CHAR_WIDTH + MLIST_PADDING; - m_servers.players.columns[1].width = 3 * CHAR_WIDTH + MLIST_PADDING; - m_servers.players.columns[2].width = 15 * CHAR_WIDTH + MLIST_PADDING; + m_servers.players.columns[0].width = 3 * CONCHAR_WIDTH + MLIST_PADDING; + m_servers.players.columns[1].width = 3 * CONCHAR_WIDTH + MLIST_PADDING; + m_servers.players.columns[2].width = 15 * CONCHAR_WIDTH + MLIST_PADDING; m_servers.players.mlFlags &= ~MLF_SCROLLBAR; } @@ -1047,22 +1047,22 @@ static void DrawStatus(void) else w = uis.width; - R_DrawFill8(0, uis.height - CHAR_HEIGHT, w, CHAR_HEIGHT, 4); - R_DrawFill8(w, uis.height - CHAR_HEIGHT, uis.width - w, CHAR_HEIGHT, 0); + R_DrawFill8(0, uis.height - CONCHAR_HEIGHT, w, CONCHAR_HEIGHT, 4); + R_DrawFill8(w, uis.height - CONCHAR_HEIGHT, uis.width - w, CONCHAR_HEIGHT, 0); if (m_servers.status_c) - UI_DrawString(uis.width / 2, uis.height - CHAR_HEIGHT, UI_CENTER, m_servers.status_c); + UI_DrawString(uis.width / 2, uis.height - CONCHAR_HEIGHT, UI_CENTER, m_servers.status_c); if (uis.width < 800) return; if (m_servers.list.numItems) - UI_DrawString(uis.width, uis.height - CHAR_HEIGHT, UI_RIGHT, m_servers.status_r); + UI_DrawString(uis.width, uis.height - CONCHAR_HEIGHT, UI_RIGHT, m_servers.status_r); if (m_servers.list.numItems && m_servers.list.curvalue >= 0) { serverslot_t *slot = m_servers.list.items[m_servers.list.curvalue]; if (slot->status > SLOT_PENDING) { - UI_DrawString(0, uis.height - CHAR_HEIGHT, UI_LEFT, slot->hostname); + UI_DrawString(0, uis.height - CONCHAR_HEIGHT, UI_LEFT, slot->hostname); } } } diff --git a/src/client/ui/ui.c b/src/client/ui/ui.c index b80b1bee9..307be2d0e 100644 --- a/src/client/ui/ui.c +++ b/src/client/ui/ui.c @@ -305,9 +305,9 @@ bool UI_CursorInRect(const vrect_t *rect) void UI_DrawString(int x, int y, int flags, const char *string) { if ((flags & UI_CENTER) == UI_CENTER) { - x -= strlen(string) * CHAR_WIDTH / 2; + x -= strlen(string) * CONCHAR_WIDTH / 2; } else if (flags & UI_RIGHT) { - x -= strlen(string) * CHAR_WIDTH; + x -= strlen(string) * CONCHAR_WIDTH; } R_DrawString(x, y, flags, MAX_STRING_CHARS, string, uis.fontHandle); @@ -320,8 +320,8 @@ void UI_DrawChar(int x, int y, int flags, int ch) void UI_StringDimensions(vrect_t *rc, int flags, const char *string) { - rc->height = CHAR_HEIGHT; - rc->width = CHAR_WIDTH * strlen(string); + rc->height = CONCHAR_HEIGHT; + rc->width = CONCHAR_WIDTH * strlen(string); if ((flags & UI_CENTER) == UI_CENTER) { rc->x -= rc->width / 2; diff --git a/src/client/ui/ui.h b/src/client/ui/ui.h index c3be79296..81bdc61d8 100644 --- a/src/client/ui/ui.h +++ b/src/client/ui/ui.h @@ -75,12 +75,12 @@ typedef enum { QMS_BEEP } menuSound_t; -#define RCOLUMN_OFFSET (CHAR_WIDTH * 2) +#define RCOLUMN_OFFSET (CONCHAR_WIDTH * 2) #define LCOLUMN_OFFSET -RCOLUMN_OFFSET #define GENERIC_SPACING(x) ((x) + (x) / 4) -#define MENU_SPACING GENERIC_SPACING(CHAR_HEIGHT) +#define MENU_SPACING GENERIC_SPACING(CONCHAR_HEIGHT) #define DOUBLE_CLICK_DELAY 300 @@ -169,9 +169,9 @@ typedef struct { #define MAX_COLUMNS 8 -#define MLIST_SPACING GENERIC_SPACING(CHAR_HEIGHT) +#define MLIST_SPACING GENERIC_SPACING(CONCHAR_HEIGHT) #define MLIST_BORDER_WIDTH 1 -#define MLIST_SCROLLBAR_WIDTH GENERIC_SPACING(CHAR_WIDTH) +#define MLIST_SCROLLBAR_WIDTH GENERIC_SPACING(CONCHAR_WIDTH) #define MLIST_PRESTEP 3 #define MLIST_PADDING (MLIST_PRESTEP*2) diff --git a/src/client/view.c b/src/client/view.c index 8e9a0c8a5..15b17f47e 100644 --- a/src/client/view.c +++ b/src/client/view.c @@ -456,6 +456,10 @@ void V_RenderView(void) Vector4Clear(cl.refdef.screen_blend); Vector4Clear(cl.refdef.damage_blend); } + if (cl.custom_fog.density) { + cl.refdef.fog = cl.custom_fog; + cl.refdef.heightfog = (player_heightfog_t){ 0 }; + } cl.refdef.num_entities = r_numentities; cl.refdef.entities = r_entities; @@ -491,11 +495,78 @@ static void V_Viewpos_f(void) Com_Printf("%s : %.f\n", vtos(cl.refdef.vieworg), cl.refdef.viewangles[YAW]); } +/* +============= +V_Fog_f +============= +*/ +static void dump_fog(const player_fog_t *fog) +{ + Com_Printf("(%.3f %.3f %.3f) %f %f\n", + fog->color[0], fog->color[1], fog->color[2], + fog->density, fog->sky_factor); +} + +static void dump_heightfog(const player_heightfog_t *fog) +{ + Com_Printf("Start : (%.3f %.3f %.3f) %.f\n", + fog->start.color[0], fog->start.color[1], fog->start.color[2], fog->start.dist); + Com_Printf("End : (%.3f %.3f %.3f) %.f\n", + fog->end.color[0], fog->end.color[1], fog->end.color[2], fog->end.dist); + Com_Printf("Density: %f\n", fog->density); + Com_Printf("Falloff: %f\n", fog->falloff); +} + +static void V_Fog_f(void) +{ + int argc = Cmd_Argc(); + float args[5]; + + if (argc == 1) { + if (cl.custom_fog.density) { + Com_Printf("User set global fog:\n"); + dump_fog(&cl.custom_fog); + return; + } + if (!cl.frame.ps.fog.density && !cl.frame.ps.heightfog.density) { + Com_Printf("No fog.\n"); + return; + } + if (cl.frame.ps.fog.density) { + Com_Printf("Global fog:\n"); + dump_fog(&cl.frame.ps.fog); + } + if (cl.frame.ps.heightfog.density) { + Com_Printf("Height fog:\n"); + dump_heightfog(&cl.frame.ps.heightfog); + } + return; + } + + if (argc < 5) { + Com_Printf("Usage: %s [sky_factor]\n", Cmd_Argv(0)); + return; + } + + for (int i = 0; i < 5; i++) + args[i] = Q_clipf(Q_atof(Cmd_Argv(i + 1)), 0, 1); + + cl.custom_fog.color[0] = args[0]; + cl.custom_fog.color[1] = args[1]; + cl.custom_fog.color[2] = args[2]; + cl.custom_fog.density = args[3]; + cl.custom_fog.sky_factor = args[4]; + + cl.refdef.fog = cl.custom_fog; + cl.refdef.heightfog = (player_heightfog_t){ 0 }; +} + static const cmdreg_t v_cmds[] = { { "gun_next", V_Gun_Next_f }, { "gun_prev", V_Gun_Prev_f }, { "gun_model", V_Gun_Model_f }, { "viewpos", V_Viewpos_f }, + { "fog", V_Fog_f }, { NULL } }; diff --git a/src/common/bsp.c b/src/common/bsp.c index 3bc3a688f..27c3d8d97 100644 --- a/src/common/bsp.c +++ b/src/common/bsp.c @@ -152,8 +152,6 @@ static list_t bsp_cache; static void BSP_PrintStats(const bsp_t *bsp) { - bool extended = bsp->extended; - for (int i = 0; i < q_countof(bsp_stats); i++) Com_Printf("%8d : %s\n", *(int *)((byte *)bsp + bsp_stats[i].ofs), bsp_stats[i].name); @@ -169,15 +167,15 @@ static void BSP_PrintStats(const bsp_t *bsp) "%8u : lightgrid leafs\n" "%8u : lightgrid samples\n", grid->numstyles, grid->numnodes, grid->numleafs, grid->numsamples); - extended = true; } - extended |= bsp->lm_decoupled; #endif - if (extended) { + if (bsp->extended || bsp->has_bspx) { Com_Printf("Features :"); if (bsp->extended) Com_Printf(" QBSP"); + if (bsp->has_bspx) + Com_Printf(" BSPX"); #if USE_REF if (bsp->lm_decoupled) Com_Printf(" DECOUPLED_LM"); @@ -186,6 +184,7 @@ static void BSP_PrintStats(const bsp_t *bsp) #endif Com_Printf("\n"); } + Com_Printf("Checksum : %#x\n", bsp->checksum); Com_Printf("------------------\n"); } @@ -717,11 +716,24 @@ static size_t BSP_ParseExtensionHeader(bsp_t *bsp, lump_t *out, const byte *buf, } } + bsp->has_bspx = true; + return extrasize; } #endif +// remaster needs ORed contents from all brushes for solid leafs +static void BSP_MergeLeafContents(bsp_t *bsp) +{ + mleaf_t *leaf; + int i, j; + + for (i = 1, leaf = bsp->leafs + i; i < bsp->numleafs; i++, leaf++) + for (j = 0; j < leaf->numleafbrushes; j++) + leaf->contents[1] |= leaf->firstleafbrush[j]->contents; +} + /* ================== BSP_Load @@ -862,6 +874,8 @@ int BSP_Load(const char *name, bsp_t **bsp_p) } #endif + BSP_MergeLeafContents(bsp); + Hunk_End(&bsp->hunk); List_Append(&bsp_cache, &bsp->entry); @@ -967,6 +981,8 @@ void BSP_LightPoint(lightpoint_t *point, const vec3_t start, const vec3_t end, c light_mask = nolm_mask; BSP_RecursiveLightPoint(headnode, 0, 1, start, end); + + LerpVector(start, end, light_point->fraction, light_point->pos); } void BSP_TransformedLightPoint(lightpoint_t *point, const vec3_t start, const vec3_t end, @@ -1003,6 +1019,8 @@ void BSP_TransformedLightPoint(lightpoint_t *point, const vec3_t start, const ve // offset plane distance point->plane.dist += DotProduct(point->plane.normal, origin); + + LerpVector(start, end, light_point->fraction, light_point->pos); } #endif @@ -1083,7 +1101,7 @@ byte *BSP_ClusterVis(const bsp_t *bsp, byte *mask, int cluster, int vis) Q_SetBit(mask, 939); Q_SetBit(mask, 947); } - } else if (bsp->checksum == 0x2b2ccdd1) { + } else if (bsp->checksum == 0x1ebe8001) { // mgu6m2, waterfall Q_SetBit(mask, 213); Q_SetBit(mask, 214); diff --git a/src/common/bsp_template.c b/src/common/bsp_template.c index 9554f7233..6e0a68716 100644 --- a/src/common/bsp_template.c +++ b/src/common/bsp_template.c @@ -455,7 +455,7 @@ BSP_LOAD(Leafs) for (int i = 0; i < count; i++, out++) { out->plane = NULL; - out->contents = BSP_Long(); + out->contents[0] = out->contents[1] = BSP_Long(); uint32_t cluster = BSP_ExtLong(); if (cluster == BSP_ExtNull) { @@ -496,7 +496,7 @@ BSP_LOAD(Leafs) out->numleafbrushes = numleafbrushes; } - BSP_ENSURE(bsp->leafs[0].contents == CONTENTS_SOLID, "Map leaf 0 is not CONTENTS_SOLID"); + BSP_ENSURE(bsp->leafs[0].contents[0] == CONTENTS_SOLID, "Map leaf 0 is not CONTENTS_SOLID"); return Q_ERR_SUCCESS; } diff --git a/src/common/cmodel.c b/src/common/cmodel.c index ee8e9b64f..b6306f37d 100644 --- a/src/common/cmodel.c +++ b/src/common/cmodel.c @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/cmd.h" #include "common/cmodel.h" #include "common/common.h" +#include "common/crc.h" #include "common/cvar.h" #include "common/files.h" #include "common/math.h" @@ -37,7 +38,6 @@ static unsigned floodvalid; static unsigned checkcount; static cvar_t *map_noareas; -static cvar_t *map_allsolid_bug; static cvar_t *map_override_path; static void FloodAreaConnections(const cm_t *cm); @@ -51,20 +51,43 @@ enum { OVERRIDE_ALL = MASK(3) }; -static void load_entstring_override(cm_t *cm, const char *server) +static void load_entstring_override(cm_t *cm) { - char buffer[MAX_QPATH], *data = NULL; - int ret; + char buffer[MAX_QPATH], name[MAX_QPATH], *data = NULL; + const bsp_t *bsp = cm->cache; + const char *path = map_override_path->string; + int ret, crc = 0; + + if (!*path) + return; + + if (!Com_ParseMapName(name, bsp->name, sizeof(name))) + return; + + // last byte is excluded from CRC (why?) + if (bsp->numentitychars > 0) + crc = CRC_Block((const byte *)bsp->entitystring, bsp->numentitychars - 1); - if (Q_snprintf(buffer, sizeof(buffer), "%s/%s.ent", map_override_path->string, server) >= sizeof(buffer)) { + // load entity string from `@.ent' + if (Q_snprintf(buffer, sizeof(buffer), "%s/%s@%04x.ent", path, name, crc) >= sizeof(buffer)) { ret = Q_ERR(ENAMETOOLONG); goto fail; } - ret = FS_LoadFileEx(buffer, (void **)&data, 0, TAG_CMODEL); - if (!data) { - if (ret == Q_ERR(ENOENT)) - return; + + // fall back to no hash + if (ret == Q_ERR(ENOENT)) { + Q_snprintf(buffer, sizeof(buffer), "%s/%s.ent", path, name); + ret = FS_LoadFileEx(buffer, (void **)&data, 0, TAG_CMODEL); + } + if (ret == Q_ERR(ENOENT)) + return; + + if (ret < 0) + goto fail; + + if (ret < 2) { + ret = Q_ERR_FILE_TOO_SMALL; goto fail; } @@ -78,7 +101,18 @@ static void load_entstring_override(cm_t *cm, const char *server) Com_EPrintf("Couldn't load entity string from %s: %s\n", buffer, Q_ErrorString(ret)); } -static void load_binary_override(cm_t *cm, char *server, size_t server_size) +/* +================== +CM_LoadOverride + +Load R1Q2-style binary override file. + +Must be called before CM_LoadMap(). +May modify server buffer if name override is in effect. +May allocate enstring, must be freed with CM_FreeMap(). +================== +*/ +void CM_LoadOverride(cm_t *cm, char *server, size_t server_size) { sizebuf_t sz; char buffer[MAX_QPATH]; @@ -86,6 +120,9 @@ static void load_binary_override(cm_t *cm, char *server, size_t server_size) int ret, bits, len; char *buf, name_buf[MAX_QPATH]; + if (!*map_override_path->string) + return; + if (Q_snprintf(buffer, sizeof(buffer), "%s/%s.bsp.override", map_override_path->string, server) >= sizeof(buffer)) { ret = Q_ERR(ENAMETOOLONG); goto fail; @@ -142,28 +179,6 @@ static void load_binary_override(cm_t *cm, char *server, size_t server_size) FS_FreeFile(data); } -/* -================== -CM_LoadOverrides - -Ugly hack to override entstring and other parameters. - -Must be called before CM_LoadMap. -May modify server buffer if name override is in effect. -May allocate enstring, must be freed with CM_FreeMap(). -================== -*/ -void CM_LoadOverrides(cm_t *cm, char *server, size_t server_size) -{ - if (!*map_override_path->string) - return; - - load_binary_override(cm, server, server_size); - - if (!(cm->override_bits & OVERRIDE_ENTS)) - load_entstring_override(cm, server); -} - /* ================== CM_FreeMap @@ -214,6 +229,9 @@ int CM_LoadMap(cm_t *cm, const char *name) if (!cm->cache) return ret; + if (!(cm->override_bits & OVERRIDE_ENTS)) + load_entstring_override(cm); + if (!(cm->override_bits & OVERRIDE_CSUM)) cm->checksum = cm->cache->checksum; @@ -287,7 +305,7 @@ static void CM_InitBoxHull(void) box_brush.firstbrushside = &box_brushsides[0]; box_brush.contents = CONTENTS_MONSTER; - box_leaf.contents = CONTENTS_MONSTER; + box_leaf.contents[0] = box_leaf.contents[1] = CONTENTS_MONSTER; box_leaf.firstleafbrush = &box_leafbrush; box_leaf.numleafbrushes = 1; @@ -412,7 +430,8 @@ rotating entities ================== */ int CM_TransformedPointContents(const vec3_t p, const mnode_t *headnode, - const vec3_t origin, const vec3_t angles) + const vec3_t origin, const vec3_t angles, + bool extended) { vec3_t p_l; vec3_t axis[3]; @@ -429,7 +448,7 @@ int CM_TransformedPointContents(const vec3_t p, const mnode_t *headnode, RotatePoint(p_l, axis); } - return BSP_PointLeaf(headnode, p_l)->contents; + return BSP_PointLeaf(headnode, p_l)->contents[extended]; } /* @@ -450,6 +469,7 @@ static vec3_t trace_extents; static trace_t *trace_trace; static int trace_contents; static bool trace_ispoint; // optimized case +static bool trace_extended; // remaster fixes /* ================ @@ -530,7 +550,7 @@ static void CM_ClipBoxToBrush(const vec3_t p1, const vec3_t p2, trace_t *trace, trace->startsolid = true; if (!getout) { trace->allsolid = true; - if (!map_allsolid_bug->integer) { + if (trace_extended) { // original Q2 didn't set these trace->fraction = 0; trace->contents = brush->contents; @@ -599,7 +619,7 @@ static void CM_TraceToLeaf(const mleaf_t *leaf) int k; mbrush_t *b, **leafbrush; - if (!(leaf->contents & trace_contents)) + if (!(leaf->contents[trace_extended] & trace_contents)) return; // trace line against all brushes in the leaf leafbrush = leaf->firstleafbrush; @@ -627,7 +647,7 @@ static void CM_TestInLeaf(const mleaf_t *leaf) int k; mbrush_t *b, **leafbrush; - if (!(leaf->contents & trace_contents)) + if (!(leaf->contents[trace_extended] & trace_contents)) return; // trace line against all brushes in the leaf leafbrush = leaf->firstleafbrush; @@ -744,7 +764,8 @@ CM_BoxTrace void CM_BoxTrace(trace_t *trace, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, - const mnode_t *headnode, int brushmask) + const mnode_t *headnode, int brushmask, + bool extended) { const vec_t *bounds[2] = { mins, maxs }; int i, j; @@ -761,6 +782,7 @@ void CM_BoxTrace(trace_t *trace, return; trace_contents = brushmask; + trace_extended = extended; VectorCopy(start, trace_start); VectorCopy(end, trace_end); for (i = 0; i < 8; i++) @@ -826,7 +848,8 @@ void CM_TransformedBoxTrace(trace_t *trace, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, const mnode_t *headnode, int brushmask, - const vec3_t origin, const vec3_t angles) + const vec3_t origin, const vec3_t angles, + bool extended) { vec3_t start_l, end_l; vec3_t axis[3]; @@ -845,15 +868,19 @@ void CM_TransformedBoxTrace(trace_t *trace, } // sweep the box through the model - CM_BoxTrace(trace, start_l, end_l, mins, maxs, headnode, brushmask); + CM_BoxTrace(trace, start_l, end_l, mins, maxs, headnode, brushmask, extended); - // rotate plane normal into the worlds frame of reference - if (rotated && trace->fraction != 1.0f) { - TransposeAxis(axis); - RotatePoint(trace->plane.normal, axis); - } + if (trace->fraction != 1.0f) { + // rotate plane normal into the worlds frame of reference + if (rotated) { + TransposeAxis(axis); + RotatePoint(trace->plane.normal, axis); + } - // FIXME: offset plane distance? + // offset plane distance + if (extended) + trace->plane.dist += DotProduct(trace->plane.normal, origin); + } LerpVector(start, end, trace->fraction, trace->endpos); } @@ -867,7 +894,7 @@ void CM_ClipEntity(trace_t *dst, const trace_t *src, struct edict_s *ent) VectorCopy(src->endpos, dst->endpos); dst->plane = src->plane; dst->surface = src->surface; - dst->contents |= src->contents; + dst->contents = src->contents; dst->ent = ent; } } @@ -1137,6 +1164,5 @@ void CM_Init(void) CM_InitBoxHull(); map_noareas = Cvar_Get("map_noareas", "0", 0); - map_allsolid_bug = Cvar_Get("map_allsolid_bug", "1", 0); map_override_path = Cvar_Get("map_override_path", "", 0); } diff --git a/src/client/crc.c b/src/common/crc.c similarity index 98% rename from src/client/crc.c rename to src/common/crc.c index b661f0a08..68aec0c27 100644 --- a/src/client/crc.c +++ b/src/common/crc.c @@ -17,7 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc., */ /* crc.c */ -#include "client.h" +#include "shared/shared.h" +#include "common/crc.h" // this is a 16 bit, non-reflected CRC using the polynomial 0x1021 // and the initial and final xor values shown below... in other words, the @@ -61,7 +62,7 @@ static const uint16_t crctable[256] = { 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; -static uint16_t CRC_Block(const byte *start, size_t count) +uint16_t CRC_Block(const byte *start, size_t count) { uint16_t crc = CRC_INIT_VALUE; @@ -71,6 +72,8 @@ static uint16_t CRC_Block(const byte *start, size_t count) return crc; } +#if USE_CLIENT + static const byte chktbl[1024] = { 0x84, 0x47, 0x51, 0xc1, 0x93, 0x22, 0x21, 0x24, 0x2f, 0x66, 0x60, 0x4d, 0xb0, 0x7c, 0xda, 0x88, 0x54, 0x15, 0x2b, 0xc6, 0x6c, 0x89, 0xc5, 0x9d, 0x48, 0xee, 0xe6, 0x8a, 0xb5, 0xf4, @@ -178,3 +181,5 @@ byte COM_BlockSequenceCRCByte(const byte *base, size_t length, int sequence) return crc; } + +#endif // USE_CLIENT diff --git a/src/common/field.c b/src/common/field.c index 8e1ac8ecf..94a879742 100644 --- a/src/common/field.c +++ b/src/common/field.c @@ -93,6 +93,7 @@ bool IF_KeyEvent(inputField_t *field, int key) while (field->text[pos] > 32) { pos++; } + Q_assert(pos < sizeof(field->text)); memmove(field->text + field->cursorPos, field->text + pos, sizeof(field->text) - pos); return true; @@ -278,7 +279,7 @@ int IF_Draw(const inputField_t *field, int x, int y, int flags, qhandle_t font) // draw blinking cursor if (flags & UI_DRAWCURSOR && com_localTime & BIT(8)) { - R_DrawChar(x + cursorPos * CHAR_WIDTH, y, flags, + R_DrawChar(x + cursorPos * CONCHAR_WIDTH, y, flags, Key_GetOverstrikeMode() ? 11 : '_', font); } diff --git a/src/common/files.c b/src/common/files.c index 62c96faa5..4d1c26b2c 100644 --- a/src/common/files.c +++ b/src/common/files.c @@ -973,7 +973,7 @@ static int check_header_coherency(FILE *fp, packfile_t *entry) static voidpf FS_zalloc(voidpf opaque, uInt items, uInt size) { - return FS_Malloc(items * size); + return FS_Malloc((size_t)items * size); } static void FS_zfree(voidpf opaque, voidpf address) diff --git a/src/common/pmove/new.c b/src/common/pmove/new.c index a47f3f4c2..58b2ba75f 100644 --- a/src/common/pmove/new.c +++ b/src/common/pmove/new.c @@ -24,4 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PMOVE_FUNC PmoveNew #define PMOVE_TIME_SHIFT pmp->time_shift #define PMOVE_C2S(x) SignExtend(COORD2SHORT(x), pmp->coord_bits) +#define PMOVE_TRACE(start, mins, maxs, end) pm->trace(start, mins, maxs, end, 0) +#define PMOVE_TRACE_MASK(start, mins, maxs, end, mask) pm->trace(start, mins, maxs, end, mask) #include "template.c" diff --git a/src/common/pmove/old.c b/src/common/pmove/old.c index 6060e7ef1..75cc92589 100644 --- a/src/common/pmove/old.c +++ b/src/common/pmove/old.c @@ -24,4 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PMOVE_FUNC PmoveOld #define PMOVE_TIME_SHIFT 3 #define PMOVE_C2S(x) COORD2SHORT(x) +#define PMOVE_TRACE(start, mins, maxs, end) pm->trace(start, mins, maxs, end) +#define PMOVE_TRACE_MASK(start, mins, maxs, end, mask) pm->trace(start, mins, maxs, end) #include "template.c" diff --git a/src/common/pmove/template.c b/src/common/pmove/template.c index 2fba4e5fb..3b3c6dc16 100644 --- a/src/common/pmove/template.c +++ b/src/common/pmove/template.c @@ -30,7 +30,6 @@ typedef struct { float frametime; csurface_t *groundsurface; - cplane_t groundplane; int groundcontents; int previous_origin[3]; @@ -117,7 +116,7 @@ static void PM_StepSlideMove_(void) for (i = 0; i < 3; i++) end[i] = pml.origin[i] + time_left * pml.velocity[i]; - trace = pm->trace(pml.origin, pm->mins, pm->maxs, end); + trace = PMOVE_TRACE(pml.origin, pm->mins, pm->maxs, end); if (trace.allsolid) { // entity is trapped in another solid @@ -218,7 +217,7 @@ static void PM_StepSlideMove(void) VectorCopy(start_o, up); up[2] += STEPSIZE; - trace = pm->trace(up, pm->mins, pm->maxs, up); + trace = PMOVE_TRACE(up, pm->mins, pm->maxs, up); if (trace.allsolid) return; // can't step up @@ -231,7 +230,7 @@ static void PM_StepSlideMove(void) // push down the final amount VectorCopy(pml.origin, down); down[2] -= STEPSIZE; - trace = pm->trace(pml.origin, pm->mins, pm->maxs, down); + trace = PMOVE_TRACE(pml.origin, pm->mins, pm->maxs, down); if (!trace.allsolid) VectorCopy(trace.endpos, pml.origin); @@ -568,8 +567,10 @@ static void PM_CategorizePosition(void) pm->s.pm_flags &= ~PMF_ON_GROUND; pm->groundentity = NULL; } else { - trace = pm->trace(pml.origin, pm->mins, pm->maxs, point); - pml.groundplane = trace.plane; + trace = PMOVE_TRACE(pml.origin, pm->mins, pm->maxs, point); +#ifdef PMOVE_NEW + pm->groundplane = trace.plane; +#endif pml.groundsurface = trace.surface; pml.groundcontents = trace.contents; @@ -715,7 +716,7 @@ static void PM_CheckSpecialMovement(void) VectorNormalize(flatforward); VectorMA(pml.origin, 1, flatforward, spot); - trace = pm->trace(pml.origin, pm->mins, pm->maxs, spot); + trace = PMOVE_TRACE_MASK(pml.origin, pm->mins, pm->maxs, spot, CONTENTS_LADDER); if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER)) pml.ladder = true; @@ -855,7 +856,7 @@ static void PM_CheckDuck(void) if (pm->s.pm_flags & PMF_DUCKED) { // try to stand up pm->maxs[2] = 32; - trace = pm->trace(pml.origin, pm->mins, pm->maxs, pml.origin); + trace = PMOVE_TRACE(pml.origin, pm->mins, pm->maxs, pml.origin); if (!trace.allsolid) pm->s.pm_flags &= ~PMF_DUCKED; } @@ -904,7 +905,7 @@ static bool PM_GoodPosition(void) for (i = 0; i < 3; i++) origin[i] = end[i] = pm->s.origin[i] * 0.125f; - trace = pm->trace(origin, pm->mins, pm->maxs, end); + trace = PMOVE_TRACE(origin, pm->mins, pm->maxs, end); return !trace.allsolid; } diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 3e78e7a14..c8e99d4de 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -805,7 +805,7 @@ void bfg_think(edict_t *self) gi.WriteByte(4); gi.WritePosition(tr.endpos); gi.WriteDir(tr.plane.normal); - gi.WriteByte(self->s.skinnum); + gi.WriteByte(0xd0); gi.multicast(tr.endpos, MULTICAST_PVS); break; } diff --git a/src/game/p_client.c b/src/game/p_client.c index b55a4e95c..50f6d79fb 100644 --- a/src/game/p_client.c +++ b/src/game/p_client.c @@ -1488,15 +1488,20 @@ void ClientDisconnect(edict_t *ent) //============================================================== edict_t *pm_passent; +int pm_clipmask; // pmove doesn't need to know about passent and contentmask +#if USE_NEW_GAME_API +trace_t q_gameabi PM_trace(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int contentmask) +{ + return gi.trace(start, mins, maxs, end, pm_passent, (game.csr.extended && contentmask) ? contentmask : pm_clipmask); +} +#else trace_t q_gameabi PM_trace(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end) { - if (pm_passent->health > 0) - return gi.trace(start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID); - else - return gi.trace(start, mins, maxs, end, pm_passent, MASK_DEADSOLID); + return gi.trace(start, mins, maxs, end, pm_passent, pm_clipmask); } +#endif /* ============== @@ -1525,8 +1530,6 @@ void ClientThink(edict_t *ent, usercmd_t *ucmd) return; } - pm_passent = ent; - if (ent->client->chase_target) { client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]); @@ -1547,6 +1550,12 @@ void ClientThink(edict_t *ent, usercmd_t *ucmd) else client->ps.pmove.pm_type = PM_NORMAL; + pm_passent = ent; + if (ent->health > 0) + pm_clipmask = MASK_PLAYERSOLID; + else + pm_clipmask = MASK_DEADSOLID; + client->ps.pmove.gravity = sv_gravity->value; pm.s = client->ps.pmove; diff --git a/src/refresh/draw.c b/src/refresh/draw.c index 95c90e159..3ba10792e 100644 --- a/src/refresh/draw.c +++ b/src/refresh/draw.c @@ -361,23 +361,26 @@ static inline void draw_char(int x, int y, int flags, int c, const image_t *imag s = (c & 15) * 0.0625f; t = (c >> 4) * 0.0625f; - if (gl_fontshadow->integer > 0 && c != 0x83) { + if (flags & UI_DROPSHADOW && c != 0x83) { uint32_t black = draw.colors[0].u32 & U32_ALPHA; - GL_StretchPic(x + 1, y + 1, CHAR_WIDTH, CHAR_HEIGHT, s, t, + GL_StretchPic(x + 1, y + 1, CONCHAR_WIDTH, CONCHAR_HEIGHT, s, t, s + 0.0625f, t + 0.0625f, black, image); if (gl_fontshadow->integer > 1) - GL_StretchPic(x + 2, y + 2, CHAR_WIDTH, CHAR_HEIGHT, s, t, + GL_StretchPic(x + 2, y + 2, CONCHAR_WIDTH, CONCHAR_HEIGHT, s, t, s + 0.0625f, t + 0.0625f, black, image); } - GL_StretchPic(x, y, CHAR_WIDTH, CHAR_HEIGHT, s, t, + GL_StretchPic(x, y, CONCHAR_WIDTH, CONCHAR_HEIGHT, s, t, s + 0.0625f, t + 0.0625f, draw.colors[c >> 7].u32, image); } void R_DrawChar(int x, int y, int flags, int c, qhandle_t font) { + if (gl_fontshadow->integer > 0) + flags |= UI_DROPSHADOW; + draw_char(x, y, flags, c & 255, IMG_ForHandle(font)); } @@ -385,10 +388,13 @@ int R_DrawString(int x, int y, int flags, size_t maxlen, const char *s, qhandle_ { const image_t *image = IMG_ForHandle(font); + if (gl_fontshadow->integer > 0) + flags |= UI_DROPSHADOW; + while (maxlen-- && *s) { byte c = *s++; draw_char(x, y, flags, c, image); - x += CHAR_WIDTH; + x += CONCHAR_WIDTH; } return x; @@ -415,7 +421,7 @@ void Draw_Stats(void) int x = 10, y = 10; R_SetScale(1.0f / get_auto_scale()); - R_DrawFill8(8, 8, 25*8, 23*10+2, 4); + R_DrawFill8(8, 8, 25*8, 24*10+2, 4); Draw_Stringf(x, y, "Nodes visible : %i", glr.nodes_visible); y += 10; Draw_Stringf(x, y, "Nodes culled : %i", c.nodesCulled); y += 10; @@ -426,6 +432,7 @@ void Draw_Stats(void) Draw_Stringf(x, y, "Boxes culled : %i", c.boxesCulled); y += 10; Draw_Stringf(x, y, "Spheres culled : %i", c.spheresCulled); y += 10; Draw_Stringf(x, y, "RtBoxes culled : %i", c.rotatedBoxesCulled); y += 10; + Draw_Stringf(x, y, "Shadows culled : %i", c.shadowsCulled); y += 10; Draw_Stringf(x, y, "Tris drawn : %i", c.trisDrawn); y += 10; Draw_Stringf(x, y, "Tex switches : %i", c.texSwitches); y += 10; Draw_Stringf(x, y, "Tex uploads : %i", c.texUploads); y += 10; diff --git a/src/refresh/gl.h b/src/refresh/gl.h index fd3f27ec7..e28c301a8 100644 --- a/src/refresh/gl.h +++ b/src/refresh/gl.h @@ -50,10 +50,34 @@ typedef GLushort glIndex_t; typedef GLuint glIndex_t; #endif +typedef uint64_t glStateBits_t; + #define TAB_SIN(x) gl_static.sintab[(x) & 255] #define TAB_COS(x) gl_static.sintab[((x) + 64) & 255] -#define NUM_AUTO_TEXTURES 9 +// auto textures +#define NUM_AUTO_TEXTURES 13 +#define AUTO_TEX(n) gl_static.texnums[n] + +#define TEXNUM_DEFAULT AUTO_TEX(0) +#define TEXNUM_SCRAP AUTO_TEX(1) +#define TEXNUM_PARTICLE AUTO_TEX(2) +#define TEXNUM_BEAM AUTO_TEX(3) +#define TEXNUM_WHITE AUTO_TEX(4) +#define TEXNUM_BLACK AUTO_TEX(5) +#define TEXNUM_RAW AUTO_TEX(6) +#define TEXNUM_CUBEMAP_DEFAULT AUTO_TEX(7) +#define TEXNUM_CUBEMAP_BLACK AUTO_TEX(8) +#define TEXNUM_PP_SCENE AUTO_TEX(9) +#define TEXNUM_PP_BLOOM AUTO_TEX(10) +#define TEXNUM_PP_BLUR_0 AUTO_TEX(11) +#define TEXNUM_PP_BLUR_1 AUTO_TEX(12) + +// framebuffers +#define FBO_COUNT 3 +#define FBO_SCENE gl_static.framebuffers[0] +#define FBO_BLUR_0 gl_static.framebuffers[1] +#define FBO_BLUR_1 gl_static.framebuffers[2] typedef struct { GLuint query; @@ -76,9 +100,8 @@ typedef struct { size_t buffer_size; vec_t size; } world; - GLuint warp_texture; - GLuint warp_renderbuffer; - GLuint warp_framebuffer; + GLuint renderbuffer; + GLuint framebuffers[FBO_COUNT]; GLuint uniform_buffer; #if USE_MD5 GLuint skeleton_buffer; @@ -92,6 +115,7 @@ typedef struct { GLenum samples_passed; GLbitfield stencil_buffer_bit; float entity_modulate; + float bloom_sigma; uint32_t inverse_intensity_33; uint32_t inverse_intensity_66; uint32_t inverse_intensity_100; @@ -127,10 +151,11 @@ typedef struct { lightpoint_t lightpoint; int num_beams; int num_flares; - int fog_bits, fog_bits_sky; + glStateBits_t fog_bits, fog_bits_sky; int framebuffer_width; int framebuffer_height; bool framebuffer_ok; + bool framebuffer_bound; } glRefdef_t; typedef enum { @@ -192,6 +217,7 @@ typedef struct { int boxesCulled; int spheresCulled; int rotatedBoxesCulled; + int shadowsCulled; int batchesDrawn2D; int uniformUploads; int vertexArrayBinds; @@ -226,6 +252,7 @@ extern cvar_t *gl_md5_use; extern cvar_t *gl_md5_distance; #endif extern cvar_t *gl_damageblend_frac; +extern cvar_t *gl_bloom; // development variables extern cvar_t *gl_znear; @@ -349,6 +376,11 @@ typedef struct { #define MD5_MAX_FRAMES 1024 /* Joint */ +typedef struct { + vec4_t pos; + vec4_t axis[3]; +} glJoint_t; + typedef struct { vec3_t pos; float scale; @@ -476,54 +508,64 @@ void GL_LoadWorld(const char *name); * gl_state.c * */ -typedef enum { - GLS_DEFAULT = 0, - GLS_DEPTHMASK_FALSE = BIT(0), - GLS_DEPTHTEST_DISABLE = BIT(1), - GLS_CULL_DISABLE = BIT(2), - GLS_BLEND_BLEND = BIT(3), - GLS_BLEND_ADD = BIT(4), - GLS_BLEND_MODULATE = BIT(5), - - GLS_ALPHATEST_ENABLE = BIT(6), - GLS_TEXTURE_REPLACE = BIT(7), - GLS_SCROLL_ENABLE = BIT(8), - GLS_LIGHTMAP_ENABLE = BIT(9), - GLS_WARP_ENABLE = BIT(10), - GLS_INTENSITY_ENABLE = BIT(11), - GLS_GLOWMAP_ENABLE = BIT(12), - GLS_CLASSIC_SKY = BIT(13), - GLS_DEFAULT_SKY = BIT(14), - GLS_DEFAULT_FLARE = BIT(15), - - GLS_MESH_MD2 = BIT(16), - GLS_MESH_MD5 = BIT(17), - GLS_MESH_LERP = BIT(18), - GLS_MESH_SHELL = BIT(19), - GLS_MESH_SHADE = BIT(20), - - GLS_SHADE_SMOOTH = BIT(21), - GLS_SCROLL_X = BIT(22), - GLS_SCROLL_Y = BIT(23), - GLS_SCROLL_FLIP = BIT(24), - GLS_SCROLL_SLOW = BIT(25), - - GLS_FOG_GLOBAL = BIT(26), - GLS_FOG_HEIGHT = BIT(27), - GLS_FOG_SKY = BIT(28), - - GLS_BLEND_MASK = GLS_BLEND_BLEND | GLS_BLEND_ADD | GLS_BLEND_MODULATE, - GLS_COMMON_MASK = GLS_DEPTHMASK_FALSE | GLS_DEPTHTEST_DISABLE | GLS_CULL_DISABLE | GLS_BLEND_MASK, - GLS_SKY_MASK = GLS_CLASSIC_SKY | GLS_DEFAULT_SKY, - GLS_FOG_MASK = GLS_FOG_GLOBAL | GLS_FOG_HEIGHT | GLS_FOG_SKY, - GLS_MESH_ANY = GLS_MESH_MD2 | GLS_MESH_MD5, - GLS_MESH_MASK = GLS_MESH_ANY | GLS_MESH_LERP | GLS_MESH_SHELL | GLS_MESH_SHADE, - GLS_SHADER_MASK = GLS_ALPHATEST_ENABLE | GLS_TEXTURE_REPLACE | GLS_SCROLL_ENABLE | - GLS_LIGHTMAP_ENABLE | GLS_WARP_ENABLE | GLS_INTENSITY_ENABLE | GLS_GLOWMAP_ENABLE | - GLS_SKY_MASK | GLS_DEFAULT_FLARE | GLS_MESH_MASK | GLS_FOG_MASK, - GLS_UNIFORM_MASK = GLS_WARP_ENABLE | GLS_LIGHTMAP_ENABLE | GLS_INTENSITY_ENABLE | GLS_SKY_MASK | GLS_FOG_MASK, - GLS_SCROLL_MASK = GLS_SCROLL_ENABLE | GLS_SCROLL_X | GLS_SCROLL_Y | GLS_SCROLL_FLIP | GLS_SCROLL_SLOW, -} glStateBits_t; +#define GLS_DEFAULT 0ULL + +#define GLS_DEPTHMASK_FALSE BIT_ULL(0) +#define GLS_DEPTHTEST_DISABLE BIT_ULL(1) +#define GLS_CULL_DISABLE BIT_ULL(2) +#define GLS_BLEND_BLEND BIT_ULL(3) +#define GLS_BLEND_ADD BIT_ULL(4) +#define GLS_BLEND_MODULATE BIT_ULL(5) + +#define GLS_ALPHATEST_ENABLE BIT_ULL(6) +#define GLS_TEXTURE_REPLACE BIT_ULL(7) +#define GLS_SCROLL_ENABLE BIT_ULL(8) +#define GLS_LIGHTMAP_ENABLE BIT_ULL(9) +#define GLS_WARP_ENABLE BIT_ULL(10) +#define GLS_INTENSITY_ENABLE BIT_ULL(11) +#define GLS_GLOWMAP_ENABLE BIT_ULL(12) +#define GLS_CLASSIC_SKY BIT_ULL(13) +#define GLS_DEFAULT_SKY BIT_ULL(14) +#define GLS_DEFAULT_FLARE BIT_ULL(15) + +#define GLS_MESH_MD2 BIT_ULL(16) +#define GLS_MESH_MD5 BIT_ULL(17) +#define GLS_MESH_LERP BIT_ULL(18) +#define GLS_MESH_SHELL BIT_ULL(19) +#define GLS_MESH_SHADE BIT_ULL(20) + +#define GLS_SHADE_SMOOTH BIT_ULL(21) +#define GLS_SCROLL_X BIT_ULL(22) +#define GLS_SCROLL_Y BIT_ULL(23) +#define GLS_SCROLL_FLIP BIT_ULL(24) +#define GLS_SCROLL_SLOW BIT_ULL(25) + +#define GLS_FOG_GLOBAL BIT_ULL(26) +#define GLS_FOG_HEIGHT BIT_ULL(27) +#define GLS_FOG_SKY BIT_ULL(28) + +#define GLS_BLOOM_GENERATE BIT_ULL(29) +#define GLS_BLOOM_OUTPUT BIT_ULL(30) +#define GLS_BLOOM_SHELL BIT_ULL(31) + +#define GLS_BLUR_GAUSS BIT_ULL(32) +#define GLS_BLUR_BOX BIT_ULL(33) + +#define GLS_BLEND_MASK (GLS_BLEND_BLEND | GLS_BLEND_ADD | GLS_BLEND_MODULATE) +#define GLS_COMMON_MASK (GLS_DEPTHMASK_FALSE | GLS_DEPTHTEST_DISABLE | GLS_CULL_DISABLE | GLS_BLEND_MASK) +#define GLS_SKY_MASK (GLS_CLASSIC_SKY | GLS_DEFAULT_SKY) +#define GLS_FOG_MASK (GLS_FOG_GLOBAL | GLS_FOG_HEIGHT | GLS_FOG_SKY) +#define GLS_MESH_ANY (GLS_MESH_MD2 | GLS_MESH_MD5) +#define GLS_MESH_MASK (GLS_MESH_ANY | GLS_MESH_LERP | GLS_MESH_SHELL | GLS_MESH_SHADE) +#define GLS_BLOOM_MASK (GLS_BLOOM_GENERATE | GLS_BLOOM_OUTPUT | GLS_BLOOM_SHELL) +#define GLS_BLUR_MASK (GLS_BLUR_GAUSS | GLS_BLUR_BOX) +#define GLS_SHADER_MASK (GLS_ALPHATEST_ENABLE | GLS_TEXTURE_REPLACE | GLS_SCROLL_ENABLE | \ + GLS_LIGHTMAP_ENABLE | GLS_WARP_ENABLE | GLS_INTENSITY_ENABLE | \ + GLS_GLOWMAP_ENABLE | GLS_SKY_MASK | GLS_DEFAULT_FLARE | GLS_MESH_MASK | \ + GLS_FOG_MASK | GLS_BLOOM_MASK | GLS_BLUR_MASK) +#define GLS_UNIFORM_MASK (GLS_WARP_ENABLE | GLS_LIGHTMAP_ENABLE | GLS_INTENSITY_ENABLE | \ + GLS_SKY_MASK | GLS_FOG_MASK | GLS_BLUR_MASK) +#define GLS_SCROLL_MASK (GLS_SCROLL_ENABLE | GLS_SCROLL_X | GLS_SCROLL_Y | GLS_SCROLL_FLIP | GLS_SCROLL_SLOW) typedef enum { VERT_ATTR_POS, @@ -559,7 +601,7 @@ typedef enum { VA_EFFECT, VA_NULLMODEL, VA_OCCLUDE, - VA_WATERWARP, + VA_POSTPROCESS, VA_MESH_SHADE, VA_MESH_FLAT, VA_2D, @@ -768,6 +810,13 @@ static inline void GL_BindBuffer(GLenum target, GLuint buffer) } } +static inline void GL_BindBufferBase(GLenum target, GLuint index, GLuint buffer) +{ + glBufferBinding_t i = GL_BindingForTarget(target); + qglBindBufferBase(target, index, buffer); + gls.currentbuffer[i] = buffer; +} + static inline void GL_ClearDepth(GLfloat d) { if (qglClearDepthf) @@ -805,10 +854,11 @@ void GL_DrawOutlines(GLsizei count, GLenum type, const void *indices); void GL_Ortho(GLfloat xmin, GLfloat xmax, GLfloat ymin, GLfloat ymax, GLfloat znear, GLfloat zfar); void GL_Frustum(GLfloat fov_x, GLfloat fov_y, GLfloat reflect_x); void GL_Setup2D(void); -void GL_Setup3D(bool waterwarp); +void GL_Setup3D(void); void GL_ClearState(void); void GL_InitState(void); void GL_ShutdownState(void); +void GL_UpdateBlurParams(void); /* * gl_draw.c @@ -838,23 +888,12 @@ void GL_Blend(void); * */ -// auto textures -#define TEXNUM_DEFAULT gl_static.texnums[0] -#define TEXNUM_SCRAP gl_static.texnums[1] -#define TEXNUM_PARTICLE gl_static.texnums[2] -#define TEXNUM_BEAM gl_static.texnums[3] -#define TEXNUM_WHITE gl_static.texnums[4] -#define TEXNUM_BLACK gl_static.texnums[5] -#define TEXNUM_RAW gl_static.texnums[6] -#define TEXNUM_CUBEMAP_DEFAULT gl_static.texnums[7] -#define TEXNUM_CUBEMAP_BLACK gl_static.texnums[8] - void Scrap_Upload(void); void GL_InitImages(void); void GL_ShutdownImages(void); -bool GL_InitWarpTexture(void); +bool GL_InitFramebuffers(void); extern cvar_t *gl_intensity; diff --git a/src/refresh/images.c b/src/refresh/images.c index 229f2a600..d0d323078 100644 --- a/src/refresh/images.c +++ b/src/refresh/images.c @@ -309,7 +309,7 @@ static int load_pcx(const byte *rawdata, size_t rawlen, IMG_FreePixels(pixels); } else { - Com_WPrintf("%s is a 24-bit PCX file. This is not portable.\n", image->name); + Com_DWPrintf("%s is a 24-bit PCX file. This is not portable.\n", image->name); *pic = pixels; image->flags |= IF_OPAQUE; } @@ -1805,10 +1805,8 @@ static void print_error(const char *name, imageflags_t flags, int err) // ugly hack for console code if (strcmp(name, "pics/conchars.pcx")) level = PRINT_WARNING; -#if USE_DEBUG - } else if (developer->integer >= 2) { + } else if (COM_DEVELOPER >= 2) { level = PRINT_DEVELOPER; -#endif } else { return; } @@ -1922,21 +1920,23 @@ static image_t *find_or_load_image(const char *name, size_t len, image_t *image; byte *pic; unsigned hash; + size_t baselen; imageformat_t fmt; int ret; Q_assert(len < MAX_QPATH); + baselen = COM_FileExtension(name) - name; // must have an extension and at least 1 char of base name - if (len <= 4 || name[len - 4] != '.') { + if (baselen < 1 || name[baselen] != '.') { ret = Q_ERR_INVALID_PATH; goto fail; } - hash = FS_HashPathLen(name, len - 4, RIMAGES_HASH); + hash = FS_HashPathLen(name, baselen, RIMAGES_HASH); // look for it - if ((image = lookup_image(name, type, hash, len - 4)) != NULL) { + if ((image = lookup_image(name, type, hash, baselen)) != NULL) { image->registration_sequence = r_registration_sequence; if (image->upload_width && image->upload_height) { image->flags |= flags & IF_PERMANENT; @@ -1954,7 +1954,7 @@ static image_t *find_or_load_image(const char *name, size_t len, // fill in some basic info memcpy(image->name, name, len + 1); - image->baselen = len - 4; + image->baselen = baselen; image->type = type; image->flags = flags; image->registration_sequence = r_registration_sequence; diff --git a/src/refresh/main.c b/src/refresh/main.c index ddf0ba9d7..9ee32eb91 100644 --- a/src/refresh/main.c +++ b/src/refresh/main.c @@ -69,6 +69,7 @@ cvar_t *gl_md5_distance; cvar_t *gl_damageblend_frac; cvar_t *gl_waterwarp; cvar_t *gl_fog; +cvar_t *gl_bloom; cvar_t *gl_swapinterval; // development variables @@ -80,6 +81,7 @@ cvar_t *gl_showtris; cvar_t* gl_showedges; //rekkie -- gl_showedges cvar_t *gl_showorigins; cvar_t *gl_showtearing; +cvar_t *gl_showbloom; #if USE_DEBUG cvar_t *gl_showstats; cvar_t *gl_showscrap; @@ -341,6 +343,7 @@ static void GL_DrawSpriteModel(const model_t *model) const mspriteframe_t *frame = &model->spriteframes[e->frame % model->numframes]; const image_t *image = frame->image; const float alpha = (e->flags & RF_TRANSLUCENT) ? e->alpha : 1.0f; + const float scale = e->scale ? e->scale : 1.0f; glStateBits_t bits = GLS_DEPTHMASK_FALSE | glr.fog_bits; vec3_t up, down, left, right; @@ -363,10 +366,10 @@ static void GL_DrawSpriteModel(const model_t *model) GL_ArrayBits(GLA_VERTEX | GLA_TC); GL_Color(1, 1, 1, alpha); - VectorScale(glr.viewaxis[1], frame->origin_x, left); - VectorScale(glr.viewaxis[1], frame->origin_x - frame->width, right); - VectorScale(glr.viewaxis[2], -frame->origin_y, down); - VectorScale(glr.viewaxis[2], frame->height - frame->origin_y, up); + VectorScale(glr.viewaxis[1], frame->origin_x * scale, left); + VectorScale(glr.viewaxis[1], (frame->origin_x - frame->width) * scale, right); + VectorScale(glr.viewaxis[2], -frame->origin_y * scale, down); + VectorScale(glr.viewaxis[2], (frame->height - frame->origin_y) * scale, up); VectorAdd3(e->origin, down, left, tess.vertices); VectorAdd3(e->origin, up, left, tess.vertices + 5); @@ -1494,6 +1497,8 @@ static void GL_OccludeFlares(void) const entity_t *e; glquery_t *q; int i, j; + vec3_t dir, org; + float scale, dist; bool set = false; if (!glr.num_flares) @@ -1517,10 +1522,16 @@ static void GL_OccludeFlares(void) } if (q) { - if (q->pending) - continue; - if (com_eventTime - q->timestamp <= 33) - continue; + // reset visibility if entity disappeared + if (com_eventTime - q->timestamp >= 2500) { + q->pending = q->visible = false; + q->frac = 0; + } else { + if (q->pending) + continue; + if (com_eventTime - q->timestamp <= 33) + continue; + } } else { glquery_t new = { 0 }; uint32_t map_size = HashMap_Size(gl_static.queries); @@ -1541,14 +1552,19 @@ static void GL_OccludeFlares(void) set = true; } - if (bsp && BSP_PointLeaf(bsp->nodes, e->origin)->contents == CONTENTS_SOLID) { - vec3_t dir, org; - VectorSubtract(glr.fd.vieworg, e->origin, dir); + VectorSubtract(e->origin, glr.fd.vieworg, dir); + dist = DotProduct(dir, glr.viewaxis[0]); + + scale = 2.5f; + if (dist > 20) + scale += dist * 0.004f; + + if (bsp && BSP_PointLeaf(bsp->nodes, e->origin)->contents[0] & CONTENTS_SOLID) { VectorNormalize(dir); - VectorMA(e->origin, 5.0f, dir, org); - make_flare_quad(org, 2.5f); + VectorMA(e->origin, -5.0f, dir, org); + make_flare_quad(org, scale); } else - make_flare_quad(e->origin, 2.5f); + make_flare_quad(e->origin, scale); GL_LockArrays(4); qglBeginQuery(gl_static.samples_passed, q->query); @@ -1692,33 +1708,71 @@ bool GL_ShowErrors(const char *func) return true; } -static void GL_WaterWarp(void) +static void GL_PostProcess(glStateBits_t bits, int x, int y, int w, int h) { - float x0, x1, y0, y1; - - GL_ForceTexture(TMU_TEXTURE, gl_static.warp_texture); - GL_BindArrays(VA_WATERWARP); + GL_BindArrays(VA_POSTPROCESS); GL_StateBits(GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_FALSE | - GLS_CULL_DISABLE | GLS_TEXTURE_REPLACE | GLS_WARP_ENABLE); + GLS_CULL_DISABLE | GLS_TEXTURE_REPLACE | bits); GL_ArrayBits(GLA_VERTEX | GLA_TC); - GL_LoadUniforms(); - - x0 = glr.fd.x; - x1 = glr.fd.x + glr.fd.width; + gl_backend->load_uniforms(); - y0 = glr.fd.y; - y1 = glr.fd.y + glr.fd.height; - - Vector4Set(tess.vertices, x0, y0, 0, 1); - Vector4Set(tess.vertices + 4, x0, y1, 0, 0); - Vector4Set(tess.vertices + 8, x1, y0, 1, 1); - Vector4Set(tess.vertices + 12, x1, y1, 1, 0); + Vector4Set(tess.vertices, x, y, 0, 1); + Vector4Set(tess.vertices + 4, x, y + h, 0, 0); + Vector4Set(tess.vertices + 8, x + w, y, 1, 1); + Vector4Set(tess.vertices + 12, x + w, y + h, 1, 0); GL_LockArrays(4); qglDrawArrays(GL_TRIANGLE_STRIP, 0, 4); GL_UnlockArrays(); } +static void GL_DrawBloom(bool waterwarp) +{ + int iterations = Cvar_ClampInteger(gl_bloom, 1, 8) * 2; + int w = glr.fd.width / 4; + int h = glr.fd.height / 4; + + qglViewport(0, 0, w, h); + GL_Ortho(0, w, h, 0, -1, 1); + + // downscale + gls.u_block.fog_color[0] = 1.0f / w; + gls.u_block.fog_color[1] = 1.0f / h; + GL_ForceTexture(TMU_TEXTURE, TEXNUM_PP_BLOOM); + qglBindFramebuffer(GL_FRAMEBUFFER, FBO_BLUR_0); + GL_PostProcess(GLS_BLUR_BOX, 0, 0, w, h); + + // blur X/Y + for (int i = 0; i < iterations; i++) { + int j = i & 1; + + gls.u_block.fog_color[0] = 1.0f / w; + gls.u_block.fog_color[1] = 1.0f / h; + gls.u_block.fog_color[j] = 0; + + GL_ForceTexture(TMU_TEXTURE, j ? TEXNUM_PP_BLUR_1 : TEXNUM_PP_BLUR_0); + qglBindFramebuffer(GL_FRAMEBUFFER, j ? FBO_BLUR_0 : FBO_BLUR_1); + GL_PostProcess(GLS_BLUR_GAUSS, 0, 0, w, h); + } + + GL_Setup2D(); + + glStateBits_t bits = GLS_BLOOM_OUTPUT; + if (q_unlikely(gl_showbloom->integer)) { + GL_ForceTexture(TMU_TEXTURE, TEXNUM_PP_BLUR_0); + bits = GLS_DEFAULT; + } else { + GL_ForceTexture(TMU_TEXTURE, TEXNUM_PP_SCENE); + GL_ForceTexture(TMU_LIGHTMAP, TEXNUM_PP_BLUR_0); + if (waterwarp) + bits |= GLS_WARP_ENABLE; + } + + // upscale & add + qglBindFramebuffer(GL_FRAMEBUFFER, 0); + GL_PostProcess(bits, glr.fd.x, glr.fd.y, glr.fd.width, glr.fd.height); +} + void R_RenderFrame(const refdef_t *fd) { GL_Flush2D(); @@ -1751,21 +1805,38 @@ void R_RenderFrame(const refdef_t *fd) lm.dirty = false; } - bool waterwarp = (glr.fd.rdflags & RDF_UNDERWATER) && gl_static.use_shaders && gl_waterwarp->integer; + bool waterwarp = false; + bool bloom = false; - if (waterwarp) { - if (glr.fd.width != glr.framebuffer_width || glr.fd.height != glr.framebuffer_height) { - glr.framebuffer_ok = GL_InitWarpTexture(); - glr.framebuffer_width = glr.fd.width; - glr.framebuffer_height = glr.fd.height; + if (gl_static.use_shaders) { + waterwarp = (glr.fd.rdflags & RDF_UNDERWATER) && gl_waterwarp->integer; + bloom = !(glr.fd.rdflags & RDF_NOWORLDMODEL) && gl_bloom->integer; + + if (waterwarp || bloom || gl_bloom->modified) { + if (glr.fd.width != glr.framebuffer_width || glr.fd.height != glr.framebuffer_height || gl_bloom->modified) { + glr.framebuffer_ok = GL_InitFramebuffers(); + glr.framebuffer_width = glr.fd.width; + glr.framebuffer_height = glr.fd.height; + gl_bloom->modified = false; + } + if (!glr.framebuffer_ok) + waterwarp = bloom = false; } - waterwarp = glr.framebuffer_ok; } - if (waterwarp) - qglBindFramebuffer(GL_FRAMEBUFFER, gl_static.warp_framebuffer); + if (waterwarp || bloom) { + qglBindFramebuffer(GL_FRAMEBUFFER, FBO_SCENE); + glr.framebuffer_bound = true; - GL_Setup3D(waterwarp); + if (gl_clear->integer) { + GLenum buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; + qglDrawBuffers(bloom + 1, buffers); + qglClear(GL_COLOR_BUFFER_BIT); + qglDrawBuffers(1, buffers); + } + } + + GL_Setup3D(); GL_SetupFrustum(); @@ -1796,14 +1867,20 @@ void R_RenderFrame(const refdef_t *fd) GL_DrawDebugObjects(); - if (waterwarp) + if (glr.framebuffer_bound) { qglBindFramebuffer(GL_FRAMEBUFFER, 0); + glr.framebuffer_bound = false; + } // go back into 2D mode GL_Setup2D(); - if (waterwarp) - GL_WaterWarp(); + if (bloom) { + GL_DrawBloom(waterwarp); + } else if (waterwarp) { + GL_ForceTexture(TMU_TEXTURE, TEXNUM_PP_SCENE); + GL_PostProcess(GLS_WARP_ENABLE, glr.fd.x, glr.fd.y, glr.fd.width, glr.fd.height); + } if (gl_polyblend->integer) GL_Blend(); @@ -1988,6 +2065,7 @@ static void GL_Register(void) gl_damageblend_frac = Cvar_Get("gl_damageblend_frac", "0.2", 0); gl_waterwarp = Cvar_Get("gl_waterwarp", "0", 0); gl_fog = Cvar_Get("gl_fog", "1", 0); + gl_bloom = Cvar_Get("gl_bloom", "0", 0); gl_swapinterval = Cvar_Get("gl_swapinterval", "1", CVAR_ARCHIVE); gl_swapinterval->changed = gl_swapinterval_changed; @@ -2001,6 +2079,7 @@ static void GL_Register(void) gl_showedges = Cvar_Get("gl_showedges", "0", CVAR_CHEAT); //rekkie -- gl_showedges gl_showorigins = Cvar_Get("gl_showorigins", "0", CVAR_CHEAT); gl_showtearing = Cvar_Get("gl_showtearing", "0", CVAR_CHEAT); + gl_showbloom = Cvar_Get("gl_showbloom", "0", CVAR_CHEAT); #if USE_DEBUG gl_showstats = Cvar_Get("gl_showstats", "0", 0); gl_showscrap = Cvar_Get("gl_showscrap", "0", 0); diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index 29fb16bab..ffd54c446 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -41,6 +41,7 @@ static vec3_t shadedir; static bool dotshading; static float celscale; +static float shadowalpha; static drawshadow_t drawshadow; static mat4_t m_shadow_view; @@ -60,7 +61,7 @@ static void setup_dotshading(void) if (!gl_dotshading->integer) return; - if (glr.ent->flags & RF_SHELL_MASK) + if (glr.ent->flags & (RF_SHELL_MASK | RF_TRACKER)) return; if (drawshadow == SHADOW_ONLY) @@ -356,7 +357,7 @@ static void setup_frame_scale(const model_t *model) static void setup_color(void) { - int flags = glr.ent->flags; + uint64_t flags = glr.ent->flags; float f, m; int i; @@ -382,6 +383,8 @@ static void setup_color(void) VectorSet(color, 1, 1, 1); } else if ((flags & RF_IR_VISIBLE) && (glr.fd.rdflags & RDF_IRGOGGLES)) { VectorSet(color, 1, 0, 0); + } else if (flags & RF_TRACKER) { + VectorClear(color); } else { GL_LightPoint(origin, color); @@ -418,7 +421,7 @@ static void setup_celshading(void) { float value = Cvar_ClampValue(gl_celshading, 0, 10); - if (value == 0 || (glr.ent->flags & (RF_TRANSLUCENT | RF_SHELL_MASK)) || !qglPolygonMode || !qglLineWidth) + if (value == 0 || (glr.ent->flags & (RF_TRANSLUCENT | RF_SHELL_MASK | RF_TRACKER)) || !qglPolygonMode || !qglLineWidth) celscale = 0; else celscale = 1.0f - Distance(origin, glr.fd.vieworg) / 700.0f; @@ -459,8 +462,7 @@ static void draw_celshading(const uint16_t *indices, int num_indices) static drawshadow_t cull_shadow(const model_t *model) { const cplane_t *plane; - float radius, d, w; - vec3_t point; + float radius, w; if (!gl_shadows->integer) return SHADOW_NO; @@ -481,19 +483,26 @@ static drawshadow_t cull_shadow(const model_t *model) if (w < 0.5f) return SHADOW_NO; // too steep - if (!gl_cull_models->integer) - return SHADOW_YES; + radius = (model->frames[newframenum].radius * frontlerp + model->frames[oldframenum].radius * backlerp) * glr.entscale; - // project on plane - d = PlaneDiffFast(origin, plane); - VectorMA(origin, -d, plane->normal, point); + shadowalpha = 0.5f; - radius = max(model->frames[newframenum].radius, model->frames[oldframenum].radius) / w; + // check if faded out + if (gl_shadows->integer >= 2) { + float dist = origin[2] - glr.lightpoint.pos[2] - radius; + if (dist > radius * 4.0f) + return SHADOW_NO; + if (dist > 0) + shadowalpha = 0.5f - dist / (radius * 8.0f); + } - for (int i = 0; i < 4; i++) { - if (PlaneDiff(point, &glr.frustumPlanes[i]) < -radius) { - c.spheresCulled++; - return SHADOW_NO; // culled out + if (gl_cull_models->integer) { + float min_d = -radius / w; + for (int i = 0; i < 4; i++) { + if (PlaneDiff(glr.lightpoint.pos, &glr.frustumPlanes[i]) < min_d) { + c.shadowsCulled++; + return SHADOW_NO; // culled out + } } } @@ -571,7 +580,7 @@ static void draw_shadow(const uint16_t *indices, int num_indices) if (gls.currentva) GL_ArrayBits(GLA_VERTEX); - uniform_mesh_color(0, 0, 0, color[3] * 0.5f); + uniform_mesh_color(0, 0, 0, color[3] * shadowalpha); GL_LoadUniforms(); qglEnable(GL_POLYGON_OFFSET_FILL); @@ -640,6 +649,8 @@ static void draw_alias_mesh(const uint16_t *indices, int num_indices, glStateBits_t state; const image_t *skin; + c.trisDrawn += num_indices / 3; + // if the model was culled, just draw the shadow if (drawshadow == SHADOW_ONLY) { GL_LockArrays(num_verts); @@ -686,6 +697,12 @@ static void draw_alias_mesh(const uint16_t *indices, int num_indices, if (skin->texnum2) state |= GLS_GLOWMAP_ENABLE; + if (glr.framebuffer_bound && gl_bloom->integer) { + state |= GLS_BLOOM_GENERATE; + if (glr.ent->flags & RF_SHELL_MASK) + state |= GLS_BLOOM_SHELL; + } + GL_StateBits(state); GL_BindTexture(TMU_TEXTURE, skin->texnum); @@ -704,7 +721,6 @@ static void draw_alias_mesh(const uint16_t *indices, int num_indices, GL_LockArrays(num_verts); qglDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, indices); - c.trisDrawn += num_indices / 3; draw_celshading(indices, num_indices); @@ -807,7 +823,7 @@ static void lerp_alias_skeleton(const md5_model_t *model) #pragma GCC reset_options #endif -static void bind_skel_arrays(const md5_mesh_t *mesh, const md5_joint_t *skel) +static void bind_skel_arrays(const md5_mesh_t *mesh) { if (gl_config.caps & QGL_CAP_SHADER_STORAGE) { qglBindBufferRange(GL_SHADER_STORAGE_BUFFER, SSBO_WEIGHTS, buffer, @@ -840,7 +856,7 @@ static void bind_skel_arrays(const md5_mesh_t *mesh, const md5_joint_t *skel) static void draw_skeleton_mesh(const md5_model_t *model, const md5_mesh_t *mesh, const md5_joint_t *skel) { if (buffer) - bind_skel_arrays(mesh, skel); + bind_skel_arrays(mesh); else if (glr.ent->flags & RF_SHELL_MASK) tess_shell_skel(mesh, skel); else if (dotshading) @@ -853,11 +869,6 @@ static void draw_skeleton_mesh(const md5_model_t *model, const md5_mesh_t *mesh, model->skins, model->num_skins); } -typedef struct { - vec4_t pos; - vec4_t axis[3]; -} glJoint_t; - static void draw_alias_skeleton(const md5_model_t *model) { const md5_joint_t *skel = temp_skeleton; diff --git a/src/refresh/models.c b/src/refresh/models.c index df05fecbd..cc5048455 100644 --- a/src/refresh/models.c +++ b/src/refresh/models.c @@ -260,26 +260,26 @@ static int MOD_LoadSP2(model_t *model, const void *rawdata, size_t length) static const char *MOD_ValidateMD2(const dmd2header_t *header, size_t length) { - ENSURE(header->num_tris <= TESS_MAX_INDICES / 3, "Too many tris"); - ENSURE(header->num_st <= INT_MAX / sizeof(dmd2stvert_t), "Too many st"); - ENSURE(header->num_xyz <= MD2_MAX_VERTS, "Too many xyz"); - ENSURE(header->num_frames <= MD2_MAX_FRAMES, "Too many frames"); - ENSURE(header->num_skins <= MD2_MAX_SKINS, "Too many skins"); + ENSURE(header->num_tris <= TESS_MAX_INDICES / 3, "Too many tris"); + ENSURE(header->num_st <= INT_MAX / sizeof(dmd2stvert_t), "Too many st"); + ENSURE(header->num_xyz <= MD2_MAX_VERTS, "Too many xyz"); + ENSURE(header->num_frames <= MD2_MAX_FRAMES, "Too many frames"); + ENSURE(header->num_skins <= MD2_MAX_SKINS, "Too many skins"); ENSURE(header->framesize >= sizeof(dmd2frame_t) + (header->num_xyz - 1) * sizeof(dmd2trivertx_t), "Too small frame size"); ENSURE(header->framesize <= MD2_MAX_FRAMESIZE, "Too big frame size"); - ENSURE((uint64_t)header->ofs_tris + header->num_tris * sizeof(dmd2triangle_t) <= length, "Bad tris offset"); - ENSURE((uint64_t)header->ofs_st + header->num_st * sizeof(dmd2stvert_t) <= length, "Bad st offset"); - ENSURE((uint64_t)header->ofs_frames + header->num_frames * header->framesize <= length, "Bad frames offset"); - ENSURE((uint64_t)header->ofs_skins + MD2_MAX_SKINNAME * header->num_skins <= length, "Bad skins offset"); + ENSURE((uint64_t)header->ofs_tris + header->num_tris * sizeof(dmd2triangle_t) <= length, "Bad tris offset"); + ENSURE((uint64_t)header->ofs_st + header->num_st * sizeof(dmd2stvert_t) <= length, "Bad st offset"); + ENSURE((uint64_t)header->ofs_frames + header->num_frames * header->framesize <= length, "Bad frames offset"); + ENSURE((uint64_t)header->ofs_skins + header->num_skins * MD2_MAX_SKINNAME <= length, "Bad skins offset"); - ENSURE(!(header->ofs_tris % q_alignof(dmd2triangle_t)), "Odd tris offset"); - ENSURE(!(header->ofs_st % q_alignof(dmd2stvert_t)), "Odd st offset"); - ENSURE(!(header->ofs_frames % q_alignof(dmd2frame_t)), "Odd frames offset"); - ENSURE(!(header->framesize % q_alignof(dmd2frame_t)), "Odd frame size"); + ENSURE(!(header->ofs_tris % q_alignof(dmd2triangle_t)), "Odd tris offset"); + ENSURE(!(header->ofs_st % q_alignof(dmd2stvert_t)), "Odd st offset"); + ENSURE(!(header->ofs_frames % q_alignof(dmd2frame_t)), "Odd frames offset"); + ENSURE(!(header->framesize % q_alignof(dmd2frame_t)), "Odd frame size"); - ENSURE(header->skinwidth >= 1 && header->skinwidth <= MAX_TEXTURE_SIZE, "Bad skin width"); + ENSURE(header->skinwidth >= 1 && header->skinwidth <= MAX_TEXTURE_SIZE, "Bad skin width"); ENSURE(header->skinheight >= 1 && header->skinheight <= MAX_TEXTURE_SIZE, "Bad skin height"); return NULL; } @@ -727,9 +727,24 @@ static int MOD_LoadMD3(model_t *model, const void *rawdata, size_t length) static void MOD_PrintError(const char *path, int err) { - Com_EPrintf("Couldn't load %s: %s\n", Com_MakePrintable(path), - err == Q_ERR_INVALID_FORMAT ? - Com_GetLastError() : Q_ErrorString(err)); + print_type_t level = PRINT_ERROR; + const char *msg; + + switch (err) { + case Q_ERR_INVALID_FORMAT: + msg = Com_GetLastError(); + break; + case Q_ERR(ENOENT): + if (COM_DEVELOPER < 2) + return; + level = PRINT_DEVELOPER; + // fall through + default: + msg = Q_ErrorString(err); + break; + } + + Com_LPrintf(level, "Couldn't load %s: %s\n", Com_MakePrintable(path), msg); } #if USE_MD5 @@ -1530,12 +1545,8 @@ qhandle_t R_RegisterModel(const char *name) } ret = FS_LoadFile(normalized, (void **)&rawdata); - if (!rawdata) { - // don't spam about missing models - if (ret == Q_ERR(ENOENT)) - return 0; + if (!rawdata) goto fail1; - } if (ret < 4) { ret = Q_ERR_FILE_TOO_SMALL; diff --git a/src/refresh/qgl.c b/src/refresh/qgl.c index 42ba5acf1..c5f3f9401 100644 --- a/src/refresh/qgl.c +++ b/src/refresh/qgl.c @@ -244,6 +244,7 @@ static const glsection_t sections[] = { QGL_FN(CreateShader), QGL_FN(DeleteProgram), QGL_FN(DeleteShader), + QGL_FN(DrawBuffers), QGL_FN(DisableVertexAttribArray), QGL_FN(EnableVertexAttribArray), QGL_FN(GetProgramInfoLog), @@ -301,6 +302,15 @@ static const glsection_t sections[] = { } }, + // GL 3.0, not ES + { + .ver_gl = QGL_VER(3, 0), + .functions = (const glfunction_t []) { + QGL_FN(BindFragDataLocation), + { NULL } + } + }, + // GL 3.1 // ES 3.2 { diff --git a/src/refresh/qgl.h b/src/refresh/qgl.h index b66e11547..24a6ea895 100644 --- a/src/refresh/qgl.h +++ b/src/refresh/qgl.h @@ -123,6 +123,7 @@ QGLAPI GLuint (APIENTRYP qglCreateProgram)(void); QGLAPI GLuint (APIENTRYP qglCreateShader)(GLenum type); QGLAPI void (APIENTRYP qglDeleteProgram)(GLuint program); QGLAPI void (APIENTRYP qglDeleteShader)(GLuint shader); +QGLAPI void (APIENTRYP qglDrawBuffers)(GLsizei n, const GLenum *bufs); QGLAPI void (APIENTRYP qglDisableVertexAttribArray)(GLuint index); QGLAPI void (APIENTRYP qglEnableVertexAttribArray)(GLuint index); QGLAPI void (APIENTRYP qglGetProgramInfoLog)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); @@ -158,6 +159,9 @@ QGLAPI const GLubyte *(APIENTRYP qglGetStringi)(GLenum name, GLuint index); QGLAPI void (APIENTRYP qglRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); QGLAPI void (APIENTRYP qglVertexAttribIPointer)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +// GL 3.0, not ES +QGLAPI void (APIENTRYP qglBindFragDataLocation)(GLuint program, GLuint colorNumber, const GLchar *name); + // GL 3.1 QGLAPI void (APIENTRYP qglGetActiveUniformBlockiv)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); QGLAPI GLuint (APIENTRYP qglGetUniformBlockIndex)(GLuint program, const GLchar *uniformBlockName); diff --git a/src/refresh/shader.c b/src/refresh/shader.c index 1e0ae1b26..27679228b 100644 --- a/src/refresh/shader.c +++ b/src/refresh/shader.c @@ -23,6 +23,25 @@ with this program; if not, write to the Free Software Foundation, Inc., #define GLSL(x) SZ_Write(buf, CONST_STR_LEN(#x "\n")); #define GLSF(x) SZ_Write(buf, CONST_STR_LEN(x)) +#define GLSP(...) shader_printf(buf, __VA_ARGS__) + +static cvar_t *gl_bloom_sigma; + +q_printf(2, 3) +static void shader_printf(sizebuf_t *buf, const char *fmt, ...) +{ + va_list ap; + size_t len; + + Q_assert(buf->cursize <= buf->maxsize); + + va_start(ap, fmt); + len = Q_vsnprintf((char *)buf->data + buf->cursize, buf->maxsize - buf->cursize, fmt, ap); + va_end(ap); + + Q_assert(len <= buf->maxsize - buf->cursize); + buf->cursize += len; +} static void write_header(sizebuf_t *buf, glStateBits_t bits) { @@ -46,7 +65,7 @@ static void write_header(sizebuf_t *buf, glStateBits_t bits) static void write_block(sizebuf_t *buf, glStateBits_t bits) { - GLSF("layout(std140) uniform u_block {\n"); + GLSF("layout(std140) uniform Uniforms {\n"); GLSL(mat4 m_vp;); GLSL(mat4 m_model;); @@ -87,7 +106,7 @@ static void write_block(sizebuf_t *buf, glStateBits_t bits) float u_heightfog_density; float u_heightfog_falloff; vec2 pad_4; - vec3 u_vieworg; + vec4 u_vieworg; ) GLSF("};\n"); } @@ -322,34 +341,120 @@ static void write_vertex_shader(sizebuf_t *buf, glStateBits_t bits) GLSL(out vec3 v_world_pos;) GLSF("void main() {\n"); - if (bits & GLS_CLASSIC_SKY) { - GLSL(v_dir = (m_sky[1] * a_pos).xyz;) - } else if (bits & GLS_DEFAULT_SKY) { - GLSL(v_dir = (m_sky[0] * a_pos).xyz;) - } else if (bits & GLS_SCROLL_ENABLE) { - GLSL(v_tc = a_tc + u_scroll;) + if (bits & GLS_CLASSIC_SKY) { + GLSL(v_dir = (m_sky[1] * a_pos).xyz;) + } else if (bits & GLS_DEFAULT_SKY) { + GLSL(v_dir = (m_sky[0] * a_pos).xyz;) + } else if (bits & GLS_SCROLL_ENABLE) { + GLSL(v_tc = a_tc + u_scroll;) + } else { + GLSL(v_tc = a_tc;) + } + + if (bits & GLS_LIGHTMAP_ENABLE) + GLSL(v_lmtc = a_lmtc;) + + if (!(bits & GLS_TEXTURE_REPLACE)) + GLSL(v_color = a_color;) + + if (bits & GLS_FOG_HEIGHT) + GLSL(v_world_pos = (m_model * a_pos).xyz;) + + GLSL(gl_Position = m_vp * a_pos;) + GLSF("}\n"); +} + +#define MAX_SIGMA 25 +#define MAX_RADIUS 50 + +// https://lisyarus.github.io/blog/posts/blur-coefficients-generator.html +static void write_gaussian_blur(sizebuf_t *buf) +{ + float sigma = gl_static.bloom_sigma; + int radius = min(sigma * 2 + 0.5f, MAX_RADIUS); + int samples = radius + 1; + int raw_samples = (radius * 2) + 1; + float offsets[MAX_RADIUS + 1]; + float weights[(MAX_RADIUS * 2) + 1]; + + // should not really happen + if (radius < 1) { + GLSL(vec4 blur(sampler2D src, vec2 tc, vec2 dir) { return texture(src, tc); }) + return; + } + + float sum = 0; + for (int i = -radius, j = 0; i <= radius; i++, j++) { + float w = expf(-(i * i) / (sigma * sigma)); + weights[j] = w; + sum += w; + } + + for (int i = 0; i < raw_samples; i++) + weights[i] /= sum; + + for (int i = -radius, j = 0; i <= radius; i += 2, j++) { + if (i == radius) { + offsets[j] = i; + weights[j] = weights[i + radius]; } else { - GLSL(v_tc = a_tc;) + float w0 = weights[i + radius + 0]; + float w1 = weights[i + radius + 1]; + float w = w0 + w1; + + if (w > 0) + offsets[j] = i + w1 / w; + else + offsets[j] = i; + + weights[j] = w; } + } - if (bits & GLS_LIGHTMAP_ENABLE) - GLSL(v_lmtc = a_lmtc;) + GLSP("#define BLUR_SAMPLES %d\n", samples); - if (!(bits & GLS_TEXTURE_REPLACE)) - GLSL(v_color = a_color;) + GLSF("const float blur_offsets[BLUR_SAMPLES] = float[BLUR_SAMPLES](\n"); + for (int i = 0; i < samples - 1; i++) + GLSP("%f, ", offsets[i]); + GLSP("%f);\n", offsets[samples - 1]); - if (bits & GLS_FOG_HEIGHT) - GLSL(v_world_pos = (m_model * a_pos).xyz;) + GLSF("const float blur_weights[BLUR_SAMPLES] = float[BLUR_SAMPLES](\n"); + for (int i = 0; i < samples - 1; i++) + GLSP("%f, ", weights[i]); + GLSP("%f);\n", weights[samples - 1]); - GLSL(gl_Position = m_vp * a_pos;) - GLSF("}\n"); + GLSL( + vec4 blur(sampler2D src, vec2 tc, vec2 dir) { + vec4 result = vec4(0.0); + for (int i = 0; i < BLUR_SAMPLES; i++) + result += texture(src, tc + dir * blur_offsets[i]) * blur_weights[i]; + return result; + } + ) +} + +static void write_box_blur(sizebuf_t *buf) +{ + GLSL( + vec4 blur(sampler2D src, vec2 tc, vec2 dir) { + vec4 result = vec4(0.0); + const float o = 0.25; + result += texture(src, tc + vec2(-o, -o) * dir) * 0.25; + result += texture(src, tc + vec2(-o, o) * dir) * 0.25; + result += texture(src, tc + vec2( o, -o) * dir) * 0.25; + result += texture(src, tc + vec2( o, o) * dir) * 0.25; + return result; + } + ) } // XXX: this is very broken. but that's how it is in re-release. -static void write_height_fog(sizebuf_t *buf) +static void write_height_fog(sizebuf_t *buf, glStateBits_t bits) { GLSL({ - float dir_z = normalize(v_world_pos - u_vieworg).z; + float dir_z = normalize(v_world_pos - u_vieworg.xyz).z; + float s = sign(dir_z); + dir_z += 0.00001 * (1.0 - s * s); float eye = u_vieworg.z - u_heightfog_start.w; float pos = v_world_pos.z - u_heightfog_start.w; float density = (exp(-u_heightfog_falloff * eye) - @@ -359,7 +464,12 @@ static void write_height_fog(sizebuf_t *buf) vec3 fog_color = mix(u_heightfog_start.rgb, u_heightfog_end.rgb, fraction) * extinction; float fog = (1.0 - exp(-(u_heightfog_density * frag_depth))) * extinction; diffuse.rgb = mix(diffuse.rgb, fog_color.rgb, fog); - }) + ) + + if (bits & GLS_BLOOM_GENERATE) + GLSL(bloom.rgb *= 1.0 - fog;) + + GLSL(}) } static void write_fragment_shader(sizebuf_t *buf, glStateBits_t bits) @@ -381,6 +491,8 @@ static void write_fragment_shader(sizebuf_t *buf, glStateBits_t bits) GLSL(uniform samplerCube u_texture;) } else { GLSL(uniform sampler2D u_texture;) + if (bits & GLS_BLOOM_OUTPUT) + GLSL(uniform sampler2D u_bloom;) } if (bits & GLS_SKY_MASK) @@ -399,84 +511,134 @@ static void write_fragment_shader(sizebuf_t *buf, glStateBits_t bits) if (!(bits & GLS_TEXTURE_REPLACE)) GLSL(in vec4 v_color;) + if (gl_config.ver_es) + GLSL(layout(location = 0)) GLSL(out vec4 o_color;) + if (bits & GLS_BLOOM_GENERATE) { + if (gl_config.ver_es) + GLSL(layout(location = 1)) + GLSL(out vec4 o_bloom;) + } + if (bits & GLS_FOG_HEIGHT) GLSL(in vec3 v_world_pos;) + if (bits & GLS_BLUR_GAUSS) + write_gaussian_blur(buf); + else if (bits & GLS_BLUR_BOX) + write_box_blur(buf); + GLSF("void main() {\n"); - if (bits & GLS_CLASSIC_SKY) { - GLSL( - float len = length(v_dir); - vec2 dir = v_dir.xy * (3.0 / len); - vec2 tc1 = dir + vec2(u_time * 0.0625); - vec2 tc2 = dir + vec2(u_time * 0.1250); - vec4 solid = texture(u_texture1, tc1); - vec4 alpha = texture(u_texture2, tc2); - vec4 diffuse = vec4((solid.rgb - alpha.rgb * 0.25) * 0.65, 1.0); - ) - } else if (bits & GLS_DEFAULT_SKY) { - GLSL(vec4 diffuse = texture(u_texture, v_dir);) - } else { - GLSL(vec2 tc = v_tc;) + if (bits & GLS_CLASSIC_SKY) { + GLSL( + float len = length(v_dir); + vec2 dir = v_dir.xy * (3.0 / len); + vec2 tc1 = dir + vec2(u_time * 0.0625); + vec2 tc2 = dir + vec2(u_time * 0.1250); + vec4 solid = texture(u_texture1, tc1); + vec4 alpha = texture(u_texture2, tc2); + vec4 diffuse = vec4((solid.rgb - alpha.rgb * 0.25) * 0.65, 1.0); + ) + } else if (bits & GLS_DEFAULT_SKY) { + GLSL(vec4 diffuse = texture(u_texture, v_dir);) + } else { + GLSL(vec2 tc = v_tc;) - if (bits & GLS_WARP_ENABLE) - GLSL(tc += w_amp * sin(tc.ts * w_phase + u_time);) + if (bits & GLS_WARP_ENABLE) + GLSL(tc += w_amp * sin(tc.ts * w_phase + u_time);) + if (bits & GLS_BLUR_MASK) + GLSL(vec4 diffuse = blur(u_texture, tc, u_fog_color.xy);) + else GLSL(vec4 diffuse = texture(u_texture, tc);) - } + } - if (bits & GLS_ALPHATEST_ENABLE) - GLSL(if (diffuse.a <= 0.666) discard;) + if (bits & GLS_ALPHATEST_ENABLE) + GLSL(if (diffuse.a <= 0.666) discard;) - if (bits & GLS_LIGHTMAP_ENABLE) { - GLSL(vec4 lightmap = texture(u_lightmap, v_lmtc);) + if (bits & GLS_BLOOM_GENERATE) + GLSL(vec4 bloom = vec4(0.0);) - if (bits & GLS_GLOWMAP_ENABLE) { - GLSL(vec4 glowmap = texture(u_glowmap, tc);) - GLSL(lightmap.rgb = mix(lightmap.rgb, vec3(1.0), glowmap.a);) - } + if (bits & GLS_LIGHTMAP_ENABLE) { + GLSL(vec4 lightmap = texture(u_lightmap, v_lmtc);) - GLSL(diffuse.rgb *= (lightmap.rgb + u_add) * u_modulate;) + if (bits & GLS_GLOWMAP_ENABLE) { + GLSL(vec4 glowmap = texture(u_glowmap, tc);) + GLSL(lightmap.rgb = mix(lightmap.rgb, vec3(1.0), glowmap.a);) + + if (bits & GLS_BLOOM_GENERATE) { + GLSL(bloom.rgb = diffuse.rgb * glowmap.a;) + if (bits & GLS_INTENSITY_ENABLE) + GLSL(bloom.rgb *= u_intensity;) + } } - if (bits & GLS_INTENSITY_ENABLE) - GLSL(diffuse.rgb *= u_intensity;) + GLSL(diffuse.rgb *= (lightmap.rgb + u_add) * u_modulate;) + } - if (bits & GLS_DEFAULT_FLARE) - GLSL( - diffuse.rgb *= (diffuse.r + diffuse.g + diffuse.b) / 3.0; - diffuse.rgb *= v_color.a; - ) + if (bits & GLS_INTENSITY_ENABLE) + GLSL(diffuse.rgb *= u_intensity;) - if (!(bits & GLS_TEXTURE_REPLACE)) - GLSL(diffuse *= v_color;) + if (bits & GLS_DEFAULT_FLARE) + GLSL( + diffuse.rgb *= (diffuse.r + diffuse.g + diffuse.b) / 3.0; + diffuse.rgb *= v_color.a; + ) - if (!(bits & GLS_LIGHTMAP_ENABLE) && (bits & GLS_GLOWMAP_ENABLE)) { - GLSL(vec4 glowmap = texture(u_glowmap, tc);) + if (!(bits & GLS_TEXTURE_REPLACE)) + GLSL(diffuse *= v_color;) + + if (!(bits & GLS_LIGHTMAP_ENABLE) && (bits & GLS_GLOWMAP_ENABLE)) { + GLSL(vec4 glowmap = texture(u_glowmap, tc);) + if (bits & GLS_INTENSITY_ENABLE) + GLSL(diffuse.rgb += glowmap.rgb * u_intensity2;) + else + GLSL(diffuse.rgb += glowmap.rgb;) + + if (bits & GLS_BLOOM_GENERATE) { + GLSL(bloom.rgb = glowmap.rgb;) if (bits & GLS_INTENSITY_ENABLE) - GLSL(diffuse.rgb += glowmap.rgb * u_intensity2;) - else - GLSL(diffuse.rgb += glowmap.rgb;) + GLSL(bloom.rgb *= u_intensity2;) } + } + + if (bits & GLS_BLOOM_GENERATE) { + if (bits & GLS_BLOOM_SHELL) + GLSL(bloom = diffuse;) + else + GLSL(bloom.a = diffuse.a;) + } + + if (bits & (GLS_FOG_GLOBAL | GLS_FOG_HEIGHT)) + GLSL(float frag_depth = gl_FragCoord.z / gl_FragCoord.w;) + + if (bits & GLS_FOG_GLOBAL) { + GLSL({ + float d = u_fog_color.a * frag_depth; + float fog = 1.0 - exp(-(d * d)); + diffuse.rgb = mix(diffuse.rgb, u_fog_color.rgb, fog); + ) + + if (bits & GLS_BLOOM_GENERATE) + GLSL(bloom.rgb *= 1.0 - fog;) - if (bits & (GLS_FOG_GLOBAL | GLS_FOG_HEIGHT)) - GLSL(float frag_depth = gl_FragCoord.z / gl_FragCoord.w;) + GLSL(}) + } + + if (bits & GLS_FOG_HEIGHT) + write_height_fog(buf, bits); - if (bits & GLS_FOG_GLOBAL) - GLSL({ - float d = u_fog_color.a * frag_depth; - float fog = 1.0f - exp(-(d * d)); - diffuse.rgb = mix(diffuse.rgb, u_fog_color.rgb, fog); - }) + if (bits & GLS_FOG_SKY) + GLSL(diffuse.rgb = mix(diffuse.rgb, u_fog_color.rgb, u_fog_sky_factor);) - if (bits & GLS_FOG_HEIGHT) - write_height_fog(buf); + if (bits & GLS_BLOOM_OUTPUT) + GLSL(diffuse.rgb += texture(u_bloom, tc).rgb;) - if (bits & GLS_FOG_SKY) - GLSL(diffuse.rgb = mix(diffuse.rgb, u_fog_color.rgb, u_fog_sky_factor);) + if (bits & GLS_BLOOM_GENERATE) + GLSL(o_bloom = bloom;) - GLSL(o_color = diffuse;) + GLSL(o_color = diffuse;) GLSF("}\n"); } @@ -491,6 +653,9 @@ static GLuint create_shader(GLenum type, const sizebuf_t *buf) return 0; } + Com_DDDPrintf("Compiling %s shader (%d bytes):\n%.*s\n", + type == GL_VERTEX_SHADER ? "vertex" : "fragment", size, size, data); + qglShaderSource(shader, 1, &data, &size); qglCompileShader(shader); GLint status = 0; @@ -513,6 +678,35 @@ static GLuint create_shader(GLenum type, const sizebuf_t *buf) return shader; } +static bool bind_uniform_block(GLuint program, const char *name, size_t cpu_size, GLuint binding) +{ + GLuint index = qglGetUniformBlockIndex(program, name); + if (index == GL_INVALID_INDEX) { + Com_EPrintf("%s block not found\n", name); + return false; + } + + GLint gpu_size = 0; + qglGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_DATA_SIZE, &gpu_size); + if (gpu_size != cpu_size) { + Com_EPrintf("%s block size mismatch: %d != %zu\n", name, gpu_size, cpu_size); + return false; + } + + qglUniformBlockBinding(program, index, binding); + return true; +} + +static void bind_texture_unit(GLuint program, const char *name, GLuint tmu) +{ + GLint loc = qglGetUniformLocation(program, name); + if (loc == -1) { + Com_EPrintf("Texture %s not found\n", name); + return; + } + qglUniform1i(loc, tmu); +} + static GLuint create_and_use_program(glStateBits_t bits) { char buffer[MAX_SHADER_CHARS]; @@ -528,14 +722,14 @@ static GLuint create_and_use_program(glStateBits_t bits) write_vertex_shader(&sb, bits); GLuint shader_v = create_shader(GL_VERTEX_SHADER, &sb); if (!shader_v) - return program; + goto fail; SZ_Clear(&sb); write_fragment_shader(&sb, bits); GLuint shader_f = create_shader(GL_FRAGMENT_SHADER, &sb); if (!shader_f) { qglDeleteShader(shader_v); - return program; + goto fail; } qglAttachShader(program, shader_v); @@ -563,6 +757,11 @@ static GLuint create_and_use_program(glStateBits_t bits) qglBindAttribLocation(program, VERT_ATTR_COLOR, "a_color"); } + if (bits & GLS_BLOOM_GENERATE && !gl_config.ver_es) { + qglBindFragDataLocation(program, 0, "o_color"); + qglBindFragDataLocation(program, 1, "o_bloom"); + } + qglLinkProgram(program); qglDeleteShader(shader_v); @@ -580,55 +779,47 @@ static GLuint create_and_use_program(glStateBits_t bits) Com_Printf("%s", buffer); Com_EPrintf("Error linking program\n"); - return program; + goto fail; } - GLuint index = qglGetUniformBlockIndex(program, "u_block"); - if (index == GL_INVALID_INDEX) { - Com_EPrintf("Uniform block not found\n"); - return program; - } - - GLint size = 0; - qglGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_DATA_SIZE, &size); - if (size != sizeof(gls.u_block)) { - Com_EPrintf("Uniform block size mismatch: %d != %zu\n", size, sizeof(gls.u_block)); - return program; - } - - qglUniformBlockBinding(program, index, UBO_UNIFORMS); + if (!bind_uniform_block(program, "Uniforms", sizeof(gls.u_block), UBO_UNIFORMS)) + goto fail; #if USE_MD5 - if (bits & GLS_MESH_MD5) { - index = qglGetUniformBlockIndex(program, "Skeleton"); - if (index == GL_INVALID_INDEX) { - Com_EPrintf("Skeleton block not found\n"); - return program; - } - qglUniformBlockBinding(program, index, UBO_SKELETON); - } + if (bits & GLS_MESH_MD5) + if (!bind_uniform_block(program, "Skeleton", sizeof(glJoint_t) * MD5_MAX_JOINTS, UBO_SKELETON)) + goto fail; #endif qglUseProgram(program); #if USE_MD5 if (bits & GLS_MESH_MD5 && !(gl_config.caps & QGL_CAP_SHADER_STORAGE)) { - qglUniform1i(qglGetUniformLocation(program, "u_weights"), TMU_SKEL_WEIGHTS); - qglUniform1i(qglGetUniformLocation(program, "u_jointnums"), TMU_SKEL_JOINTNUMS); + bind_texture_unit(program, "u_weights", TMU_SKEL_WEIGHTS); + bind_texture_unit(program, "u_jointnums", TMU_SKEL_JOINTNUMS); } #endif + if (bits & GLS_CLASSIC_SKY) { - qglUniform1i(qglGetUniformLocation(program, "u_texture1"), TMU_TEXTURE); - qglUniform1i(qglGetUniformLocation(program, "u_texture2"), TMU_LIGHTMAP); + bind_texture_unit(program, "u_texture1", TMU_TEXTURE); + bind_texture_unit(program, "u_texture2", TMU_LIGHTMAP); } else { - qglUniform1i(qglGetUniformLocation(program, "u_texture"), TMU_TEXTURE); + bind_texture_unit(program, "u_texture", TMU_TEXTURE); + if (bits & GLS_BLOOM_OUTPUT) + bind_texture_unit(program, "u_bloom", TMU_LIGHTMAP); } + if (bits & GLS_LIGHTMAP_ENABLE) - qglUniform1i(qglGetUniformLocation(program, "u_lightmap"), TMU_LIGHTMAP); + bind_texture_unit(program, "u_lightmap", TMU_LIGHTMAP); + if (bits & GLS_GLOWMAP_ENABLE) - qglUniform1i(qglGetUniformLocation(program, "u_glowmap"), TMU_GLOWMAP); + bind_texture_unit(program, "u_glowmap", TMU_GLOWMAP); return program; + +fail: + qglDeleteProgram(program); + return 0; } static void shader_use_program(glStateBits_t key) @@ -657,6 +848,14 @@ static void shader_state_bits(glStateBits_t bits) GL_ScrollPos(gls.u_block.scroll, bits); gls.u_block_dirty = true; } + + if (diff & GLS_BLOOM_GENERATE && glr.framebuffer_bound) { + int n = (bits & GLS_BLOOM_GENERATE) ? 2 : 1; + qglDrawBuffers(n, (const GLenum []) { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1 + }); + } } static void shader_array_bits(glArrayBits_t bits) @@ -800,20 +999,57 @@ static void shader_clear_state(void) shader_use_program(GLS_DEFAULT); } +void GL_UpdateBlurParams(void) +{ + if (!gl_static.programs) + return; + if (!gl_bloom->integer) + return; + + float sigma = Cvar_ClampValue(gl_bloom_sigma, 1, MAX_SIGMA) * glr.fd.height / 1080; + + if (gl_static.bloom_sigma == sigma) + return; + + Com_DDPrintf("%s: %.1f\n", __func__, sigma); + gl_static.bloom_sigma = sigma; + + bool changed = false; + uint32_t map_size = HashMap_Size(gl_static.programs); + for (int i = 0; i < map_size; i++) { + glStateBits_t *bits = HashMap_GetKey(glStateBits_t, gl_static.programs, i); + if (*bits & GLS_BLUR_GAUSS) { + GLuint *prog = HashMap_GetValue(GLuint, gl_static.programs, i); + qglDeleteProgram(*prog); + *prog = create_and_use_program(*bits); + changed = true; + } + } + + if (changed) + shader_use_program(gls.state_bits & GLS_SHADER_MASK); +} + +static void gl_bloom_sigma_changed(cvar_t *self) +{ + GL_UpdateBlurParams(); +} + static void shader_init(void) { - gl_static.programs = HashMap_TagCreate(glStateBits_t, GLuint, HashInt32, NULL, TAG_RENDERER); + gl_bloom_sigma = Cvar_Get("gl_bloom_sigma", "4", 0); + gl_bloom_sigma->changed = gl_bloom_sigma_changed; + + gl_static.programs = HashMap_TagCreate(glStateBits_t, GLuint, HashInt64, NULL, TAG_RENDERER); qglGenBuffers(1, &gl_static.uniform_buffer); - GL_BindBuffer(GL_UNIFORM_BUFFER, gl_static.uniform_buffer); - qglBindBufferBase(GL_UNIFORM_BUFFER, UBO_UNIFORMS, gl_static.uniform_buffer); + GL_BindBufferBase(GL_UNIFORM_BUFFER, UBO_UNIFORMS, gl_static.uniform_buffer); qglBufferData(GL_UNIFORM_BUFFER, sizeof(gls.u_block), NULL, GL_DYNAMIC_DRAW); #if USE_MD5 if (gl_config.caps & QGL_CAP_SKELETON_MASK) { qglGenBuffers(1, &gl_static.skeleton_buffer); - GL_BindBuffer(GL_UNIFORM_BUFFER, gl_static.skeleton_buffer); - qglBindBufferBase(GL_UNIFORM_BUFFER, UBO_SKELETON, gl_static.skeleton_buffer); + GL_BindBufferBase(GL_UNIFORM_BUFFER, UBO_SKELETON, gl_static.skeleton_buffer); if ((gl_config.caps & QGL_CAP_SKELETON_MASK) == QGL_CAP_BUFFER_TEXTURE) qglGenTextures(2, gl_static.skeleton_tex); @@ -829,6 +1065,9 @@ static void shader_shutdown(void) shader_disable_state(); qglUseProgram(0); + gl_static.bloom_sigma = 0; + gl_bloom_sigma->changed = NULL; + if (gl_static.programs) { uint32_t map_size = HashMap_Size(gl_static.programs); for (int i = 0; i < map_size; i++) { diff --git a/src/refresh/sky.c b/src/refresh/sky.c index b90236b9d..d603d9531 100644 --- a/src/refresh/sky.c +++ b/src/refresh/sky.c @@ -450,14 +450,20 @@ void R_SetSky(const char *name, float rotate, bool autorotate, const vec3_t axis return; } + Com_DDPrintf("%s: %s %.1f %d (%.1f %.1f %.1f)\n", __func__, + name, rotate, autorotate, axis[0], axis[1], axis[2]); + + if (VectorEmpty(axis)) + rotate = 0; + if (!rotate) + autorotate = false; + skyrotate = rotate; skyautorotate = autorotate; VectorNormalize2(axis, skyaxis); SetupRotationMatrix(skymatrix, skyaxis, skyrotate); if (gl_static.use_cubemaps) TransposeAxis(skymatrix); - if (!skyrotate) - skyautorotate = false; // try to load cubemap image first if (gl_static.use_cubemaps) { diff --git a/src/refresh/state.c b/src/refresh/state.c index ab66c5203..747f5ef57 100644 --- a/src/refresh/state.c +++ b/src/refresh/state.c @@ -297,9 +297,9 @@ static void GL_RotateForViewer(void) GL_ForceMatrix(matrix); } -void GL_Setup3D(bool waterwarp) +void GL_Setup3D(void) { - if (waterwarp) + if (glr.framebuffer_bound) qglViewport(0, 0, glr.fd.width, glr.fd.height); else qglViewport(glr.fd.x, r_config.height - (glr.fd.y + glr.fd.height), diff --git a/src/refresh/surf.c b/src/refresh/surf.c index 648b5a733..3e488fcff 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -554,8 +554,8 @@ static uint32_t color_for_surface(const mface_t *surf) static bool enable_intensity_for_surface(const mface_t *surf) { - // enable for any surface with a lightmap in DECOUPLED_LM maps - if (surf->lightmap && gl_static.world.cache->lm_decoupled) + // enable for any surface with a lightmap in BSPX maps + if (surf->lightmap && gl_static.world.cache->has_bspx) return true; // enable for non-transparent, non-warped surfaces @@ -895,8 +895,6 @@ static void upload_world_surfaces(void) currvert = 0; lastvert = 0; for (i = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { - if (surf->drawflags & SURF_SKY && !gl_static.use_cubemaps) - continue; if (surf->drawflags & SURF_NODRAW) continue; @@ -995,6 +993,69 @@ void GL_FreeWorld(void) memset(&gl_static.world, 0, sizeof(gl_static.world)); } +static const mnode_t *find_face_node(const bsp_t *bsp, const mface_t *face) +{ + const mnode_t *node; + int i, left, right; + + left = 0; + right = bsp->numnodes - 1; + while (left <= right) { + i = (left + right) / 2; + node = &bsp->nodes[i]; + if (node->firstface + node->numfaces <= face) + left = i + 1; + else if (node->firstface > face) + right = i - 1; + else + return node; + } + + return NULL; +} + +static void remove_fake_sky_faces(const bsp_t *bsp) +{ + const mleaf_t *leaf; + const mnode_t *node; + int i, j, k, count = 0; + mface_t *face; + + // find CONTENTS_MIST leafs + for (i = 1, leaf = bsp->leafs + i; i < bsp->numleafs; i++, leaf++) { + if (!(leaf->contents[0] & CONTENTS_MIST)) + continue; + + // remove sky faces in this leaf + for (j = 0; j < leaf->numleaffaces; j++) { + face = leaf->firstleafface[j]; + if (!(face->drawflags & SURF_SKY)) + continue; + + face->drawflags = SURF_NODRAW; + count++; + + // find node this face is on + node = find_face_node(bsp, face); + if (!node) { + Com_DPrintf("Sky face node not found\n"); + continue; + } + + // remove other sky faces on this node + for (k = 0, face = node->firstface; k < node->numfaces; k++, face++) { + if (face->drawflags & SURF_SKY) { + face->drawflags = SURF_NODRAW; + count++; + } + } + } + } + + if (count) + Com_DPrintf("Removed %d fake sky faces\n", count); +} + void GL_LoadWorld(const char *name) { char buffer[MAX_QPATH]; @@ -1046,7 +1107,7 @@ void GL_LoadWorld(const char *name) if (info->c.flags & SURF_SKY) { if (!gl_static.use_cubemaps) { info->image = R_NOTEXTURE; - } else if (Q_stricmpn(info->name, CONST_STR_LEN("n64/env/sky")) == 0) { + } else if (Q_stristr(info->name, "env/sky")) { Q_concat(buffer, sizeof(buffer), "textures/", info->name, ".tga"); info->image = IMG_Find(buffer, IT_SKY, IF_REPEAT | IF_CLASSIC_SKY); } else if (Q_stricmpn(info->name, CONST_STR_LEN("sky/")) == 0) { @@ -1055,7 +1116,7 @@ void GL_LoadWorld(const char *name) } else { info->image = R_SKYTEXTURE; } - } else if (info->c.flags & SURF_NODRAW) { + } else if (info->c.flags & SURF_NODRAW && bsp->has_bspx) { info->image = R_NOTEXTURE; } else { imageflags_t flags = (info->c.flags & SURF_WARP) ? IF_TURBULENT : IF_NONE; @@ -1064,8 +1125,7 @@ void GL_LoadWorld(const char *name) } } - // calculate vertex buffer size in bytes - size = 0; + // setup drawflags, etc for (i = n64surfs = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { // hack surface flags into drawflags for faster access surf->drawflags |= surf->texinfo->c.flags & ~DSURF_PLANEBACK; @@ -1073,20 +1133,35 @@ void GL_LoadWorld(const char *name) // clear statebits from previous load surf->statebits = GLS_DEFAULT; - // don't count sky surfaces + // don't count sky surfaces unless using cubemaps if (surf->drawflags & SURF_SKY) { - if (!gl_static.use_cubemaps) + if (!gl_static.use_cubemaps) { + surf->drawflags |= SURF_NODRAW; // simplify other code continue; + } surf->drawflags &= ~SURF_NODRAW; } - if (surf->drawflags & SURF_NODRAW) - continue; - if (surf->drawflags & SURF_N64_UV) - n64surfs++; - size += surf->numsurfedges * VERTEX_SIZE * sizeof(vec_t); + // ignore NODRAW bit in vanilla maps for compatibility + if (surf->drawflags & SURF_NODRAW) { + if (bsp->has_bspx) + continue; + surf->drawflags &= ~SURF_NODRAW; + } + + if (surf->drawflags & (SURF_N64_UV | SURF_N64_SCROLL_X | SURF_N64_SCROLL_Y)) + n64surfs++; } + // remove fake sky faces in vanilla maps + if (!bsp->has_bspx && gl_static.use_cubemaps) + remove_fake_sky_faces(bsp); + + // calculate vertex buffer size in bytes + for (i = size = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) + if (!(surf->drawflags & SURF_NODRAW)) + size += surf->numsurfedges * VERTEX_SIZE * sizeof(vec_t); + // try VBO first, then allocate on heap if (create_surface_vbo(size)) { Com_DPrintf("%s: %zu bytes of vertex data as VBO\n", __func__, size); @@ -1097,15 +1172,13 @@ void GL_LoadWorld(const char *name) gl_static.world.buffer_size = size; gl_static.nolm_mask = SURF_NOLM_MASK_DEFAULT; - gl_static.use_bmodel_skies = false; + gl_static.use_bmodel_skies = gl_static.use_cubemaps && bsp->has_bspx; - // only supported in DECOUPLED_LM maps because vanilla maps have broken + // only supported in BSPX and N64 maps because vanilla maps have broken // lightofs for liquids/alphas. legacy renderer doesn't support lightmapped // liquids too. - if ((bsp->lm_decoupled || n64surfs > 100) && gl_static.use_shaders) { + if ((bsp->has_bspx || n64surfs > 100) && gl_static.use_shaders) gl_static.nolm_mask = SURF_NOLM_MASK_REMASTER; - gl_static.use_bmodel_skies = gl_static.use_cubemaps; - } glr.fd.lightstyles = &(lightstyle_t){ 1 }; diff --git a/src/refresh/tess.c b/src/refresh/tess.c index 8fe3f08d2..3a49fb569 100644 --- a/src/refresh/tess.c +++ b/src/refresh/tess.c @@ -20,9 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., tesselator_t tess; -#define FACE_HASH_BITS 8 -#define FACE_HASH_SIZE (1 << FACE_HASH_BITS) -#define FACE_HASH_MASK (FACE_HASH_SIZE - 1) +#define FACE_HASH_SIZE 256 static mface_t *faces_head[FACE_HASH_SIZE]; static mface_t **faces_next[FACE_HASH_SIZE]; @@ -97,7 +95,7 @@ void GL_DrawParticles(void) scale = 1.0f; if (dist > 20) scale += dist * 0.004f; - scale *= gl_partscale->value; + scale *= gl_partscale->value * p->scale; scale2 = scale * PARTICLE_SCALE; VectorMA(p->origin, scale2, glr.viewaxis[1], dst_vert); @@ -138,6 +136,7 @@ static void GL_FlushBeamSegments(void) if (!tess.numindices) return; + glStateBits_t state = GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE | glr.fog_bits; glArrayBits_t array = GLA_VERTEX | GLA_COLOR; GLuint texnum = TEXNUM_BEAM; @@ -146,8 +145,11 @@ static void GL_FlushBeamSegments(void) else array |= GLA_TC; + if (glr.framebuffer_bound && gl_bloom->integer) + state |= GLS_BLOOM_GENERATE | GLS_BLOOM_SHELL; + GL_BindTexture(TMU_TEXTURE, texnum); - GL_StateBits(GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE | glr.fog_bits); + GL_StateBits(state); GL_ArrayBits(array); GL_DrawIndexed(SHOWTRIS_FX); @@ -517,7 +519,7 @@ static const glVaDesc_t arraydescs[VA_TOTAL][VERT_ATTR_COUNT] = { [VA_OCCLUDE] = { [VERT_ATTR_POS] = ATTR_FLOAT(3, 3, 0), }, - [VA_WATERWARP] = { + [VA_POSTPROCESS] = { [VERT_ATTR_POS] = ATTR_FLOAT(2, 4, 0), [VERT_ATTR_TC] = ATTR_FLOAT(2, 4, 2), }, @@ -663,6 +665,8 @@ void GL_Flush3D(void) if (tess.texnum[TMU_GLOWMAP]) state |= GLS_GLOWMAP_ENABLE; } + if (glr.framebuffer_bound && gl_bloom->integer) + state |= GLS_BLOOM_GENERATE; if (!(state & GLS_TEXTURE_REPLACE)) array |= GLA_COLOR; diff --git a/src/refresh/texture.c b/src/refresh/texture.c index 58b8824cc..72e82cbb6 100644 --- a/src/refresh/texture.c +++ b/src/refresh/texture.c @@ -38,6 +38,7 @@ static cvar_t *gl_downsample_skins; static cvar_t *gl_gamma_scale_pics; static cvar_t *gl_bilerp_chars; static cvar_t *gl_bilerp_pics; +static cvar_t *gl_bilerp_skies; static cvar_t *gl_upscale_pcx; static cvar_t *gl_texturemode; static cvar_t *gl_texturebits; @@ -121,7 +122,7 @@ static void gl_texturemode_changed(cvar_t *self) } // change all the existing mipmap texture objects - update_image_params(BIT(IT_WALL) | BIT(IT_SKIN) | BIT(IT_SKY)); + update_image_params(BIT(IT_WALL) | BIT(IT_SKIN)); } static void gl_texturemode_g(genctx_t *ctx) @@ -161,6 +162,12 @@ static void gl_bilerp_pics_changed(cvar_t *self) GL_InitRawTexture(); } +static void gl_bilerp_skies_changed(cvar_t *self) +{ + // change all the existing sky texture objects + update_image_params(BIT(IT_SKY)); +} + static void gl_texturebits_changed(cvar_t *self) { if (!(gl_config.caps & QGL_CAP_TEXTURE_BITS)) { @@ -436,6 +443,20 @@ static bool GL_MakePowerOfTwo(int *width, int *height) return false; } +static void GL_ClampTextureSize(int *width, int *height) +{ + while (*width > gl_config.max_texture_size || + *height > gl_config.max_texture_size) { + *width >>= 1; + *height >>= 1; + } + + if (*width < 1) + *width = 1; + if (*height < 1) + *height = 1; +} + /* =============== GL_Upload32 @@ -467,17 +488,7 @@ static void GL_Upload32(byte *data, int width, int height, int baselevel, imaget } // don't ever bother with >256 textures - while (scaled_width > gl_config.max_texture_size || - scaled_height > gl_config.max_texture_size) { - scaled_width >>= 1; - scaled_height >>= 1; - } - - if (scaled_width < 1) - scaled_width = 1; - if (scaled_height < 1) - scaled_height = 1; - + GL_ClampTextureSize(&scaled_width, &scaled_height); upload_width = scaled_width; upload_height = scaled_height; @@ -616,9 +627,6 @@ static void GL_SetFilterAndRepeat(imagetype_t type, imageflags_t flags) if (type == IT_WALL || type == IT_SKIN) { qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } else if (type == IT_SKY) { - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); } else { bool nearest; @@ -631,6 +639,8 @@ static void GL_SetFilterAndRepeat(imagetype_t type, imageflags_t flags) nearest = (gl_bilerp_pics->integer == 0 || gl_bilerp_pics->integer == 1); else nearest = (gl_bilerp_pics->integer == 0); + } else if (type == IT_SKY) { + nearest = (gl_bilerp_skies->integer == 0); } else { nearest = false; } @@ -689,8 +699,10 @@ static const byte gl_env_ofs[6][14] = { static void GL_SetCubemapFilterAndRepeat(void) { - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gl_filter_max); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gl_filter_max); + GLenum filter = gl_bilerp_skies->integer ? GL_LINEAR : GL_NEAREST; + + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, filter); + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, filter); qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -1145,25 +1157,42 @@ static void GL_InitCubemaps(void) sky->texnum = TEXNUM_CUBEMAP_DEFAULT; } -bool GL_InitWarpTexture(void) +static void GL_InitPostProcTexture(int w, int h) { - GL_ClearErrors(); - - GL_ForceTexture(TMU_TEXTURE, gl_static.warp_texture); - qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glr.fd.width, glr.fd.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +bool GL_InitFramebuffers(void) +{ + Q_assert(gl_static.use_shaders); + + GL_ClearErrors(); + + GL_ForceTexture(TMU_TEXTURE, TEXNUM_PP_SCENE); + GL_InitPostProcTexture(glr.fd.width, glr.fd.height); - qglBindFramebuffer(GL_FRAMEBUFFER, gl_static.warp_framebuffer); - qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl_static.warp_texture, 0); + int w = glr.fd.width; + int h = glr.fd.height; - qglBindRenderbuffer(GL_RENDERBUFFER, gl_static.warp_renderbuffer); + if (!gl_bloom->integer) + w = h = 0; + + GL_ForceTexture(TMU_TEXTURE, TEXNUM_PP_BLOOM); + GL_InitPostProcTexture(w, h); + + qglBindFramebuffer(GL_FRAMEBUFFER, FBO_SCENE); + qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TEXNUM_PP_SCENE, 0); + qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gl_bloom->integer ? TEXNUM_PP_BLOOM : GL_NONE, 0); + + qglBindRenderbuffer(GL_RENDERBUFFER, gl_static.renderbuffer); qglRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, glr.fd.width, glr.fd.height); qglBindRenderbuffer(GL_RENDERBUFFER, 0); - qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl_static.warp_renderbuffer); + qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl_static.renderbuffer); GLenum status = qglCheckFramebufferStatus(GL_FRAMEBUFFER); qglBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -1176,23 +1205,25 @@ bool GL_InitWarpTexture(void) return false; } - return true; -} + GL_UpdateBlurParams(); -static void GL_DeleteWarpTexture(void) -{ - if (gl_static.warp_framebuffer) { - qglDeleteFramebuffers(1, &gl_static.warp_framebuffer); - gl_static.warp_framebuffer = 0; - } - if (gl_static.warp_renderbuffer) { - qglDeleteRenderbuffers(1, &gl_static.warp_renderbuffer); - gl_static.warp_renderbuffer = 0; - } - if (gl_static.warp_texture) { - qglDeleteTextures(1, &gl_static.warp_texture); - gl_static.warp_texture = 0; - } + GL_ForceTexture(TMU_TEXTURE, TEXNUM_PP_BLUR_0); + GL_InitPostProcTexture(w / 4, h / 4); + + GL_ForceTexture(TMU_TEXTURE, TEXNUM_PP_BLUR_1); + GL_InitPostProcTexture(w / 4, h / 4); + + qglBindFramebuffer(GL_FRAMEBUFFER, FBO_BLUR_0); + qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl_bloom->integer ? TEXNUM_PP_BLUR_0 : GL_NONE, 0); + + qglBindFramebuffer(GL_FRAMEBUFFER, FBO_BLUR_1); + qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl_bloom->integer ? TEXNUM_PP_BLUR_1 : GL_NONE, 0); + + qglBindFramebuffer(GL_FRAMEBUFFER, 0); + + GL_ShowErrors(__func__); + + return true; } static void gl_partshape_changed(cvar_t *self) @@ -1211,6 +1242,8 @@ void GL_InitImages(void) gl_bilerp_chars->changed = gl_bilerp_chars_changed; gl_bilerp_pics = Cvar_Get("gl_bilerp_pics", "1", 0); gl_bilerp_pics->changed = gl_bilerp_pics_changed; + gl_bilerp_skies = Cvar_Get("gl_bilerp_skies", "1", 0); + gl_bilerp_skies->changed = gl_bilerp_skies_changed; gl_texturemode = Cvar_Get("gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE); gl_texturemode->changed = gl_texturemode_changed; gl_texturemode->generator = gl_texturemode_g; @@ -1269,9 +1302,8 @@ void GL_InitImages(void) qglGenTextures(LM_MAX_LIGHTMAPS, lm.texnums); if (gl_static.use_shaders) { - qglGenTextures(1, &gl_static.warp_texture); - qglGenRenderbuffers(1, &gl_static.warp_renderbuffer); - qglGenFramebuffers(1, &gl_static.warp_framebuffer); + qglGenRenderbuffers(1, &gl_static.renderbuffer); + qglGenFramebuffers(FBO_COUNT, gl_static.framebuffers); } Scrap_Init(); @@ -1299,6 +1331,7 @@ void GL_ShutdownImages(void) { gl_bilerp_chars->changed = NULL; gl_bilerp_pics->changed = NULL; + gl_bilerp_skies->changed = NULL; gl_texturemode->changed = NULL; gl_texturemode->generator = NULL; gl_anisotropy->changed = NULL; @@ -1312,7 +1345,14 @@ void GL_ShutdownImages(void) memset(gl_static.texnums, 0, sizeof(gl_static.texnums)); memset(lm.texnums, 0, sizeof(lm.texnums)); - GL_DeleteWarpTexture(); + // delete framebuffers + if (gl_static.use_shaders) { + qglDeleteFramebuffers(FBO_COUNT, gl_static.framebuffers); + memset(gl_static.framebuffers, 0, sizeof(gl_static.framebuffers)); + + qglDeleteRenderbuffers(1, &gl_static.renderbuffer); + gl_static.renderbuffer = 0; + } #if USE_DEBUG r_charset = 0; diff --git a/src/refresh/world.c b/src/refresh/world.c index 77618b830..28711ad3b 100644 --- a/src/refresh/world.c +++ b/src/refresh/world.c @@ -167,7 +167,7 @@ static bool GL_LightPoint_(const vec3_t start, vec3_t color) end[2] = start[2] - 8192; // get base lightpoint from world - BSP_LightPoint(&glr.lightpoint, start, end, bsp->nodes, gl_static.nolm_mask); + BSP_LightPoint(&glr.lightpoint, start, end, bsp->nodes, gl_static.nolm_mask | SURF_TRANS_MASK); // trace to other BSP models for (i = 0, ent = glr.fd.entities; i < glr.fd.num_entities; i++, ent++) { @@ -201,7 +201,7 @@ static bool GL_LightPoint_(const vec3_t start, vec3_t color) } BSP_TransformedLightPoint(&pt, start, end, model->headnode, - gl_static.nolm_mask, ent->origin, angles); + gl_static.nolm_mask | SURF_TRANS_MASK, ent->origin, angles); if (pt.fraction < glr.lightpoint.fraction) glr.lightpoint = pt; @@ -339,12 +339,12 @@ static void GL_MarkLeaves(void) leaf = BSP_PointLeaf(bsp->nodes, glr.fd.vieworg); cluster1 = cluster2 = leaf->cluster; VectorCopy(glr.fd.vieworg, tmp); - if (!leaf->contents) + if (!leaf->contents[0]) tmp[2] -= 16; else tmp[2] += 16; leaf = BSP_PointLeaf(bsp->nodes, tmp); - if (!(leaf->contents & CONTENTS_SOLID)) + if (!(leaf->contents[0] & CONTENTS_SOLID)) cluster2 = leaf->cluster; if (cluster1 == glr.viewcluster1 && cluster2 == glr.viewcluster2) @@ -511,7 +511,8 @@ static inline bool GL_ClipNode(const mnode_t *node, int *clipflags) static inline void GL_DrawLeaf(const mleaf_t *leaf) { - if (leaf->contents == CONTENTS_SOLID) + // FIXME: use `&' here? + if (leaf->contents[0] == CONTENTS_SOLID) return; // solid leaf if (glr.fd.areabits && !Q_IsBitSet(glr.fd.areabits, leaf->area)) diff --git a/src/server/entities.c b/src/server/entities.c index 72caaeeb8..a189feddc 100644 --- a/src/server/entities.c +++ b/src/server/entities.c @@ -49,7 +49,7 @@ static bool SV_TruncPacketEntities(client_t *client, const client_frame_t *from, if (!sv_trunc_packet_entities->integer || client->netchan.type) return false; - SV_DPrintf(0, "Truncating frame %d at %u bytes for %s\n", + SV_DPrintf(1, "Truncating frame %d at %u bytes for %s\n", client->framenum, msg_write.cursize, client->name); if (!from) diff --git a/src/server/game.c b/src/server/game.c index 0bdccae69..fdeb9c47e 100644 --- a/src/server/game.c +++ b/src/server/game.c @@ -101,13 +101,13 @@ static void PF_Unicast(edict_t *ent, qboolean reliable) clientNum = NUM_FOR_EDICT(ent) - 1; if (clientNum < 0 || clientNum >= sv_maxclients->integer) { - Com_WPrintf("%s to a non-client %d\n", __func__, clientNum); + Com_DWPrintf("%s to a non-client %d\n", __func__, clientNum); goto clear; } client = svs.client_pool + clientNum; if (client->state <= cs_zombie) { - Com_WPrintf("%s to a free/zombie client %d\n", __func__, clientNum); + Com_DWPrintf("%s to a free/zombie client %d\n", __func__, clientNum); goto clear; } @@ -162,7 +162,7 @@ static void PF_bprintf(int level, const char *fmt, ...) va_end(argptr); if (len >= sizeof(string)) { - Com_WPrintf("%s: overflow\n", __func__); + Com_DWPrintf("%s: overflow\n", __func__); return; } @@ -241,7 +241,7 @@ static void PF_cprintf(edict_t *ent, int level, const char *fmt, ...) va_end(argptr); if (len >= sizeof(msg)) { - Com_WPrintf("%s: overflow\n", __func__); + Com_DWPrintf("%s: overflow\n", __func__); return; } @@ -252,12 +252,13 @@ static void PF_cprintf(edict_t *ent, int level, const char *fmt, ...) clientNum = NUM_FOR_EDICT(ent) - 1; if (clientNum < 0 || clientNum >= sv_maxclients->integer) { - Com_Error(ERR_DROP, "%s to a non-client %d", __func__, clientNum); + Com_DWPrintf("%s to a non-client %d\n", __func__, clientNum); + return; } client = svs.client_pool + clientNum; if (client->state <= cs_zombie) { - Com_WPrintf("%s to a free/zombie client %d\n", __func__, clientNum); + Com_DWPrintf("%s to a free/zombie client %d\n", __func__, clientNum); return; } @@ -295,7 +296,7 @@ static void PF_centerprintf(edict_t *ent, const char *fmt, ...) n = NUM_FOR_EDICT(ent); if (n < 1 || n > sv_maxclients->integer) { - Com_WPrintf("%s to a non-client %d\n", __func__, n - 1); + Com_DWPrintf("%s to a non-client %d\n", __func__, n - 1); return; } @@ -304,7 +305,7 @@ static void PF_centerprintf(edict_t *ent, const char *fmt, ...) va_end(argptr); if (len >= sizeof(msg)) { - Com_WPrintf("%s: overflow\n", __func__); + Com_DWPrintf("%s: overflow\n", __func__); return; } @@ -374,7 +375,7 @@ static void PF_configstring(int index, const char *val) Com_Error(ERR_DROP, "%s: bad index: %d", __func__, index); if (sv.state == ss_dead) { - Com_WPrintf("%s: not yet initialized\n", __func__); + Com_DWPrintf("%s: not yet initialized\n", __func__); return; } @@ -393,7 +394,7 @@ static void PF_configstring(int index, const char *val) // print a warning and truncate everything else maxlen = Com_ConfigstringSize(&svs.csr, index); if (len >= maxlen) { - Com_WPrintf( + Com_DWPrintf( "%s: index %d overflowed: %zu > %zu\n", __func__, index, len, maxlen - 1); len = maxlen - 1; @@ -767,10 +768,6 @@ static void PF_FreeTags(unsigned tag) Z_FreeTags(tag + TAG_MAX); } -static void PF_DebugGraph(float value, int color) -{ -} - static int PF_LoadFile(const char *path, void **buffer, unsigned flags, unsigned tag) { if (tag > UINT16_MAX - TAG_MAX) { @@ -839,7 +836,7 @@ static const game_import_t game_import = { .args = Cmd_RawArgs, .AddCommandString = PF_AddCommandString, - .DebugGraph = PF_DebugGraph, + .DebugGraph = SCR_DebugGraph, .SetAreaPortalState = PF_SetAreaPortalState, .AreasConnected = PF_AreasConnected, }; diff --git a/src/server/init.c b/src/server/init.c index 93a3ffc4a..818145ee3 100644 --- a/src/server/init.c +++ b/src/server/init.c @@ -268,11 +268,12 @@ static bool parse_and_check_server(mapcmd_t *cmd, const char *server, bool nexts if (!sv_cinematics->integer && nextserver) return false; // skip it if (Q_concat(expanded, sizeof(expanded), "video/", cmd->server) < sizeof(expanded)) - ret = SCR_CheckForCinematic(expanded); + ret = COM_DEDICATED ? Q_ERR_SUCCESS : SCR_CheckForCinematic(expanded); break; + // demos are handled specially, because they are played locally on the client case ss_demo: - if (!sv_cinematics->integer && nextserver) + if (nextserver && (!sv_cinematics->integer || (sv.state && sv_maxclients->integer > 1))) return false; // skip it if (Q_concat(expanded, sizeof(expanded), "demos/", cmd->server) >= sizeof(expanded)) break; @@ -288,7 +289,7 @@ static bool parse_and_check_server(mapcmd_t *cmd, const char *server, bool nexts default: if (sv_load_ent->integer) - CM_LoadOverrides(&cmd->cm, cmd->server, sizeof(cmd->server)); // may override server! + CM_LoadOverride(&cmd->cm, cmd->server, sizeof(cmd->server)); // may override server! if (Q_concat(expanded, sizeof(expanded), "maps/", cmd->server, ".bsp") < sizeof(expanded)) ret = CM_LoadMap(&cmd->cm, expanded); if (ret < 0) diff --git a/src/server/main.c b/src/server/main.c index 14832f484..3d9798687 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -2317,7 +2317,7 @@ static void sv_hostname_changed(cvar_t *self) #if USE_ZLIB voidpf SV_zalloc(voidpf opaque, uInt items, uInt size) { - return SV_Malloc(items * size); + return SV_Malloc((size_t)items * size); } void SV_zfree(voidpf opaque, voidpf address) diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index 327a1db3d..7dd80bed6 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -1100,7 +1100,7 @@ static void send_stream_stop(gtv_t *gtv) #if USE_ZLIB static voidpf gtv_zalloc(voidpf opaque, uInt items, uInt size) { - return MVD_Malloc(items * size); + return MVD_Malloc((size_t)items * size); } static void gtv_zfree(voidpf opaque, voidpf address) diff --git a/src/server/mvd/game.c b/src/server/mvd/game.c index 3b1278fb2..a88680232 100644 --- a/src/server/mvd/game.c +++ b/src/server/mvd/game.c @@ -53,7 +53,7 @@ LAYOUTS // clients per screen page #define PAGE_CLIENTS 16 -#define VER_OFS (272 - (int)(sizeof(VERSION) - 1) * CHAR_WIDTH) +#define VER_OFS (272 - (int)(sizeof(VERSION) - 1) * CONCHAR_WIDTH) static void MVD_LayoutClients(mvd_client_t *client) { @@ -666,7 +666,7 @@ static void MVD_UpdateClient(mvd_client_t *client) if (mvd->cm.cache) { vec3_t vieworg; VectorMA(client->ps.viewoffset, 0.125f, client->ps.pmove.origin, vieworg); - contents = CM_PointContents(vieworg, mvd->cm.cache->nodes); + contents = CM_PointContents(vieworg, mvd->cm.cache->nodes, mvd->csr->extended); } if (contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) @@ -2049,7 +2049,7 @@ static mvd_player_t *MVD_HitPlayer(mvd_client_t *client) if (mvd->cm.cache) { CM_BoxTrace(&trace, start, end, vec3_origin, vec3_origin, - mvd->cm.cache->nodes, CONTENTS_SOLID); + mvd->cm.cache->nodes, CONTENTS_SOLID, mvd->csr->extended); fraction = trace.fraction; } else { fraction = 1; @@ -2070,7 +2070,8 @@ static mvd_player_t *MVD_HitPlayer(mvd_client_t *client) CM_TransformedBoxTrace(&trace, start, end, vec3_origin, vec3_origin, CM_HeadnodeForBox(ent->mins, ent->maxs), - CONTENTS_MONSTER, ent->s.origin, vec3_origin); + CONTENTS_MONSTER, ent->s.origin, vec3_origin, + mvd->csr->extended); if (trace.fraction < fraction) { fraction = trace.fraction; @@ -2081,7 +2082,7 @@ static mvd_player_t *MVD_HitPlayer(mvd_client_t *client) return target; } -static trace_t q_gameabi MVD_Trace(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end) +static trace_t q_gameabi MVD_Trace(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int contentmask) { trace_t trace; diff --git a/src/server/mvd/parse.c b/src/server/mvd/parse.c index 05c77d981..2013e8671 100644 --- a/src/server/mvd/parse.c +++ b/src/server/mvd/parse.c @@ -27,7 +27,7 @@ static bool match_ended_hack; #if USE_DEBUG #define SHOWNET(level, ...) \ - do { if (mvd_shownet->integer > level) \ + do { if (mvd_shownet->integer >= level) \ Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) static const char *MVD_ServerCommandString(int cmd) @@ -377,7 +377,7 @@ static void MVD_ParseUnicast(mvd_t *mvd, bool reliable, int extrabits) while (msg_read.readcount < last) { cmd = MSG_ReadByte(); - SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); + SHOWNET(2, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); switch (cmd) { case svc_layout: @@ -393,7 +393,7 @@ static void MVD_ParseUnicast(mvd_t *mvd, bool reliable, int extrabits) MVD_UnicastStuff(mvd, reliable, player); break; default: - SHOWNET(1, "%3u:SKIPPING UNICAST\n", msg_read.readcount - 1); + SHOWNET(2, "%3u:SKIPPING UNICAST\n", msg_read.readcount - 1); // send remaining data and return data = msg_read.data + msg_read.readcount - 1; length = last - msg_read.readcount + 1; @@ -404,7 +404,7 @@ static void MVD_ParseUnicast(mvd_t *mvd, bool reliable, int extrabits) } } - SHOWNET(1, "%3u:END OF UNICAST\n", msg_read.readcount); + SHOWNET(2, "%3u:END OF UNICAST\n", msg_read.readcount); if (msg_read.readcount > last) { MVD_Destroyf(mvd, "%s: read past end of unicast", __func__); @@ -671,7 +671,7 @@ static void MVD_ParsePacketEntities(mvd_t *mvd) ent = &mvd->edicts[number]; #if USE_DEBUG - if (mvd_shownet->integer > 2) { + if (mvd_shownet->integer >= 3) { Com_LPrintf(PRINT_DEVELOPER, "%3u:%s:%d ", readcount, ent->inuse ? "delta" : "baseline", number); MSG_ShowDeltaEntityBits(bits); @@ -691,7 +691,7 @@ static void MVD_ParsePacketEntities(mvd_t *mvd) // shuffle current origin to old if removed if (bits & U_REMOVE) { - SHOWNET(2, "%3u:remove:%d\n", readcount, number); + SHOWNET(3, "%3u:remove:%d\n", readcount, number); if (!(ent->s.renderfx & RF_BEAM)) { VectorCopy(ent->s.origin, ent->s.old_origin); } @@ -745,7 +745,7 @@ static void MVD_ParsePacketPlayers(mvd_t *mvd) } #if USE_DEBUG - if (mvd_shownet->integer > 2) { + if (mvd_shownet->integer >= 3) { Com_LPrintf(PRINT_DEVELOPER, "%3u:%s:%d ", readcount, player->inuse ? "delta" : "baseline", number); MSG_ShowDeltaPlayerstateBits_Packet(bits); @@ -756,7 +756,7 @@ static void MVD_ParsePacketPlayers(mvd_t *mvd) MSG_ParseDeltaPlayerstate_Packet(&player->ps, bits, mvd->psFlags); if (bits & PPS_REMOVE) { - SHOWNET(2, "%3u:remove:%d\n", readcount, number); + SHOWNET(3, "%3u:remove:%d\n", readcount, number); player->inuse = false; continue; } @@ -784,11 +784,11 @@ static void MVD_ParseFrame(mvd_t *mvd) if (!mvd->demoseeking) CM_SetPortalStates(&mvd->cm, data, length); - SHOWNET(1, "%3u:playerinfo\n", msg_read.readcount); + SHOWNET(2, "%3u:playerinfo\n", msg_read.readcount); MVD_ParsePacketPlayers(mvd); - SHOWNET(1, "%3u:packetentities\n", msg_read.readcount); + SHOWNET(2, "%3u:packetentities\n", msg_read.readcount); MVD_ParsePacketEntities(mvd); - SHOWNET(1, "%3u:frame:%u\n", msg_read.readcount, mvd->framenum); + SHOWNET(2, "%3u:frame:%u\n", msg_read.readcount, mvd->framenum); MVD_PlayerToEntityStates(mvd); // update clients now so that effects datagram that @@ -1069,7 +1069,7 @@ bool MVD_ParseMessage(mvd_t *mvd) #if USE_DEBUG if (mvd_shownet->integer == 1) { Com_LPrintf(PRINT_DEVELOPER, "%u ", msg_read.cursize); - } else if (mvd_shownet->integer > 1) { + } else if (mvd_shownet->integer >= 2) { Com_LPrintf(PRINT_DEVELOPER, "------------------\n"); } #endif @@ -1083,7 +1083,7 @@ bool MVD_ParseMessage(mvd_t *mvd) MVD_Destroyf(mvd, "Read past end of message"); } if (msg_read.readcount == msg_read.cursize) { - SHOWNET(1, "%3u:END OF MESSAGE\n", msg_read.readcount); + SHOWNET(2, "%3u:END OF MESSAGE\n", msg_read.readcount); break; } @@ -1091,7 +1091,7 @@ bool MVD_ParseMessage(mvd_t *mvd) extrabits = cmd >> SVCMD_BITS; cmd &= SVCMD_MASK; - SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MVD_ServerCommandString(cmd)); + SHOWNET(2, "%3u:%s\n", msg_read.readcount - 1, MVD_ServerCommandString(cmd)); switch (cmd) { case mvd_serverdata: diff --git a/src/server/send.c b/src/server/send.c index 98e7eee77..fb51434ee 100644 --- a/src/server/send.c +++ b/src/server/send.c @@ -75,7 +75,7 @@ static bool SV_RateDrop(client_t *client) #endif if (total > client->rate) { - SV_DPrintf(0, "Frame %d suppressed for %s (total = %zu)\n", + SV_DPrintf(1, "Frame %d suppressed for %s (total = %zu)\n", client->framenum, client->name, total); client->frameflags |= FF_SUPPRESSED; client->suppress_count++; @@ -404,11 +404,11 @@ void SV_ClientAddMessage(client_t *client, int flags) if ((flags & MSG_COMPRESS) && (len = compress_message(client)) && len < msg_write.cursize) { client->AddMessage(client, get_compressed_data(), len, flags & MSG_RELIABLE); - SV_DPrintf(0, "Compressed %sreliable message to %s: %u into %d\n", + SV_DPrintf(1, "Compressed %sreliable message to %s: %u into %d\n", (flags & MSG_RELIABLE) ? "" : "un", client->name, msg_write.cursize, len); } else { client->AddMessage(client, msg_write.data, msg_write.cursize, flags & MSG_RELIABLE); - SV_DPrintf(1, "Added %sreliable message to %s: %u bytes\n", + SV_DPrintf(2, "Added %sreliable message to %s: %u bytes\n", (flags & MSG_RELIABLE) ? "" : "un", client->name, msg_write.cursize); } @@ -540,7 +540,7 @@ static void emit_snd(const client_t *client, const message_packet_t *msg) // check if position needs to be explicitly sent if (!(flags & SND_POS) && !check_entity(client, entnum)) { - SV_DPrintf(1, "Forcing position on entity %d for %s\n", + SV_DPrintf(2, "Forcing position on entity %d for %s\n", entnum, client->name); flags |= SND_POS; // entity is not present in frame } @@ -627,7 +627,7 @@ static void write_reliables_old(client_t *client, unsigned maxsize) int count; if (client->netchan.reliable_length) { - SV_DPrintf(1, "%s to %s: unacked\n", __func__, client->name); + SV_DPrintf(2, "%s to %s: unacked\n", __func__, client->name); return; // there is still outgoing reliable message pending } @@ -644,7 +644,7 @@ static void write_reliables_old(client_t *client, unsigned maxsize) break; } - SV_DPrintf(1, "%s to %s: writing msg %d: %d bytes\n", + SV_DPrintf(2, "%s to %s: writing msg %d: %d bytes\n", __func__, client->name, count, msg->cursize); SZ_Write(&client->netchan.message, msg->data, msg->cursize); @@ -733,7 +733,7 @@ static void write_datagram_old(client_t *client) // send over all the relevant entity_state_t // and the player_state_t if (!client->WriteFrame(client, maxsize)) { - SV_DPrintf(0, "Frame %d overflowed for %s\n", client->framenum, client->name); + SV_DPrintf(1, "Frame %d overflowed for %s\n", client->framenum, client->name); SZ_Clear(&msg_write); } @@ -999,7 +999,7 @@ void SV_SendAsyncPackets(void) // make sure all fragments are transmitted first if (netchan->fragment_pending) { cursize = Netchan_TransmitNextFragment(netchan); - SV_DPrintf(1, "%s: frag: %d\n", client->name, cursize); + SV_DPrintf(2, "%s: frag: %d\n", client->name, cursize); goto calctime; } @@ -1027,7 +1027,7 @@ void SV_SendAsyncPackets(void) if (netchan->message.cursize || netchan->reliable_ack_pending || netchan->reliable_length || retransmit) { cursize = Netchan_Transmit(netchan, 0, NULL, 1); - SV_DPrintf(1, "%s: send: %d\n", client->name, cursize); + SV_DPrintf(2, "%s: send: %d\n", client->name, cursize); calctime: SV_CalcSendTime(client, cursize); } diff --git a/src/server/server.h b/src/server/server.h index a7edebffd..715525ae8 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -61,7 +61,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #if USE_DEBUG #define SV_DPrintf(level,...) \ - do { if (sv_debug && sv_debug->integer > level) \ + do { if (sv_debug && sv_debug->integer >= level) \ Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #else #define SV_DPrintf(...) @@ -94,7 +94,7 @@ with this program; if not, write to the Free Software Foundation, Inc., GMF_IPV6_ADDRESS_AWARE | GMF_ALLOW_INDEX_OVERFLOW | \ GMF_PROTOCOL_EXTENSIONS) -// flag indicating if game uses gclient_new_t or gclient_old_t. +// flag indicating if game uses new versions of gclient_t and pmove_t. // doesn't enable protocol extensions by itself. #define IS_NEW_GAME_API (ge->apiversion == GAME_API_VERSION_NEW) @@ -156,6 +156,7 @@ typedef struct { typedef struct { server_state_t state; // precache commands are only valid during load int spawncount; // random number generated each server spawn + bool nextserver_pending; #if USE_FPS int framerate; @@ -356,14 +357,14 @@ typedef struct client_s { entity_packed_t *entities; // [num_entities] // server state pointers (hack for MVD channels implementation) - configstring_t *configstrings; - const cs_remap_t *csr; - char *gamedir, *mapname; - const game_export_t *ge; - cm_t *cm; - int infonum; // slot number visible to client - int spawncount; - int maxclients; + const configstring_t *configstrings; + const cs_remap_t *csr; + const char *gamedir, *mapname; + const game_export_t *ge; + const cm_t *cm; + int infonum; // slot number visible to client + int spawncount; + int maxclients; // netchan type dependent methods void (*AddMessage)(struct client_s *, const byte *, size_t, bool); diff --git a/src/server/user.c b/src/server/user.c index 330152033..eab2e58c6 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -116,9 +116,9 @@ static void maybe_flush_msg(size_t size) static void write_configstrings(void) { - int i; - char *string; - size_t length; + int i; + const char *string; + size_t length; // write a packet full of data for (i = 0; i < sv_client->csr->end; i++) { @@ -148,7 +148,7 @@ static void write_baseline(const entity_packed_t *base) static void write_baselines(void) { int i, j; - entity_packed_t *base; + const entity_packed_t *base; // write a packet full of data for (i = 0; i < SV_BASELINES_CHUNKS; i++) { @@ -173,9 +173,9 @@ static void write_baselines(void) static void write_configstring_stream(void) { - int i; - char *string; - size_t length; + int i; + const char *string; + size_t length; MSG_WriteByte(svc_configstringstream); @@ -206,7 +206,7 @@ static void write_configstring_stream(void) static void write_baseline_stream(void) { int i, j; - entity_packed_t *base; + const entity_packed_t *base; MSG_WriteByte(svc_baselinestream); @@ -236,10 +236,10 @@ static void write_baseline_stream(void) static void write_gamestate(void) { - entity_packed_t *base; + const entity_packed_t *base; int i, j; size_t length; - char *string; + const char *string; MSG_WriteByte(svc_gamestate); @@ -846,7 +846,10 @@ static void SV_NextServer_f(void) if (Q_atoi(Cmd_Argv(1)) != sv.spawncount) return; // leftover from last server - sv.spawncount ^= 1; // make sure another doesn't sneak in + if (sv.nextserver_pending) + return; + + sv.nextserver_pending = true; // make sure another doesn't sneak in const char *v = Cvar_VariableString("nextserver"); if (*v) { diff --git a/src/server/world.c b/src/server/world.c index 1a6959d8d..4398893fe 100644 --- a/src/server/world.c +++ b/src/server/world.c @@ -477,7 +477,7 @@ int SV_PointContents(const vec3_t p) int contents; // get base contents from world - contents = CM_PointContents(p, SV_WorldNodes()); + contents = CM_PointContents(p, SV_WorldNodes(), svs.csr.extended); // or in contents from all the other entities num = SV_AreaEdicts(p, p, touch, q_countof(touch), AREA_SOLID); @@ -487,7 +487,8 @@ int SV_PointContents(const vec3_t p) // might intersect, so do an exact clip contents |= CM_TransformedPointContents(p, SV_HullForEntity(hit, false), - hit->s.origin, hit->s.angles); + hit->s.origin, hit->s.angles, + svs.csr.extended); } return contents; @@ -554,7 +555,8 @@ static void SV_ClipMoveToEntities(trace_t *tr, // might intersect, so do an exact clip CM_TransformedBoxTrace(&trace, start, end, mins, maxs, SV_HullForEntity(touch, false), contentmask, - touch->s.origin, touch->s.angles); + touch->s.origin, touch->s.angles, + svs.csr.extended); CM_ClipEntity(tr, &trace, touch); } @@ -580,7 +582,7 @@ trace_t q_gameabi SV_Trace(const vec3_t start, const vec3_t mins, maxs = vec3_origin; // clip to world - CM_BoxTrace(&trace, start, end, mins, maxs, SV_WorldNodes(), contentmask); + CM_BoxTrace(&trace, start, end, mins, maxs, SV_WorldNodes(), contentmask, svs.csr.extended); trace.ent = ge->edicts; if (trace.fraction == 0) return trace; // blocked by the world @@ -659,11 +661,12 @@ trace_t q_gameabi SV_Clip(const vec3_t start, const vec3_t mins, maxs = vec3_origin; if (clip == ge->edicts) - CM_BoxTrace(&trace, start, end, mins, maxs, SV_WorldNodes(), contentmask); + CM_BoxTrace(&trace, start, end, mins, maxs, SV_WorldNodes(), contentmask, svs.csr.extended); else CM_TransformedBoxTrace(&trace, start, end, mins, maxs, SV_HullForEntity(clip, true), contentmask, - clip->s.origin, clip->s.angles); + clip->s.origin, clip->s.angles, + svs.csr.extended); trace.ent = clip; return trace; } diff --git a/src/unix/video/sdl.c b/src/unix/video/sdl.c index 954120ebf..d27c4bda6 100644 --- a/src/unix/video/sdl.c +++ b/src/unix/video/sdl.c @@ -303,8 +303,8 @@ static bool init(void) SDL_SetWindowMinimumSize(sdl.window, 320, 240); - SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(q2icon_bits, q2icon_width, q2icon_height, - 1, q2icon_width / 8, 0, 0, 0, 0); + SDL_Surface *icon = SDL_CreateRGBSurfaceWithFormatFrom(q2icon_bits, q2icon_width, q2icon_height, + 1, q2icon_width / 8, SDL_PIXELFORMAT_INDEX1LSB); if (icon) { SDL_Color colors[2] = { { 255, 255, 255 }, diff --git a/subprojects/libcurl.wrap b/subprojects/libcurl.wrap index ce2622169..d7172a4f2 100644 --- a/subprojects/libcurl.wrap +++ b/subprojects/libcurl.wrap @@ -1,8 +1,8 @@ [wrap-file] -directory = curl-8.10.1 -source_url = https://curl.se/download/curl-8.10.1.tar.xz -source_filename = curl-8.10.1.tar.xz -source_hash = 73a4b0e99596a09fa5924a4fb7e4b995a85fda0d18a2c02ab9cf134bebce04ee +directory = curl-8.11.1 +source_url = https://curl.se/download/curl-8.11.1.tar.xz +source_filename = curl-8.11.1.tar.xz +source_hash = c7ca7db48b0909743eaef34250da02c19bc61d4f1dcedd6603f109409536ab56 patch_directory = curl [provide] diff --git a/subprojects/libjpeg-turbo.wrap b/subprojects/libjpeg-turbo.wrap index f9eda5fb3..f8dd1641f 100644 --- a/subprojects/libjpeg-turbo.wrap +++ b/subprojects/libjpeg-turbo.wrap @@ -1,13 +1,13 @@ [wrap-file] -directory = libjpeg-turbo-3.0.4 -source_url = https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.0.4/libjpeg-turbo-3.0.4.tar.gz -source_filename = libjpeg-turbo-3.0.4.tar.gz -source_hash = 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b -patch_filename = libjpeg-turbo_3.0.4-2_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/libjpeg-turbo_3.0.4-2/get_patch -patch_hash = f12d14c6ff4ae83eddc1a2e8cfd96a9b7a40b6bdc8ff345ca8094abf4c3da928 -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libjpeg-turbo_3.0.4-2/libjpeg-turbo-3.0.4.tar.gz -wrapdb_version = 3.0.4-2 +directory = libjpeg-turbo-3.1.0 +source_url = https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.1.0/libjpeg-turbo-3.1.0.tar.gz +source_filename = libjpeg-turbo-3.1.0.tar.gz +source_hash = 9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 +patch_filename = libjpeg-turbo_3.1.0-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/libjpeg-turbo_3.1.0-1/get_patch +patch_hash = 970435d4d90cbcf3b372f597dd5770e1fc834d9608fb1ed787c07e421929aede +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libjpeg-turbo_3.1.0-1/libjpeg-turbo-3.1.0.tar.gz +wrapdb_version = 3.1.0-1 [provide] dependency_names = libjpeg, libturbojpeg diff --git a/subprojects/packagefiles/curl/meson.build b/subprojects/packagefiles/curl/meson.build index 919fd9c99..d3c54c17e 100644 --- a/subprojects/packagefiles/curl/meson.build +++ b/subprojects/packagefiles/curl/meson.build @@ -1,4 +1,4 @@ -project('libcurl', 'c', version: '8.10.1', license: 'bsd') +project('libcurl', 'c', version: '8.11.1', license: 'bsd') src = [ 'lib/vauth/cleartext.c', @@ -39,6 +39,7 @@ src = [ 'lib/vssh/libssh.c', 'lib/vssh/libssh2.c', + 'lib/vssh/curl_path.c', 'lib/vssh/wolfssh.c', 'lib/altsvc.c', @@ -69,7 +70,6 @@ src = [ 'lib/curl_memrchr.c', 'lib/curl_multibyte.c', 'lib/curl_ntlm_core.c', - 'lib/curl_path.c', 'lib/curl_range.c', 'lib/curl_rtmp.c', 'lib/curl_sasl.c',