mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-29 07:32:25 +00:00
Merge soft particles from thedarkmod 2.04
don't really work, though
This commit is contained in:
parent
10eee1eb43
commit
41eef54611
12 changed files with 379 additions and 33 deletions
|
@ -409,6 +409,10 @@ idParticleStage *idDeclParticle::ParseParticleStage( idLexer &src ) {
|
|||
stage->gravity = src.ParseFloat();
|
||||
continue;
|
||||
}
|
||||
if ( !token.Icmp( "softeningRadius" ) ) { // #3878 soft particles
|
||||
stage->softeningRadius = src.ParseFloat();
|
||||
continue;
|
||||
}
|
||||
|
||||
src.Error( "unknown token %s\n", token.c_str() );
|
||||
}
|
||||
|
@ -733,6 +737,7 @@ idParticleStage::idParticleStage( void ) {
|
|||
hidden = false;
|
||||
boundsExpansion = 0.0f;
|
||||
bounds.Clear();
|
||||
softeningRadius = -2.0f; // -2 means "auto" - #3878 soft particles
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -806,6 +811,7 @@ void idParticleStage::Default() {
|
|||
randomDistribution = true;
|
||||
entityColor = false;
|
||||
cycleMsec = ( particleLife + deadTime ) * 1000;
|
||||
softeningRadius = -2.0f; // -2 means "auto" - #3878 soft particles
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -193,6 +193,16 @@ public:
|
|||
float boundsExpansion; // user tweak to fix poorly calculated bounds
|
||||
|
||||
idBounds bounds; // derived
|
||||
|
||||
/* Soft particles -- SteveL #3878
|
||||
-2.0 is the value at initialization, meaning no user specification: "auto".
|
||||
-1.0 means no change to old system: suppress soft particles, but allow modelDepthhack if specified.
|
||||
0 means disable all softening for this stage, including modelDepthHack.
|
||||
+ve value means apply soft particle effect, allowing overdraw up to the specified depth.
|
||||
This is more flexible even when not using soft particles, as modelDepthHack
|
||||
can be turned off for specific stages to stop them poking through walls.
|
||||
*/
|
||||
float softeningRadius;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -183,7 +183,8 @@ public:
|
|||
|
||||
void CopyFramebuffer( int x, int y, int width, int height, bool useOversizedBuffer );
|
||||
|
||||
void CopyDepthbuffer( int x, int y, int width, int height );
|
||||
void CopyDepthbuffer( int x, int y, int width, int height, bool useOversizedBuffer );
|
||||
|
||||
|
||||
void UploadScratch( const byte *pic, int width, int height );
|
||||
|
||||
|
@ -417,6 +418,9 @@ public:
|
|||
idImage * specular2DTableImage; // 2D intensity texture with our specular function with variable specularity
|
||||
idImage * borderClampImage; // white inside, black outside
|
||||
|
||||
|
||||
idImage * currentDepthImage; // #3877. Allow shaders to access scene depth
|
||||
|
||||
//--------------------------------------------------------
|
||||
|
||||
idImage * AllocImage( const char *name );
|
||||
|
|
|
@ -1993,6 +1993,7 @@ void idImageManager::Init() {
|
|||
accumImage = ImageFromFunction("_accum", R_RGBA8Image );
|
||||
scratchCubeMapImage = ImageFromFunction("_scratchCubeMap", makeNormalizeVectorCubeMap );
|
||||
currentRenderImage = ImageFromFunction("_currentRender", R_RGBA8Image );
|
||||
currentDepthImage = ImageFromFunction( "_currentDepth", R_RGBA8Image ); // #3877. Allow shaders to access scene depth
|
||||
|
||||
cmdSystem->AddCommand( "reloadImages", R_ReloadImages_f, CMD_FL_RENDERER, "reloads images" );
|
||||
cmdSystem->AddCommand( "listImages", R_ListImages_f, CMD_FL_RENDERER, "lists images" );
|
||||
|
|
|
@ -1898,26 +1898,30 @@ CopyDepthbuffer
|
|||
This should just be part of copyFramebuffer once we have a proper image type field
|
||||
====================
|
||||
*/
|
||||
void idImage::CopyDepthbuffer( int x, int y, int imageWidth, int imageHeight ) {
|
||||
Bind();
|
||||
|
||||
void idImage::CopyDepthbuffer( int x, int y, int imageWidth, int imageHeight, bool useOversizedBuffer )
|
||||
{
|
||||
this->Bind();
|
||||
// if the size isn't a power of 2, the image must be increased in size
|
||||
int potWidth, potHeight;
|
||||
|
||||
potWidth = MakePowerOfTwo( imageWidth );
|
||||
potHeight = MakePowerOfTwo( imageHeight );
|
||||
|
||||
if ( uploadWidth != potWidth || uploadHeight != potHeight ) {
|
||||
GetDownsize( imageWidth, imageHeight );
|
||||
GetDownsize( potWidth, potHeight );
|
||||
// Ensure we are reading from the back buffer:
|
||||
qglReadBuffer( GL_BACK );
|
||||
// only resize if the current dimensions can't hold it at all,
|
||||
// otherwise subview renderings could thrash this
|
||||
if ( ( useOversizedBuffer && ( uploadWidth < potWidth || uploadHeight < potHeight ) ) || ( !useOversizedBuffer && ( uploadWidth != potWidth || uploadHeight != potHeight ) ) )
|
||||
{
|
||||
uploadWidth = potWidth;
|
||||
uploadHeight = potHeight;
|
||||
if ( potWidth == imageWidth && potHeight == imageHeight ) {
|
||||
qglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, x, y, imageWidth, imageHeight, 0 );
|
||||
} else {
|
||||
// we need to create a dummy image with power of two dimensions,
|
||||
// then do a qglCopyTexSubImage2D of the data we want
|
||||
qglTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, potWidth, potHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
|
||||
qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight );
|
||||
}
|
||||
// This bit runs once only at map start, because it tests whether the image is too small to hold the screen.
|
||||
// It resizes the texture to a power of two that can hold the screen,
|
||||
// and then subsequent captures to the texture put the depth component into the RGB channels
|
||||
qglTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24_ARB, potWidth, potHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
|
||||
qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight );
|
||||
|
||||
} else {
|
||||
// otherwise, just subimage upload it so that drivers can tell we are going to be changing
|
||||
// it and don't try and do a texture compression or some other silliness
|
||||
|
|
|
@ -1434,6 +1434,10 @@ void idMaterial::ParseStage( idLexer &src, const textureRepeat_t trpDefault ) {
|
|||
ss->drawStateBits |= GLS_DEPTHMASK;
|
||||
continue;
|
||||
}
|
||||
if ( !token.Icmp( "ignoreDepth" ) ) { // Added in #3877.
|
||||
ss->drawStateBits |= GLS_DEPTHFUNC_ALWAYS;
|
||||
continue;
|
||||
}
|
||||
if ( !token.Icmp( "alphaTest" ) ) {
|
||||
ss->hasAlphaTest = true;
|
||||
ss->alphaTestRegister = ParseExpression( src );
|
||||
|
|
|
@ -302,8 +302,13 @@ public:
|
|||
virtual float DepthHack() const;
|
||||
virtual int Memory() const;
|
||||
|
||||
float SofteningRadius( const int stage ) const; // #3878 soft particles
|
||||
|
||||
private:
|
||||
void SetSofteningRadii(); // #3878 soft particles
|
||||
|
||||
const idDeclParticle * particleSystem;
|
||||
idList<float> softeningRadii; // #3878 soft particles
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -50,6 +50,7 @@ idRenderModelPrt::InitFromFile
|
|||
void idRenderModelPrt::InitFromFile( const char *fileName ) {
|
||||
name = fileName;
|
||||
particleSystem = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, fileName ) );
|
||||
SetSofteningRadii(); // # 3878
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -286,3 +287,64 @@ int idRenderModelPrt::Memory() const {
|
|||
|
||||
return total;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idRenderModelPrt::SetSofteningRadii
|
||||
|
||||
Calculate "depth" of each particle stage that represents a 3d volume, so the particle can
|
||||
be allowed to overdraw solid geometry by the right amount, and the particle "thickness" (visibility)
|
||||
can be adjusted by how much of it is visible in front of the background surface.
|
||||
|
||||
"depth" is by default 0.8 of the particle radius, and particles less than 2 units in size won't be softened.
|
||||
The particles that represent 3d volumes are the view-aligned ones. Others have depth set to 0.
|
||||
|
||||
Cache these values rather than calculate them for each stage every frame.
|
||||
Added for soft particles -- SteveL #3878.
|
||||
====================
|
||||
*/
|
||||
void idRenderModelPrt::SetSofteningRadii()
|
||||
{
|
||||
softeningRadii.AssureSize( particleSystem->stages.Num() );
|
||||
|
||||
for ( int i = 0; i < particleSystem->stages.Num(); ++i )
|
||||
{
|
||||
const idParticleStage* ps = particleSystem->stages[i];
|
||||
if ( ps->softeningRadius > -2.0f ) // User has specified a setting
|
||||
{
|
||||
softeningRadii[i] = ps->softeningRadius;
|
||||
}
|
||||
else if ( ps->orientation == POR_VIEW ) // Only view-aligned particle stages qualify for softening
|
||||
{
|
||||
float diameter = Max( ps->size.from, ps->size.to );
|
||||
float scale = Max( ps->aspect.from, ps->aspect.to );
|
||||
diameter *= Max( scale, 1.0f ); // aspect applies to 1 axis only. If it's < 1, the other axis will still be at scale 1
|
||||
if ( diameter > 2.0f ) // Particle is big enough to soften
|
||||
{
|
||||
softeningRadii[i] = diameter * 0.8f / 2.0f;
|
||||
}
|
||||
else // Particle is small. Disable both softening and modelDepthHack
|
||||
{
|
||||
softeningRadii[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
else // Particle isn't view-aligned, and no user setting. Don't change anything.
|
||||
{
|
||||
softeningRadii[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idRenderModelPrt::SofteningRadius
|
||||
|
||||
Return the max radius of the individual quads that make up this stage.
|
||||
Added for soft particles #3878.
|
||||
====================
|
||||
*/
|
||||
float idRenderModelPrt::SofteningRadius( const int stage ) const {
|
||||
assert( particleSystem );
|
||||
assert( stage > -1 && stage < softeningRadii.Num() );
|
||||
return softeningRadii[stage];
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ void RB_ARB2_DrawInteraction( const drawInteraction_t *din ) {
|
|||
float parm[4];
|
||||
parm[0] = parm[1] = parm[2] = r_brightness.GetFloat();
|
||||
parm[3] = 1.0/r_gamma.GetFloat(); // 1.0/gamma so the shader doesn't have to do this calculation
|
||||
qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 4, parm );
|
||||
qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_GAMMA_BRIGHTNESS, parm );
|
||||
}
|
||||
|
||||
// set the textures
|
||||
|
@ -345,6 +345,10 @@ static progDef_t progs[MAX_GLPROGS] = {
|
|||
{ GL_VERTEX_PROGRAM_ARB, VPROG_GLASSWARP, "arbVP_glasswarp.txt" },
|
||||
{ GL_FRAGMENT_PROGRAM_ARB, FPROG_GLASSWARP, "arbFP_glasswarp.txt" },
|
||||
|
||||
// SteveL #3878: Particle softening applied by the engine
|
||||
{ GL_VERTEX_PROGRAM_ARB, VPROG_SOFT_PARTICLE, "soft_particle.vfp" }, // TODO: can we specify this in C++?
|
||||
{ GL_FRAGMENT_PROGRAM_ARB, FPROG_SOFT_PARTICLE, "soft_particle.vfp" },
|
||||
|
||||
// additional programs can be dynamically specified in materials
|
||||
};
|
||||
|
||||
|
@ -468,10 +472,10 @@ void R_LoadARBProgram( int progIndex ) {
|
|||
// POW might not work with a negative base (it looks wrong with intel's Linux driver)
|
||||
// and clamping values >1 to 1 is ok because when writing to result.color
|
||||
// it's clamped anyway and pow(base, exp) is always >= 1 for base >= 1
|
||||
"MUL_SAT dhewm3tmpres.xyz, program.env[4], dhewm3tmpres;\n" // first multiply with brightness
|
||||
"POW result.color.x, dhewm3tmpres.x, program.env[4].w;\n" // then do pow(dhewm3tmpres.xyz, vec3(1/gamma))
|
||||
"POW result.color.y, dhewm3tmpres.y, program.env[4].w;\n" // (apparently POW only supports scalars, not whole vectors)
|
||||
"POW result.color.z, dhewm3tmpres.z, program.env[4].w;\n"
|
||||
"MUL_SAT dhewm3tmpres.xyz, program.env[21], dhewm3tmpres;\n" // first multiply with brightness
|
||||
"POW result.color.x, dhewm3tmpres.x, program.env[21].w;\n" // then do pow(dhewm3tmpres.xyz, vec3(1/gamma))
|
||||
"POW result.color.y, dhewm3tmpres.y, program.env[21].w;\n" // (apparently POW only supports scalars, not whole vectors)
|
||||
"POW result.color.z, dhewm3tmpres.z, program.env[21].w;\n"
|
||||
"MOV result.color.w, dhewm3tmpres.w;\n" // alpha remains unmodified
|
||||
"\nEND\n\n"; // we add this block right at the end, replacing the original "END" string
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
extern idCVar r_useCarmacksReverse;
|
||||
extern idCVar r_useStencilOpSeparate;
|
||||
|
||||
idCVar r_skipDepthCapture( "r_skipDepthCapture", "0", CVAR_RENDERER | CVAR_BOOL, "skip depth capture" ); // #3877
|
||||
|
||||
/*
|
||||
=====================
|
||||
RB_BakeTextureMatrixIntoTexgen
|
||||
|
@ -313,7 +316,7 @@ void RB_FinishStageTexturing( const shaderStage_t *pStage, const drawSurf_t *sur
|
|||
qglDisable( GL_FRAGMENT_PROGRAM_ARB );
|
||||
qglDisable( GL_VERTEX_PROGRAM_ARB );
|
||||
// Fixme: Hack to get around an apparent bug in ATI drivers. Should remove as soon as it gets fixed.
|
||||
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 );
|
||||
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 ); // FIXME ...
|
||||
} else {
|
||||
qglDisable( GL_TEXTURE_GEN_S );
|
||||
qglDisable( GL_TEXTURE_GEN_T );
|
||||
|
@ -513,6 +516,9 @@ void RB_T_FillDepthBuffer( const drawSurf_t *surf ) {
|
|||
|
||||
}
|
||||
|
||||
|
||||
void RB_SetProgramEnvironment( bool isPostProcess ); // so RB_STD_FillDepthBuffer() can use it
|
||||
|
||||
/*
|
||||
=====================
|
||||
RB_STD_FillDepthBuffer
|
||||
|
@ -553,6 +559,19 @@ void RB_STD_FillDepthBuffer( drawSurf_t **drawSurfs, int numDrawSurfs ) {
|
|||
|
||||
RB_RenderDrawSurfListWithFunction( drawSurfs, numDrawSurfs, RB_T_FillDepthBuffer );
|
||||
|
||||
// Make the early depth pass available to shaders. #3877
|
||||
if ( backEnd.viewDef->renderView.viewID >= 0 // Suppress for lightgem rendering passes
|
||||
&& !r_skipDepthCapture.GetBool() )
|
||||
{
|
||||
globalImages->currentDepthImage->CopyDepthbuffer( backEnd.viewDef->viewport.x1,
|
||||
backEnd.viewDef->viewport.y1,
|
||||
backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1,
|
||||
backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1,
|
||||
true );
|
||||
bool isPostProcess = false; // TODO
|
||||
RB_SetProgramEnvironment( isPostProcess );
|
||||
}
|
||||
|
||||
if ( backEnd.viewDef->numClipPlanes ) {
|
||||
GL_SelectTexture( 1 );
|
||||
globalImages->BindNull();
|
||||
|
@ -575,6 +594,19 @@ SHADER PASSES
|
|||
RB_SetProgramEnvironment
|
||||
|
||||
Sets variables that can be used by all vertex programs
|
||||
|
||||
[SteveL #3877] Note on the use of fragment program environmental variables.
|
||||
Parameters 0 and 1 are set here to allow conversion of screen coordinates to
|
||||
texture coordinates, for use when sampling _currentRender.
|
||||
Those same parameters 0 and 1, plus 2 and 3, are given entirely different
|
||||
meanings in draw_arb2.cpp while light interactions are being drawn.
|
||||
This function is called again before currentRender size is needed by post processing
|
||||
effects are done, so there's no clash.
|
||||
// TODO: I'm using 4 for gamma in shaders, so the following shit must be incremented by 1
|
||||
Only parameters 0..3 were in use before #3877 - and in dhewm3 also 4, for gamma in shader.
|
||||
Now I've used a new parameter 5 for the size of _currentDepth. It's needed throughout,
|
||||
including by light interactions, and its size might in theory differ from _currentRender.
|
||||
Parameters 6 and 7 are used by soft particles #3878. Note these can be freely reused by different draw calls.
|
||||
==================
|
||||
*/
|
||||
void RB_SetProgramEnvironment( bool isPostProcess ) {
|
||||
|
@ -643,9 +675,23 @@ void RB_SetProgramEnvironment( bool isPostProcess ) {
|
|||
// (setting them to 1.0 makes them no-ops)
|
||||
parm[0] = parm[1] = parm[2] = parm[3] = 1.0f;
|
||||
}
|
||||
qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 4, parm );
|
||||
qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_GAMMA_BRIGHTNESS, parm );
|
||||
}
|
||||
|
||||
// #3877: Allow shaders to access depth buffer.
|
||||
// Two useful ratios are packed into this parm: [0] and [1] hold the x,y multipliers you need to map a screen
|
||||
// coordinate (fragment position) to the depth image: those are simply the reciprocal of the depth
|
||||
// image size, which has been rounded up to a power of two. Slots [3] and [4] hold the ratio of the depth image
|
||||
// size to the current render image size. These sizes can differ if the game crops the render viewport temporarily
|
||||
// during post-processing effects. The depth render is smaller during the effect too, but the depth image doesn't
|
||||
// need to be downsized, whereas the current render image does get downsized when it's captured by the game after
|
||||
// the skybox render pass. The ratio is needed to map between the two render images.
|
||||
parm[0] = 1.0f / globalImages->currentDepthImage->uploadWidth;
|
||||
parm[1] = 1.0f / globalImages->currentDepthImage->uploadHeight;
|
||||
parm[2] = static_cast<float>(globalImages->currentRenderImage->uploadWidth) / globalImages->currentDepthImage->uploadWidth;
|
||||
parm[3] = static_cast<float>(globalImages->currentRenderImage->uploadHeight) / globalImages->currentDepthImage->uploadHeight;
|
||||
qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_CURDEPTH_RECIPR, parm );
|
||||
|
||||
//
|
||||
// set eye position in global space
|
||||
//
|
||||
|
@ -654,8 +700,6 @@ void RB_SetProgramEnvironment( bool isPostProcess ) {
|
|||
parm[2] = backEnd.viewDef->renderView.vieworg[2];
|
||||
parm[3] = 1.0;
|
||||
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 1, parm );
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -749,6 +793,9 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
return;
|
||||
}
|
||||
|
||||
// check whether we're drawing a soft particle surface #3878
|
||||
const bool soft_particle = ( surf->dsFlags & DSF_SOFT_PARTICLE ) != 0;
|
||||
|
||||
// get the expressions for conditionals / color / texcoords
|
||||
regs = surf->shaderRegisters;
|
||||
|
||||
|
@ -765,7 +812,8 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
RB_EnterWeaponDepthHack();
|
||||
}
|
||||
|
||||
if ( surf->space->modelDepthHack != 0.0f ) {
|
||||
if ( surf->space->modelDepthHack != 0.0f && !soft_particle ) // #3878 soft particles don't want modelDepthHack, which is
|
||||
{ // an older way to slightly "soften" particles
|
||||
RB_EnterModelDepthHack( surf->space->modelDepthHack );
|
||||
}
|
||||
|
||||
|
@ -791,6 +839,9 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// determine the blend mode (used by soft particles #3878)
|
||||
const int src_blend = pStage->drawStateBits & GLS_SRCBLEND_BITS;
|
||||
|
||||
// see if we are a new-style stage
|
||||
newShaderStage_t *newStage = pStage->newStage;
|
||||
if ( newStage ) {
|
||||
|
@ -866,7 +917,7 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
qglDisable( GL_VERTEX_PROGRAM_ARB );
|
||||
qglDisable( GL_FRAGMENT_PROGRAM_ARB );
|
||||
// Fixme: Hack to get around an apparent bug in ATI drivers. Should remove as soon as it gets fixed.
|
||||
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 );
|
||||
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 ); // FIXME: ...
|
||||
|
||||
qglDisableClientState( GL_COLOR_ARRAY );
|
||||
qglDisableVertexAttribArrayARB( 9 );
|
||||
|
@ -874,6 +925,142 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
qglDisableClientState( GL_NORMAL_ARRAY );
|
||||
continue;
|
||||
}
|
||||
else if ( soft_particle
|
||||
&& surf->particle_radius > 0.0f
|
||||
&& ( src_blend == GLS_SRCBLEND_ONE || src_blend == GLS_SRCBLEND_SRC_ALPHA )
|
||||
&& tr.backEndRenderer == BE_ARB2
|
||||
&& !r_skipNewAmbient.GetBool() )
|
||||
{
|
||||
// SteveL #3878. Particles are automatically softened by the engine, unless they have shader programs of
|
||||
// their own (i.e. are "newstages" handled above). This section comes after the newstage part so that if a
|
||||
// designer has specified their own shader programs, those will be used instead of the soft particle program.
|
||||
if ( pStage->vertexColor == SVC_IGNORE )
|
||||
{
|
||||
// Ignoring vertexColor is not recommended for particles. The particle system uses vertexColor for fading.
|
||||
// However, there are existing particle effects that don't use it, in which case we default to using the
|
||||
// rgb color modulation specified in the material like the "old stages" do below.
|
||||
color[0] = regs[pStage->color.registers[0]];
|
||||
color[1] = regs[pStage->color.registers[1]];
|
||||
color[2] = regs[pStage->color.registers[2]];
|
||||
color[3] = regs[pStage->color.registers[3]];
|
||||
qglColor4fv( color );
|
||||
}
|
||||
else
|
||||
{
|
||||
// A properly set-up particle shader
|
||||
qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), (void *)&ac->color );
|
||||
qglEnableClientState( GL_COLOR_ARRAY );
|
||||
}
|
||||
|
||||
GL_State( pStage->drawStateBits | GLS_DEPTHFUNC_ALWAYS ); // Disable depth clipping. The fragment program will
|
||||
// handle it to allow overdraw.
|
||||
//GL_State( pStage->drawStateBits );
|
||||
|
||||
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_SOFT_PARTICLE );
|
||||
qglEnable( GL_VERTEX_PROGRAM_ARB );
|
||||
|
||||
// Bind image and _currentDepth
|
||||
GL_SelectTexture( 0 );
|
||||
pStage->texture.image->Bind();
|
||||
GL_SelectTexture( 1 );
|
||||
globalImages->currentDepthImage->Bind();
|
||||
|
||||
qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_SOFT_PARTICLE );
|
||||
qglEnable( GL_FRAGMENT_PROGRAM_ARB );
|
||||
|
||||
// Set up parameters for fragment program
|
||||
const char* srcblendstr = "???";
|
||||
if ( src_blend >= 0 && src_blend <= 9 ) {
|
||||
const char* blendModes[] = {
|
||||
"ONE",
|
||||
"ZERO",
|
||||
"!! INVALID !!",
|
||||
"DST_COLOR",
|
||||
"ONE_MINUS_DST_COLOR",
|
||||
"SRC_ALPHA",
|
||||
"ONE_MINUS_SRC_ALPHA",
|
||||
"DST_ALPHA",
|
||||
"ONE_MINUS_DST_ALPHA",
|
||||
"ALPHA_SATURATE"
|
||||
};
|
||||
srcblendstr = blendModes[src_blend];
|
||||
}
|
||||
|
||||
/*
|
||||
int dst_blend =
|
||||
|
||||
const int GLS_DSTBLEND_ZERO = 0x0;
|
||||
const int GLS_DSTBLEND_ONE = 0x00000020;
|
||||
const int GLS_DSTBLEND_SRC_COLOR = 0x00000030;
|
||||
const int GLS_DSTBLEND_ONE_MINUS_SRC_COLOR = 0x00000040;
|
||||
const int GLS_DSTBLEND_SRC_ALPHA = 0x00000050;
|
||||
const int GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA = 0x00000060;
|
||||
const int GLS_DSTBLEND_DST_ALPHA = 0x00000070;
|
||||
const int GLS_DSTBLEND_ONE_MINUS_DST_ALPHA = 0x00000080;
|
||||
const int GLS_DSTBLEND_BITS = 0x000000f0;
|
||||
*/
|
||||
|
||||
|
||||
printf("XX mat: %s (%s), src_blend = %d (%s)\n", shader->GetName(), shader->GetDescription(), src_blend, srcblendstr);
|
||||
|
||||
// program.env[5] is the particle radius, given as { radius, 1/(faderange), 1/radius }
|
||||
float fadeRange;
|
||||
// fadeRange is the particle diameter for alpha blends (like smoke), but the particle radius for additive
|
||||
// blends (light glares), because additive effects work differently. Fog is half as apparent when a wall
|
||||
// is in the middle of it. Light glares lose no visibility when they have something to reflect off. See
|
||||
// issue #3878 for diagram
|
||||
if ( src_blend == GLS_SRCBLEND_SRC_ALPHA ) // an alpha blend material
|
||||
{
|
||||
fadeRange = surf->particle_radius * 2.0f;
|
||||
}
|
||||
else if ( src_blend == GLS_SRCBLEND_ONE ) // an additive (blend add) material
|
||||
{
|
||||
fadeRange = surf->particle_radius;
|
||||
}
|
||||
|
||||
float parm[4] = {
|
||||
surf->particle_radius,
|
||||
1.0f / ( fadeRange ),
|
||||
1.0f / surf->particle_radius,
|
||||
0.0f
|
||||
};
|
||||
qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_PARTICLE_RADIUS, parm );
|
||||
|
||||
// program.env[6] is the color channel mask. It gets added to the fade multiplier, so adding 1
|
||||
// to a channel will make sure it doesn't get faded at all. Particles with additive blend
|
||||
// need their RGB channels modifying to blend them out. Particles with an alpha blend need
|
||||
// their alpha channel modifying.
|
||||
if ( src_blend == GLS_SRCBLEND_SRC_ALPHA ) // an alpha blend material
|
||||
{
|
||||
parm[0] = parm[1] = parm[2] = 1.0f; // Leave the rgb channels at full strength when fading
|
||||
parm[3] = 0.0f; // but fade the alpha channel
|
||||
}
|
||||
else if ( src_blend == GLS_SRCBLEND_ONE ) // an additive (blend add) material
|
||||
{
|
||||
parm[0] = parm[1] = parm[2] = 0.0f; // Fade the rgb channels but
|
||||
parm[3] = 1.0f; // leave the alpha channel at full strength
|
||||
}
|
||||
//parm[0] = parm[1] = parm[2] = 0.0f; // XXX hack
|
||||
//parm[3] = 1.0f; // XXX hack
|
||||
qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_PARTICLE_COLCHAN_MASK, parm );
|
||||
|
||||
// draw it
|
||||
RB_DrawElementsWithCounters( tri );
|
||||
|
||||
// Clean up GL state
|
||||
GL_SelectTexture( 1 );
|
||||
globalImages->BindNull();
|
||||
GL_SelectTexture( 0 );
|
||||
globalImages->BindNull();
|
||||
|
||||
qglDisable( GL_VERTEX_PROGRAM_ARB );
|
||||
qglDisable( GL_FRAGMENT_PROGRAM_ARB );
|
||||
|
||||
if ( pStage->vertexColor != SVC_IGNORE ) {
|
||||
qglDisableClientState( GL_COLOR_ARRAY );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
//
|
||||
|
@ -972,7 +1159,8 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
if ( shader->TestMaterialFlag(MF_POLYGONOFFSET) ) {
|
||||
qglDisable( GL_POLYGON_OFFSET_FILL );
|
||||
}
|
||||
if ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) {
|
||||
if ( surf->space->weaponDepthHack || ( !soft_particle && surf->space->modelDepthHack != 0.0f ) ) // #3878 soft particles
|
||||
{
|
||||
RB_LeaveDepthHack();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,8 +35,13 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
#include "renderer/tr_local.h"
|
||||
|
||||
#include "Model_local.h"
|
||||
|
||||
|
||||
static const float CHECK_BOUNDS_EPSILON = 1.0f;
|
||||
|
||||
static idCVar r_useSoftParticles( "r_useSoftParticles", "1", CVAR_RENDERER | CVAR_BOOL, "soften particle transitions when player walks through them or they cross solid geometry" );
|
||||
|
||||
/*
|
||||
===========================================================================================
|
||||
|
||||
|
@ -673,6 +678,8 @@ void R_LinkLightSurf( const drawSurf_t **link, const srfTriangles_t *tri, const
|
|||
drawSurf->material = shader;
|
||||
drawSurf->scissorRect = scissor;
|
||||
drawSurf->dsFlags = 0;
|
||||
drawSurf->particle_radius = 0.0f; // #3878
|
||||
|
||||
if ( viewInsideShadow ) {
|
||||
drawSurf->dsFlags |= DSF_VIEW_INSIDE_SHADOW;
|
||||
}
|
||||
|
@ -1186,7 +1193,8 @@ R_AddDrawSurf
|
|||
=================
|
||||
*/
|
||||
void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity,
|
||||
const idMaterial *shader, const idScreenRect &scissor ) {
|
||||
const idMaterial *shader, const idScreenRect &scissor, const float soft_particle_radius )
|
||||
{
|
||||
drawSurf_t *drawSurf;
|
||||
const float *shaderParms;
|
||||
static float refRegs[MAX_EXPRESSION_REGISTERS]; // don't put on stack, or VC++ will do a page touch
|
||||
|
@ -1198,7 +1206,17 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const
|
|||
drawSurf->material = shader;
|
||||
drawSurf->scissorRect = scissor;
|
||||
drawSurf->sort = shader->GetSort() + tr.sortOffset;
|
||||
drawSurf->dsFlags = 0;
|
||||
|
||||
if ( soft_particle_radius != -1.0f ) // #3878
|
||||
{
|
||||
drawSurf->dsFlags = DSF_SOFT_PARTICLE;
|
||||
drawSurf->particle_radius = soft_particle_radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawSurf->dsFlags = 0;
|
||||
drawSurf->particle_radius = 0.0f;
|
||||
}
|
||||
|
||||
// bumping this offset each time causes surfaces with equal sort orders to still
|
||||
// deterministically draw in the order they are added
|
||||
|
@ -1218,7 +1236,7 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const
|
|||
}
|
||||
tr.viewDef->drawSurfs = (drawSurf_t **)R_FrameAlloc( tr.viewDef->maxDrawSurfs * sizeof( tr.viewDef->drawSurfs[0] ) );
|
||||
if(count > 0)
|
||||
memcpy( tr.viewDef->drawSurfs, old, count ); // XXX null pointer passed as argument 2, which is declared to never be null
|
||||
memcpy( tr.viewDef->drawSurfs, old, count );
|
||||
}
|
||||
tr.viewDef->drawSurfs[tr.viewDef->numDrawSurfs] = drawSurf;
|
||||
tr.viewDef->numDrawSurfs++;
|
||||
|
@ -1423,8 +1441,21 @@ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) {
|
|||
vertexCache.Touch( tri->indexCache );
|
||||
}
|
||||
|
||||
// Soft Particles -- SteveL #3878
|
||||
float particle_radius = -1.0f; // Default = disallow softening, but allow modelDepthHack if specified in the decl.
|
||||
if ( r_useSoftParticles.GetBool()
|
||||
&& !shader->ReceivesLighting() // don't soften surfaces that are meant to be solid
|
||||
&& tr.viewDef->renderView.viewID >= 0 ) // Skip during "invisible" rendering passes (e.g. lightgem)
|
||||
{
|
||||
const idRenderModelPrt* prt = dynamic_cast<const idRenderModelPrt*>( def->parms.hModel ); // yuck.
|
||||
if ( prt )
|
||||
{
|
||||
particle_radius = prt->SofteningRadius( surf->id );
|
||||
}
|
||||
}
|
||||
|
||||
// add the surface for drawing
|
||||
R_AddDrawSurf( tri, vEntity, &vEntity->entityDef->parms, shader, vEntity->scissorRect );
|
||||
R_AddDrawSurf( tri, vEntity, &vEntity->entityDef->parms, shader, vEntity->scissorRect, particle_radius );
|
||||
|
||||
// ambientViewCount is used to allow light interactions to be rejected
|
||||
// if the ambient surface isn't visible at all
|
||||
|
@ -1514,6 +1545,14 @@ void R_AddModelSurfaces( void ) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Don't let particle entities re-instantiate their dynamic model during non-visible
|
||||
// views (in TDM, the light gem render) -- SteveL #3970
|
||||
if ( tr.viewDef->renderView.viewID < 0
|
||||
&& dynamic_cast<const idRenderModelPrt*>( vEntity->entityDef->parms.hModel ) != NULL ) // yuck.
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// add the ambient surface if it has a visible rectangle
|
||||
if ( !vEntity->scissorRect.IsEmpty() ) {
|
||||
model = R_EntityDefDynamicModel( vEntity->entityDef );
|
||||
|
|
|
@ -109,6 +109,7 @@ SURFACES
|
|||
|
||||
// drawSurf_t are always allocated and freed every frame, they are never cached
|
||||
static const int DSF_VIEW_INSIDE_SHADOW = 1;
|
||||
static const int DSF_SOFT_PARTICLE = 2; // #3878 - soft particles
|
||||
|
||||
typedef struct drawSurf_s {
|
||||
const srfTriangles_t *geo;
|
||||
|
@ -121,6 +122,7 @@ typedef struct drawSurf_s {
|
|||
int dsFlags; // DSF_VIEW_INSIDE_SHADOW, etc
|
||||
struct vertCache_s *dynamicTexCoords; // float * in vertex cache memory
|
||||
// specular directions for non vertex program cards, skybox texcoords, etc
|
||||
float particle_radius; // The radius of individual quads for soft particles #3878
|
||||
} drawSurf_t;
|
||||
|
||||
|
||||
|
@ -1179,7 +1181,7 @@ viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def );
|
|||
viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *def );
|
||||
|
||||
void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity,
|
||||
const idMaterial *shader, const idScreenRect &scissor );
|
||||
const idMaterial *shader, const idScreenRect &scissor, const float soft_particle_radius = -1.0f ); // soft particles in #3878
|
||||
|
||||
void R_LinkLightSurf( const drawSurf_t **link, const srfTriangles_t *tri, const viewEntity_t *space,
|
||||
const idRenderLightLocal *light, const idMaterial *shader, const idScreenRect &scissor, bool viewInsideShadow );
|
||||
|
@ -1315,6 +1317,10 @@ typedef enum {
|
|||
FPROG_AMBIENT,
|
||||
VPROG_GLASSWARP,
|
||||
FPROG_GLASSWARP,
|
||||
// SteveL #3878: soft particles
|
||||
VPROG_SOFT_PARTICLE,
|
||||
FPROG_SOFT_PARTICLE,
|
||||
//
|
||||
PROG_USER
|
||||
} program_t;
|
||||
|
||||
|
@ -1362,9 +1368,22 @@ typedef enum {
|
|||
PP_SPECULAR_MATRIX_S,
|
||||
PP_SPECULAR_MATRIX_T,
|
||||
PP_COLOR_MODULATE,
|
||||
PP_COLOR_ADD,
|
||||
PP_COLOR_ADD, // 17
|
||||
|
||||
PP_LIGHT_FALLOFF_TQ = 20 // only for NV programs
|
||||
PP_LIGHT_FALLOFF_TQ = 20, // only for NV programs - DG: unused
|
||||
PP_GAMMA_BRIGHTNESS = 21, // DG: for gamma in shader: { r_brightness, r_brightness, r_brightness, 1/r_gamma }
|
||||
// DG: for soft particles from TDM: reciprocal of _currentDepth size.
|
||||
// Lets us convert a screen position to a texcoord in _currentDepth
|
||||
PP_CURDEPTH_RECIPR = 22,
|
||||
// DG: for soft particles from TDM: particle radius, given as { radius, 1/(fadeRange), 1/radius }
|
||||
// fadeRange is the particle diameter for alpha blends (like smoke), but the particle radius for additive
|
||||
// blends (light glares), because additive effects work differently. Fog is half as apparent when a wall
|
||||
// is in the middle of it. Light glares lose no visibility when they have something to reflect off.
|
||||
PP_PARTICLE_RADIUS = 23,
|
||||
// DG: for soft particles from TDM: color channel mask.
|
||||
// Particles with additive blend need their RGB channels modifying to blend them out
|
||||
// Particles with an alpha blend need their alpha channel modifying.
|
||||
PP_PARTICLE_COLCHAN_MASK = 24,
|
||||
} programParameter_t;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue