01 Jul 2010

This commit is contained in:
g-cont 2010-07-01 00:00:00 +04:00 committed by Alibek Omarov
parent 9eb4e5cde1
commit 99ecb9fcbe
28 changed files with 576 additions and 931 deletions

View File

@ -180,11 +180,6 @@ void TE_ParseExplosion( void )
if(!( flags & TE_EXPLFLAG_NOPARTICLES ))
g_engfuncs.pEfxAPI->R_RunParticleEffect( pos, g_vecZero, 224, 200 );
char szDecal[32];
sprintf( szDecal, "{scorch%i", RANDOM_LONG( 1, 3 ));
g_pTempEnts->PlaceDecal( pos2, 0, szDecal );
if( !( flags & TE_EXPLFLAG_NOSOUND ))
{
CL_PlaySound( "weapons/explode3.wav", 1.0f, pos2 );
@ -425,6 +420,7 @@ void TE_ParseBSPDecal( void )
entityIndex = READ_SHORT();
if( entityIndex != NULLENT_INDEX )
modelIndex = READ_SHORT();
else modelIndex = 0;
g_pTempEnts->PlaceDecal( pos, entityIndex, decalIndex );
}
@ -793,9 +789,8 @@ void TE_ParseDecal( int type )
decalIndex = READ_BYTE();
if( type == TE_DECAL || type == TE_DECALHIGH )
{
entityIndex = READ_SHORT();
}
else entityIndex = 0;
if( type == TE_DECALHIGH || type == TE_WORLDDECALHIGH )
decalIndex += 256;
@ -984,6 +979,7 @@ Create a colored decal, get settings from client
void TE_ParsePlayerDecal( void )
{
int clientIndex, decalIndex, entityIndex;
byte color[4];
Vector pos;
clientIndex = READ_BYTE();
@ -993,9 +989,14 @@ void TE_ParsePlayerDecal( void )
entityIndex = READ_SHORT();
decalIndex = READ_BYTE();
// FIXME: get logo color from user variable
color[0] = 255;
color[1] = 255;
color[2] = 255;
color[3] = 255; // alpha
HSPRITE hDecal = g_engfuncs.pEfxAPI->CL_DecalIndex( decalIndex );
edict_t *pEnt = GetEntityByIndex( entityIndex );
g_engfuncs.pEfxAPI->R_DecalShoot( hDecal, pEnt, pEnt->v.modelindex, pos, 0 );
g_engfuncs.pEfxAPI->R_PlayerDecal( hDecal, entityIndex, pos, 0 );
}
/*

View File

@ -1506,7 +1506,7 @@ void CTempEnts::PlaceDecal( Vector pos, int entityIndex, int decalIndex )
pEnt = GetEntityByIndex( entityIndex );
if( pEnt && !pEnt->free ) modelIndex = pEnt->v.modelindex;
hDecal = g_engfuncs.pEfxAPI->CL_DecalIndex( decalIndex );
g_engfuncs.pEfxAPI->R_DecalShoot( hDecal, pEnt, modelIndex, pos, 0 );
g_engfuncs.pEfxAPI->R_DecalShoot( hDecal, entityIndex, modelIndex, pos, 0 );
}
void CTempEnts::PlaceDecal( Vector pos, int entityIndex, const char *decalname )
@ -1518,7 +1518,7 @@ void CTempEnts::PlaceDecal( Vector pos, int entityIndex, const char *decalname )
pEnt = GetEntityByIndex( entityIndex );
if( pEnt && !pEnt->free ) modelIndex = pEnt->v.modelindex;
hDecal = g_engfuncs.pEfxAPI->CL_DecalIndexFromName( decalname );
g_engfuncs.pEfxAPI->R_DecalShoot( hDecal, pEnt, modelIndex, pos, 0 );
g_engfuncs.pEfxAPI->R_DecalShoot( hDecal, entityIndex, modelIndex, pos, 0 );
}
void CTempEnts::AllocDLight( Vector pos, byte r, byte g, byte b, float radius, float time, float decay )

View File

@ -264,11 +264,6 @@ typedef enum
#define IN_ALT1 (1<<14)
#define IN_SCORE (1<<15) // Used by client.dll for when scoreboard is held down
// temp entity bounce sound types
#define TE_BOUNCE_NULL 0
#define TE_BOUNCE_SHELL 1
#define TE_BOUNCE_SHOTSHELL 2
// rendering constants
typedef enum
{
@ -360,6 +355,16 @@ typedef enum
#define RDF_NOFOVADJUSTMENT (1<<3) // do not adjust fov for widescreen
#define RDF_THIRDPERSON (1<<4) // enable chase cam instead firstperson
// decal flags
#define FDECAL_PERMANENT 0x01 // This decal should not be removed in favor of any new decals
#define FDECAL_REFERENCE 0x02 // This is a decal that's been moved from another level
#define FDECAL_CUSTOM 0x04 // This is a custom clan logo and should not be saved/restored
#define FDECAL_DYNAMIC 0x08 // Indicates the decal is dynamic
#define FDECAL_DONTSAVE 0x10 // Decal was loaded from adjacent level, don't save it for this level
#define FDECAL_CLIPTEST 0x20 // Decal needs to be clip-tested
#define FDECAL_NOCLIP 0x40 // Decal is not clipped by containing polygon
#define FDECAL_USESAXIS 0x80 // Uses the s axis field to determine orientation (footprints)
// client modelindexes
#define NULLENT_INDEX -1 // engine always return NULL, only for internal use
#define VIEWENT_INDEX -2 // can get viewmodel for local client

View File

@ -27,20 +27,6 @@ struct dlight_s
bool dark; // subtracts light instead of adding
};
// decal flags
#define FDECAL_PERMANENT 0x01 // This decal should not be removed in favor of any new decals
#define FDECAL_REFERENCE 0x02 // This is a decal that's been moved from another level
#define FDECAL_CUSTOM 0x04 // This is a custom clan logo and should not be saved/restored
#define FDECAL_HFLIP 0x08 // Flip horizontal (U/S) axis
#define FDECAL_VFLIP 0x10 // Flip vertical (V/T) axis
#define FDECAL_CLIPTEST 0x20 // Decal needs to be clip-tested
#define FDECAL_NOCLIP 0x40 // Decal is not clipped by containing polygon
#define FDECAL_USESAXIS 0x80 // Uses the s axis field to determine orientation
#define FDECAL_DYNAMIC 0x100 // Indicates the decal is dynamic
#define FDECAL_SECONDPASS 0x200 // Decals that have to be drawn after everything else
#define FDECAL_WATER 0x400 // Decal should only be applied to water
#define FDECAL_DONTSAVE 0x800 // Decal was loaded from adjacent level, don't save it for this level
typedef struct efxapi_s
{
particle_t* (*R_AllocParticle)( void );
@ -55,7 +41,8 @@ typedef struct efxapi_s
void (*R_GetPaletteColor)( int colorIndex, float *outColor );
int (*CL_DecalIndex)( int id );
int (*CL_DecalIndexFromName)( const char *szDecalName );
void (*R_DecalShoot)( HSPRITE hDecal, edict_t *pEnt, int modelIndex, float *pos, int flags );
void (*R_DecalShoot)( HSPRITE hDecal, int entityIndex, int modelIndex, float *pos, int flags );
void (*R_PlayerDecal)( HSPRITE hDecal, int entityIndex, float *pos, byte *color );
dlight_t* (*CL_AllocDLight)( int key );
dlight_t* (*CL_AllocELight)( int key );
void (*R_LightForPoint)( const float *rgflOrigin, float *lightValue );

View File

@ -954,270 +954,45 @@ void CL_RocketTrail( const vec3_t org, const vec3_t end, int type )
}
/*
==============================================================
===============
CL_DecalShoot
DECALS MANAGEMENT
==============================================================
normal temporary decal
===============
*/
#define MAX_DRAWDECALS 1024
#define MAX_DECAL_VERTS 128 // per one decal
#define MAX_DECAL_FRAGMENTS 64
typedef struct cdecal_s
void CL_DecalShoot( HSPRITE hDecal, int entityIndex, int modelIndex, float *pos, int flags )
{
struct cdecal_s *prev;
struct cdecal_s *next;
edict_t *pent; // parent entity
poly_t *poly;
} cdecal_t;
static cdecal_t cl_decals[MAX_DRAWDECALS];
static cdecal_t cl_decals_headnode, *cl_free_decals;
static poly_t cl_decal_polys[MAX_DRAWDECALS];
static vec3_t cl_decal_verts[MAX_DRAWDECALS][MAX_DECAL_VERTS];
static vec2_t cl_decal_stcoords[MAX_DRAWDECALS][MAX_DECAL_VERTS];
static rgba_t cl_decal_colors[MAX_DRAWDECALS][MAX_DECAL_VERTS];
/*
=================
CL_ClearDecals
=================
*/
void CL_ClearDecals( void )
{
int i;
Mem_Set( cl_decals, 0, sizeof( cl_decals ));
Mem_Set( cl_decal_polys, 0, sizeof( cl_decal_polys ));
// link decals
cl_free_decals = cl_decals;
cl_decals_headnode.prev = &cl_decals_headnode;
cl_decals_headnode.next = &cl_decals_headnode;
for( i = 0; i < MAX_DRAWDECALS; i++ )
{
if( i < MAX_DRAWDECALS - 1 )
cl_decals[i].next = &cl_decals[i+1];
cl_decals[i].poly = &cl_decal_polys[i];
cl_decals[i].poly->verts = cl_decal_verts[i];
cl_decals[i].poly->stcoords = cl_decal_stcoords[i];
cl_decals[i].poly->colors = cl_decal_colors[i];
}
}
/*
=================
CL_AllocDecal
Returns either a free decal or the oldest one
=================
*/
cdecal_t *CL_AllocDecal( void )
{
cdecal_t *dl;
if( cl_free_decals )
{
// take a free decal if possible
dl = cl_free_decals;
cl_free_decals = dl->next;
}
else
{
// grab the oldest one otherwise
dl = cl_decals_headnode.prev;
dl->prev->next = dl->next;
dl->next->prev = dl->prev;
}
// put the decal at the start of the list
dl->prev = &cl_decals_headnode;
dl->next = cl_decals_headnode.next;
dl->next->prev = dl;
dl->prev->next = dl;
return dl;
}
/*
=================
CL_FreeDecal
=================
*/
void CL_FreeDecal( cdecal_t *dl )
{
// remove from linked active list
dl->prev->next = dl->next;
dl->next->prev = dl->prev;
// insert into linked free list
dl->next = cl_free_decals;
cl_free_decals = dl;
}
/*
=================
CL_SpawnDecal
=================
*/
int CL_SpawnDecal( HSPRITE m_hDecal, edict_t *pEnt, const vec3_t pos, int colorIndex, float roll, float scale )
{
cdecal_t *dl;
poly_t *poly;
vec3_t axis[3];
int i, j, numfragments;
vec3_t dir, verts[MAX_DECAL_VERTS];
fragment_t *fr, fragments[MAX_DECAL_FRAGMENTS];
rgba_t color;
// invalid decal
if( scale <= 0.0f || !m_hDecal )
return false;
CL_FindExplosionPlane( pos, scale, dir );
// calculate orientation matrix
VectorNormalize2( dir, axis[0] );
PerpendicularVector( axis[1], axis[0] );
RotatePointAroundVector( axis[2], axis[0], axis[1], roll );
CrossProduct( axis[0], axis[2], axis[1] );
numfragments = re->GetFragments( pos, scale, axis, MAX_DECAL_VERTS, verts, MAX_DECAL_FRAGMENTS, fragments );
// no valid fragments
if( !numfragments ) return false;
// setup decal color
if( colorIndex )
{
colorIndex = bound( 0, colorIndex, 255 );
color[0] = cl_particlePalette[colorIndex][0];
color[1] = cl_particlePalette[colorIndex][1];
color[2] = cl_particlePalette[colorIndex][2];
color[3] = 0xFF;
}
else Vector4Set( color, 255, 255, 255, 255 );
scale = 0.5f / scale;
VectorScale( axis[1], scale, axis[1] );
VectorScale( axis[2], scale, axis[2] );
for( i = 0, fr = fragments; i < numfragments; i++, fr++ )
{
if( fr->numverts >= MAX_DECAL_VERTS )
return -1; // in case we partially failed
else if( fr->numverts <= 0 )
continue;
// allocate decal
dl = CL_AllocDecal();
dl->pent = pEnt;
// setup polygon for drawing
poly = dl->poly;
poly->shadernum = m_hDecal;
poly->numverts = fr->numverts;
poly->fognum = fr->fognum;
for( j = 0; j < fr->numverts; j++ )
{
vec3_t v;
VectorCopy( verts[fr->firstvert+j], poly->verts[j] );
VectorSubtract( poly->verts[j], pos, v );
poly->stcoords[j][0] = DotProduct( v, axis[1] ) + 0.5f;
poly->stcoords[j][1] = DotProduct( v, axis[2] ) + 0.5f;
*(int *)poly->colors[j] = *(int *)color;
}
}
return true; // all done
}
/*
=================
CL_AddDecals
=================
*/
void CL_AddDecals( void )
{
cdecal_t *dl, *next, *hnode;
// add decals in first-spawned - first-drawn order
hnode = &cl_decals_headnode;
for( dl = hnode->prev; dl != hnode; dl = next )
{
next = dl->prev;
if( dl->pent && dl->pent->free )
{
// remove attached decals
CL_FreeDecal( dl );
continue;
}
re->AddPolygon( dl->poly );
}
}
void CL_DecalShoot( HSPRITE hDecal, edict_t *pEnt, int modelIndex, float *pos, int flags )
{
int entityIndex = 0;
rgba_t color;
if( CL_IsValidEdict( pEnt ))
entityIndex = pEnt->serialnumber;
Vector4Set( color, 255, 255, 255, 255 );
if( re ) re->DecalShoot( hDecal, entityIndex, modelIndex, pos, NULL, 0, color );
Vector4Set( color, 255, 255, 255, 255 ); // don't use custom colors
if( re ) re->DecalShoot( hDecal, entityIndex, modelIndex, pos, NULL, flags, color, 0.0f, 0.0f );
}
/*
===============
CL_SpawnStaticDecal
CL_PlayerDecal
spray custom colored decal (clan logo etc)
===============
*/
void CL_SpawnStaticDecal( vec3_t origin, int decalIndex, int entityIndex, int modelIndex )
void CL_PlayerDecal( HSPRITE hDecal, int entityIndex, float *pos, byte *color )
{
rgba_t color;
edict_t *pEnt;
int modelIndex = 0;
decalIndex = bound( 0, decalIndex, MAX_DECALNAMES - 1 );
Vector4Set( color, 255, 255, 255, 255 );
pEnt = CL_GetEdictByIndex( entityIndex );
if( CL_IsValidEdict( pEnt )) modelIndex = pEnt->v.modelindex;
if( re ) re->DecalShoot( cl.decal_shaders[decalIndex], entityIndex, modelIndex, origin, NULL, 0, color );
if( re ) re->DecalShoot( hDecal, entityIndex, modelIndex, pos, NULL, FDECAL_CUSTOM, color, 0.0f, 0.0f );
}
void CL_FindExplosionPlane( const vec3_t origin, float radius, vec3_t result )
{
static vec3_t planes[6] = {{0, 0, 1}, {0, 1, 0}, {1, 0, 0}, {0, 0, -1}, {0, -1, 0}, {-1, 0, 0}};
float best = 1.0f;
vec3_t point, dir;
trace_t trace;
int i;
if( !result ) return;
VectorClear( dir );
for( i = 0; i < 6; i++ )
{
VectorMA( origin, radius, planes[i], point );
trace = CL_Move( origin, vec3_origin, vec3_origin, point, MOVE_NOMONSTERS, NULL );
if( trace.fAllSolid || trace.flFraction == 1.0f )
continue;
if( trace.flFraction < best )
{
best = trace.flFraction;
VectorCopy( trace.vecPlaneNormal, dir );
}
}
VectorCopy( dir, result );
}
/*
===============
CL_LightForPoint
get lighting color for specified point
===============
*/
void CL_LightForPoint( const vec3_t point, vec3_t ambientLight )
{
if( re ) re->LightForPoint( point, ambientLight );
@ -1392,5 +1167,4 @@ void CL_ClearEffects( void )
CL_ClearParticles ();
CL_ClearDlights ();
CL_ClearLightStyles ();
CL_ClearDecals ();
}
}

View File

@ -334,7 +334,6 @@ void CL_AddEntities( void )
CL_AddParticles();
CL_AddDLights();
CL_AddLightStyles();
CL_AddDecals();
// perfomance test
CL_TestEntities();

View File

@ -2028,7 +2028,7 @@ static int pfnDecalIndexFromName( const char *szDecalName )
if( !com.stricmp( szDecalName, cl.configstrings[CS_DECALS+i+1] ))
return cl.decal_shaders[i+1];
}
return 0; // invalid sprite
return 0; // invalid decal
}
/*
@ -2399,6 +2399,7 @@ static efxapi_t gEfxApi =
pfnDecalIndex,
pfnDecalIndexFromName,
CL_DecalShoot,
CL_PlayerDecal,
CL_AllocDlight,
CL_AllocElight,
CL_LightForPoint,

View File

@ -431,10 +431,11 @@ void CL_ParseStaticDecal( sizebuf_t *msg )
decalIndex = MSG_ReadWord( msg );
entityIndex = MSG_ReadShort( msg );
if( entityIndex > 0 )
if( entityIndex != NULLENT_INDEX )
modelIndex = MSG_ReadWord( msg );
else modelIndex = 0;
CL_SpawnStaticDecal( origin, decalIndex, entityIndex, modelIndex );
CL_DecalShoot( cl.decal_shaders[decalIndex], entityIndex, modelIndex, origin, FDECAL_PERMANENT );
}
void CL_ParseSoundFade( sizebuf_t *msg )

View File

@ -547,7 +547,6 @@ void CL_GetEntitySpatialization( int ent, vec3_t origin, vec3_t velocity );
// cl_effects.c
//
void CL_AddParticles( void );
void CL_AddDecals( void );
void CL_ClearEffects( void );
void CL_TestLights( void );
void CL_TestEntities( void );
@ -562,11 +561,10 @@ void CL_ParticleExplosion( const vec3_t org );
void CL_RocketTrail( const vec3_t start, const vec3_t end, int type );
void CL_ParticleExplosion2( const vec3_t org, int colorStart, int colorLength );
void CL_GetPaletteColor( int colorIndex, vec3_t outColor );
void CL_FindExplosionPlane( const vec3_t origin, float radius, vec3_t result );
void CL_LightForPoint( const vec3_t point, vec3_t ambientLight );
void CL_DecalShoot( HSPRITE hDecal, edict_t *pEnt, int modelIndex, float *pos, int flags );
void CL_DecalShoot( HSPRITE hDecal, int entityIndex, int modelIndex, float *pos, int flags );
void CL_PlayerDecal( HSPRITE hDecal, int entityIndex, float *pos, byte *color );
void CL_ParticleEffect( const vec3_t org, const vec3_t dir, int color, int count ); // q1 legacy
void CL_SpawnStaticDecal( vec3_t origin, int decalIndex, int entityIndex, int modelIndex );
void CL_QueueEvent( int flags, int index, float delay, event_args_t *args );
word CL_PrecacheEvent( const char *name );
void CL_ResetEvent( event_info_t *ei );

View File

@ -850,7 +850,7 @@ void Host_Main( void )
oldtime = Sys_DoubleTime();
// main window message loop
while( host.state != HOST_OFFLINE )
while( host.type != HOST_OFFLINE )
{
IN_Frame();

View File

@ -2593,7 +2593,7 @@ void pfnStaticDecal( const float *origin, int decalIndex, int entityIndex, int m
MSG_WritePos( &sv.multicast, origin );
MSG_WriteWord( &sv.multicast, decalIndex );
MSG_WriteShort( &sv.multicast, entityIndex );
if( entityIndex > 0 )
if( entityIndex != NULLENT_INDEX )
MSG_WriteWord( &sv.multicast, modelIndex );
MSG_Send( MSG_INIT, NULL, NULL );
}

View File

@ -362,6 +362,11 @@ int EntityInSolid( edict_t *ent )
if( pParent->v.flags & FL_CLIENT )
return 0;
}
// never suppressing logical entities
if( !ent->v.modelindex )
return 0;
return SV_TestEntityPosition( ent );
}

View File

@ -1339,8 +1339,8 @@ void UI_Shutdown( void )
Cmd_RemoveCommand( "menu_loadgame" );
Cmd_RemoveCommand( "menu_savegame" );
Cmd_RemoveCommand( "menu_saveload" );
Cmd_RemoveCommand( "menu_recdemo" );
Cmd_RemoveCommand( "menu_playdemo" );
Cmd_RemoveCommand( "menu_record" );
Cmd_RemoveCommand( "menu_playpack" );
Cmd_RemoveCommand( "menu_playrec" );
Cmd_RemoveCommand( "menu_multiplayer" );
Cmd_RemoveCommand( "menu_options" );

View File

@ -560,7 +560,6 @@ bool Image_LoadMIP( const char *name, const byte *buffer, size_t filesize )
}
break;
}
rendermode = LUMP_NORMAL;
}
}

View File

@ -57,13 +57,17 @@ typedef struct
typedef struct
{
int firstvert;
int numverts; // can't exceed MAX_POLY_VERTS
int fognum; // -1 - do not bother adding fog later at rendering stage
// 0 - determine fog later
// >0 - valid fog volume number returned by R_GetClippedFragments
vec3_t normal;
} fragment_t;
vec3_t position;
char name[64]; // same as CS_SIZE
short entityIndex;
byte depth;
byte flags;
// this is the surface plane that we hit so that
// we can move certain decals across
// transitions if they hit similar geometry
vec3_t impactPlaneNormal;
} decallist_t;
typedef struct
{
@ -165,7 +169,7 @@ typedef struct render_exp_s
// prepare frame to rendering
bool (*AddRefEntity)( edict_t *pRefEntity, int ed_type, shader_t customShader );
bool (*AddTmpEntity)( struct tempent_s *TempEnt, int ed_type, shader_t customShader );
bool (*DecalShoot)( shader_t decal, int ent, model_t mod, vec3_t pos, vec3_t saxis, int flags, rgba_t color );
bool (*DecalShoot)( shader_t decal, int ent, int model, vec3_t pos, vec3_t saxis, int flags, rgba_t color, float fadeTime, float fadeDuration );
bool (*AddDLight)( vec3_t pos, rgb_t color, float radius, int flags );
bool (*AddPolygon)( const poly_t *poly );
bool (*AddLightStyle)( int stylenum, vec3_t color );
@ -195,15 +199,15 @@ typedef struct render_exp_s
void (*SetParms)( shader_t handle, kRenderMode_t rendermode, int frame );
void (*GetParms)( int *w, int *h, int *frames, int frame, shader_t shader );
bool (*ScrShot)( const char *filename, int shot_type ); // write screenshot with same name
bool (*EnvShot)( const char *filename, uint size, const float *vieworg, bool skyshot ); // write envshot with same name
bool (*EnvShot)( const char *filename, uint size, const float *vieworg, bool skyshot );
void (*LightForPoint)( const vec3_t point, vec3_t ambientLight );
void (*DrawStretchRaw)( int x, int y, int w, int h, int cols, int rows, byte *data, bool redraw );
void (*DrawStretchPic)( float x, float y, float w, float h, float s1, float t1, float s2, float t2, shader_t shader );
int (*GetFragments)( const vec3_t org, float rad, vec3_t axis[3], int maxverts, vec3_t *verts, int maxfrags, fragment_t *frags );
int (*WorldToScreen)( const float *world, float *screen );
void (*ScreenToWorld)( const float *screen, float *world );
bool (*CullBox)( const vec3_t mins, const vec3_t maxs );
bool (*RSpeedsMessage)( char *out, size_t size );
int (*CreateDecalList)( decallist_t *pList ); // helper to serialize decals
bool (*Support)( int extension );
byte *(*GetCurrentVis)( void );
void (*RestoreGamma)( void );

View File

@ -191,7 +191,7 @@ void S_MixAllChannels( int endtime, int end )
for( i = 0, ch = channels; i < total_channels; i++, ch++ )
{
if( !ch->sfx ) continue;
if( !ch->leftvol && !ch->rightvol )
if( !ch->leftvol && !ch->rightvol && !ch->isSentence )
continue;
// only local sounds can be playing in menus or on pause

View File

@ -26,4 +26,8 @@ Xash 0.72 Beta 5.07.10
2.clgame interface - new revision OK
3.entity_state - new revision OK
4.rework dlights OK
5.rework decals
5.rework decals OK
6.batch drawing decals OK
7.draw lightmapped decals OK
8.draw decals on bmodels OK
9.implement save\restore for decals

View File

@ -1281,6 +1281,7 @@ static _inline texture_t *R_ShaderpassTex( const ref_stage_t *pass, int unit )
if( !RI.currententity ) return pass->textures[0]; // assume error
return pass->textures[angleframe];
}
if( pass->flags & SHADERSTAGE_FRAMES && !(pass->flags & SHADERSTAGE_ANIMFREQUENCY))
{
if( glState.in2DMode || triState.fActive )
@ -2666,7 +2667,7 @@ void R_RenderMeshBuffer( const meshbuffer_t *mb )
msurface_t *surf;
ref_stage_t *pass;
mfog_t *fog;
int i;
int i, j, type;
if( !r_backacc.numVerts || !r_backacc.numElems )
{
@ -2676,10 +2677,33 @@ void R_RenderMeshBuffer( const meshbuffer_t *mb )
Com_Assert( mb == NULL );
surf = mb->infokey > 0 ? &r_worldbrushmodel->surfaces[mb->infokey-1] : NULL;
if( surf ) r_currentLightStyle = &tr.superLightStyles[surf->superLightStyle];
else r_currentLightStyle = NULL;
type = mb->sortkey & 3;
r_currentLightStyle = NULL;
r_currentMeshBuffer = mb;
surf = NULL;
// trying to extract lightstyle for mesh
switch( type )
{
case MB_MODEL:
if( RI.currentmodel )
{
switch( RI.currentmodel->type )
{
case mod_world:
case mod_brush:
surf = mb->infokey > 0 ? &r_worldbrushmodel->surfaces[mb->infokey-1] : NULL;
if( surf ) r_currentLightStyle = &tr.superLightStyles[surf->superLightStyle];
break;
}
}
break;
case MB_DECAL:
j = ((mb->sortkey>>10) & (MAX_SUPER_STYLES - 1));
r_currentLightStyle = &tr.superLightStyles[j - 1];
surf = R_DecalFromMeshbuf( mb )->psurf;
break;
}
MB_NUM2SHADER( mb->shaderkey, r_currentShader );
@ -2960,9 +2984,6 @@ static _inline void R_SetColorForOutlines( void )
}
}
break;
case MB_SPRITE:
pglColor4fv( colorBlue );
break;
case MB_POLY:
case MB_DECAL:
pglColor4fv( colorGreen );

View File

@ -11,7 +11,7 @@
#include "bspfile.h"
#include "const.h"
#define DECAL_DISTANCE 4 // FIXME: revert to 10 ?
#define DECAL_DISTANCE 4 // too big values produce more clipped polygons
#define MAX_DECALCLIPVERT 32 // produced vertexes of fragmented decal
#define DECAL_CACHEENTRY 256 // MUST BE POWER OF 2 or code below needs to change!
@ -19,6 +19,13 @@
#define MAX_OVERLAP_DECALS 4
#define DECAL_OVERLAP_DIST 8
typedef struct
{
vec3_t m_vPos;
vec2_t m_tCoords; // these are the texcoords for the decal itself
vec2_t m_LMCoords; // lightmap texcoords for the decal.
} decalvert_t;
// FIXME: move this out to the r_math.c ?
typedef struct
{
@ -61,62 +68,38 @@ typedef struct
int m_Flags;
int m_Entity; // Entity the decal is applied to.
float m_scale;
float m_flFadeTime;
float m_flFadeDuration;
int m_decalWidth;
int m_decalHeight;
rgba_t m_Color;
vec3_t m_Basis[3];
} decalinfo_t;
typedef struct
{
int decalIndex;
decalvert_t decalVert[4];
} decalcache_t;
decalcache_t gDecalCache[DECAL_CACHEENTRY];
// list of actual decals, that we needs to rendering
uint r_numDecals;
decal_t *r_drawdecals[MAX_DECALS];
static decalvert_t g_DecalClipVerts[MAX_DECALCLIPVERT];
static decalvert_t g_DecalClipVerts2[MAX_DECALCLIPVERT];
static mesh_t decal_mesh;
static byte *r_decalPool; // pool of decal meshes
static decal_t gDecalPool[MAX_DECALS];
static int gDecalCount;
static int R_DecalIndex( decal_t *pdecal )
void R_ClearDecals( void )
{
return ( pdecal - gDecalPool );
Mem_EmptyPool( r_decalPool );
Mem_Set( gDecalPool, 0, sizeof( gDecalPool ));
gDecalCount = 0;
}
static int R_DecalCacheIndex( int index )
// Init the decal pool
void R_InitDecals( void )
{
return index & (DECAL_CACHEENTRY-1);
r_decalPool = Mem_AllocPool( "Decals Mesh Pool" );
R_ClearDecals ();
}
static decalcache_t *R_DecalCacheSlot( int decalIndex )
void R_ShutdownDecals( void )
{
int cacheIndex;
cacheIndex = R_DecalCacheIndex( decalIndex ); // find the cache slot
return gDecalCache + cacheIndex;
}
// release the cache entry for this decal
static void R_DecalCacheClear( decal_t *pdecal )
{
int index;
decalcache_t *pCache;
index = R_DecalIndex( pdecal );
pCache = R_DecalCacheSlot( index ); // Find the cache slot
if( pCache->decalIndex == index ) // If this is the decal that's cached here, clear it.
pCache->decalIndex = -1;
Mem_FreePool( &r_decalPool );
}
// unlink pdecal from any surface it's attached to
@ -124,7 +107,6 @@ static void R_DecalUnlink( decal_t *pdecal )
{
decal_t *tmp;
R_DecalCacheClear( pdecal );
if( pdecal->psurf )
{
if( pdecal->psurf->pdecals == pdecal )
@ -147,7 +129,12 @@ static void R_DecalUnlink( decal_t *pdecal )
}
}
}
if( pdecal->mesh )
Mem_Free( pdecal->mesh );
pdecal->psurf = NULL;
pdecal->mesh = NULL;
}
@ -187,10 +174,14 @@ static decal_t *R_DecalAlloc( decal_t *pdecal )
//-----------------------------------------------------------------------------
// compute the decal basis based on surface normal, and preferred saxis
//-----------------------------------------------------------------------------
void R_DecalComputeBasis( vec3_t surfaceNormal, vec3_t pSAxis, vec3_t textureSpaceBasis[3] )
void R_DecalComputeBasis( msurface_t *surf, vec3_t pSAxis, vec3_t textureSpaceBasis[3] )
{
// get the surface normal.
VectorCopy( surfaceNormal, textureSpaceBasis[2] );
vec3_t surfaceNormal;
// setup normal
if( surf->flags & SURF_PLANEBACK )
VectorNegate( surf->plane->normal, surfaceNormal );
else VectorCopy( surf->plane->normal, surfaceNormal );
if( pSAxis )
{
@ -211,36 +202,16 @@ void R_DecalComputeBasis( vec3_t surfaceNormal, vec3_t pSAxis, vec3_t textureSpa
// Fall through to the standard algorithm for parallel or antiparallel
}
// floor/ceiling?
if( fabs( surfaceNormal[2] ) > 0.70710678118654752440084436210485f ) // sin( 45 ) degrees
{
textureSpaceBasis[0][0] = 1.0f;
textureSpaceBasis[0][1] = 0.0f;
textureSpaceBasis[0][2] = 0.0f;
// T = S cross N
CrossProduct( textureSpaceBasis[0], textureSpaceBasis[2], textureSpaceBasis[1] );
// S = N cross T
CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] );
}
else // wall
{
textureSpaceBasis[1][0] = 0.0f;
textureSpaceBasis[1][1] = 0.0f;
textureSpaceBasis[1][2] = -1.0f;
// S = N cross T
CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] );
// T = S cross N
CrossProduct( textureSpaceBasis[0], textureSpaceBasis[2], textureSpaceBasis[1] );
}
// original Half-Life algorithm: get textureBasis from linked surface
VectorCopy( surf->texinfo->vecs[0], textureSpaceBasis[0] );
VectorCopy( surf->texinfo->vecs[1], textureSpaceBasis[1] );
VectorCopy( surfaceNormal, textureSpaceBasis[2] );
VectorNormalizeFast( textureSpaceBasis[0] );
VectorNormalizeFast( textureSpaceBasis[1] );
}
void R_SetupDecalTextureSpaceBasis( decal_t *pDecal, vec3_t vSurfNormal, ref_shader_t *pShader, vec3_t textureSpaceBasis[3], float decalWorldScale[2] )
void R_SetupDecalTextureSpaceBasis( decal_t *pDecal, msurface_t *surf, ref_shader_t *pShader, vec3_t textureSpaceBasis[3], float decalWorldScale[2] )
{
float *sAxis = NULL;
@ -248,7 +219,7 @@ void R_SetupDecalTextureSpaceBasis( decal_t *pDecal, vec3_t vSurfNormal, ref_sha
sAxis = pDecal->saxis;
// Compute the non-scaled decal basis
R_DecalComputeBasis( vSurfNormal, sAxis, textureSpaceBasis );
R_DecalComputeBasis( surf, sAxis, textureSpaceBasis );
// world width of decal = ptexture->width / pDecal->scale
// world height of decal = ptexture->height / pDecal->scale
@ -268,21 +239,20 @@ void R_SetupDecalVertsForMSurface( decal_t *pDecal, msurface_t *surf, vec3_t tex
for( j = 0; j < surf->mesh->numVerts; j++ )
{
Vector4Copy( surf->mesh->vertexArray[j], pVerts[j].m_vPos ); // copy model space coordinates
VectorCopy( surf->mesh->vertexArray[j], pVerts[j].m_vPos ); // copy model space coordinates
pVerts[j].m_tCoords[0] = DotProduct( pVerts[j].m_vPos, textureSpaceBasis[0] ) - pDecal->dx + 0.5f;
pVerts[j].m_tCoords[1] = DotProduct( pVerts[j].m_vPos, textureSpaceBasis[1] ) - pDecal->dy + 0.5f;
pVerts[j].m_LMCoords[0] = pVerts[j].m_LMCoords[1] = 0.0f;
}
}
// Figure out where the decal maps onto the surface.
void R_SetupDecalClip( decalvert_t *pOutVerts, decal_t *pDecal, vec3_t vSurfNormal, ref_shader_t *pMaterial, vec3_t textureSpaceBasis[3], float decalWorldScale[2] )
void R_SetupDecalClip( decalvert_t *pOutVerts, decal_t *pDecal, msurface_t *surf, ref_shader_t *pMaterial, vec3_t textureSpaceBasis[3], float decalWorldScale[2] )
{
// if ( pOutVerts == NULL )
// pOutVerts = &g_DecalClipVerts[0];
R_SetupDecalTextureSpaceBasis( pDecal, vSurfNormal, pMaterial, textureSpaceBasis, decalWorldScale );
R_SetupDecalTextureSpaceBasis( pDecal, surf, pMaterial, textureSpaceBasis, decalWorldScale );
// Generate texture coordinates for each vertex in decal s,t space
// probably should pre-generate this, store it and use it for decal-decal collisions
@ -370,7 +340,7 @@ decalvert_t *R_DoDecalSHClip( decalvert_t *pInVerts, decalvert_t *pOutVerts, dec
s = v->m_tCoords[0];
t = v->m_tCoords[1];
if ( (s != 0.0 && s != 1.0) || (t != 0.0 && t != 1.0) )
if (( s != 0.0f && s != 1.0f ) || ( t != 0.0f && t != 1.0f ))
clipped = 1;
}
@ -394,7 +364,7 @@ decalvert_t *R_DecalVertsClip( decalvert_t *pOutVerts, decal_t *pDecal, msurface
vec3_t textureSpaceBasis[3];
// figure out where the decal maps onto the surface.
R_SetupDecalClip( pOutVerts, pDecal, surf->plane->normal, pShader, textureSpaceBasis, decalWorldScale );
R_SetupDecalClip( pOutVerts, pDecal, surf, pShader, textureSpaceBasis, decalWorldScale );
// build the initial list of vertices from the surface verts.
R_SetupDecalVertsForMSurface( pDecal, surf, textureSpaceBasis, g_DecalClipVerts );
@ -431,25 +401,11 @@ static void R_DecalVertsLight( decalvert_t *v, msurface_t *surf, int vertCount )
static decalvert_t* R_DecalVertsNoclip( decal_t *pdecal, msurface_t *surf, ref_shader_t *pShader )
{
decalcache_t *pCache;
decalvert_t *vlist;
int decalIndex;
int outCount;
decalIndex = R_DecalIndex( pdecal );
pCache = R_DecalCacheSlot( decalIndex );
// Is the decal cached?
if ( pCache->decalIndex == decalIndex )
{
return &pCache->decalVert[0];
}
pCache->decalIndex = decalIndex;
vlist = &pCache->decalVert[0];
// use the old code for now, and just cache them
vlist = R_DecalVertsClip( vlist, pdecal, surf, pShader, &outCount );
vlist = R_DecalVertsClip( NULL, pdecal, surf, pShader, &outCount );
R_DecalVertsLight( vlist, surf, 4 );
@ -505,7 +461,7 @@ static decal_t *R_DecalIntersect( decalinfo_t *decalinfo, msurface_t *surf, int
vec2_t vDecalMin, vDecalMax;
vec2_t vUnionMin, vUnionMax;
R_SetupDecalTextureSpaceBasis( pDecal, surf->plane->normal, pShader, testBasis, testWorldScale );
R_SetupDecalTextureSpaceBasis( pDecal, surf, pShader, testBasis, testWorldScale );
VectorSubtract( decalinfo->m_Position, decalExtents[0], testPosition[0] );
VectorSubtract( decalinfo->m_Position, decalExtents[1], testPosition[1] );
@ -551,7 +507,6 @@ static decal_t *R_DecalIntersect( decalinfo_t *decalinfo, msurface_t *surf, int
}
// Add the decal to the surface's list of decals.
// If the surface is a displacement, let the displacement precalculate data for the decal.
static void R_AddDecalToSurface( decal_t *pdecal, msurface_t *surf, decalinfo_t *decalinfo )
{
decal_t *pold;
@ -570,9 +525,12 @@ static void R_AddDecalToSurface( decal_t *pdecal, msurface_t *surf, decalinfo_t
surf->pdecals = pdecal;
}
// Tag surface
// tag surface
pdecal->psurf = surf;
pdecal->m_Size = decalinfo->m_Size;
// at this point decal are linked with surface
// and will be culled, drawing and sorting
// together with surface
}
static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, float y )
@ -608,16 +566,13 @@ static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, fl
pdecal->entityIndex = decalinfo->m_Entity;
// Get dynamic information from the material (fade start, fade time)
/*
// pseudo-code for future expansions
if( shader->decalFadeTime )
if( decalinfo->m_flFadeDuration != 0.0f )
{
pdecal->flags |= FDECAL_DYNAMIC;
pdecal->fadeStartTime = RI.refdef.time + RANDOM_LONG( shader->decalTime / 2, shader->decalTime );
pdecal->fadeDuration = decalinfo->m_flFadeDuration;
pdecal->fadeStartTime = decalinfo->m_flFadeTime;
pdecal->fadeStartTime += RI.refdef.time;
}
*/
// Is this a second-pass decal?
// if( shader->decalSecondPass ) pdecal->flags |= FDECAL_SECONDPASS;
// check to see if the decal actually intersects the surface
// if not, then remove the decal
@ -629,8 +584,6 @@ static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, fl
return;
}
Msg( "R_AddDecalToSurface( %i verts )\n", vertCount );
// add to the surface's list
R_AddDecalToSurface( pdecal, surf, decalinfo );
}
@ -657,7 +610,7 @@ void R_DecalSurface( msurface_t *surf, decalinfo_t *decalinfo )
if( decalinfo->m_Flags & FDECAL_USESAXIS )
sAxis = decalinfo->m_SAxis;
R_DecalComputeBasis( surf->plane->normal, sAxis, decalinfo->m_Basis );
R_DecalComputeBasis( surf, sAxis, decalinfo->m_Basis );
// Compute an effective width and height (axis aligned) in the parent texture space
// How does this work? decalBasis[0] represents the u-direction (width)
@ -703,43 +656,14 @@ static void R_DecalNodeSurfaces( mnode_t* node, decalinfo_t *decalinfo )
for( i = 0, surf = node->firstface; i < node->numfaces; i++, surf++ )
{
// If this is a water decal, ONLY decal water, reject other surfaces
if( decalinfo->m_Flags & FDECAL_WATER )
{
if(!( surf->flags & SURF_DRAWTURB ))
continue;
}
// never apply decals on the water or sky surfaces
if( surf->flags & (SURF_DRAWTURB|SURF_DRAWSKY))
continue;
R_DecalSurface( surf, decalinfo );
}
}
void R_DecalLeaf( mleaf_t *pleaf, decalinfo_t *decalinfo )
{
msurface_t **mark, *surf;
int i;
for( i = 0, mark = pleaf->firstMarkSurface; i < pleaf->numMarkSurfaces; i++, mark++ )
{
float dist;
surf = *mark;
// If this is a water decal, ONLY decal water, reject other surfaces
if( decalinfo->m_Flags & FDECAL_WATER )
{
if(!( surf->flags & SURF_DRAWTURB ))
continue;
}
dist = fabs( DotProduct( decalinfo->m_Position, surf->plane->normal ) - surf->plane->dist );
if( dist < DECAL_DISTANCE )
{
R_DecalSurface( surf, decalinfo );
}
}
}
//-----------------------------------------------------------------------------
// Recursive routine to find surface to apply a decal to. World coordinates of
// the decal are passed in r_recalpos like the rest of the engine. This should
@ -750,12 +674,11 @@ static void R_DecalNode( mnode_t *node, decalinfo_t *decalinfo )
cplane_t *splitplane;
float dist;
if( !node ) return;
Com_Assert( node == NULL );
if( !node->plane )
{
// hit a leaf
R_DecalLeaf(( mleaf_t *)node, decalinfo );
return;
}
@ -789,7 +712,7 @@ static void R_DecalNode( mnode_t *node, decalinfo_t *decalinfo )
}
// Shoots a decal onto the surface of the BSP. position is the center of the decal in world coords
static void R_DecalShoot_( ref_shader_t *shader, int entity, ref_model_t *model, vec3_t pos, vec3_t saxis, int flags, rgba_t color )
static void R_DecalShoot_( ref_shader_t *shader, int entity, ref_model_t *model, vec3_t pos, vec3_t saxis, int flags, rgba_t color, float fadeTime, float fadeDuration )
{
decalinfo_t decalInfo;
mbrushmodel_t *bmodel;
@ -807,10 +730,43 @@ static void R_DecalShoot_( ref_shader_t *shader, int entity, ref_model_t *model,
return;
}
VectorCopy( pos, decalInfo.m_Position ); // pass position in global
decalInfo.m_pModel = model;
if( model ) decalInfo.m_pModel = model;
else decalInfo.m_pModel = NULL;
if( model->type == mod_brush )
{
edict_t *ent = ri.GetClientEdict( entity );
vec3_t pos_l;
if( ent && !ent->free )
{
// transform decal position in local bmodel space
VectorSubtract( pos, ent->v.origin, pos_l );
if( !VectorIsNull( ent->v.angles ))
{
vec3_t temp, forward, right, up;
VectorCopy( ent->v.angles, temp );
AngleVectors( temp, forward, right, up );
VectorCopy( pos_l, temp );
pos_l[0] = DotProduct( temp, forward );
pos_l[1] = -DotProduct( temp, right );
pos_l[2] = DotProduct( temp, up );
}
VectorCopy( pos_l, decalInfo.m_Position );
}
else
{
// give untransformed pos
VectorCopy( pos, decalInfo.m_Position );
}
}
else
{
// pass position in global
VectorCopy( pos, decalInfo.m_Position );
}
// deal with the s axis if one was passed in
if( saxis )
@ -822,6 +778,9 @@ static void R_DecalShoot_( ref_shader_t *shader, int entity, ref_model_t *model,
// more state used by R_DecalNode()
decalInfo.m_pShader = shader;
decalInfo.m_flFadeTime = fadeTime;
decalInfo.m_flFadeDuration = fadeDuration;
// don't optimize custom decals
if(!( flags & FDECAL_CUSTOM ))
flags |= FDECAL_CLIPTEST;
@ -838,7 +797,7 @@ static void R_DecalShoot_( ref_shader_t *shader, int entity, ref_model_t *model,
// compute the decal dimensions in world space
decalInfo.m_decalWidth = shader->stages[0].textures[0]->srcWidth / decalInfo.m_scale;
decalInfo.m_decalHeight = shader->stages[0].textures[0]->srcHeight / decalInfo.m_scale;
Vector4Copy( color, decalInfo.m_Color );
if( color ) Vector4Copy( color, decalInfo.m_Color );
bmodel = (mbrushmodel_t *)decalInfo.m_pModel->extradata;
pnodes = bmodel->firstmodelnode;
@ -846,7 +805,7 @@ static void R_DecalShoot_( ref_shader_t *shader, int entity, ref_model_t *model,
R_DecalNode( pnodes, &decalInfo );
}
bool R_DecalShoot( shader_t texture, int entity, model_t modelIndex, vec3_t pos, vec3_t saxis, int flags, rgba_t color )
bool R_DecalShoot( shader_t texture, int entityIndex, model_t modelIndex, vec3_t pos, vec3_t saxis, int flags, rgba_t color, float fadeTime, float fadeDuration )
{
ref_shader_t *shader;
ref_model_t *model;
@ -860,15 +819,16 @@ bool R_DecalShoot( shader_t texture, int entity, model_t modelIndex, vec3_t pos,
model = r_worldmodel;
else model = cl_models[modelIndex];
R_DecalShoot_( shader, entity, model, pos, saxis, flags, color );
R_DecalShoot_( shader, entityIndex, model, pos, saxis, flags, color, fadeTime, fadeDuration );
return true;
}
void R_AddSurfaceDecals( msurface_t *surf )
{
decal_t *plist;
decal_t *plist;
meshbuffer_t *mb;
Com_Assert( surf == NULL );
plist = surf->pdecals;
@ -877,15 +837,11 @@ void R_AddSurfaceDecals( msurface_t *surf )
{
// Store off the next pointer, DecalUpdateAndDrawSingle could unlink
decal_t *pnext = plist->pnext;
if( r_numDecals >= MAX_DECALS )
{
MsgDev( D_ERROR, "R_AddSurfaceDecals: too many decals\n" );
break;
}
int decalNum = -((signed int)(plist - gDecalPool) + 1);
// add decals into list
r_drawdecals[r_numDecals++] = plist;
mb = R_AddMeshToList( MB_DECAL, surf->fog, plist->shader, decalNum );
if( mb ) mb->sortkey |= (( surf->superLightStyle+1 ) << 10 );
plist = pnext;
}
}
@ -906,7 +862,7 @@ bool DecalUpdate( decal_t *pDecal )
// Build the vertex list for a decal on a surface and clip it to the surface.
// This is a template so it can work on world surfaces and dynamic displacement
// triangles the same way.
decalvert_t* R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, ref_shader_t *pShader, int *outCount )
decalvert_t *R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, ref_shader_t *pShader, int *outCount )
{
decalvert_t *v;
@ -923,6 +879,113 @@ decalvert_t* R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, ref_shader_t
return v;
}
/*
====================
R_BuildMeshForDecal
creates mesh for decal on first rendering
====================
*/
mesh_t *R_BuildMeshForDecal( decal_t *pDecal )
{
decalvert_t *v;
uint index, bufSize;
bool createSTverts = false;
int i, numVerts, numElems;
byte *buffer;
vec3_t normal;
mesh_t *mesh;
if( pDecal->mesh )
{
// already have mesh
return pDecal->mesh;
}
// first rendering? create mesh for it
v = R_DecalSetupVerts( pDecal, pDecal->psurf, pDecal->shader, &numVerts );
// degenerate polygon
if( !numVerts ) return NULL;
// allocate mesh
numElems = (numVerts - 2) * 3;
if( mapConfig.deluxeMappingEnabled || ( pDecal->shader->flags & SHADER_PORTAL_CAPTURE2 ))
createSTverts = true;
// mesh + ( align vertex, align normal, (st + lmst) + elem * numElems) * numVerts;
bufSize = sizeof( mesh_t ) + numVerts * ( sizeof( vec4_t ) + sizeof( vec4_t ) + sizeof( vec4_t )) + numElems * sizeof( elem_t );
if( createSTverts ) bufSize += numVerts * sizeof( vec4_t );
buffer = Mem_Alloc( r_decalPool, bufSize );
mesh = (mesh_t *)buffer;
buffer += sizeof( mesh_t );
mesh->numVerts = numVerts;
mesh->numElems = numElems;
// setup pointers
mesh->vertexArray = (vec4_t *)buffer;
buffer += numVerts * sizeof( vec4_t );
mesh->normalsArray = (vec4_t *)buffer;
buffer += numVerts * sizeof( vec4_t );
mesh->stCoordArray = (vec2_t *)buffer;
buffer += numVerts * sizeof( vec2_t );
mesh->lmCoordArray = (vec2_t *)buffer;
buffer += numVerts * sizeof( vec2_t );
mesh->elems = (elem_t *)buffer;
buffer += numElems * sizeof( elem_t );
// create indices
for( i = 0, index = 2; i < mesh->numElems; i += 3, index++ )
{
mesh->elems[i+0] = 0;
mesh->elems[i+1] = index - 1;
mesh->elems[i+2] = index;
}
// setup normal
if( pDecal->psurf->flags & SURF_PLANEBACK )
VectorNegate( pDecal->psurf->plane->normal, normal );
else VectorCopy( pDecal->psurf->plane->normal, normal );
VectorNormalize( normal );
// create vertices
mesh->numVerts = numVerts;
for( i = 0; i < numVerts; i++, v++ )
{
VectorCopy( v->m_vPos, mesh->vertexArray[i] );
VectorCopy( normal, mesh->normalsArray[i] );
Vector2Copy( v->m_tCoords, mesh->stCoordArray[i] );
Vector2Copy( v->m_LMCoords, mesh->lmCoordArray[i] );
}
if( createSTverts )
{
mesh->sVectorsArray = (vec4_t *)buffer;
buffer += numVerts * sizeof( vec4_t );
R_BuildTangentVectors( mesh->numVerts, mesh->vertexArray, mesh->normalsArray, mesh->stCoordArray, mesh->numElems / 3, mesh->elems, mesh->sVectorsArray );
}
return mesh;
}
decal_t *R_DecalFromMeshbuf( const meshbuffer_t *mb )
{
decal_t *pDecal;
pDecal = &gDecalPool[-mb->infokey-1];
// in case we compare two meshes for batching
if( !pDecal->mesh )
pDecal->mesh = R_BuildMeshForDecal( pDecal );
return pDecal;
}
/*
=================
R_PushDecal
@ -933,83 +996,169 @@ void R_PushDecal( const meshbuffer_t *mb )
decal_t *pDecal;
ref_shader_t *shader;
bool retire = false;
int i, outCount, features;
decalvert_t *v;
int features;
MB_NUM2SHADER( mb->shaderkey, shader );
pDecal = r_drawdecals[-mb->infokey-1];
Com_Assert( pDecal == NULL );
if( !pDecal->shader )
return;
pDecal = &gDecalPool[-mb->infokey-1];
// update dynamic decals
if( pDecal->flags & FDECAL_DYNAMIC )
retire = DecalUpdate( pDecal );
v = R_DecalSetupVerts( pDecal, pDecal->psurf, pDecal->shader, &outCount );
if( !outCount ) return; // nothing to draw
if( retire ) R_DecalUnlink( pDecal );
features = ( shader->features|MF_TRIFAN );
decal_mesh.numVerts = outCount;
decal_mesh.vertexArray = inVertsArray;
decal_mesh.normalsArray = inNormalsArray;
decal_mesh.stCoordArray = inCoordsArray;
decal_mesh.colorsArray = inColorsArray;
decal_mesh.lmCoordArray = inLightmapCoordsArray;
for( i = 0; i < outCount; i++, v++ )
if( !pDecal->mesh )
{
Vector4Copy( v->m_vPos, inVertsArray[r_backacc.numVerts+i] );
Vector4Copy( pDecal->color, inColorsArray[r_backacc.numVerts+i] );
Vector2Copy( v->m_tCoords, inCoordsArray[r_backacc.numVerts+i] );
Vector2Copy( v->m_LMCoords, inLightmapCoordsArray[r_backacc.numVerts+i] );
Vector4Set( inNormalsArray[r_backacc.numVerts+i], 0.0f, 0.0f, 1.0f, 1.0f );
// first draw? create mesh for it
pDecal->mesh = R_BuildMeshForDecal( pDecal );
}
R_PushMesh( &decal_mesh, features );
if( !pDecal->mesh || retire )
{
// invalid or expired decal, unlink it
R_DecalUnlink( pDecal );
return;
}
features = shader->features;
// Deal with fading out... (should this be done in the shader?)
// Note that we do it with per-vertex color even though the translucency
// is constant so as to not change any rendering state (like the constant
// alpha value)
if( pDecal->flags & FDECAL_DYNAMIC )
{
float fadeval;
rgba_t color;
Vector4Copy( pDecal->color, color );
// negative fadeDuration value means to fade in
if( pDecal->fadeDuration < 0 )
{
fadeval = -( RI.refdef.time - pDecal->fadeStartTime ) / pDecal->fadeDuration;
}
else
{
fadeval = 1.0f - ( RI.refdef.time - pDecal->fadeStartTime ) / pDecal->fadeDuration;
}
color[3] = bound( 0, (byte)(fadeval * 255), 255 );
// FIXME: apply custom color to decal
}
R_PushMesh( pDecal->mesh, features );
}
/*
================
R_AddDecalsToList
=============================================================
list contain only decals that passed culling
================
DECALS SERIALIZATION
=============================================================
*/
void R_AddDecalsToList( void )
static bool R_DecalUnProject( decal_t *pdecal, decallist_t *entry )
{
decal_t *decal;
meshbuffer_t *mb;
int i;
if( !pdecal || !( pdecal->psurf ))
return false;
RI.currententity = r_worldent;
RI.currentmodel = r_worldmodel;
for( i = 0; i < r_numDecals; i++ )
{
decal = r_drawdecals[i];
Com_Assert( decal == NULL );
Com_Assert( decal->shader == NULL );
mb = R_AddMeshToList( MB_DECAL, NULL, decal->shader, -((signed int)i + 1 ));
// if( mb ) mb->lastPoly = i;
}
VectorCopy( pdecal->position, entry->position );
entry->entityIndex = pdecal->entityIndex;
// Grab surface plane equation
VectorCopy( pdecal->psurf->plane->normal, entry->impactPlaneNormal );
return true;
}
void R_DrawSingleDecal( const meshbuffer_t *mb )
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pList -
// count -
// Output : static int
//-----------------------------------------------------------------------------
static int DecalListAdd( decallist_t *pList, int count )
{
RI.currententity = r_worldent;
RI.currentmodel = r_worldmodel;
vec3_t tmp;
decallist_t *pdecal;
int i;
// decals are already batched at this point
R_PushDecal( mb );
pdecal = pList + count;
if( RI.previousentity != RI.currententity )
R_LoadIdentity();
R_RenderMeshBuffer( mb );
for( i = 0; i < count; i++ )
{
if( !com.strcmp( pdecal->name, pList[i].name ) && pdecal->entityIndex == pList[i].entityIndex )
{
VectorSubtract( pdecal->position, pList[i].position, tmp ); // Merge
if( VectorLength( tmp ) < 2 )
{
// UNDONE: Tune this '2' constant
return count;
}
}
}
// this is a new decal
return count + 1;
}
static int DecalDepthCompare( const void *a, const void *b )
{
const decallist_t *elem1, *elem2;
elem1 = (const decallist_t *)a;
elem2 = (const decallist_t *)b;
if ( elem1->depth > elem2->depth )
return -1;
if ( elem1->depth < elem2->depth )
return 1;
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Called by CSaveRestore::SaveClientState
// Input : *pList -
// Output : int
//-----------------------------------------------------------------------------
int R_CreateDecalList( decallist_t *pList )
{
int total = 0;
int i, depth;
if( r_worldmodel && !( RI.refdef.flags & RDF_NOWORLDMODEL ))
{
for( i = 0; i < MAX_DECALS; i++ )
{
decal_t *decal = &gDecalPool[i];
decal_t *pdecals;
// decal is in use and is not a custom decal
if( decal->psurf == NULL || (decal->flags & ( FDECAL_CUSTOM|FDECAL_DONTSAVE )))
continue;
// compute depth
depth = 0;
pdecals = decal->psurf->pdecals;
while( pdecals && pdecals != decal )
{
depth++;
pdecals = pdecals->pnext;
}
pList[total].depth = depth;
pList[total].flags = decal->flags;
R_DecalUnProject( decal, &pList[total] );
com.strncpy( pList[total].name, decal->shader->name, sizeof( pList[total].name ));
// check to see if the decal should be added
total = DecalListAdd( pList, total );
}
}
// sort the decals lowest depth first, so they can be re-applied in order
qsort( pList, total, sizeof( decallist_t ), DecalDepthCompare );
return total;
}

View File

@ -44,7 +44,7 @@ extern byte *r_temppool;
#define Host_Error com.error
typedef unsigned int elem_t;
typedef enum { RT_NONE, RT_MODEL, RT_SPRITE, RT_PORTALSURFACE, NUM_RTYPES } refEntityType_t;
typedef enum { RT_NONE, RT_MODEL, RT_PORTALSURFACE, NUM_RTYPES } refEntityType_t;
/*
skins will be outline flood filled and mip mapped
@ -321,9 +321,6 @@ extern ref_entity_t r_entities[MAX_ENTITIES];
extern uint r_numDlights;
extern ref_dlight_t r_dlights[MAX_DLIGHTS];
extern uint r_numDecals;
extern decal_t *r_drawdecals[MAX_DECALS];
extern uint r_numPolys;
extern poly_t r_polys[MAX_POLYS];
@ -708,17 +705,20 @@ void R_ProgramDump_f( void );
// r_decals.c
//
bool R_DecalShoot( shader_t texture, int entity, model_t modelIndex, vec3_t pos, vec3_t saxis, int flags, rgba_t color );
void R_InitDecals( void );
void R_ClearDecals( void );
void R_ShutdownDecals( void );
bool R_DecalShoot( shader_t texture, int entity, model_t modelIndex, vec3_t pos, vec3_t saxis, int flags, rgba_t color, float fadeTime, float fadeDuration );
decal_t *R_DecalFromMeshbuf( const meshbuffer_t *mb );
int R_CreateDecalList( decallist_t *pList );
void R_AddSurfaceDecals( msurface_t *surf );
void R_DrawSingleDecal( const meshbuffer_t *mb );
void R_AddDecalsToList( void );
void R_PushDecal( const meshbuffer_t *mb );
//
// r_poly.c
//
void R_PushPoly( const meshbuffer_t *mb );
void R_AddPolysToList( void );
int R_GetClippedFragments( const vec3_t origin, float radius, vec3_t axis[3], int maxfverts, vec3_t *fverts, int maxfragments, fragment_t *fragments );
msurface_t *R_TransformedTraceLine( trace_t *tr, const vec3_t start, const vec3_t end, ref_entity_t *test );
//

View File

@ -728,29 +728,6 @@ static void R_AddSpriteModelToList( ref_entity_t *e )
if( mb ) mb->shaderkey |= ( bound( 1, 0x4000 - (uint)dist, 0x4000 - 1 )<<12 );
}
/*
=================
R_AddSpritePolyToList
=================
*/
static void R_AddSpritePolyToList( ref_entity_t *e )
{
float dist;
meshbuffer_t *mb;
dist = (e->origin[0] - RI.refdef.vieworg[0]) * RI.vpn[0] + (e->origin[1] - RI.refdef.vieworg[1]) * RI.vpn[1] + (e->origin[2] - RI.refdef.vieworg[2]) * RI.vpn[2];
if( dist < 0 ) return; // cull it because we don't want to sort unneeded things
if( RI.refdef.flags & ( RDF_PORTALINVIEW|RDF_SKYPORTALINVIEW ) || ( RI.params & RP_SKYPORTALVIEW ) )
{
if( R_VisCullSphere( e->origin, e->radius ) )
return;
}
mb = R_AddMeshToList( MB_SPRITE, R_FogForSphere( e->origin, e->radius ), e->customShader, -1 );
if( mb ) mb->shaderkey |= ( bound( 1, 0x4000 - (unsigned int)dist, 0x4000 - 1 ) << 12 );
}
/*
=================
R_SpriteOverflow
@ -1337,9 +1314,6 @@ static void R_CullEntities( void )
default: break;
}
break;
case RT_SPRITE:
culled = ( e->radius <= 0 ) || ( e->customShader == NULL );
break;
case RT_NONE:
default: break;
}
@ -1438,10 +1412,6 @@ add:
default: break;
}
break;
case RT_SPRITE:
if( !shadowmap )
R_AddSpritePolyToList( e );
break;
case RT_NONE:
default: break;
}
@ -1621,8 +1591,6 @@ void R_RenderView( const ref_params_t *fd )
R_AddPolysToList();
R_AddDecalsToList();
if( r_speeds->integer )
r_add_polys += ( Sys_DoubleTime() - starttime );
}
@ -1791,7 +1759,6 @@ void R_ClearScene( void )
{
r_numEntities = 1; // worldmodel
r_numDlights = 0;
r_numDecals = 0;
r_numPolys = 0;
RI.previousentity = NULL;
RI.currententity = r_worldent;
@ -2740,10 +2707,10 @@ render_exp_t DLLEXPORT *CreateAPI(stdlib_api_t *input, render_imp_t *engfuncs )
re.DrawStretchRaw = R_DrawStretchRaw;
re.DrawStretchPic = R_DrawStretchPic;
re.GetSpriteTexture = R_GetSpriteTexture;
re.GetFragments = R_GetClippedFragments;
re.ScreenToWorld = R_ScreenToWorld;
re.WorldToScreen = R_WorldToScreen;
re.RSpeedsMessage = R_SpeedsMessage;
re.CreateDecalList = R_CreateDecalList;
re.CullBox = Mod_CullBox;
re.Support = GL_Support;
re.GetCurrentVis = Mod_GetCurrentVis;

View File

@ -406,6 +406,7 @@ static void R_BatchMeshBuffer( const meshbuffer_t *mb, const meshbuffer_t *nextm
int type, features;
bool nonMergable;
msurface_t *surf, *nextSurf;
decal_t *decal, *nextDecal;
ref_shader_t *shader;
ref_entity_t *ent;
@ -491,7 +492,6 @@ static void R_BatchMeshBuffer( const meshbuffer_t *mb, const meshbuffer_t *nextm
break;
}
break;
case MB_SPRITE:
case MB_CORONA:
nonMergable = R_PushSpritePoly( mb );
if( nonMergable || !nextmb || (( nextmb->shaderkey & 0xFC000FFF ) != ( mb->shaderkey & 0xFC000FFF ))
@ -518,7 +518,44 @@ static void R_BatchMeshBuffer( const meshbuffer_t *mb, const meshbuffer_t *nextm
R_RenderMeshBuffer( mb );
break;
case MB_DECAL:
R_DrawSingleDecal( mb );
MB_NUM2SHADER( mb->shaderkey, shader );
features = shader->features;
if( r_shownormals->integer )
features |= MF_NORMALS;
nextDecal = NULL;
decal = R_DecalFromMeshbuf( mb );
if( features & MF_NONBATCHED )
{
nonMergable = true;
}
else
{ // check if we need to render batched geometry this frame
if( nextmb
&& ( nextmb->shaderkey == mb->shaderkey )
&& ( nextmb->sortkey == mb->sortkey )
&& ( nextmb->dlightbits == mb->dlightbits )
&& ( nextmb->shadowbits == mb->shadowbits ))
{
if(( nextmb->sortkey & 3 ) == MB_DECAL )
nextDecal = R_DecalFromMeshbuf( nextmb );
}
nonMergable = nextDecal ? R_MeshOverflow2( decal->mesh, nextDecal->mesh ) : true;
if( nonMergable && !r_backacc.numVerts )
features |= MF_NONBATCHED;
}
R_PushDecal( mb );
if( nonMergable )
{
if( RI.previousentity != RI.currententity )
R_RotateForEntity( RI.currententity );
R_RenderMeshBuffer( mb );
}
break;
}
}

View File

@ -28,11 +28,10 @@ enum
enum
{
MB_MODEL,
MB_SPRITE,
MB_POLY,
MB_DECAL,
MB_CORONA,
MB_MAXTYPES = 5
MB_MAXTYPES = 4
};
typedef struct mesh_s

View File

@ -377,6 +377,16 @@ static void Mod_UpdateShaders( ref_model_t *mod )
if( !mod || !mod->name )
return;
if( mod->type == mod_world || mod->type == mod_brush )
{
mbrushmodel_t *bmodel;
// clearing all linked decals here
bmodel = (mbrushmodel_t *)mod->extradata;
for( i = 0; i < bmodel->numsurfaces; i++ )
bmodel->surfaces[i].pdecals = NULL;
}
for( i = 0; i < mod->numshaders; i++ )
{
shader = mod->shaders[i];

View File

@ -58,14 +58,6 @@ typedef struct
cplane_t *planes;
} mfog_t;
typedef struct
{
vec4_t m_vPos;
vec2_t m_tCoords; // these are the texcoords for the decal itself
vec2_t m_LMCoords; // lightmap texcoords for the decal.
// FIXME: adds the lightmapnum here ?
} decalvert_t;
typedef struct decal_s
{
struct decal_s *pnext; // linked list for each surface
@ -74,16 +66,13 @@ typedef struct decal_s
vec3_t position; // location of the decal center in world space.
vec3_t saxis; // direction of the s axis in world space
float dx; // Offsets into surface texture
float dy;
float dx, dy; // Offsets into surface texture
float scale; // pixel scale
short flags; // decal flags FDECAL_*
short entityIndex; // entity this is attached to
int m_Size; // size of decal, used for rejecting on dispinfo planes
mesh_t *mesh; // cached mesh, created on first decal rendering
// NOTE: The following variables are dynamic variables.
// We could put these into a separate array and reference them
// by index to reduce memory costs of this...
// dynamic decals stuff
float fadeDuration; // Negative value means to fade in
float fadeStartTime;
rgba_t color;

View File

@ -104,346 +104,7 @@ void R_AddPolysToList( void )
//==================================================================================
static int numFragmentVerts;
static int maxFragmentVerts;
static vec3_t *fragmentVerts;
static int numClippedFragments;
static int maxClippedFragments;
static fragment_t *clippedFragments;
static cplane_t fragmentPlanes[6];
static vec3_t fragmentNormal;
static float fragmentDiameterSquared;
static int r_fragmentframecount;
#define MAX_FRAGMENT_VERTS 64
/*
=================
R_WindingClipFragment
This function operates on windings (convex polygons without
any points inside) like triangles, quads, etc. The output is
a convex fragment (polygon, trifan) which the result of clipping
the input winding by six fragment planes.
=================
*/
static bool R_WindingClipFragment( vec3_t *wVerts, int numVerts, msurface_t *surf, vec3_t snorm )
{
int i, j;
int stage, newc, numv;
cplane_t *plane;
bool front;
float *v, *nextv, d;
float dists[MAX_FRAGMENT_VERTS+1];
int sides[MAX_FRAGMENT_VERTS+1];
vec3_t *verts, *newverts, newv[2][MAX_FRAGMENT_VERTS], t;
fragment_t *fr;
numv = numVerts;
verts = wVerts;
for( stage = 0, plane = fragmentPlanes; stage < 6; stage++, plane++ )
{
for( i = 0, v = verts[0], front = false; i < numv; i++, v += 3 )
{
d = PlaneDiff( v, plane );
if( d > ON_EPSILON )
{
front = true;
sides[i] = SIDE_FRONT;
}
else if( d < -ON_EPSILON )
{
sides[i] = SIDE_BACK;
}
else
{
front = true;
sides[i] = SIDE_ON;
}
dists[i] = d;
}
if( !front )
return false;
// clip it
sides[i] = sides[0];
dists[i] = dists[0];
newc = 0;
newverts = newv[stage & 1];
for( i = 0, v = verts[0]; i < numv; i++, v += 3 )
{
switch( sides[i] )
{
case SIDE_FRONT:
if( newc == MAX_FRAGMENT_VERTS )
return false;
VectorCopy( v, newverts[newc] );
newc++;
break;
case SIDE_BACK:
break;
case SIDE_ON:
if( newc == MAX_FRAGMENT_VERTS )
return false;
VectorCopy( v, newverts[newc] );
newc++;
break;
}
if( sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i] )
continue;
if( newc == MAX_FRAGMENT_VERTS )
return false;
d = dists[i] / ( dists[i] - dists[i+1] );
nextv = ( i == numv - 1 ) ? verts[0] : v + 3;
for( j = 0; j < 3; j++ )
newverts[newc][j] = v[j] + d * ( nextv[j] - v[j] );
newc++;
}
if( newc <= 2 )
return false;
// continue with new verts
numv = newc;
verts = newverts;
}
// fully clipped
if( numFragmentVerts + numv > maxFragmentVerts )
return false;
fr = &clippedFragments[numClippedFragments++];
fr->numverts = numv;
fr->firstvert = numFragmentVerts;
fr->fognum = surf->fog ? surf->fog - r_worldbrushmodel->fogs + 1 : -1;
VectorCopy( snorm, fr->normal );
for( i = 0, v = verts[0], nextv = fragmentVerts[numFragmentVerts]; i < numv; i++, v += 3, nextv += 3 )
VectorCopy( v, nextv );
numFragmentVerts += numv;
if( numFragmentVerts == maxFragmentVerts && numClippedFragments == maxClippedFragments )
return true;
// if all of the following is true:
// a) all clipping planes are perpendicular
// b) there are 4 in a clipped fragment
// c) all sides of the fragment are equal (it is a quad)
// d) all sides are radius*2 +- epsilon (0.001)
// then it is safe to assume there's only one fragment possible
// not sure if it's 100% correct, but sounds convincing
if( numv == 4 )
{
for( i = 0, v = verts[0]; i < numv; i++, v += 3 )
{
nextv = ( i == 3 ) ? verts[0] : v + 3;
VectorSubtract( v, nextv, t );
d = fragmentDiameterSquared - DotProduct( t, t );
if( d > 0.01 || d < -0.01 )
return false;
}
return true;
}
return false;
}
/*
=================
R_PlanarSurfClipFragment
NOTE: one might want to combine this function with
R_WindingClipFragment for special cases like trifans (q1 and
q2 polys) or tristrips for ultra-fast clipping, providing there's
enough stack space (depending on MAX_FRAGMENT_VERTS value).
=================
*/
static bool R_PlanarSurfClipFragment( msurface_t *surf, const vec3_t normal )
{
int i;
mesh_t *mesh;
elem_t *elem;
vec4_t *verts;
vec3_t poly[4];
vec3_t dir1, dir2, snorm;
bool planar;
planar = surf->plane && !VectorCompare( surf->plane->normal, vec3_origin );
if( planar )
{
VectorCopy( surf->plane->normal, snorm );
if( DotProduct( normal, snorm ) < 0.5 )
return false; // greater than 60 degrees
}
mesh = surf->mesh;
elem = mesh->elems;
verts = mesh->vertexArray;
// clip each triangle individually
for( i = 0; i < mesh->numElems; i += 3, elem += 3 )
{
VectorCopy( verts[elem[0]], poly[0] );
VectorCopy( verts[elem[1]], poly[1] );
VectorCopy( verts[elem[2]], poly[2] );
if( !planar )
{
// calculate two mostly perpendicular edge directions
VectorSubtract( poly[0], poly[1], dir1 );
VectorSubtract( poly[2], poly[1], dir2 );
// we have two edge directions, we can calculate a third vector from
// them, which is the direction of the triangle normal
CrossProduct( dir1, dir2, snorm );
VectorNormalize( snorm );
// we multiply 0.5 by length of snorm to avoid normalizing
if( DotProduct( normal, snorm ) < 0.5 )
continue; // greater than 60 degrees
}
if( R_WindingClipFragment( poly, 3, surf, snorm ) )
return true;
}
return false;
}
/*
=================
R_RecursiveFragmentNode
=================
*/
static void R_RecursiveFragmentNode( mnode_t *node, const vec3_t origin, const vec3_t normal, float radius )
{
float dist;
cplane_t *plane;
msurface_t *surf;
int i, inside;
if( !node->plane ) return; // hit a leaf
if( numFragmentVerts == maxFragmentVerts || numClippedFragments == maxClippedFragments )
return; // already reached the limit somewhere else
// find which side of the node we are on
plane = node->plane;
if( plane->type < 3 )
dist = origin[plane->type] - plane->dist;
else dist = DotProduct( origin, plane->normal ) - plane->dist;
// go down the appropriate sides
if( dist > radius )
{
R_RecursiveFragmentNode( node->children[0], origin, normal, radius );
return;
}
if( dist < -radius )
{
R_RecursiveFragmentNode( node->children[1], origin, normal, radius );
return;
}
// clip to each surface
surf = node->firstface;
for( i = 0; i < node->numfaces; i++, surf++ )
{
if( numFragmentVerts == maxFragmentVerts || numClippedFragments == maxClippedFragments )
break; // already reached the limit
if( surf->fragmentframe == r_fragmentframecount )
continue; // already checked this surface in another node
surf->fragmentframe = r_fragmentframecount;
if( surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
continue; // don't bother clipping
if( surf->shader->flags & SHADER_NOFRAGMENTS )
continue; // don't bother clipping
if( !BoundsAndSphereIntersect( surf->mins, surf->maxs, origin, radius ))
continue; // no intersection
if(!( surf->flags & SURF_PLANEBACK ))
{
if( DotProduct( normal, surf->plane->normal ) < 0.5f )
continue; // greater than 60 degrees
}
else
{
if( DotProduct( normal, surf->plane->normal ) > -0.5f )
continue; // greater than 60 degrees
}
// clip to the surface
inside = R_PlanarSurfClipFragment( surf, normal );
if( inside ) return;
}
// recurse down the children
R_RecursiveFragmentNode( node->children[0], origin, normal, radius );
R_RecursiveFragmentNode( node->children[1], origin, normal, radius );
}
/*
=================
R_GetClippedFragments
=================
*/
int R_GetClippedFragments( const vec3_t origin, float radius, vec3_t axis[3], int maxfverts, vec3_t *fverts, int maxfragments, fragment_t *fragments )
{
int i;
float d;
if( maxfverts <= 0 || fverts == NULL || maxfragments <= 0 || fragments == NULL )
return 0; // invalid arguments
r_fragmentframecount++;
// initialize fragments
numFragmentVerts = 0;
maxFragmentVerts = maxfverts;
fragmentVerts = fverts;
numClippedFragments = 0;
maxClippedFragments = maxfragments;
clippedFragments = fragments;
fragmentDiameterSquared = radius * radius * 4;
// calculate clipping planes
for( i = 0; i < 3; i++ )
{
d = DotProduct( origin, axis[i] );
VectorCopy( axis[i], fragmentPlanes[i*2].normal );
fragmentPlanes[i*2].dist = d - radius;
fragmentPlanes[i*2].type = PlaneTypeForNormal( fragmentPlanes[i*2].normal );
VectorNegate( axis[i], fragmentPlanes[i*2+1].normal );
fragmentPlanes[i*2+1].dist = -d - radius;
fragmentPlanes[i*2+1].type = PlaneTypeForNormal( fragmentPlanes[i*2+1].normal );
}
// clip against world geometry
R_RecursiveFragmentNode( r_worldbrushmodel->nodes, origin, axis[0], radius );
return numClippedFragments;
}
//==================================================================================
static vec3_t trace_start, trace_end;
static vec3_t trace_absmins, trace_absmaxs;
static float trace_fraction;
@ -689,9 +350,12 @@ msurface_t *R_TransformedTraceLine( trace_t *tr, const vec3_t start, const vec3_
{
if( model->type == mod_world || model->type == mod_brush )
{
mbrushmodel_t *bmodel = ( mbrushmodel_t * )model->extradata;
mbrushmodel_t *bmodel = (mbrushmodel_t *)model->extradata;
vec3_t temp, start_l, end_l, axis[3];
bool rotated = !Matrix3x3_Compare( test->axis, matrix3x3_identity );
vec3_t model_mins, model_maxs;
float v, max = 0.0f;
int i;
// transform
VectorSubtract( start, test->origin, start_l );
@ -702,6 +366,27 @@ msurface_t *R_TransformedTraceLine( trace_t *tr, const vec3_t start, const vec3_
Matrix3x3_Transform( test->axis, temp, start_l );
VectorCopy( end_l, temp );
Matrix3x3_Transform( test->axis, temp, end_l );
// expand mins/maxs for rotation
for( i = 0; i < 3; i++ )
{
v = fabs( model->mins[i] );
if( v > max ) max = v;
v = fabs( model->maxs[i] );
if( v > max ) max = v;
}
for( i = 0; i < 3; i++ )
{
model_mins[i] = test->origin[i] - max;
model_maxs[i] = test->origin[i] + max;
}
}
else
{
VectorAdd( test->origin, model->mins, model_mins );
VectorAdd( test->origin, model->maxs, model_maxs );
}
VectorCopy( start_l, trace_start );
@ -711,7 +396,7 @@ msurface_t *R_TransformedTraceLine( trace_t *tr, const vec3_t start, const vec3_
// just walk the list of surfaces linearly
if( test->model->type == mod_world )
R_RecursiveHullCheck( bmodel->nodes, start_l, end_l );
else if( BoundsIntersect( model->mins, model->maxs, trace_absmins, trace_absmaxs ) )
else if( BoundsIntersect( model_mins, model_maxs, trace_absmins, trace_absmaxs ) )
R_TraceAgainstBmodel( bmodel );
// transform back

View File

@ -1016,6 +1016,7 @@ static void R_InitMedia( void )
R_InitCinematics ();
R_InitShaders();
R_InitModels();
R_InitDecals();
R_InitCoronas();
R_InitShadows();
R_InitOcclusionQueries();
@ -1039,6 +1040,7 @@ static void R_FreeMedia( void )
return;
R_ShutdownOcclusionQueries();
R_ShutdownDecals();
R_ShutdownShadows();
R_ShutdownModels();
R_ShutdownShaders();
@ -1115,7 +1117,9 @@ void R_NewMap( void )
R_InitCustomColors(); // clear custom colors
R_InitCoronas(); // update corona shader (because we can't make it static)
R_StudioFreeAllExtradata(); // free boneposes
R_ClearDecals(); // purge all decals
GL_SetDefaultTexState ();
Mem_Set( &RI, 0, sizeof( refinst_t ));

View File

@ -3413,21 +3413,27 @@ static ref_shader_t *Shader_CreateDefault( ref_shader_t *shader, int type, int a
{
case SHADER_DECAL:
shader->type = SHADER_DECAL;
shader->flags = SHADER_DEPTHWRITE|SHADER_CULL_FRONT|SHADER_POLYGONOFFSET;
shader->features = MF_STCOORDS|MF_COLORS;
shader->flags = SHADER_DEPTHWRITE|SHADER_CULL_FRONT|SHADER_POLYGONOFFSET|SHADER_HASLIGHTMAP;
shader->features = MF_STCOORDS|MF_LMCOORDS;
shader->sort = SORT_DECAL;
shader->num_stages = 1;
shader->num_stages = 2;
shader->name = Shader_Malloc( length + 1 + sizeof( ref_stage_t ) * shader->num_stages );
strcpy( shader->name, shortname );
shader->stages = ( ref_stage_t * )(( byte * )shader->name + length + 1 );
shader->stages = (ref_stage_t *)((byte *)shader->name + length + 1 );
pass = &shader->stages[0];
pass->flags = SHADERSTAGE_BLEND_DECAL;
pass->flags = SHADERSTAGE_BLEND_REPLACE;
pass->glState = GLSTATE_SRCBLEND_SRC_ALPHA|GLSTATE_DSTBLEND_ONE_MINUS_SRC_ALPHA;
pass->tcgen = TCGEN_BASE;
pass->textures[0] = Shader_FindImage( shader, shortname, addFlags );
pass->textures[0] = Shader_FindImage( shader, shortname, TF_CLAMP|addFlags );
pass->rgbGen.type = RGBGEN_IDENTITY_LIGHTING;
pass->alphaGen.type = ALPHAGEN_VERTEX;
pass->alphaGen.type = ALPHAGEN_VERTEX; // for fading decals
pass->num_textures++;
pass = &shader->stages[1];
pass->flags = SHADERSTAGE_LIGHTMAP|SHADERSTAGE_NOCOLORARRAY|SHADERSTAGE_BLEND_REPLACE;
pass->glState = GLSTATE_SRCBLEND_DST_COLOR|GLSTATE_DSTBLEND_ZERO;
pass->tcgen = TCGEN_LIGHTMAP;
pass->rgbGen.type = RGBGEN_IDENTITY;
pass->alphaGen.type = ALPHAGEN_IDENTITY;
break;
case SHADER_FLARE:
shader->type = SHADER_FLARE;