From 0718522b2ca6b8a53f8a29ea6e6a28ea29830779 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sun, 17 Apr 2016 23:58:31 -0500 Subject: [PATCH 1/5] spearmint: CGame API 0.35 Add far clip to refdef_t and GetGlobalFog and GetViewFog. This allows disabling the farclip for specific types of linear fog or enabling it without linear fog. Now the far clip for the portal skybox refdef can be disabled to match RTCW behavior. View fog no longer has a far clip. This makes it more useable now that it doesn't cause the sky to be visible. Instead the geometry is just completely fogged beyond the depth to opaque. The reason water fog still uses far clip is that the RTCW maps (mp_beach at least) have sky visible underwater (literally a hole in the wall) and need the clip plane to appear the same as vanilla RTCW. New maps could use viewfogvars instead of waterfogvars. The benefit of not using a clip plane is that water can be transparent and the sky is still visible. --- code/cgame/cg_public.h | 2 +- code/client/cl_cgame.c | 4 ++-- code/renderercommon/tr_public.h | 4 ++-- code/renderercommon/tr_types.h | 3 +++ code/renderergl1/tr_backend.c | 2 +- code/renderergl1/tr_bsp.c | 1 + code/renderergl1/tr_cmds.c | 16 ++++++++++++++-- code/renderergl1/tr_local.h | 9 +++++++-- code/renderergl1/tr_main.c | 5 ++--- code/renderergl1/tr_scene.c | 2 ++ code/renderergl1/tr_shader.c | 8 ++++++++ code/renderergl1/tr_sky.c | 9 +++------ code/renderergl2/tr_backend.c | 2 +- code/renderergl2/tr_bsp.c | 1 + code/renderergl2/tr_cmds.c | 16 ++++++++++++++-- code/renderergl2/tr_local.h | 9 +++++++-- code/renderergl2/tr_main.c | 5 ++--- code/renderergl2/tr_scene.c | 2 ++ code/renderergl2/tr_shader.c | 8 ++++++++ code/renderergl2/tr_sky.c | 9 +++------ 20 files changed, 84 insertions(+), 33 deletions(-) diff --git a/code/cgame/cg_public.h b/code/cgame/cg_public.h index fdfcea87a..919f2494b 100644 --- a/code/cgame/cg_public.h +++ b/code/cgame/cg_public.h @@ -36,7 +36,7 @@ Suite 120, Rockville, Maryland 20850 USA. // major 0 means each minor is an API break. // major > 0 means each major is an API break and each minor extends API. #define CG_API_MAJOR_VERSION 0 -#define CG_API_MINOR_VERSION 34 +#define CG_API_MINOR_VERSION 35 #define CMD_BACKUP 64 diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index c35c3d66f..0da110693 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -1421,10 +1421,10 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { case CG_R_LERPTAG_TORSO: return re.LerpTag( VMA(1), args[2], args[3], args[4], args[5], args[6], VMF(7), VMA(8), VMA(9), VMA(10), args[11], args[12], args[13], args[14], VMF(15) ); case CG_R_GET_GLOBAL_FOG: - re.GetGlobalFog( VMA(1), VMA(2), VMA(3), VMA(4) ); + re.GetGlobalFog( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5) ); return 0; case CG_R_GET_VIEW_FOG: - re.GetViewFog( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6] ); + re.GetViewFog( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), VMA(6), args[7] ); return 0; case CG_GETCLIPBOARDDATA: CL_GetClipboardData( VMA(1), args[2] ); diff --git a/code/renderercommon/tr_public.h b/code/renderercommon/tr_public.h index fda4bdebf..b58719c1a 100644 --- a/code/renderercommon/tr_public.h +++ b/code/renderercommon/tr_public.h @@ -129,8 +129,8 @@ typedef struct { void (*TakeVideoFrame)( int h, int w, byte* captureBuffer, byte *encodeBuffer, qboolean motionJpeg ); - void (*GetGlobalFog)( fogType_t *type, vec3_t color, float *depthForOpaque, float *density ); - void (*GetViewFog)( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, qboolean inwater ); + void (*GetGlobalFog)( fogType_t *type, vec3_t color, float *depthForOpaque, float *density, float *farClip ); + void (*GetViewFog)( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, float *farClip, qboolean inwater ); void (*SetSurfaceShader)( int surfaceNum, const char *name ); qhandle_t (*GetSurfaceShader)( int surfaceNum, int lightmapIndex ); diff --git a/code/renderercommon/tr_types.h b/code/renderercommon/tr_types.h index b338c9fae..d1febc270 100644 --- a/code/renderercommon/tr_types.h +++ b/code/renderercommon/tr_types.h @@ -227,6 +227,9 @@ typedef struct { // for alphaGen skyAlpha and oneMinusSkyAlpha float skyAlpha; + + // maximum distance for the far clip plane + float farClip; } refdef_t; diff --git a/code/renderergl1/tr_backend.c b/code/renderergl1/tr_backend.c index a70bc054d..2e9c1fe7b 100644 --- a/code/renderergl1/tr_backend.c +++ b/code/renderergl1/tr_backend.c @@ -457,7 +457,7 @@ void RB_BeginDrawingView (void) { { clearBits |= GL_STENCIL_BUFFER_BIT; } - if ( ( backEnd.refdef.fogType == FT_LINEAR || r_fastsky->integer ) + if ( ( backEnd.refdef.maxFarClip > 1 || r_fastsky->integer ) && !( backEnd.refdef.rdflags & (RDF_NOWORLDMODEL|RDF_NOSKY) ) ) { clearBits |= GL_COLOR_BUFFER_BIT; diff --git a/code/renderergl1/tr_bsp.c b/code/renderergl1/tr_bsp.c index 0d7ab281e..44ca0636e 100644 --- a/code/renderergl1/tr_bsp.c +++ b/code/renderergl1/tr_bsp.c @@ -2165,6 +2165,7 @@ void RE_LoadWorldMap( const bspFile_t *bsp ) { VectorCopy( shader->fogParms.color, tr.globalFogColor ); tr.globalFogDepthForOpaque = shader->fogParms.depthForOpaque; tr.globalFogDensity = shader->fogParms.density; + tr.globalFogFarClip = shader->fogParms.farClip; } R_InitExternalShaders(); diff --git a/code/renderergl1/tr_cmds.c b/code/renderergl1/tr_cmds.c index 32e519887..b7dd534fe 100644 --- a/code/renderergl1/tr_cmds.c +++ b/code/renderergl1/tr_cmds.c @@ -448,7 +448,7 @@ void RE_2DPolyies( polyVert_t* verts, int numverts, qhandle_t hShader ) { RE_GetGlobalFog ==================== */ -void RE_GetGlobalFog( fogType_t *type, vec3_t color, float *depthForOpaque, float *density ) { +void RE_GetGlobalFog( fogType_t *type, vec3_t color, float *depthForOpaque, float *density, float *farClip ) { if (type) { *type = tr.globalFogType; } @@ -464,6 +464,10 @@ void RE_GetGlobalFog( fogType_t *type, vec3_t color, float *depthForOpaque, floa if (density) { *density = tr.globalFogDensity; } + + if (farClip) { + *farClip = tr.globalFogFarClip; + } } /* @@ -498,22 +502,25 @@ qboolean R_PointInBrush( const vec3_t point, const bmodel_t *bmodel ) { RE_GetViewFog ==================== */ -void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, qboolean inwater ) { +void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, float *farClip, qboolean inwater ) { fogType_t fogType; vec3_t fogColor; float fogDepthForOpaque; float fogDensity; + float fogFarClip; if ( inwater ) { fogType = tr.waterFogParms.fogType; VectorCopy( tr.waterFogParms.color, fogColor ); fogDepthForOpaque = tr.waterFogParms.depthForOpaque; fogDensity = tr.waterFogParms.density; + fogFarClip = tr.waterFogParms.farClip; } else { fogType = FT_NONE; VectorSet( fogColor, 0, 0, 0 ); fogDepthForOpaque = 0; fogDensity = 0; + fogFarClip = 0; } if ( tr.world && tr.world->numBModels > 1 ) { @@ -541,6 +548,7 @@ void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *d VectorCopy( surface->shader->viewFogParms.color, fogColor ); fogDepthForOpaque = surface->shader->viewFogParms.depthForOpaque; fogDensity = surface->shader->viewFogParms.density; + fogFarClip = surface->shader->viewFogParms.farClip; break; } } @@ -566,6 +574,10 @@ void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *d if (density) { *density = fogDensity; } + + if (farClip) { + *farClip = fogFarClip; + } } #define MODE_RED_CYAN 1 diff --git a/code/renderergl1/tr_local.h b/code/renderergl1/tr_local.h index 6c27045e4..40b3aec2c 100644 --- a/code/renderergl1/tr_local.h +++ b/code/renderergl1/tr_local.h @@ -358,6 +358,7 @@ typedef struct { vec3_t color; float depthForOpaque; float density; + float farClip; } fogParms_t; @@ -458,6 +459,9 @@ typedef struct { float fogDensity; float fogTcScale; + // maximum distance for the far clip plane + float maxFarClip; + int num_entities; trRefEntity_t *entities; @@ -1101,6 +1105,7 @@ typedef struct { vec3_t globalFogColor; float globalFogDepthForOpaque; float globalFogDensity; + float globalFogFarClip; // set by skyfogvars in a shader fogType_t skyFogType; @@ -1855,8 +1860,8 @@ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, void RE_SaveTGA(char * filename, int image_width, int image_height, byte *image_buffer, int padding); void RE_TakeVideoFrame( int width, int height, byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ); -void RE_GetGlobalFog( fogType_t *type, vec3_t color, float *depthForOpaque, float *density ); -void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, qboolean inwater ); +void RE_GetGlobalFog( fogType_t *type, vec3_t color, float *depthForOpaque, float *density, float *farClip ); +void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, float *farClip, qboolean inwater ); //------------------------------------------------------------------------------ // Ridah, mesh compression diff --git a/code/renderergl1/tr_main.c b/code/renderergl1/tr_main.c index b45578e4f..12e81ee3d 100644 --- a/code/renderergl1/tr_main.c +++ b/code/renderergl1/tr_main.c @@ -701,9 +701,8 @@ static void R_SetFarClip( void ) } tr.viewParms.zFar = sqrt( farthestCornerDistance ); - // global fog - if ( tr.refdef.fogType == FT_LINEAR && tr.refdef.fogDepthForOpaque > 1 && tr.refdef.fogDepthForOpaque < tr.viewParms.zFar ) { - tr.viewParms.zFar = tr.refdef.fogDepthForOpaque; + if ( tr.refdef.maxFarClip > 1 && tr.refdef.maxFarClip < tr.viewParms.zFar ) { + tr.viewParms.zFar = tr.refdef.maxFarClip; } } diff --git a/code/renderergl1/tr_scene.c b/code/renderergl1/tr_scene.c index c183da4fa..4605a1c15 100644 --- a/code/renderergl1/tr_scene.c +++ b/code/renderergl1/tr_scene.c @@ -615,6 +615,8 @@ void RE_RenderScene( const refdef_t *vmRefDef, int vmRefDefSize ) { } tr.refdef.fogTcScale = R_FogTcScale( tr.refdef.fogType, tr.refdef.fogDepthForOpaque, tr.refdef.fogDensity ); + tr.refdef.maxFarClip = fd.farClip; + // copy the areamask data over and note if it has changed, which // will force a reset of the visible leafs even if the view hasn't moved tr.refdef.areamaskModified = qfalse; diff --git a/code/renderergl1/tr_shader.c b/code/renderergl1/tr_shader.c index f654ed615..c2294a5d5 100644 --- a/code/renderergl1/tr_shader.c +++ b/code/renderergl1/tr_shader.c @@ -2533,12 +2533,14 @@ static qboolean ParseShader( char **text ) if ( !Q_stricmp( token, "linear" ) ) { shader.fogParms.fogType = FT_LINEAR; shader.fogParms.density = DEFAULT_FOG_LINEAR_DENSITY; + shader.fogParms.farClip = shader.fogParms.depthForOpaque; } else { if ( Q_stricmp( token, "exp" ) && !Q_isanumber( token ) ) ri.Printf( PRINT_WARNING, "WARNING: unknown fog type '%s' for 'fogParms' keyword in shader '%s'\n", token, shader.name ); shader.fogParms.fogType = FT_EXP; shader.fogParms.density = DEFAULT_FOG_EXP_DENSITY; + shader.fogParms.farClip = 0; } // note: skips any old gradient directions @@ -2625,10 +2627,12 @@ static qboolean ParseShader( char **text ) tr.waterFogParms.fogType = FT_LINEAR; tr.waterFogParms.depthForOpaque = fogvar; tr.waterFogParms.density = DEFAULT_FOG_LINEAR_DENSITY; + tr.waterFogParms.farClip = fogvar; } else { tr.waterFogParms.fogType = FT_EXP; tr.waterFogParms.density = fogvar; tr.waterFogParms.depthForOpaque = DEFAULT_FOG_EXP_DEPTH_FOR_OPAQUE; + tr.waterFogParms.farClip = 0; } VectorCopy( waterColor, tr.waterFogParms.color ); @@ -2668,6 +2672,8 @@ static qboolean ParseShader( char **text ) shader.viewFogParms.depthForOpaque = DEFAULT_FOG_EXP_DEPTH_FOR_OPAQUE; } + shader.viewFogParms.farClip = 0; + VectorCopy( viewColor, shader.viewFogParms.color ); continue; } @@ -2694,10 +2700,12 @@ static qboolean ParseShader( char **text ) tr.globalFogType = FT_LINEAR; tr.globalFogDepthForOpaque = fogvar; tr.globalFogDensity = DEFAULT_FOG_LINEAR_DENSITY; + tr.globalFogFarClip = fogvar; } else { tr.globalFogType = FT_EXP; tr.globalFogDensity = fogvar; tr.globalFogDepthForOpaque = DEFAULT_FOG_EXP_DEPTH_FOR_OPAQUE; + tr.globalFogFarClip = 0; } VectorCopy( fogColor, tr.globalFogColor ); diff --git a/code/renderergl1/tr_sky.c b/code/renderergl1/tr_sky.c index 9c30a054f..6cc1b1289 100644 --- a/code/renderergl1/tr_sky.c +++ b/code/renderergl1/tr_sky.c @@ -778,12 +778,9 @@ void RB_StageIteratorSky( void ) { return; } - // RTCW doesn't draw sky if world global fog is linear. - // However, skies are drawn in sky box refdefs that use linear fog - // so cannot check if the current refdef uses linear fog. - // Water fog does not draw sky if there is linear fog. - if ( !r_globalLinearFogDrawSky->integer && ( tr.globalFogType == FT_LINEAR - || ( ( backEnd.refdef.rdflags & RDF_UNDERWATER ) && backEnd.refdef.fogType == FT_LINEAR ) ) ) { + // RTCW doesn't draw sky if world/water global fog is linear (they use clip plane). + // Skies are drawn in sky box refdefs that use linear fog (they do not use clip plane). + if ( !r_globalLinearFogDrawSky->integer && backEnd.refdef.fogType == FT_LINEAR && backEnd.refdef.maxFarClip > 1 ) { return; } diff --git a/code/renderergl2/tr_backend.c b/code/renderergl2/tr_backend.c index 4cf16d0ca..7a6a73cf7 100644 --- a/code/renderergl2/tr_backend.c +++ b/code/renderergl2/tr_backend.c @@ -419,7 +419,7 @@ void RB_BeginDrawingView (void) { { clearBits |= GL_STENCIL_BUFFER_BIT; } - if ( ( backEnd.refdef.fogType == FT_LINEAR || r_fastsky->integer ) + if ( ( backEnd.refdef.maxFarClip > 1 || r_fastsky->integer ) && !( backEnd.refdef.rdflags & (RDF_NOWORLDMODEL|RDF_NOSKY) ) ) { clearBits |= GL_COLOR_BUFFER_BIT; diff --git a/code/renderergl2/tr_bsp.c b/code/renderergl2/tr_bsp.c index 36f0e346d..26010fcda 100644 --- a/code/renderergl2/tr_bsp.c +++ b/code/renderergl2/tr_bsp.c @@ -3934,6 +3934,7 @@ void RE_LoadWorldMap( const bspFile_t *bsp ) { VectorCopy( shader->fogParms.color, tr.globalFogColor ); tr.globalFogDepthForOpaque = shader->fogParms.depthForOpaque; tr.globalFogDensity = shader->fogParms.density; + tr.globalFogFarClip = shader->fogParms.farClip; } R_InitExternalShaders(); diff --git a/code/renderergl2/tr_cmds.c b/code/renderergl2/tr_cmds.c index 709f85ec5..dd1f9f602 100644 --- a/code/renderergl2/tr_cmds.c +++ b/code/renderergl2/tr_cmds.c @@ -494,7 +494,7 @@ void RE_2DPolyies( polyVert_t* verts, int numverts, qhandle_t hShader ) { RE_GetGlobalFog ==================== */ -void RE_GetGlobalFog( fogType_t *type, vec3_t color, float *depthForOpaque, float *density ) { +void RE_GetGlobalFog( fogType_t *type, vec3_t color, float *depthForOpaque, float *density, float *farClip ) { if (type) { *type = tr.globalFogType; } @@ -510,6 +510,10 @@ void RE_GetGlobalFog( fogType_t *type, vec3_t color, float *depthForOpaque, floa if (density) { *density = tr.globalFogDensity; } + + if (farClip) { + *farClip = tr.globalFogFarClip; + } } /* @@ -544,22 +548,25 @@ qboolean R_PointInBrush( const vec3_t point, const bmodel_t *bmodel ) { RE_GetViewFog ==================== */ -void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, qboolean inwater ) { +void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, float *farClip, qboolean inwater ) { fogType_t fogType; vec3_t fogColor; float fogDepthForOpaque; float fogDensity; + float fogFarClip; if ( inwater ) { fogType = tr.waterFogParms.fogType; VectorCopy( tr.waterFogParms.color, fogColor ); fogDepthForOpaque = tr.waterFogParms.depthForOpaque; fogDensity = tr.waterFogParms.density; + fogFarClip = tr.waterFogParms.farClip; } else { fogType = FT_NONE; VectorSet( fogColor, 0, 0, 0 ); fogDepthForOpaque = 0; fogDensity = 0; + fogFarClip = 0; } if ( tr.world && tr.world->numBModels > 1 ) { @@ -587,6 +594,7 @@ void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *d VectorCopy( surface->shader->viewFogParms.color, fogColor ); fogDepthForOpaque = surface->shader->viewFogParms.depthForOpaque; fogDensity = surface->shader->viewFogParms.density; + fogFarClip = surface->shader->viewFogParms.farClip; break; } } @@ -612,6 +620,10 @@ void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *d if (density) { *density = fogDensity; } + + if (farClip) { + *farClip = fogFarClip; + } } #define MODE_RED_CYAN 1 diff --git a/code/renderergl2/tr_local.h b/code/renderergl2/tr_local.h index 6d80b746f..b9fbfa45e 100644 --- a/code/renderergl2/tr_local.h +++ b/code/renderergl2/tr_local.h @@ -476,6 +476,7 @@ typedef struct { vec3_t color; float depthForOpaque; float density; + float farClip; } fogParms_t; typedef struct shader_s { @@ -820,6 +821,9 @@ typedef struct { float fogDensity; float fogTcScale; + // maximum distance for the far clip plane + float maxFarClip; + int num_entities; trRefEntity_t *entities; @@ -1802,6 +1806,7 @@ typedef struct { vec3_t globalFogColor; float globalFogDepthForOpaque; float globalFogDensity; + float globalFogFarClip; // set by skyfogvars in a shader fogType_t skyFogType; @@ -2751,8 +2756,8 @@ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, void RE_SaveTGA(char * filename, int image_width, int image_height, byte *image_buffer, int padding); void RE_TakeVideoFrame( int width, int height, byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ); -void RE_GetGlobalFog( fogType_t *type, vec3_t color, float *depthForOpaque, float *density ); -void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, qboolean inwater ); +void RE_GetGlobalFog( fogType_t *type, vec3_t color, float *depthForOpaque, float *density, float *farClip ); +void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, float *farClip, qboolean inwater ); //------------------------------------------------------------------------------ // Ridah, mesh compression diff --git a/code/renderergl2/tr_main.c b/code/renderergl2/tr_main.c index 7786d787b..2b6bd05e7 100644 --- a/code/renderergl2/tr_main.c +++ b/code/renderergl2/tr_main.c @@ -1237,9 +1237,8 @@ static void R_SetFarClip( void ) } tr.viewParms.zFar = sqrt( farthestCornerDistance ); - // global fog - if ( tr.refdef.fogType == FT_LINEAR && tr.refdef.fogDepthForOpaque > 1 && tr.refdef.fogDepthForOpaque < tr.viewParms.zFar ) { - tr.viewParms.zFar = tr.refdef.fogDepthForOpaque; + if ( tr.refdef.maxFarClip > 1 && tr.refdef.maxFarClip < tr.viewParms.zFar ) { + tr.viewParms.zFar = tr.refdef.maxFarClip; } } diff --git a/code/renderergl2/tr_scene.c b/code/renderergl2/tr_scene.c index b6a5ba1a5..c8a761b8a 100644 --- a/code/renderergl2/tr_scene.c +++ b/code/renderergl2/tr_scene.c @@ -590,6 +590,8 @@ void RE_BeginScene(const refdef_t *fd) } tr.refdef.fogTcScale = R_FogTcScale( tr.refdef.fogType, tr.refdef.fogDepthForOpaque, tr.refdef.fogDensity ); + tr.refdef.maxFarClip = fd->farClip; + // copy the areamask data over and note if it has changed, which // will force a reset of the visible leafs even if the view hasn't moved tr.refdef.areamaskModified = qfalse; diff --git a/code/renderergl2/tr_shader.c b/code/renderergl2/tr_shader.c index 91dd88040..c5eff8953 100644 --- a/code/renderergl2/tr_shader.c +++ b/code/renderergl2/tr_shader.c @@ -2889,12 +2889,14 @@ static qboolean ParseShader( char **text ) if ( !Q_stricmp( token, "linear" ) ) { shader.fogParms.fogType = FT_LINEAR; shader.fogParms.density = DEFAULT_FOG_LINEAR_DENSITY; + shader.fogParms.farClip = shader.fogParms.depthForOpaque; } else { if ( Q_stricmp( token, "exp" ) && !Q_isanumber( token ) ) ri.Printf( PRINT_WARNING, "WARNING: unknown fog type '%s' for 'fogParms' keyword in shader '%s'\n", token, shader.name ); shader.fogParms.fogType = FT_EXP; shader.fogParms.density = DEFAULT_FOG_EXP_DENSITY; + shader.fogParms.farClip = 0; } // note: skips any old gradient directions @@ -2982,10 +2984,12 @@ static qboolean ParseShader( char **text ) tr.waterFogParms.fogType = FT_LINEAR; tr.waterFogParms.depthForOpaque = fogvar; tr.waterFogParms.density = DEFAULT_FOG_LINEAR_DENSITY; + tr.waterFogParms.farClip = fogvar; } else { tr.waterFogParms.fogType = FT_EXP; tr.waterFogParms.density = fogvar; tr.waterFogParms.depthForOpaque = DEFAULT_FOG_EXP_DEPTH_FOR_OPAQUE; + tr.waterFogParms.farClip = 0; } VectorCopy( waterColor, tr.waterFogParms.color ); @@ -3025,6 +3029,8 @@ static qboolean ParseShader( char **text ) shader.viewFogParms.depthForOpaque = DEFAULT_FOG_EXP_DEPTH_FOR_OPAQUE; } + shader.viewFogParms.farClip = 0; + VectorCopy( viewColor, shader.viewFogParms.color ); continue; } @@ -3051,10 +3057,12 @@ static qboolean ParseShader( char **text ) tr.globalFogType = FT_LINEAR; tr.globalFogDepthForOpaque = fogvar; tr.globalFogDensity = DEFAULT_FOG_LINEAR_DENSITY; + tr.globalFogFarClip = fogvar; } else { tr.globalFogType = FT_EXP; tr.globalFogDensity = fogvar; tr.globalFogDepthForOpaque = DEFAULT_FOG_EXP_DEPTH_FOR_OPAQUE; + tr.globalFogFarClip = 0; } VectorCopy( fogColor, tr.globalFogColor ); diff --git a/code/renderergl2/tr_sky.c b/code/renderergl2/tr_sky.c index 3ae8c6371..ddc105fe9 100644 --- a/code/renderergl2/tr_sky.c +++ b/code/renderergl2/tr_sky.c @@ -881,12 +881,9 @@ void RB_StageIteratorSky( void ) { return; } - // RTCW doesn't draw sky if world global fog is linear. - // However, skies are drawn in sky box refdefs that use linear fog - // so cannot check if the current refdef uses linear fog. - // Water fog does not draw sky if there is linear fog. - if ( !r_globalLinearFogDrawSky->integer && ( tr.globalFogType == FT_LINEAR - || ( ( backEnd.refdef.rdflags & RDF_UNDERWATER ) && backEnd.refdef.fogType == FT_LINEAR ) ) ) { + // RTCW doesn't draw sky if world/water global fog is linear (they use clip plane). + // Skies are drawn in sky box refdefs that use linear fog (they do not use clip plane). + if ( !r_globalLinearFogDrawSky->integer && backEnd.refdef.fogType == FT_LINEAR && backEnd.refdef.maxFarClip > 1 ) { return; } From a819c9a90e75995a52ecdec25eb95271e1bc94d9 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sun, 24 Apr 2016 08:36:26 -0500 Subject: [PATCH 2/5] spearmint: Game API 0.12 Add plane to aas_trace_t (mainly to get rid of the hacks in sv_game.c). Allow parsing the entities string multiple times (letting Game VM track the offsets separate in case say the botlib quit parsing in the middle, which would screw up anything that tried to parse the entities later.) --- code/game/g_public.h | 5 +-- code/qcommon/cm_load.c | 22 ++++++++++ code/qcommon/cm_public.h | 1 + code/server/sv_game.c | 89 ++-------------------------------------- 4 files changed, 29 insertions(+), 88 deletions(-) diff --git a/code/game/g_public.h b/code/game/g_public.h index a35e4024c..2d1f1ab06 100644 --- a/code/game/g_public.h +++ b/code/game/g_public.h @@ -36,7 +36,7 @@ Suite 120, Rockville, Maryland 20850 USA. // major 0 means each minor is an API break. // major > 0 means each major is an API break and each minor extends API. #define GAME_API_MAJOR_VERSION 0 -#define GAME_API_MINOR_VERSION 11 +#define GAME_API_MINOR_VERSION 12 // entity->svFlags @@ -251,10 +251,9 @@ typedef enum { G_GET_USERCMD, // ( int playerNum, usercmd_t *cmd ) - G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize ) + G_GET_ENTITY_TOKEN, // qboolean ( int *parseOffset, char *buffer, int bufferSize ) // Retrieves the next string token from the entity spawn text, returning // false when all tokens have been parsed. - // This should only be done at GAME_INIT time. G_DEBUG_POLYGON_CREATE, G_DEBUG_POLYGON_DELETE, diff --git a/code/qcommon/cm_load.c b/code/qcommon/cm_load.c index 514c4fcb4..dc5061993 100644 --- a/code/qcommon/cm_load.c +++ b/code/qcommon/cm_load.c @@ -950,6 +950,28 @@ char *CM_EntityString( void ) { return cm.entityString; } +qboolean CM_GetEntityToken( int *parseOffset, char *token, int size ) { + const char *s; + char *parsePoint = cm.entityString; + + if ( !cm.entityString || *parseOffset < 0 || *parseOffset >= cm.numEntityChars ) { + return qfalse; + } + + parsePoint = cm.entityString + *parseOffset; + + s = COM_Parse( &parsePoint ); + Q_strncpyz( token, s, size ); + + if ( !parsePoint && !s[0] ) { + *parseOffset = 0; + return qfalse; + } else { + *parseOffset = parsePoint - cm.entityString; + return qtrue; + } +} + int CM_LeafCluster( int leafnum ) { if (leafnum < 0 || leafnum >= cm.numLeafs) { Com_Error (ERR_DROP, "CM_LeafCluster: bad number"); diff --git a/code/qcommon/cm_public.h b/code/qcommon/cm_public.h index ea9108339..fb9d5e1a8 100644 --- a/code/qcommon/cm_public.h +++ b/code/qcommon/cm_public.h @@ -41,6 +41,7 @@ void CM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ); int CM_NumClusters (void); int CM_NumInlineModels( void ); char *CM_EntityString (void); +qboolean CM_GetEntityToken( int *parseOffset, char *token, int size ); // returns an ORed contents mask int CM_PointContents( const vec3_t p, clipHandle_t model ); diff --git a/code/server/sv_game.c b/code/server/sv_game.c index 123933170..97539d53f 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -291,34 +291,6 @@ void SV_GetUsercmd( int playerNum, usercmd_t *cmd ) { //============================================== -// These includes and structs are needed for Game API compatibility with Spearmint 0.2 -#include "../botlib/aasfile.h" -#include "../botlib/be_aas.h" - -typedef struct -{ - qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - int ent; // entity blocking the trace - int lastarea; // last area the trace was in (zero if none) - int area; // area blocking the trace (zero if none) - int planenum; // number of the AAS plane that was hit -} old_aas_trace_t; - -typedef struct -{ - vec3_t endpos; //position at the end of movement prediction - int endarea; //area at end of movement prediction - vec3_t velocity; //velocity at the end of movement prediction - old_aas_trace_t trace; //last trace - int presencetype; //presence type at end of movement prediction - int stopevent; //event that made the prediction stop - int endcontents; //contents at the end of movement prediction - float time; //time predicted ahead - int frames; //number of frames predicted ahead -} old_aas_clientmove_t; - /* ==================== SV_GameSystemCalls @@ -518,17 +490,7 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { SV_GetUsercmd( args[1], VMA(2) ); return 0; case G_GET_ENTITY_TOKEN: - { - const char *s; - - s = COM_Parse( &sv.entityParsePoint ); - Q_strncpyz( VMA(1), s, args[2] ); - if ( !sv.entityParsePoint && !s[0] ) { - return qfalse; - } else { - return qtrue; - } - } + return CM_GetEntityToken( VMA(1), VMA(2), args[3] ); case G_DEBUG_POLYGON_CREATE: return BotImport_DebugPolygonCreate( args[1], args[2], VMA(3) ); @@ -603,19 +565,7 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { case BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX: return botlib_export->aas.AAS_PointReachabilityAreaIndex( VMA(1) ); case BOTLIB_AAS_TRACE_PLAYER_BBOX: - { - // work around different aas_trace_t in engine and game VM - // ZTM: TODO: Get rid of this when the API breaks compatibility, or maybe have separate structures? - // I don't think the plane is even usable from TracePlayerBBox? - old_aas_trace_t *vmTrace = VMA(1); - aas_trace_t trace; - - Com_Memcpy2( &trace, sizeof( trace ), vmTrace, sizeof( old_aas_trace_t ) ); - - botlib_export->aas.AAS_TracePlayerBBox( &trace, VMA(2), VMA(3), args[4], args[5], args[6] ); - - Com_Memcpy2( vmTrace, sizeof( old_aas_trace_t ), &trace, sizeof( trace ) ); - } + botlib_export->aas.AAS_TracePlayerBBox( VMA(1), VMA(2), VMA(3), args[4], args[5], args[6] ); return 0; case BOTLIB_AAS_TRACE_AREAS: return botlib_export->aas.AAS_TraceAreas( VMA(1), VMA(2), VMA(3), VMA(4), args[5] ); @@ -683,39 +633,8 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { return botlib_export->aas.AAS_PredictRoute( VMA(1), args[2], VMA(3), args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11] ); case BOTLIB_AAS_PREDICT_PLAYER_MOVEMENT: - { - // compatibility is a bitch - // work around different aas_trace_t in engine and game VM - // ZTM: TODO: Get rid of this when the API breaks compatibility - old_aas_clientmove_t *vmMove = VMA(1); - aas_clientmove_t move; - qboolean success; - - VectorCopy( vmMove->endpos, move.endpos ); - move.endarea = vmMove->endarea; - VectorCopy( vmMove->velocity, move.velocity ); - Com_Memcpy2( &move.trace, sizeof( aas_trace_t ), &vmMove->trace, sizeof( old_aas_trace_t ) ); - move.presencetype = vmMove->presencetype; - move.stopevent = vmMove->stopevent; - move.endcontents = vmMove->endcontents; - move.time = vmMove->time; - move.frames = vmMove->frames; - - success = botlib_export->aas.AAS_PredictPlayerMovement( &move, args[2], VMA(3), args[4], args[5], - VMA(6), VMA(7), args[8], args[9], VMF(10), args[11], args[12], args[13], args[14] ); - - VectorCopy( move.endpos, vmMove->endpos ); - vmMove->endarea = move.endarea; - VectorCopy( move.velocity, vmMove->velocity ); - Com_Memcpy2( &vmMove->trace, sizeof( old_aas_trace_t ), &move.trace, sizeof( aas_trace_t ) ); - vmMove->presencetype = move.presencetype; - vmMove->stopevent = move.stopevent; - vmMove->endcontents = move.endcontents; - vmMove->time = move.time; - vmMove->frames = move.frames; - - return success; - } + return botlib_export->aas.AAS_PredictPlayerMovement( VMA(1), args[2], VMA(3), args[4], args[5], + VMA(6), VMA(7), args[8], args[9], VMF(10), args[11], args[12], args[13], args[14] ); case BOTLIB_AAS_ON_GROUND: return botlib_export->aas.AAS_OnGround( VMA(1), args[2], args[3], args[4] ); case BOTLIB_AAS_SWIMMING: From a763ac5621c8dbc177ff2fb1c7c8dfc073a5ff0c Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sun, 8 May 2016 04:30:54 -0500 Subject: [PATCH 3/5] spearmint: CGame API 0.36 - stateless GetEntityToken --- code/cgame/cg_public.h | 2 +- code/client/cl_cgame.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/cgame/cg_public.h b/code/cgame/cg_public.h index 919f2494b..ba0b49c54 100644 --- a/code/cgame/cg_public.h +++ b/code/cgame/cg_public.h @@ -36,7 +36,7 @@ Suite 120, Rockville, Maryland 20850 USA. // major 0 means each minor is an API break. // major > 0 means each major is an API break and each minor extends API. #define CG_API_MAJOR_VERSION 0 -#define CG_API_MINOR_VERSION 35 +#define CG_API_MINOR_VERSION 36 #define CMD_BACKUP 64 diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index 0da110693..f215bae1b 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -1686,7 +1686,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { return getCameraInfo(args[1], VMA(2), VMA(3)); */ case CG_GET_ENTITY_TOKEN: - return re.GetEntityToken( VMA(1), args[2] ); + return CM_GetEntityToken( VMA(1), VMA(2), args[3] ); case CG_R_INPVS: return re.inPVS( VMA(1), VMA(2) ); From dbb589da5ce6324a09504b079ef5ceb3bcc932db Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sun, 8 May 2016 05:12:24 -0500 Subject: [PATCH 4/5] spearmint: Game API 0.13 - DebugPolygonShow --- code/game/g_public.h | 7 ++++--- code/server/server.h | 1 + code/server/sv_bot.c | 33 ++++++++++++++++++++++++--------- code/server/sv_game.c | 3 +++ 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/code/game/g_public.h b/code/game/g_public.h index 2d1f1ab06..9d56f4daf 100644 --- a/code/game/g_public.h +++ b/code/game/g_public.h @@ -36,7 +36,7 @@ Suite 120, Rockville, Maryland 20850 USA. // major 0 means each minor is an API break. // major > 0 means each major is an API break and each minor extends API. #define GAME_API_MAJOR_VERSION 0 -#define GAME_API_MINOR_VERSION 12 +#define GAME_API_MINOR_VERSION 13 // entity->svFlags @@ -255,8 +255,9 @@ typedef enum { // Retrieves the next string token from the entity spawn text, returning // false when all tokens have been parsed. - G_DEBUG_POLYGON_CREATE, - G_DEBUG_POLYGON_DELETE, + G_DEBUG_POLYGON_CREATE, // ( int color, int numPoints, vec3_t *points ); + G_DEBUG_POLYGON_SHOW, // ( int id, int color, int numPoints, vec3_t *points ); + G_DEBUG_POLYGON_DELETE, // ( int id ); G_TRACECAPSULE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ); G_ENTITY_CONTACTCAPSULE, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ); diff --git a/code/server/server.h b/code/server/server.h index 42cb6a500..978ce408e 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -451,6 +451,7 @@ int SV_BotGetSnapshotEntity( int playerNum, int ent ); int SV_BotGetConsoleMessage( int playerNum, char *buf, int size ); int BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points); +void BotImport_DebugPolygonShow(int id, int color, int numPoints, vec3_t *points); void BotImport_DebugPolygonDelete(int id); void SV_ForceClientCommand( int playerNum, const char *command ); diff --git a/code/server/sv_bot.c b/code/server/sv_bot.c index 00f8fdcfe..8b8e19469 100644 --- a/code/server/sv_bot.c +++ b/code/server/sv_bot.c @@ -340,8 +340,12 @@ int BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points) { poly = &debugpolygons[i]; poly->inuse = qtrue; poly->color = color; - poly->numPoints = numPoints; - Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); + if (!points || numPoints <= 0) { + poly->numPoints = 0; + } else { + poly->numPoints = numPoints; + Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); + } // return i; } @@ -351,15 +355,23 @@ int BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points) { BotImport_DebugPolygonShow ================== */ -static void BotImport_DebugPolygonShow(int id, int color, int numPoints, vec3_t *points) { +void BotImport_DebugPolygonShow(int id, int color, int numPoints, vec3_t *points) { bot_debugpoly_t *poly; - if (!debugpolygons) return; + if (!debugpolygons) + return; + if (id < 0 || id >= bot_maxdebugpolys) + return; + poly = &debugpolygons[id]; poly->inuse = qtrue; poly->color = color; - poly->numPoints = numPoints; - Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); + if (!points || numPoints <= 0) { + poly->numPoints = 0; + } else { + poly->numPoints = numPoints; + Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); + } } /* @@ -369,7 +381,11 @@ BotImport_DebugPolygonDelete */ void BotImport_DebugPolygonDelete(int id) { - if (!debugpolygons) return; + if (!debugpolygons) + return; + if (id < 0 || id >= bot_maxdebugpolys) + return; + debugpolygons[id].inuse = qfalse; } @@ -379,8 +395,7 @@ BotImport_DebugLineCreate ================== */ static int BotImport_DebugLineCreate(void) { - vec3_t points[1]; - return BotImport_DebugPolygonCreate(0, 0, points); + return BotImport_DebugPolygonCreate(0, 0, NULL); } /* diff --git a/code/server/sv_game.c b/code/server/sv_game.c index 97539d53f..841733b20 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -494,6 +494,9 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { case G_DEBUG_POLYGON_CREATE: return BotImport_DebugPolygonCreate( args[1], args[2], VMA(3) ); + case G_DEBUG_POLYGON_SHOW: + BotImport_DebugPolygonShow( args[1], args[2], args[3], VMA(4) ); + return 0; case G_DEBUG_POLYGON_DELETE: BotImport_DebugPolygonDelete( args[1] ); return 0; From ef98e70259b1491f6f879bea11049e0f6db7a28a Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Fri, 13 May 2016 02:53:21 -0500 Subject: [PATCH 5/5] spearmint: Change version to 0.3, protocol to 5 Protocol was changed so that network games with incompatible VMs are separate. --- Makefile | 2 +- code/qcommon/common.c | 2 +- code/qcommon/qcommon.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 88c08b5f2..2c921e61d 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ endif export CROSS_COMPILING ifndef VERSION -VERSION=0.2 +VERSION=0.3 endif ifndef CLIENTBIN diff --git a/code/qcommon/common.c b/code/qcommon/common.c index c4ee9e902..c030b628f 100644 --- a/code/qcommon/common.c +++ b/code/qcommon/common.c @@ -44,7 +44,7 @@ Suite 120, Rockville, Maryland 20850 USA. // List of demo protocols that are supported for playback. // Also plays protocol com_protocol int demo_protocols[] = -{ PROTOCOL_VERSION, 3, 2, 0 }; +{ PROTOCOL_VERSION, 4, 3, 2, 0 }; #define MAX_NUM_ARGVS 50 diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 440cb9460..2dabf9f61 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -39,7 +39,7 @@ Suite 120, Rockville, Maryland 20850 USA. // Keep this in-sync with VERSION in Makefile. #ifndef PRODUCT_VERSION - #define PRODUCT_VERSION "0.2" + #define PRODUCT_VERSION "0.3" #endif #define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION @@ -318,7 +318,7 @@ PROTOCOL ============================================================== */ -#define PROTOCOL_VERSION 4 +#define PROTOCOL_VERSION 5 #define PROTOCOL_LEGACY_VERSION 0 // maintain a list of compatible protocols for demo playing