mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 19:45:05 +08:00
Compare commits
9 Commits
continuous
...
tw_port
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a131a59414 | ||
|
|
cd7727b7de | ||
|
|
462b64b8ce | ||
|
|
5525af3769 | ||
|
|
e334699c0b | ||
|
|
f5832faaa0 | ||
|
|
547a41ef2d | ||
|
|
ab60b1e981 | ||
|
|
d3e698d042 |
@@ -54,6 +54,7 @@ BRUSH MODELS
|
|||||||
#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND)
|
#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND)
|
||||||
#define SURF_UNDERWATER BIT( 7 ) // caustics
|
#define SURF_UNDERWATER BIT( 7 ) // caustics
|
||||||
#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP)
|
#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP)
|
||||||
|
#define SURF_REFLECT BIT( 31 ) // mirrors
|
||||||
|
|
||||||
// lightstyle management
|
// lightstyle management
|
||||||
#define LM_STYLES 4 // MAXLIGHTMAPS
|
#define LM_STYLES 4 // MAXLIGHTMAPS
|
||||||
|
|||||||
@@ -228,7 +228,9 @@ typedef struct mextrasurf_s
|
|||||||
unsigned short numverts; // world->vertexes[]
|
unsigned short numverts; // world->vertexes[]
|
||||||
int firstvertex; // fisrt look up in tr.tbn_vectors[], then acess to world->vertexes[]
|
int firstvertex; // fisrt look up in tr.tbn_vectors[], then acess to world->vertexes[]
|
||||||
|
|
||||||
intptr_t reserved[32]; // just for future expansions or mod-makers
|
struct mextrasurf_s *mirrorchain; // engine-side mirrors, may be ignored in mods with custom renderers
|
||||||
|
|
||||||
|
intptr_t reserved[31]; // just for future expansions or mod-makers
|
||||||
} mextrasurf_t;
|
} mextrasurf_t;
|
||||||
|
|
||||||
struct msurface_s
|
struct msurface_s
|
||||||
|
|||||||
@@ -92,6 +92,7 @@
|
|||||||
#define SOLID_BSP 4 // bsp clip, touch on edge, block
|
#define SOLID_BSP 4 // bsp clip, touch on edge, block
|
||||||
#define SOLID_CUSTOM 5 // call external callbacks for tracing
|
#define SOLID_CUSTOM 5 // call external callbacks for tracing
|
||||||
#define SOLID_PORTAL 6 // borrowed from FTE
|
#define SOLID_PORTAL 6 // borrowed from FTE
|
||||||
|
#define SOLID_GIB 7 // do not block, only collide with solid brushes
|
||||||
|
|
||||||
// edict->deadflag values
|
// edict->deadflag values
|
||||||
#define DEAD_NO 0 // alive
|
#define DEAD_NO 0 // alive
|
||||||
@@ -114,6 +115,8 @@
|
|||||||
#define EF_LIGHT 64 // rocket flare glow sprite
|
#define EF_LIGHT 64 // rocket flare glow sprite
|
||||||
#define EF_NODRAW 128 // don't draw entity
|
#define EF_NODRAW 128 // don't draw entity
|
||||||
|
|
||||||
|
#define EF_NOREFLECT (1U<<24) // Entity won't reflecting in mirrors
|
||||||
|
#define EF_REFLECTONLY (1U<<25) // Entity will be drawing only in mirrors
|
||||||
#define EF_WATERSIDES (1U<<26) // Do not remove sides for func_water entity
|
#define EF_WATERSIDES (1U<<26) // Do not remove sides for func_water entity
|
||||||
#define EF_FULLBRIGHT (1U<<27) // Just get fullbright
|
#define EF_FULLBRIGHT (1U<<27) // Just get fullbright
|
||||||
#define EF_NOSHADOW (1U<<28) // ignore shadow for this entity
|
#define EF_NOSHADOW (1U<<28) // ignore shadow for this entity
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ GNU General Public License for more details.
|
|||||||
#define ENGINE_COMPUTE_STUDIO_LERP (1<<7) // enable MOVETYPE_STEP lerping back in engine
|
#define ENGINE_COMPUTE_STUDIO_LERP (1<<7) // enable MOVETYPE_STEP lerping back in engine
|
||||||
#define ENGINE_LINEAR_GAMMA_SPACE (1<<8) // disable influence of gamma/brightness cvars to textures/lightmaps, for mods with custom renderer
|
#define ENGINE_LINEAR_GAMMA_SPACE (1<<8) // disable influence of gamma/brightness cvars to textures/lightmaps, for mods with custom renderer
|
||||||
|
|
||||||
|
#define ENGINE_ALLOW_MIRRORS (1U<<30) // allow mirrors in engine renderer
|
||||||
#define ENGINE_STEP_POSHISTORY_LERP (1U<<31) // enable MOVETYPE_STEP interpolation based on position history. Incompatible with ENGINE_COMPUTE_STUDIO_LERP!
|
#define ENGINE_STEP_POSHISTORY_LERP (1U<<31) // enable MOVETYPE_STEP interpolation based on position history. Incompatible with ENGINE_COMPUTE_STUDIO_LERP!
|
||||||
|
|
||||||
// adjust the mask when features will be added or removed
|
// adjust the mask when features will be added or removed
|
||||||
@@ -40,6 +41,7 @@ GNU General Public License for more details.
|
|||||||
| ENGINE_IMPROVED_LINETRACE \
|
| ENGINE_IMPROVED_LINETRACE \
|
||||||
| ENGINE_COMPUTE_STUDIO_LERP \
|
| ENGINE_COMPUTE_STUDIO_LERP \
|
||||||
| ENGINE_LINEAR_GAMMA_SPACE \
|
| ENGINE_LINEAR_GAMMA_SPACE \
|
||||||
|
| ENGINE_ALLOW_MIRRORS \
|
||||||
| ENGINE_STEP_POSHISTORY_LERP )
|
| ENGINE_STEP_POSHISTORY_LERP )
|
||||||
|
|
||||||
#endif//FEATURES_H
|
#endif//FEATURES_H
|
||||||
|
|||||||
@@ -2026,6 +2026,14 @@ static qboolean Mod_LooksLikeWaterTexture( const char *name )
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static qboolean Mod_LooksLikeReflectiveTexture( const char *name )
|
||||||
|
{
|
||||||
|
if( !Q_strcmp( name, "reflect1" ) || !Q_strncmp( name, "!reflect", 8 ))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
|
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
|
||||||
{
|
{
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
@@ -2480,6 +2488,13 @@ static void Mod_LoadSurfaces( model_t *mod, dbspmodel_t *bmod )
|
|||||||
if( !Q_strncmp( tex->name, "{scroll", 7 ))
|
if( !Q_strncmp( tex->name, "{scroll", 7 ))
|
||||||
SetBits( out->flags, SURF_CONVEYOR|SURF_TRANSPARENT );
|
SetBits( out->flags, SURF_CONVEYOR|SURF_TRANSPARENT );
|
||||||
|
|
||||||
|
// some mods don't work with mirrors or make random surfaces reflective
|
||||||
|
if( FBitSet( host.features, ENGINE_ALLOW_MIRRORS ) && Mod_LooksLikeReflectiveTexture( tex->name ))
|
||||||
|
{
|
||||||
|
SetBits( world.flags, FWORLD_HAS_MIRRORS );
|
||||||
|
SetBits( out->flags, SURF_REFLECT );
|
||||||
|
}
|
||||||
|
|
||||||
if( tex->name[0] == '{' )
|
if( tex->name[0] == '{' )
|
||||||
SetBits( out->flags, SURF_TRANSPARENT );
|
SetBits( out->flags, SURF_TRANSPARENT );
|
||||||
|
|
||||||
@@ -2697,6 +2712,9 @@ static void Mod_LoadLeafs( model_t *mod, dbspmodel_t *bmod )
|
|||||||
{
|
{
|
||||||
// mark underwater surfaces
|
// mark underwater surfaces
|
||||||
SetBits( out->firstmarksurface[j]->flags, SURF_UNDERWATER );
|
SetBits( out->firstmarksurface[j]->flags, SURF_UNDERWATER );
|
||||||
|
|
||||||
|
// underwater surfaces can't have reflection (performance)
|
||||||
|
ClearBits( out->firstmarksurface[j]->flags, SURF_REFLECT );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ GNU General Public License for more details.
|
|||||||
#define FWORLD_CUSTOM_SKYBOX BIT( 1 )
|
#define FWORLD_CUSTOM_SKYBOX BIT( 1 )
|
||||||
#define FWORLD_WATERALPHA BIT( 2 )
|
#define FWORLD_WATERALPHA BIT( 2 )
|
||||||
#define FWORLD_HAS_DELUXEMAP BIT( 3 )
|
#define FWORLD_HAS_DELUXEMAP BIT( 3 )
|
||||||
|
#define FWORLD_HAS_MIRRORS BIT( 4 )
|
||||||
|
|
||||||
// special rendermode for screenfade modulate
|
// special rendermode for screenfade modulate
|
||||||
// (probably will be expanded at some point)
|
// (probably will be expanded at some point)
|
||||||
|
|||||||
@@ -1045,7 +1045,9 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
|
|||||||
// make cvars consistant
|
// make cvars consistant
|
||||||
if( coop.value ) Cvar_SetValue( "deathmatch", 0 );
|
if( coop.value ) Cvar_SetValue( "deathmatch", 0 );
|
||||||
current_skill = Q_rint( skill.value );
|
current_skill = Q_rint( skill.value );
|
||||||
|
#if 0 // a1ba: don't limit the skill, it's limited in game rules anyway
|
||||||
current_skill = bound( 0, current_skill, 3 );
|
current_skill = bound( 0, current_skill, 3 );
|
||||||
|
#endif
|
||||||
Cvar_SetValue( "skill", (float)current_skill );
|
Cvar_SetValue( "skill", (float)current_skill );
|
||||||
|
|
||||||
// enforce hpk_maxsize
|
// enforce hpk_maxsize
|
||||||
|
|||||||
@@ -802,7 +802,7 @@ static trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apu
|
|||||||
|
|
||||||
if( ent->v.movetype == MOVETYPE_FLYMISSILE )
|
if( ent->v.movetype == MOVETYPE_FLYMISSILE )
|
||||||
type = MOVE_MISSILE;
|
type = MOVE_MISSILE;
|
||||||
else if( ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT )
|
else if( ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_GIB )
|
||||||
type = MOVE_NOMONSTERS; // only clip against bmodels
|
type = MOVE_NOMONSTERS; // only clip against bmodels
|
||||||
else type = MOVE_NORMAL;
|
else type = MOVE_NORMAL;
|
||||||
|
|
||||||
@@ -878,7 +878,7 @@ static qboolean SV_CanBlock( edict_t *ent )
|
|||||||
if( ent->v.mins[0] == ent->v.maxs[0] )
|
if( ent->v.mins[0] == ent->v.maxs[0] )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_TRIGGER )
|
if( ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_GIB )
|
||||||
{
|
{
|
||||||
// clear bounds for deadbody
|
// clear bounds for deadbody
|
||||||
ent->v.mins[0] = ent->v.mins[1] = 0;
|
ent->v.mins[0] = ent->v.mins[1] = 0;
|
||||||
|
|||||||
@@ -1069,7 +1069,7 @@ static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( touch == clip->passedict || touch->v.solid == SOLID_NOT )
|
if( touch == clip->passedict || touch->v.solid == SOLID_NOT || touch->v.solid == SOLID_GIB )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( touch->v.solid == SOLID_TRIGGER )
|
if( touch->v.solid == SOLID_TRIGGER )
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ void GL_BackendEndFrame( void )
|
|||||||
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i tempents\n%3i viewbeams\n%3i particles",
|
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i tempents\n%3i viewbeams\n%3i particles",
|
||||||
r_stats.c_active_tents_count, r_stats.c_view_beams_count, r_stats.c_particle_count );
|
r_stats.c_active_tents_count, r_stats.c_view_beams_count, r_stats.c_particle_count );
|
||||||
break;
|
break;
|
||||||
|
case 6:
|
||||||
|
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i mirrors\n", r_stats.c_mirror_passes );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset( &r_stats, 0, sizeof( r_stats ));
|
memset( &r_stats, 0, sizeof( r_stats ));
|
||||||
|
|||||||
@@ -119,6 +119,10 @@ qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly )
|
|||||||
vec3_t mins, maxs;
|
vec3_t mins, maxs;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
// support for custom mirror management
|
||||||
|
if( RI.currentbeam && R_CullEntityInMirror( RI.currentbeam ))
|
||||||
|
return true;
|
||||||
|
|
||||||
for( i = 0; i < 3; i++ )
|
for( i = 0; i < 3; i++ )
|
||||||
{
|
{
|
||||||
if( start[i] < end[i] )
|
if( start[i] < end[i] )
|
||||||
|
|||||||
@@ -35,6 +35,31 @@ qboolean R_CullBox( const vec3_t mins, const vec3_t maxs )
|
|||||||
return GL_FrustumCullBox( &RI.frustum, mins, maxs, 0 );
|
return GL_FrustumCullBox( &RI.frustum, mins, maxs, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
R_CullEntityInMirror
|
||||||
|
|
||||||
|
decide whether entity should be reflected in mirror
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
qboolean R_CullEntityInMirror( cl_entity_t *e )
|
||||||
|
{
|
||||||
|
if( FBitSet( RI.params, RP_MIRRORVIEW ))
|
||||||
|
{
|
||||||
|
// cull this entity out of mirrors but not normal views
|
||||||
|
if( FBitSet( e->curstate.effects, EF_NOREFLECT ))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// cull this entity out of normal views but not mirrors
|
||||||
|
if( FBitSet( e->curstate.effects, EF_REFLECTONLY ))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
R_CullModel
|
R_CullModel
|
||||||
@@ -53,6 +78,9 @@ int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax )
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( R_CullEntityInMirror( e ))
|
||||||
|
return 1;
|
||||||
|
|
||||||
if( R_CullBox( absmin, absmax ))
|
if( R_CullBox( absmin, absmax ))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -98,7 +126,7 @@ int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags )
|
|||||||
}
|
}
|
||||||
else dist = PlaneDiff( tr.modelorg, surf->plane );
|
else dist = PlaneDiff( tr.modelorg, surf->plane );
|
||||||
|
|
||||||
if( glState.faceCull == GL_FRONT )
|
if( glState.faceCull == GL_FRONT || FBitSet( RI.params, RP_MIRRORVIEW ))
|
||||||
{
|
{
|
||||||
if( FBitSet( surf->flags, SURF_PLANEBACK ))
|
if( FBitSet( surf->flags, SURF_PLANEBACK ))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ extern poolhandle_t r_temppool;
|
|||||||
#define SUBDIVIDE_SIZE 64
|
#define SUBDIVIDE_SIZE 64
|
||||||
#define MAX_DECAL_SURFS 4096
|
#define MAX_DECAL_SURFS 4096
|
||||||
#define MAX_DRAW_STACK 2 // normal view and menu view
|
#define MAX_DRAW_STACK 2 // normal view and menu view
|
||||||
|
#define MAX_MIRRORS 32 // per frame
|
||||||
|
#define MAX_MIRROR_ENTITIES MAX_VISIBLE_PACKET
|
||||||
|
|
||||||
#define SHADEDOT_QUANT 16 // precalculated dot products for quantized angles
|
#define SHADEDOT_QUANT 16 // precalculated dot products for quantized angles
|
||||||
#define SHADE_LAMBERT 1.4953241
|
#define SHADE_LAMBERT 1.4953241
|
||||||
@@ -84,8 +86,9 @@ extern poolhandle_t r_temppool;
|
|||||||
#define RP_ENVVIEW BIT( 0 ) // used for cubemapshot
|
#define RP_ENVVIEW BIT( 0 ) // used for cubemapshot
|
||||||
#define RP_OLDVIEWLEAF BIT( 1 )
|
#define RP_OLDVIEWLEAF BIT( 1 )
|
||||||
#define RP_CLIPPLANE BIT( 2 )
|
#define RP_CLIPPLANE BIT( 2 )
|
||||||
|
#define RP_MIRRORVIEW BIT( 3 ) // lock pvs at vieworg
|
||||||
|
|
||||||
#define RP_NONVIEWERREF (RP_ENVVIEW)
|
#define RP_NONVIEWERREF (RP_ENVVIEW|RP_MIRRORVIEW)
|
||||||
#define R_ModelOpaque( rm ) ( rm == kRenderNormal )
|
#define R_ModelOpaque( rm ) ( rm == kRenderNormal )
|
||||||
#define R_StaticEntity( ent ) ( VectorIsNull( ent->origin ) && VectorIsNull( ent->angles ))
|
#define R_StaticEntity( ent ) ( VectorIsNull( ent->origin ) && VectorIsNull( ent->angles ))
|
||||||
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( gp_cl->playernum + 1 ) && e->player )
|
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( gp_cl->playernum + 1 ) && e->player )
|
||||||
@@ -136,6 +139,13 @@ typedef struct gltexture_s
|
|||||||
struct gltexture_s *nextHash;
|
struct gltexture_s *nextHash;
|
||||||
} gl_texture_t;
|
} gl_texture_t;
|
||||||
|
|
||||||
|
// mirror entity
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
cl_entity_t *ent;
|
||||||
|
mextrasurf_t *chain;
|
||||||
|
} gl_entity_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int params; // rendering parameters
|
int params; // rendering parameters
|
||||||
@@ -200,9 +210,11 @@ typedef struct
|
|||||||
cl_entity_t *solid_entities[MAX_VISIBLE_PACKET]; // opaque moving or alpha brushes
|
cl_entity_t *solid_entities[MAX_VISIBLE_PACKET]; // opaque moving or alpha brushes
|
||||||
cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes
|
cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes
|
||||||
cl_entity_t *beam_entities[MAX_VISIBLE_PACKET];
|
cl_entity_t *beam_entities[MAX_VISIBLE_PACKET];
|
||||||
|
gl_entity_t mirror_entities[MAX_MIRROR_ENTITIES]; // an entities that has mirror
|
||||||
uint num_solid_entities;
|
uint num_solid_entities;
|
||||||
uint num_trans_entities;
|
uint num_trans_entities;
|
||||||
uint num_beam_entities;
|
uint num_beam_entities;
|
||||||
|
uint num_mirror_entities;
|
||||||
} draw_list_t;
|
} draw_list_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -218,6 +230,8 @@ typedef struct
|
|||||||
int dlightTexture; // custom dlight texture
|
int dlightTexture; // custom dlight texture
|
||||||
int skyboxTextures[SKYBOX_MAX_SIDES]; // skybox sides
|
int skyboxTextures[SKYBOX_MAX_SIDES]; // skybox sides
|
||||||
int cinTexture; // cinematic texture
|
int cinTexture; // cinematic texture
|
||||||
|
int mirrorTextures[MAX_MIRRORS];
|
||||||
|
int num_mirrors_used;
|
||||||
|
|
||||||
int skytexturenum; // this not a gl_texturenum!
|
int skytexturenum; // this not a gl_texturenum!
|
||||||
int skyboxbasenum; // start with 5800
|
int skyboxbasenum; // start with 5800
|
||||||
@@ -280,6 +294,8 @@ typedef struct
|
|||||||
uint c_client_ents; // entities that moved to client
|
uint c_client_ents; // entities that moved to client
|
||||||
double t_world_node;
|
double t_world_node;
|
||||||
double t_world_draw;
|
double t_world_draw;
|
||||||
|
|
||||||
|
uint c_mirror_passes;
|
||||||
} ref_speeds_t;
|
} ref_speeds_t;
|
||||||
|
|
||||||
extern ref_speeds_t r_stats;
|
extern ref_speeds_t r_stats;
|
||||||
@@ -324,6 +340,7 @@ qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly );
|
|||||||
//
|
//
|
||||||
int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax );
|
int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax );
|
||||||
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs );
|
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs );
|
||||||
|
qboolean R_CullEntityInMirror( cl_entity_t *e );
|
||||||
int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags );
|
int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags );
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -496,7 +513,7 @@ void EmitWaterPolys( msurface_t *warp, qboolean reverse );
|
|||||||
void R_InitRipples( void );
|
void R_InitRipples( void );
|
||||||
void R_ResetRipples( void );
|
void R_ResetRipples( void );
|
||||||
void R_AnimateRipples( void );
|
void R_AnimateRipples( void );
|
||||||
void R_UploadRipples( texture_t *image );
|
void R_UploadRipples( texture_t *image, qboolean is_mirror );
|
||||||
|
|
||||||
//
|
//
|
||||||
// gl_vgui.c
|
// gl_vgui.c
|
||||||
@@ -515,7 +532,13 @@ void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr );
|
|||||||
void VGUI_GetTextureSizes( int *width, int *height );
|
void VGUI_GetTextureSizes( int *width, int *height );
|
||||||
int VGUI_GenerateTexture( void );
|
int VGUI_GenerateTexture( void );
|
||||||
|
|
||||||
//#include "vid_common.h"
|
//
|
||||||
|
// gl_mirror.c
|
||||||
|
//
|
||||||
|
void R_BeginDrawMirror( msurface_t *fa );
|
||||||
|
void R_EndDrawMirror( void );
|
||||||
|
void R_DrawMirrors( void );
|
||||||
|
void R_FindMirrors( void );
|
||||||
|
|
||||||
//
|
//
|
||||||
// renderer exports
|
// renderer exports
|
||||||
@@ -541,7 +564,6 @@ void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, c
|
|||||||
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum );
|
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum );
|
||||||
qboolean R_SpeedsMessage( char *out, size_t size );
|
qboolean R_SpeedsMessage( char *out, size_t size );
|
||||||
void R_SetupSky( const char *skyboxname );
|
void R_SetupSky( const char *skyboxname );
|
||||||
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs );
|
|
||||||
int R_WorldToScreen( const vec3_t point, vec3_t screen );
|
int R_WorldToScreen( const vec3_t point, vec3_t screen );
|
||||||
void R_ScreenToWorld( const vec3_t screen, vec3_t point );
|
void R_ScreenToWorld( const vec3_t screen, vec3_t point );
|
||||||
qboolean R_AddEntity( struct cl_entity_s *pRefEntity, int entityType );
|
qboolean R_AddEntity( struct cl_entity_s *pRefEntity, int entityType );
|
||||||
@@ -767,6 +789,7 @@ extern convar_t gl_test; // cvar to testify new effects
|
|||||||
extern convar_t gl_msaa;
|
extern convar_t gl_msaa;
|
||||||
extern convar_t gl_stencilbits;
|
extern convar_t gl_stencilbits;
|
||||||
extern convar_t gl_overbright;
|
extern convar_t gl_overbright;
|
||||||
|
extern convar_t gl_allow_mirrors;
|
||||||
|
|
||||||
extern convar_t r_lighting_extended;
|
extern convar_t r_lighting_extended;
|
||||||
extern convar_t r_lighting_ambient;
|
extern convar_t r_lighting_ambient;
|
||||||
@@ -786,6 +809,9 @@ extern convar_t r_studio_drawelements;
|
|||||||
extern convar_t r_ripple;
|
extern convar_t r_ripple;
|
||||||
extern convar_t r_ripple_updatetime;
|
extern convar_t r_ripple_updatetime;
|
||||||
extern convar_t r_ripple_spawntime;
|
extern convar_t r_ripple_spawntime;
|
||||||
|
extern convar_t r_water_warp;
|
||||||
|
extern convar_t r_water_warp_x;
|
||||||
|
extern convar_t r_water_warp_y;
|
||||||
|
|
||||||
//
|
//
|
||||||
// engine shared convars
|
// engine shared convars
|
||||||
|
|||||||
615
ref/gl/gl_mirror.c
Normal file
615
ref/gl/gl_mirror.c
Normal file
@@ -0,0 +1,615 @@
|
|||||||
|
/*
|
||||||
|
gl_mirror.c - draw reflected surfaces
|
||||||
|
Copyright (C) 2010 Uncle Mike
|
||||||
|
|
||||||
|
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 3 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gl_local.h"
|
||||||
|
#include "mod_local.h"
|
||||||
|
#include "xash3d_mathlib.h"
|
||||||
|
|
||||||
|
static void GL_LoadTexMatrix( const matrix4x4 m )
|
||||||
|
{
|
||||||
|
pglMatrixMode( GL_TEXTURE );
|
||||||
|
GL_LoadMatrix( m );
|
||||||
|
glState.texIdentityMatrix[glState.activeTMU] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Matrix4x4_CreateScale( matrix4x4 out, float x )
|
||||||
|
{
|
||||||
|
out[0][0] = x;
|
||||||
|
out[0][1] = out[0][2] = out[0][3] = 0.0f;
|
||||||
|
out[1][0] = out[1][2] = out[1][3] = 0.0f;
|
||||||
|
out[1][1] = x;
|
||||||
|
out[2][0] = out[2][1] = out[2][3] = 0.0f;
|
||||||
|
out[2][2] = x;
|
||||||
|
out[3][0] = out[3][1] = out[3][2] = 0.0f;
|
||||||
|
out[3][3] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Matrix4x4_ConcatScale( matrix4x4 out, float x )
|
||||||
|
{
|
||||||
|
matrix4x4 base, temp;
|
||||||
|
|
||||||
|
Matrix4x4_Copy( base, out );
|
||||||
|
Matrix4x4_CreateScale( temp, x );
|
||||||
|
Matrix4x4_Concat( out, base, temp );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_BeginDrawMirror
|
||||||
|
|
||||||
|
Setup texture matrix for mirror texture
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_BeginDrawMirror( msurface_t *fa )
|
||||||
|
{
|
||||||
|
matrix4x4 m1, m2, matrix;
|
||||||
|
GLfloat genVector[4][4];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
Matrix4x4_Copy( matrix, fa->info->mirrormatrix );
|
||||||
|
|
||||||
|
Matrix4x4_LoadIdentity( m1 );
|
||||||
|
Matrix4x4_ConcatScale( m1, 0.5f );
|
||||||
|
Matrix4x4_Concat( m2, m1, matrix );
|
||||||
|
|
||||||
|
Matrix4x4_LoadIdentity( m1 );
|
||||||
|
Matrix4x4_ConcatTranslate( m1, 0.5f, 0.5f, 0.5f );
|
||||||
|
Matrix4x4_Concat( matrix, m1, m2 );
|
||||||
|
|
||||||
|
for( i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
|
genVector[0][i] = i == 0 ? 1 : 0;
|
||||||
|
genVector[1][i] = i == 1 ? 1 : 0;
|
||||||
|
genVector[2][i] = i == 2 ? 1 : 0;
|
||||||
|
genVector[3][i] = i == 3 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL_TexGen( GL_S, GL_OBJECT_LINEAR );
|
||||||
|
GL_TexGen( GL_T, GL_OBJECT_LINEAR );
|
||||||
|
GL_TexGen( GL_R, GL_OBJECT_LINEAR );
|
||||||
|
GL_TexGen( GL_Q, GL_OBJECT_LINEAR );
|
||||||
|
|
||||||
|
pglTexGenfv( GL_S, GL_OBJECT_PLANE, genVector[0] );
|
||||||
|
pglTexGenfv( GL_T, GL_OBJECT_PLANE, genVector[1] );
|
||||||
|
pglTexGenfv( GL_R, GL_OBJECT_PLANE, genVector[2] );
|
||||||
|
pglTexGenfv( GL_Q, GL_OBJECT_PLANE, genVector[3] );
|
||||||
|
|
||||||
|
GL_LoadTexMatrix( matrix );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_EndDrawMirror
|
||||||
|
|
||||||
|
Restore identity texmatrix
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_EndDrawMirror( void )
|
||||||
|
{
|
||||||
|
GL_CleanUpTextureUnits( 0 );
|
||||||
|
pglMatrixMode( GL_MODELVIEW );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============================================================
|
||||||
|
|
||||||
|
MIRROR RENDERING
|
||||||
|
|
||||||
|
=============================================================
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_PlaneForMirror
|
||||||
|
|
||||||
|
Get transformed mirrorplane and entity matrix
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
static void R_PlaneForMirror( msurface_t *surf, mplane_t *out, matrix4x4 m )
|
||||||
|
{
|
||||||
|
cl_entity_t *ent;
|
||||||
|
|
||||||
|
ent = RI.currententity;
|
||||||
|
|
||||||
|
// setup mirror plane
|
||||||
|
*out = *surf->plane;
|
||||||
|
|
||||||
|
if( surf->flags & SURF_PLANEBACK )
|
||||||
|
{
|
||||||
|
VectorNegate( out->normal, out->normal );
|
||||||
|
out->dist = -out->dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !VectorIsNull( ent->origin ) || !VectorIsNull( ent->angles ))
|
||||||
|
{
|
||||||
|
mplane_t tmp;
|
||||||
|
|
||||||
|
if( !VectorIsNull( ent->angles )) Matrix4x4_CreateFromEntity( m, ent->angles, ent->origin, 1.0f );
|
||||||
|
else Matrix4x4_CreateFromEntity( m, vec3_origin, ent->origin, 1.0f );
|
||||||
|
|
||||||
|
tmp = *out;
|
||||||
|
|
||||||
|
// transform mirror plane by entity matrix
|
||||||
|
Matrix4x4_TransformPositivePlane( m, tmp.normal, tmp.dist, out->normal, &out->dist );
|
||||||
|
}
|
||||||
|
else Matrix4x4_LoadIdentity( m );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_AllocateMirrorTexture
|
||||||
|
|
||||||
|
Allocate the screen texture and make copy
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
static int R_AllocateMirrorTexture( void )
|
||||||
|
{
|
||||||
|
rgbdata_t r_screen;
|
||||||
|
int i, texture;
|
||||||
|
char txName[16];
|
||||||
|
|
||||||
|
i = tr.num_mirrors_used;
|
||||||
|
if( i >= MAX_MIRRORS )
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Printf( S_ERROR "%s: mirror textures limit exceeded!\n", __func__ );
|
||||||
|
return 0; // disable
|
||||||
|
}
|
||||||
|
|
||||||
|
texture = tr.mirrorTextures[i];
|
||||||
|
tr.num_mirrors_used++;
|
||||||
|
|
||||||
|
if( !texture )
|
||||||
|
{
|
||||||
|
// not initialized ?
|
||||||
|
memset( &r_screen, 0, sizeof( r_screen ));
|
||||||
|
Q_snprintf( txName, sizeof( txName ), "*screen%i", i );
|
||||||
|
|
||||||
|
r_screen.width = RI.viewport[2];
|
||||||
|
r_screen.height = RI.viewport[3];
|
||||||
|
r_screen.type = PF_RGBA_32;
|
||||||
|
r_screen.size = r_screen.width * r_screen.height * 4;
|
||||||
|
r_screen.flags = IMAGE_HAS_COLOR;
|
||||||
|
r_screen.buffer = NULL; // create empty texture for now
|
||||||
|
tr.mirrorTextures[i] = GL_LoadTextureInternal( txName, &r_screen, TF_IMAGE );
|
||||||
|
texture = tr.mirrorTextures[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
GL_Bind( XASH_TEXTURE0, texture );
|
||||||
|
pglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, RI.viewport[0], RI.viewport[1], RI.viewport[2], RI.viewport[3], 0 );
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_DrawMirrors
|
||||||
|
|
||||||
|
Draw all viewpasess from mirror position
|
||||||
|
Mirror textures will be drawn in normal pass
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_DrawMirrors( void )
|
||||||
|
{
|
||||||
|
ref_instance_t oldRI;
|
||||||
|
mplane_t plane;
|
||||||
|
msurface_t *surf, *surf2;
|
||||||
|
int i, oldframecount;
|
||||||
|
mextrasurf_t *es, *tmp, *mirrorchain;
|
||||||
|
vec3_t forward, right, up;
|
||||||
|
vec3_t origin, angles;
|
||||||
|
matrix4x4 mirrormatrix;
|
||||||
|
cl_entity_t *e;
|
||||||
|
model_t *m;
|
||||||
|
float d;
|
||||||
|
|
||||||
|
if( !tr.draw_list->num_mirror_entities ) return; // mo mirrors for this frame
|
||||||
|
|
||||||
|
oldRI = RI; // make refinst backup
|
||||||
|
oldframecount = tr.framecount;
|
||||||
|
|
||||||
|
for( i = 0; i < tr.draw_list->num_mirror_entities; i++ )
|
||||||
|
{
|
||||||
|
mirrorchain = tr.draw_list->mirror_entities[i].chain;
|
||||||
|
|
||||||
|
for( es = mirrorchain; es != NULL; es = es->mirrorchain )
|
||||||
|
{
|
||||||
|
RI.currententity = e = tr.draw_list->mirror_entities[i].ent;
|
||||||
|
RI.currentmodel = m = RI.currententity->model;
|
||||||
|
|
||||||
|
surf = es->surf;
|
||||||
|
|
||||||
|
ASSERT( RI.currententity != NULL );
|
||||||
|
ASSERT( RI.currentmodel != NULL );
|
||||||
|
|
||||||
|
// NOTE: copy mirrortexture and mirrormatrix from another surfaces
|
||||||
|
// from this entity\world that has same planes and reduce number of viewpasses
|
||||||
|
|
||||||
|
// make sure what we have one pass at least
|
||||||
|
if( es != mirrorchain )
|
||||||
|
{
|
||||||
|
for( tmp = mirrorchain; tmp != es; tmp = tmp->mirrorchain )
|
||||||
|
{
|
||||||
|
surf2 = tmp->surf;
|
||||||
|
|
||||||
|
if( !tmp->mirrortexturenum )
|
||||||
|
continue; // not filled?
|
||||||
|
|
||||||
|
if( surf->plane->dist != surf2->plane->dist )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( !VectorCompare( surf->plane->normal, surf2->plane->normal ))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// found surface with same plane!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( tmp != es && tmp && tmp->mirrortexturenum )
|
||||||
|
{
|
||||||
|
// just copy reflection texture from surface with same plane
|
||||||
|
Matrix4x4_Copy( es->mirrormatrix, tmp->mirrormatrix );
|
||||||
|
es->mirrortexturenum = tmp->mirrortexturenum;
|
||||||
|
continue; // pass skiped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R_PlaneForMirror( surf, &plane, mirrormatrix );
|
||||||
|
|
||||||
|
d = -2.0f * ( DotProduct( RI.vieworg, plane.normal ) - plane.dist );
|
||||||
|
VectorMA( RI.vieworg, d, plane.normal, origin );
|
||||||
|
|
||||||
|
d = -2.0f * DotProduct( RI.vforward, plane.normal );
|
||||||
|
VectorMA( RI.vforward, d, plane.normal, forward );
|
||||||
|
VectorNormalize( forward );
|
||||||
|
|
||||||
|
d = -2.0f * DotProduct( RI.vright, plane.normal );
|
||||||
|
VectorMA( RI.vright, d, plane.normal, right );
|
||||||
|
VectorNormalize( right );
|
||||||
|
|
||||||
|
d = -2.0f * DotProduct( RI.vup, plane.normal );
|
||||||
|
VectorMA( RI.vup, d, plane.normal, up );
|
||||||
|
VectorNormalize( up );
|
||||||
|
|
||||||
|
VectorsAngles( forward, right, up, angles );
|
||||||
|
angles[ROLL] = -angles[ROLL];
|
||||||
|
|
||||||
|
RI.params = RP_MIRRORVIEW|RP_CLIPPLANE|RP_OLDVIEWLEAF;
|
||||||
|
RI.clipPlane = plane;
|
||||||
|
|
||||||
|
GL_FrustumSetPlane( &RI.frustum, FRUSTUM_NEAR, plane.normal, plane.dist );
|
||||||
|
|
||||||
|
RI.viewangles[0] = anglemod( angles[0] );
|
||||||
|
RI.viewangles[1] = anglemod( angles[1] );
|
||||||
|
RI.viewangles[2] = anglemod( angles[2] );
|
||||||
|
VectorCopy( origin, RI.vieworg );
|
||||||
|
VectorCopy( origin, RI.cullorigin );
|
||||||
|
|
||||||
|
// put pvsorigin before the mirror plane to avoid get full visibility on world mirrors
|
||||||
|
if( RI.currententity == tr.entities )
|
||||||
|
{
|
||||||
|
VectorMA( es->origin, 1.0f, plane.normal, origin );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Matrix4x4_VectorTransform( mirrormatrix, es->origin, origin );
|
||||||
|
VectorMA( origin, 1.0f, plane.normal, origin );
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorCopy( origin, RI.pvsorigin );
|
||||||
|
|
||||||
|
if( GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
|
||||||
|
{
|
||||||
|
// allow screen size
|
||||||
|
RI.viewport[2] = bound( 96, RI.viewport[2], 1024 );
|
||||||
|
RI.viewport[3] = bound( 72, RI.viewport[3], 768 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RI.viewport[2] = NearestPOW( RI.viewport[2], true );
|
||||||
|
RI.viewport[3] = NearestPOW( RI.viewport[3], true );
|
||||||
|
RI.viewport[2] = bound( 128, RI.viewport[2], 1024 );
|
||||||
|
RI.viewport[3] = bound( 64, RI.viewport[3], 512 );
|
||||||
|
}
|
||||||
|
|
||||||
|
R_RenderScene();
|
||||||
|
r_stats.c_mirror_passes++;
|
||||||
|
|
||||||
|
es->mirrortexturenum = R_AllocateMirrorTexture();
|
||||||
|
|
||||||
|
// create personal projection matrix for mirror
|
||||||
|
if( VectorIsNull( e->origin ) && VectorIsNull( e->angles ))
|
||||||
|
{
|
||||||
|
Matrix4x4_Copy( es->mirrormatrix, RI.worldviewProjectionMatrix );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, mirrormatrix );
|
||||||
|
Matrix4x4_Concat( es->mirrormatrix, RI.projectionMatrix, RI.modelviewMatrix );
|
||||||
|
}
|
||||||
|
|
||||||
|
RI = oldRI; // restore ref instance
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear chain for this entity
|
||||||
|
for( es = mirrorchain; es != NULL; )
|
||||||
|
{
|
||||||
|
tmp = es->mirrorchain;
|
||||||
|
es->mirrorchain = NULL;
|
||||||
|
es = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.draw_list->mirror_entities[i].chain = NULL; // done
|
||||||
|
tr.draw_list->mirror_entities[i].ent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RI.viewleaf = NULL; // force markleafs next frame
|
||||||
|
tr.draw_list->num_mirror_entities = 0;
|
||||||
|
tr.num_mirrors_used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_RecursiveMirrorNode
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
static void R_RecursiveMirrorNode( mnode_t *node, uint clipflags )
|
||||||
|
{
|
||||||
|
int i, clipped;
|
||||||
|
msurface_t *surf, **mark;
|
||||||
|
mleaf_t *pleaf;
|
||||||
|
int c, side;
|
||||||
|
float dot;
|
||||||
|
|
||||||
|
if( node->contents == CONTENTS_SOLID )
|
||||||
|
return; // hit a solid leaf
|
||||||
|
|
||||||
|
if( node->visframe != tr.visframecount )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( clipflags )
|
||||||
|
{
|
||||||
|
for( i = 0; i < 6; i++ )
|
||||||
|
{
|
||||||
|
const mplane_t *p = &RI.frustum.planes[i];
|
||||||
|
|
||||||
|
if( !FBitSet( clipflags, BIT( i )))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, p );
|
||||||
|
if( clipped == 2 ) return;
|
||||||
|
if( clipped == 1 ) ClearBits( clipflags, BIT( i ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if a leaf node, draw stuff
|
||||||
|
if( node->contents < 0 )
|
||||||
|
{
|
||||||
|
pleaf = (mleaf_t *)node;
|
||||||
|
|
||||||
|
mark = pleaf->firstmarksurface;
|
||||||
|
c = pleaf->nummarksurfaces;
|
||||||
|
|
||||||
|
if( c )
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
(*mark)->visframe = tr.framecount;
|
||||||
|
mark++;
|
||||||
|
} while( --c );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// node is just a decision point, so go down the apropriate sides
|
||||||
|
|
||||||
|
// find which side of the node we are on
|
||||||
|
dot = PlaneDiff( tr.modelorg, node->plane );
|
||||||
|
side = (dot >= 0) ? 0 : 1;
|
||||||
|
|
||||||
|
// recurse down the children, front side first
|
||||||
|
R_RecursiveMirrorNode( node->children[side], clipflags );
|
||||||
|
|
||||||
|
// draw stuff
|
||||||
|
for( c = node->numsurfaces, surf = WORLDMODEL->surfaces + node->firstsurface; c; c--, surf++ )
|
||||||
|
{
|
||||||
|
if( !FBitSet( surf->flags, SURF_REFLECT ))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( R_CullSurface( surf, &RI.frustum, clipflags ))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
surf->info->mirrorchain = tr.draw_list->mirror_entities[0].chain;
|
||||||
|
tr.draw_list->mirror_entities[0].chain = surf->info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse down the back side
|
||||||
|
R_RecursiveMirrorNode( node->children[!side], clipflags );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
R_FindBmodelMirrors
|
||||||
|
|
||||||
|
Check all bmodel surfaces and make personal mirror chain
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
static void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity )
|
||||||
|
{
|
||||||
|
vec3_t mins, maxs;
|
||||||
|
msurface_t *psurf;
|
||||||
|
model_t *clmodel;
|
||||||
|
qboolean rotated;
|
||||||
|
gl_frustum_t *frustum = NULL;
|
||||||
|
int i;
|
||||||
|
draw_list_t *const draw_list = tr.draw_list;
|
||||||
|
|
||||||
|
if( draw_list->num_mirror_entities >= MAX_MIRROR_ENTITIES )
|
||||||
|
return;
|
||||||
|
|
||||||
|
clmodel = e->model;
|
||||||
|
|
||||||
|
// don't draw any water reflections if we underwater
|
||||||
|
if( ENGINE_GET_PARM( PARM_WATER_LEVEL ) >= 3 && FBitSet( clmodel->flags, MODEL_LIQUID ))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( static_entity )
|
||||||
|
{
|
||||||
|
Matrix4x4_LoadIdentity( RI.objectMatrix );
|
||||||
|
|
||||||
|
if( R_CullBox( clmodel->mins, clmodel->maxs ))
|
||||||
|
return;
|
||||||
|
|
||||||
|
VectorCopy( RI.cullorigin, tr.modelorg );
|
||||||
|
frustum = &RI.frustum;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !VectorIsNull( e->angles ))
|
||||||
|
{
|
||||||
|
for( i = 0; i < 3; i++ )
|
||||||
|
{
|
||||||
|
mins[i] = e->origin[i] - clmodel->radius;
|
||||||
|
maxs[i] = e->origin[i] + clmodel->radius;
|
||||||
|
}
|
||||||
|
rotated = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VectorAdd( e->origin, clmodel->mins, mins );
|
||||||
|
VectorAdd( e->origin, clmodel->maxs, maxs );
|
||||||
|
rotated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( R_CullBox( mins, maxs ))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( !VectorIsNull( e->origin ) || !VectorIsNull( e->angles ))
|
||||||
|
{
|
||||||
|
if( rotated ) Matrix4x4_CreateFromEntity( RI.objectMatrix, e->angles, e->origin, 1.0f );
|
||||||
|
else Matrix4x4_CreateFromEntity( RI.objectMatrix, vec3_origin, e->origin, 1.0f );
|
||||||
|
}
|
||||||
|
else Matrix4x4_LoadIdentity( RI.objectMatrix );
|
||||||
|
|
||||||
|
e->visframe = tr.framecount; // visible
|
||||||
|
|
||||||
|
if( rotated ) Matrix4x4_VectorITransform( RI.objectMatrix, RI.cullorigin, tr.modelorg );
|
||||||
|
else VectorSubtract( RI.cullorigin, e->origin, tr.modelorg );
|
||||||
|
}
|
||||||
|
|
||||||
|
psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
|
||||||
|
for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ )
|
||||||
|
{
|
||||||
|
if( !FBitSet( psurf->flags, SURF_REFLECT ))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( R_CullSurface( psurf, frustum, 0 ))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
psurf->info->mirrorchain = draw_list->mirror_entities[draw_list->num_mirror_entities].chain;
|
||||||
|
draw_list->mirror_entities[draw_list->num_mirror_entities].chain = psurf->info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store new mirror entity
|
||||||
|
if( !static_entity && draw_list->mirror_entities[draw_list->num_mirror_entities].chain != NULL )
|
||||||
|
{
|
||||||
|
draw_list->mirror_entities[draw_list->num_mirror_entities].ent = RI.currententity;
|
||||||
|
draw_list->num_mirror_entities++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
R_CheckEntitiesOnList
|
||||||
|
|
||||||
|
Check all bmodels for mirror surfaces
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
static void R_CheckEntitiesOnList( void )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// world has mirror surfaces
|
||||||
|
if( tr.draw_list->mirror_entities[0].chain != NULL )
|
||||||
|
{
|
||||||
|
tr.draw_list->mirror_entities[0].ent = tr.entities;
|
||||||
|
tr.draw_list->num_mirror_entities++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check solid entities
|
||||||
|
for( i = 0; i < tr.draw_list->num_solid_entities; i++ )
|
||||||
|
{
|
||||||
|
RI.currententity = tr.draw_list->solid_entities[i];
|
||||||
|
RI.currentmodel = RI.currententity->model;
|
||||||
|
|
||||||
|
ASSERT( RI.currententity != NULL );
|
||||||
|
ASSERT( RI.currententity->model != NULL );
|
||||||
|
|
||||||
|
switch( RI.currentmodel->type )
|
||||||
|
{
|
||||||
|
case mod_brush:
|
||||||
|
R_FindBmodelMirrors( RI.currententity, false );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check translucent entities
|
||||||
|
for( i = 0; i < tr.draw_list->num_trans_entities; i++ )
|
||||||
|
{
|
||||||
|
RI.currententity = tr.draw_list->trans_entities[i];
|
||||||
|
RI.currentmodel = RI.currententity->model;
|
||||||
|
|
||||||
|
ASSERT( RI.currententity != NULL );
|
||||||
|
ASSERT( RI.currententity->model != NULL );
|
||||||
|
|
||||||
|
switch( RI.currentmodel->type )
|
||||||
|
{
|
||||||
|
case mod_brush:
|
||||||
|
R_FindBmodelMirrors( RI.currententity, false );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_FindMirrors
|
||||||
|
|
||||||
|
Build mirror chains for this frame
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_FindMirrors( void )
|
||||||
|
{
|
||||||
|
if( !FBitSet( tr.world->flags, FWORLD_HAS_MIRRORS ) || RI.drawOrtho || !RI.drawWorld || RI.onlyClientDraw || !WORLDMODEL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// NOTE: we already has initial params at this point like vieworg, viewangles
|
||||||
|
// all other will be sets into R_SetupFrustum
|
||||||
|
R_FindViewLeaf ();
|
||||||
|
|
||||||
|
// player is outside world. Don't update mirrors for speedup reasons
|
||||||
|
if(( RI.viewleaf - WORLDMODEL->leafs - 1 ) == -1 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
R_SetupFrustum ();
|
||||||
|
R_MarkLeaves ();
|
||||||
|
|
||||||
|
VectorCopy( RI.cullorigin, tr.modelorg );
|
||||||
|
RI.currententity = tr.entities;
|
||||||
|
RI.currentmodel = RI.currententity->model;
|
||||||
|
|
||||||
|
R_RecursiveMirrorNode( WORLDMODEL->nodes, RI.frustum.clipFlags );
|
||||||
|
|
||||||
|
R_CheckEntitiesOnList();
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ CVAR_DEFINE_AUTO( gl_test, "0", 0, "engine developer cvar for quick testing new
|
|||||||
CVAR_DEFINE_AUTO( gl_msaa, "1", FCVAR_GLCONFIG, "enable or disable multisample anti-aliasing" );
|
CVAR_DEFINE_AUTO( gl_msaa, "1", FCVAR_GLCONFIG, "enable or disable multisample anti-aliasing" );
|
||||||
CVAR_DEFINE_AUTO( gl_stencilbits, "8", FCVAR_GLCONFIG|FCVAR_READ_ONLY, "pixelformat stencil bits (0 - auto)" );
|
CVAR_DEFINE_AUTO( gl_stencilbits, "8", FCVAR_GLCONFIG|FCVAR_READ_ONLY, "pixelformat stencil bits (0 - auto)" );
|
||||||
CVAR_DEFINE_AUTO( gl_overbright, "1", FCVAR_GLCONFIG, "overbrights" );
|
CVAR_DEFINE_AUTO( gl_overbright, "1", FCVAR_GLCONFIG, "overbrights" );
|
||||||
|
CVAR_DEFINE_AUTO( gl_allow_mirrors, "1", FCVAR_GLCONFIG, "allow to draw mirror surfaces" );
|
||||||
CVAR_DEFINE_AUTO( r_lighting_extended, "1", FCVAR_GLCONFIG, "allow to get lighting from world and bmodels" );
|
CVAR_DEFINE_AUTO( r_lighting_extended, "1", FCVAR_GLCONFIG, "allow to get lighting from world and bmodels" );
|
||||||
CVAR_DEFINE_AUTO( r_lighting_ambient, "0.3", FCVAR_GLCONFIG, "map ambient lighting scale" );
|
CVAR_DEFINE_AUTO( r_lighting_ambient, "0.3", FCVAR_GLCONFIG, "map ambient lighting scale" );
|
||||||
CVAR_DEFINE_AUTO( r_detailtextures, "1", FCVAR_ARCHIVE, "enable detail textures support" );
|
CVAR_DEFINE_AUTO( r_detailtextures, "1", FCVAR_ARCHIVE, "enable detail textures support" );
|
||||||
@@ -36,6 +37,9 @@ CVAR_DEFINE( r_vbo_overbrightmode, "gl_vbo_overbrightmode", "0", FCVAR_ARCHIVE,
|
|||||||
CVAR_DEFINE_AUTO( r_ripple, "0", FCVAR_GLCONFIG, "enable software-like water texture ripple simulation" );
|
CVAR_DEFINE_AUTO( r_ripple, "0", FCVAR_GLCONFIG, "enable software-like water texture ripple simulation" );
|
||||||
CVAR_DEFINE_AUTO( r_ripple_updatetime, "0.05", FCVAR_GLCONFIG, "how fast ripple simulation is" );
|
CVAR_DEFINE_AUTO( r_ripple_updatetime, "0.05", FCVAR_GLCONFIG, "how fast ripple simulation is" );
|
||||||
CVAR_DEFINE_AUTO( r_ripple_spawntime, "0.1", FCVAR_GLCONFIG, "how fast new ripples spawn" );
|
CVAR_DEFINE_AUTO( r_ripple_spawntime, "0.1", FCVAR_GLCONFIG, "how fast new ripples spawn" );
|
||||||
|
CVAR_DEFINE_AUTO( r_water_warp, "1", FCVAR_GLCONFIG, "set water warp style (0: disable, 1: sine waves, 2: constant scroll)" );
|
||||||
|
CVAR_DEFINE_AUTO( r_water_warp_x, "6", FCVAR_GLCONFIG, "water warp scroll x axis speed" );
|
||||||
|
CVAR_DEFINE_AUTO( r_water_warp_y, "6", FCVAR_GLCONFIG, "water warp scroll y axis speed" );
|
||||||
|
|
||||||
|
|
||||||
DEFINE_ENGINE_SHARED_CVAR_LIST()
|
DEFINE_ENGINE_SHARED_CVAR_LIST()
|
||||||
@@ -1191,6 +1195,9 @@ static void GL_InitCommands( void )
|
|||||||
gEngfuncs.Cvar_RegisterVariable( &r_ripple );
|
gEngfuncs.Cvar_RegisterVariable( &r_ripple );
|
||||||
gEngfuncs.Cvar_RegisterVariable( &r_ripple_updatetime );
|
gEngfuncs.Cvar_RegisterVariable( &r_ripple_updatetime );
|
||||||
gEngfuncs.Cvar_RegisterVariable( &r_ripple_spawntime );
|
gEngfuncs.Cvar_RegisterVariable( &r_ripple_spawntime );
|
||||||
|
gEngfuncs.Cvar_RegisterVariable( &r_water_warp );
|
||||||
|
gEngfuncs.Cvar_RegisterVariable( &r_water_warp_x );
|
||||||
|
gEngfuncs.Cvar_RegisterVariable( &r_water_warp_y );
|
||||||
|
|
||||||
gEngfuncs.Cvar_RegisterVariable( &gl_extensions );
|
gEngfuncs.Cvar_RegisterVariable( &gl_extensions );
|
||||||
gEngfuncs.Cvar_RegisterVariable( &gl_texture_nearest );
|
gEngfuncs.Cvar_RegisterVariable( &gl_texture_nearest );
|
||||||
@@ -1207,6 +1214,7 @@ static void GL_InitCommands( void )
|
|||||||
gEngfuncs.Cvar_RegisterVariable( &gl_stencilbits );
|
gEngfuncs.Cvar_RegisterVariable( &gl_stencilbits );
|
||||||
gEngfuncs.Cvar_RegisterVariable( &gl_round_down );
|
gEngfuncs.Cvar_RegisterVariable( &gl_round_down );
|
||||||
gEngfuncs.Cvar_RegisterVariable( &gl_overbright );
|
gEngfuncs.Cvar_RegisterVariable( &gl_overbright );
|
||||||
|
gEngfuncs.Cvar_RegisterVariable( &gl_allow_mirrors );
|
||||||
|
|
||||||
// these cvar not used by engine but some mods requires this
|
// these cvar not used by engine but some mods requires this
|
||||||
gEngfuncs.Cvar_RegisterVariable( &gl_polyoffset );
|
gEngfuncs.Cvar_RegisterVariable( &gl_polyoffset );
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ void R_ClearScene( void )
|
|||||||
tr.draw_list->num_solid_entities = 0;
|
tr.draw_list->num_solid_entities = 0;
|
||||||
tr.draw_list->num_trans_entities = 0;
|
tr.draw_list->num_trans_entities = 0;
|
||||||
tr.draw_list->num_beam_entities = 0;
|
tr.draw_list->num_beam_entities = 0;
|
||||||
|
tr.draw_list->num_mirror_entities = 0;
|
||||||
|
|
||||||
// clear the scene befor start new frame
|
// clear the scene befor start new frame
|
||||||
if( gEngfuncs.drawFuncs->R_ClearScene != NULL )
|
if( gEngfuncs.drawFuncs->R_ClearScene != NULL )
|
||||||
@@ -1127,6 +1128,14 @@ void R_RenderFrame( const ref_viewpass_t *rvp )
|
|||||||
R_RunViewmodelEvents();
|
R_RunViewmodelEvents();
|
||||||
|
|
||||||
tr.realframecount++; // right called after viewmodel events
|
tr.realframecount++; // right called after viewmodel events
|
||||||
|
|
||||||
|
if( gl_allow_mirrors.value )
|
||||||
|
{
|
||||||
|
// render mirrors
|
||||||
|
R_FindMirrors();
|
||||||
|
R_DrawMirrors();
|
||||||
|
}
|
||||||
|
|
||||||
R_RenderScene();
|
R_RenderScene();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1142,7 +1142,7 @@ R_RenderBrushPoly
|
|||||||
*/
|
*/
|
||||||
static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
|
static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
|
||||||
{
|
{
|
||||||
qboolean is_dynamic = false;
|
qboolean is_dynamic = false, is_mirror = false;
|
||||||
int maps;
|
int maps;
|
||||||
texture_t *t;
|
texture_t *t;
|
||||||
|
|
||||||
@@ -1153,15 +1153,46 @@ static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
|
|||||||
|
|
||||||
t = R_TextureAnimation( fa );
|
t = R_TextureAnimation( fa );
|
||||||
|
|
||||||
|
// set mirror texture
|
||||||
|
if( RP_NORMALPASS() && FBitSet( fa->flags, SURF_REFLECT ))
|
||||||
|
{
|
||||||
|
if( fa->info->mirrortexturenum )
|
||||||
|
{
|
||||||
|
GL_Bind( XASH_TEXTURE0, fa->info->mirrortexturenum );
|
||||||
|
is_mirror = true;
|
||||||
|
|
||||||
|
// reset just in case if mirror failed to render
|
||||||
|
fa->info->mirrortexturenum = 0;
|
||||||
|
|
||||||
|
// blend-in water
|
||||||
|
if( FBitSet( fa->flags, SURF_DRAWTURB ))
|
||||||
|
{
|
||||||
|
R_BeginDrawMirror( fa );
|
||||||
|
R_UploadRipples( t, true );
|
||||||
|
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||||
|
|
||||||
|
// warp texture, no lightmaps
|
||||||
|
EmitWaterPolys( fa, (cull_type == CULL_BACKSIDE));
|
||||||
|
|
||||||
|
R_EndDrawMirror();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( FBitSet( fa->flags, SURF_DRAWTURB ))
|
if( FBitSet( fa->flags, SURF_DRAWTURB ))
|
||||||
{
|
{
|
||||||
R_UploadRipples( t );
|
R_UploadRipples( t, false );
|
||||||
|
|
||||||
// warp texture, no lightmaps
|
// warp texture, no lightmaps
|
||||||
EmitWaterPolys( fa, (cull_type == CULL_BACKSIDE));
|
EmitWaterPolys( fa, (cull_type == CULL_BACKSIDE));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else GL_Bind( XASH_TEXTURE0, t->gl_texturenum );
|
else if( !is_mirror ) // already set up mirror texture
|
||||||
|
{
|
||||||
|
GL_Bind( XASH_TEXTURE0, t->gl_texturenum );
|
||||||
|
}
|
||||||
|
|
||||||
if( t->fb_texturenum )
|
if( t->fb_texturenum )
|
||||||
{
|
{
|
||||||
@@ -1199,7 +1230,9 @@ static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( is_mirror ) R_BeginDrawMirror( fa );
|
||||||
DrawGLPoly( fa->polys, 0.0f, 0.0f );
|
DrawGLPoly( fa->polys, 0.0f, 0.0f );
|
||||||
|
if( is_mirror ) R_EndDrawMirror();
|
||||||
|
|
||||||
if( RI.currententity->curstate.rendermode == kRenderNormal )
|
if( RI.currententity->curstate.rendermode == kRenderNormal )
|
||||||
{
|
{
|
||||||
@@ -1213,6 +1246,10 @@ static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
|
|||||||
DrawSurfaceDecals( fa, true, (cull_type == CULL_BACKSIDE));
|
DrawSurfaceDecals( fa, true, (cull_type == CULL_BACKSIDE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: draw mirror through in mirror show dummy lightmapped texture
|
||||||
|
if( RP_NORMALPASS() && FBitSet( fa->flags, SURF_REFLECT ))
|
||||||
|
return; // no lightmaps for mirror
|
||||||
|
|
||||||
if( FBitSet( fa->flags, SURF_DRAWTILED ))
|
if( FBitSet( fa->flags, SURF_DRAWTILED ))
|
||||||
return; // no lightmaps anyway
|
return; // no lightmaps anyway
|
||||||
|
|
||||||
@@ -1432,7 +1469,7 @@ void R_DrawWaterSurfaces( void )
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// set modulate mode explicitly
|
// set modulate mode explicitly
|
||||||
R_UploadRipples( t );
|
R_UploadRipples( t, false );
|
||||||
|
|
||||||
for( ; s; s = s->texturechain )
|
for( ; s; s = s->texturechain )
|
||||||
EmitWaterPolys( s, false );
|
EmitWaterPolys( s, false );
|
||||||
@@ -1551,6 +1588,9 @@ void R_DrawBrushModel( cl_entity_t *e )
|
|||||||
if( clmodel->surfaces != WORLDMODEL->surfaces )
|
if( clmodel->surfaces != WORLDMODEL->surfaces )
|
||||||
allow_vbo = false;
|
allow_vbo = false;
|
||||||
|
|
||||||
|
if( R_CullEntityInMirror( e ))
|
||||||
|
return;
|
||||||
|
|
||||||
if( !VectorIsNull( e->angles ))
|
if( !VectorIsNull( e->angles ))
|
||||||
{
|
{
|
||||||
for( i = 0; i < 3; i++ )
|
for( i = 0; i < 3; i++ )
|
||||||
@@ -1903,7 +1943,7 @@ void R_GenerateVBO( void )
|
|||||||
if( surf->lightmaptexturenum != k )
|
if( surf->lightmaptexturenum != k )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS ) )
|
if( FBitSet( surf->flags, SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS | SURF_REFLECT ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( R_TextureAnimation( surf ) != world->textures[j] )
|
if( R_TextureAnimation( surf ) != world->textures[j] )
|
||||||
@@ -1972,7 +2012,7 @@ void R_GenerateVBO( void )
|
|||||||
if( surf->lightmaptexturenum != k )
|
if( surf->lightmaptexturenum != k )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS ) )
|
if( FBitSet( surf->flags, SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS | SURF_REFLECT ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( R_TextureAnimation( surf ) != world->textures[j] )
|
if( R_TextureAnimation( surf ) != world->textures[j] )
|
||||||
@@ -3821,7 +3861,14 @@ void GL_BuildLightmaps( void )
|
|||||||
GL_FreeTexture( tr.lightmapTextures[i] );
|
GL_FreeTexture( tr.lightmapTextures[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( i = 0; i < MAX_MIRRORS; i++ )
|
||||||
|
{
|
||||||
|
if( !tr.mirrorTextures[i] ) break;
|
||||||
|
GL_FreeTexture( tr.mirrorTextures[i] );
|
||||||
|
}
|
||||||
|
|
||||||
memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures ));
|
memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures ));
|
||||||
|
memset( tr.mirrorTextures, 0, sizeof( tr.mirrorTextures ));
|
||||||
memset( &RI, 0, sizeof( RI ));
|
memset( &RI, 0, sizeof( RI ));
|
||||||
|
|
||||||
// update the lightmap blocksize
|
// update the lightmap blocksize
|
||||||
@@ -3837,6 +3884,8 @@ void GL_BuildLightmaps( void )
|
|||||||
tr.realframecount = 1;
|
tr.realframecount = 1;
|
||||||
nColinElim = 0;
|
nColinElim = 0;
|
||||||
|
|
||||||
|
tr.num_mirrors_used = 0;
|
||||||
|
|
||||||
// setup the texture for dlights
|
// setup the texture for dlights
|
||||||
R_InitDlightTexture();
|
R_InitDlightTexture();
|
||||||
|
|
||||||
|
|||||||
@@ -701,6 +701,9 @@ static qboolean R_SpriteOccluded( cl_entity_t *e, vec3_t origin, float *pscale )
|
|||||||
float blend;
|
float blend;
|
||||||
vec3_t v;
|
vec3_t v;
|
||||||
|
|
||||||
|
if( R_CullEntityInMirror( e ))
|
||||||
|
return true;
|
||||||
|
|
||||||
TriWorldToScreen( origin, v );
|
TriWorldToScreen( origin, v );
|
||||||
|
|
||||||
if( v[0] < RI.viewport[0] || v[0] > RI.viewport[0] + RI.viewport[2] )
|
if( v[0] < RI.viewport[0] || v[0] > RI.viewport[0] + RI.viewport[2] )
|
||||||
|
|||||||
@@ -32,8 +32,11 @@ typedef struct
|
|||||||
model_t *model;
|
model_t *model;
|
||||||
} player_model_t;
|
} player_model_t;
|
||||||
|
|
||||||
// never gonna change, just shut up const warning
|
// never gonna change you up, never gonna override you down
|
||||||
cvar_t r_shadows = { (char *)"r_shadows", (char *)"0", 0 };
|
// TODO: actually let client.dll override it
|
||||||
|
CVAR_DEFINE_AUTO( r_shadows, "0", FCVAR_ARCHIVE, "drop ugly shadow" );
|
||||||
|
CVAR_DEFINE_AUTO( r_shadow_alpha, "0.5", FCVAR_ARCHIVE, "ugly shadow opacity" );
|
||||||
|
CVAR_DEFINE_AUTO( r_shadow_height, "0", FCVAR_ARCHIVE, "ugly shadow height" );
|
||||||
|
|
||||||
static vec3_t hullcolor[8] =
|
static vec3_t hullcolor[8] =
|
||||||
{
|
{
|
||||||
@@ -154,8 +157,12 @@ void R_StudioInit( void )
|
|||||||
|
|
||||||
Matrix3x4_LoadIdentity( g_studio.rotationmatrix );
|
Matrix3x4_LoadIdentity( g_studio.rotationmatrix );
|
||||||
|
|
||||||
// g-cont. cvar disabled by Valve
|
// a1ba: enabled since HL25
|
||||||
// gEngfuncs.Cvar_RegisterVariable( &r_shadows );
|
gEngfuncs.Cvar_RegisterVariable( &r_shadows );
|
||||||
|
|
||||||
|
// a1ba: TimeWarp cvars (TODO: move to client.dll)
|
||||||
|
gEngfuncs.Cvar_RegisterVariable( &r_shadow_alpha );
|
||||||
|
gEngfuncs.Cvar_RegisterVariable( &r_shadow_height );
|
||||||
|
|
||||||
g_studio.interpolate = true;
|
g_studio.interpolate = true;
|
||||||
g_studio.framecount = 0;
|
g_studio.framecount = 0;
|
||||||
@@ -2930,25 +2937,35 @@ R_StudioDrawPointsShadow
|
|||||||
static void R_StudioDrawPointsShadow( void )
|
static void R_StudioDrawPointsShadow( void )
|
||||||
{
|
{
|
||||||
float *av, height;
|
float *av, height;
|
||||||
float vec_x, vec_y;
|
|
||||||
mstudiomesh_t *pmesh;
|
mstudiomesh_t *pmesh;
|
||||||
vec3_t point;
|
|
||||||
int i, k;
|
int i, k;
|
||||||
|
pmtrace_t tr;
|
||||||
|
vec3_t trEnd;
|
||||||
|
|
||||||
if( FBitSet( RI.currententity->curstate.effects, EF_NOSHADOW ))
|
if( FBitSet( RI.currententity->curstate.effects, EF_NOSHADOW ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
VectorCopy( RI.currententity->origin, trEnd );
|
||||||
|
trEnd[2] -= 4096;
|
||||||
|
|
||||||
|
tr = gEngfuncs.CL_TraceLine( RI.currententity->origin, trEnd, PM_STUDIO_IGNORE | PM_GLASS_IGNORE );
|
||||||
|
|
||||||
|
// didn't hit floor
|
||||||
|
if( tr.fraction >= 1.0f )
|
||||||
|
return;
|
||||||
|
|
||||||
if( glState.stencilEnabled )
|
if( glState.stencilEnabled )
|
||||||
pglEnable( GL_STENCIL_TEST );
|
pglEnable( GL_STENCIL_TEST );
|
||||||
|
|
||||||
height = g_studio.lightspot[2] + 1.0f;
|
height = r_shadow_height.value;
|
||||||
vec_x = -g_studio.lightvec[0] * 8.0f;
|
|
||||||
vec_y = -g_studio.lightvec[1] * 8.0f;
|
|
||||||
|
|
||||||
for( k = 0; k < m_pSubModel->nummesh; k++ )
|
for( k = 0; k < m_pSubModel->nummesh; k++ )
|
||||||
{
|
{
|
||||||
short *ptricmds;
|
short *ptricmds;
|
||||||
|
|
||||||
|
if( FBitSet( g_studio.meshes[k].flags, STUDIO_NF_MASKED | STUDIO_NF_ADDITIVE | STUDIO_NF_FULLBRIGHT ))
|
||||||
|
continue;
|
||||||
|
|
||||||
pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + k;
|
pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + k;
|
||||||
ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex);
|
ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex);
|
||||||
|
|
||||||
@@ -2970,11 +2987,7 @@ static void R_StudioDrawPointsShadow( void )
|
|||||||
for( ; i > 0; i--, ptricmds += 4 )
|
for( ; i > 0; i--, ptricmds += 4 )
|
||||||
{
|
{
|
||||||
av = g_studio.verts[ptricmds[0]];
|
av = g_studio.verts[ptricmds[0]];
|
||||||
point[0] = av[0] - (vec_x * ( av[2] - g_studio.lightspot[2] ));
|
pglVertex3f( av[0], av[1], tr.endpos[2] + height + 0.16f );
|
||||||
point[1] = av[1] - (vec_y * ( av[2] - g_studio.lightspot[2] ));
|
|
||||||
point[2] = g_studio.lightspot[2] + 1.0f;
|
|
||||||
|
|
||||||
pglVertex3fv( point );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pglEnd();
|
pglEnd();
|
||||||
@@ -3035,12 +3048,10 @@ static void GL_StudioDrawShadow( void )
|
|||||||
|
|
||||||
if( r_shadows.value && g_studio.rendermode != kRenderTransAdd && !FBitSet( RI.currentmodel->flags, STUDIO_AMBIENT_LIGHT ))
|
if( r_shadows.value && g_studio.rendermode != kRenderTransAdd && !FBitSet( RI.currentmodel->flags, STUDIO_AMBIENT_LIGHT ))
|
||||||
{
|
{
|
||||||
float color = 1.0f - (tr.blend * 0.5f);
|
|
||||||
|
|
||||||
pglDisable( GL_TEXTURE_2D );
|
pglDisable( GL_TEXTURE_2D );
|
||||||
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||||
pglEnable( GL_BLEND );
|
pglEnable( GL_BLEND );
|
||||||
pglColor4f( 0.0f, 0.0f, 0.0f, 1.0f - color );
|
pglColor4f( 0.0f, 0.0f, 0.0f, ( tr.blend - 1 ) + r_shadow_alpha.value );
|
||||||
|
|
||||||
pglDepthFunc( GL_LESS );
|
pglDepthFunc( GL_LESS );
|
||||||
R_StudioDrawPointsShadow();
|
R_StudioDrawPointsShadow();
|
||||||
|
|||||||
@@ -781,7 +781,7 @@ Does a water warp on the pre-fragmented glpoly_t chain
|
|||||||
void EmitWaterPolys( msurface_t *warp, qboolean reverse )
|
void EmitWaterPolys( msurface_t *warp, qboolean reverse )
|
||||||
{
|
{
|
||||||
float *v, nv, waveHeight;
|
float *v, nv, waveHeight;
|
||||||
float s, t, os, ot;
|
float s, t, os, ot, warp_s, warp_t;
|
||||||
glpoly_t *p;
|
glpoly_t *p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -822,15 +822,29 @@ void EmitWaterPolys( msurface_t *warp, qboolean reverse )
|
|||||||
os = v[3];
|
os = v[3];
|
||||||
ot = v[4];
|
ot = v[4];
|
||||||
|
|
||||||
if( !r_ripple.value )
|
switch((int)r_water_warp.value )
|
||||||
{
|
{
|
||||||
s = os + r_turbsin[(int)((ot * 0.125f + gp_cl->time) * TURBSCALE) & 255];
|
case 0:
|
||||||
t = ot + r_turbsin[(int)((os * 0.125f + gp_cl->time) * TURBSCALE) & 255];
|
warp_s = warp_t = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
warp_s = r_turbsin[(int)((ot * 0.125f + gp_cl->time) * TURBSCALE) & 255];
|
||||||
|
warp_t = r_turbsin[(int)((os * 0.125f + gp_cl->time) * TURBSCALE) & 255];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
default:
|
||||||
|
warp_s = gp_cl->time * r_water_warp_x.value;
|
||||||
|
warp_t = gp_cl->time * r_water_warp_y.value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
s = os + warp_s;
|
||||||
|
t = ot + warp_t;
|
||||||
|
|
||||||
|
if( r_ripple.value )
|
||||||
{
|
{
|
||||||
s = os / g_ripple.texturescale;
|
s /= g_ripple.texturescale;
|
||||||
t = ot / g_ripple.texturescale;
|
t /= g_ripple.texturescale;
|
||||||
}
|
}
|
||||||
|
|
||||||
s *= ( 1.0f / SUBDIVIDE_SIZE );
|
s *= ( 1.0f / SUBDIVIDE_SIZE );
|
||||||
@@ -963,28 +977,29 @@ void R_AnimateRipples( void )
|
|||||||
R_RunRipplesAnimation( g_ripple.oldbuf, g_ripple.curbuf );
|
R_RunRipplesAnimation( g_ripple.oldbuf, g_ripple.curbuf );
|
||||||
}
|
}
|
||||||
|
|
||||||
void R_UploadRipples( texture_t *image )
|
void R_UploadRipples( texture_t *image, qboolean is_mirror )
|
||||||
{
|
{
|
||||||
gl_texture_t *glt;
|
gl_texture_t *glt;
|
||||||
uint32_t *pixels;
|
uint32_t *pixels;
|
||||||
int wbits, wmask, wshft;
|
int wbits, wmask, wshft;
|
||||||
int y;
|
int y;
|
||||||
|
int tmu = is_mirror ? XASH_TEXTURE1 : XASH_TEXTURE0;
|
||||||
|
|
||||||
// discard unuseful textures
|
// discard unuseful textures
|
||||||
if( !r_ripple.value || image->width > RIPPLES_CACHEWIDTH || image->width != image->height )
|
if( !r_ripple.value || image->width > RIPPLES_CACHEWIDTH || image->width != image->height )
|
||||||
{
|
{
|
||||||
GL_Bind( XASH_TEXTURE0, image->gl_texturenum );
|
GL_Bind( tmu, image->gl_texturenum );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glt = R_GetTexture( image->gl_texturenum );
|
glt = R_GetTexture( image->gl_texturenum );
|
||||||
if( !glt || !glt->original || !glt->original->buffer || !FBitSet( glt->flags, TF_EXPAND_SOURCE ))
|
if( !glt || !glt->original || !glt->original->buffer || !FBitSet( glt->flags, TF_EXPAND_SOURCE ))
|
||||||
{
|
{
|
||||||
GL_Bind( XASH_TEXTURE0, image->gl_texturenum );
|
GL_Bind( tmu, image->gl_texturenum );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL_Bind( XASH_TEXTURE0, g_ripple.rippletexturenum );
|
GL_Bind( tmu, g_ripple.rippletexturenum );
|
||||||
|
|
||||||
// no updates this frame
|
// no updates this frame
|
||||||
if( !g_ripple.update && image->gl_texturenum == g_ripple.gl_texturenum )
|
if( !g_ripple.update && image->gl_texturenum == g_ripple.gl_texturenum )
|
||||||
|
|||||||
Reference in New Issue
Block a user