Skip to content

Commit

Permalink
#3878 Soft particles
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.thedarkmod.com/svn/darkmod_src/trunk@6171 49c82d7f-2e2a-0410-a16f-ae8f201b507f
  • Loading branch information
stevel committed Nov 23, 2014
1 parent 06f9a14 commit cf14f50
Show file tree
Hide file tree
Showing 10 changed files with 243 additions and 14 deletions.
6 changes: 6 additions & 0 deletions framework/DeclParticle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,10 @@ idParticleStage *idDeclParticle::ParseParticleStage( idLexer &src ) {
stage->gravity = src.ParseFloat();
continue;
}
if ( !token.Icmp( "softeningRadius" ) ) {
stage->softeningRadius = src.ParseFloat();
continue;
}

src.Error( "unknown token %s\n", token.c_str() );
}
Expand Down Expand Up @@ -723,6 +727,7 @@ idParticleStage::idParticleStage( void ) {
hidden = false;
boundsExpansion = 0.0f;
bounds.Clear();
softeningRadius = -2.0f; // -2 means "auto"
}

/*
Expand Down Expand Up @@ -796,6 +801,7 @@ void idParticleStage::Default() {
randomDistribution = true;
entityColor = false;
cycleMsec = ( particleLife + deadTime ) * 1000;
softeningRadius = -2.0f; // -2 means "auto"
}

/*
Expand Down
10 changes: 10 additions & 0 deletions framework/DeclParticle.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,16 @@ class idParticleStage {
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;
};


Expand Down
2 changes: 1 addition & 1 deletion renderer/Material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1417,7 +1417,7 @@ void idMaterial::ParseStage( idLexer &src, const textureRepeat_t trpDefault ) {
ss->drawStateBits |= GLS_DEPTHMASK;
continue;
}
else if ( !token.Icmp( "ignoreDepth" ) ) { // Added in #3877. For use by soft particles #3878
else if ( !token.Icmp( "ignoreDepth" ) ) { // Added in #3877.
ss->drawStateBits |= GLS_DEPTHFUNC_ALWAYS;
continue;
}
Expand Down
10 changes: 8 additions & 2 deletions renderer/Model_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class idRenderModelStatic : public idRenderModel {
virtual void Print() const;
virtual void List() const;
virtual int Memory() const;
virtual ID_TIME_T Timestamp() const;
virtual ID_TIME_T Timestamp() const;
virtual int NumSurfaces() const;
virtual int NumBaseSurfaces() const;
virtual const modelSurface_t *Surface( int surfaceNum ) const;
Expand Down Expand Up @@ -110,7 +110,7 @@ class idRenderModelStatic : public idRenderModel {
bool fastLoad; // don't generate tangents and shadow data
bool reloadable; // if not, reloadModels won't check timestamp
bool levelLoadReferenced; // for determining if it needs to be freed
ID_TIME_T timeStamp;
ID_TIME_T timeStamp;

static idCVar r_mergeModelSurfaces; // combine model surfaces with the same material
static idCVar r_slopVertex; // merge xyz coordinates this far apart
Expand Down Expand Up @@ -286,9 +286,15 @@ class idRenderModelPrt : public idRenderModelStatic {
virtual idBounds Bounds( const struct renderEntity_s *ent ) const;
virtual float DepthHack() const;
virtual int Memory() const;

public:
float SofteningRadius( const int stage ) const; // #3878 soft particles
private:
virtual void SetSofteningRadii();

private:
const idDeclParticle * particleSystem;
idList<float> softeningRadii;
};

/*
Expand Down
64 changes: 64 additions & 0 deletions renderer/Model_prt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

static bool versioned = RegisterVersionedFile("$Id$");

#include <algorithm>
#include "tr_local.h"
#include "Model_local.h"

Expand All @@ -44,6 +45,7 @@ idRenderModelPrt::InitFromFile
void idRenderModelPrt::InitFromFile( const char *fileName ) {
name = fileName;
particleSystem = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, fileName ) );
SetSofteningRadii(); // # 3878
}

/*
Expand Down Expand Up @@ -267,3 +269,65 @@ 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 = ( std::max )( ps->size.from, ps->size.to );
float scale = ( std::max )( ps->aspect.from, ps->aspect.to );
diameter *= ( std::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];
}

2 changes: 1 addition & 1 deletion renderer/RenderSystem_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ idCVar r_skipBump( "r_skipBump", "0", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE,
idCVar r_skipDiffuse( "r_skipDiffuse", "0", CVAR_RENDERER | CVAR_BOOL, "use black for diffuse" );
idCVar r_skipROQ( "r_skipROQ", "0", CVAR_RENDERER | CVAR_BOOL, "skip ROQ decoding" );
idCVar r_skipDepthCapture( "r_skipDepthCapture", "0", CVAR_RENDERER | CVAR_BOOL, "skip depth capture" ); // #3877

idCVar r_useSoftParticles( "r_useSoftParticles", "1", CVAR_RENDERER | CVAR_BOOL, "soften particle transitions when player walks through them or they cross solid geometry" ); // #3878

idCVar r_ignore( "r_ignore", "0", CVAR_RENDERER, "used for random debugging without defining new vars" );
idCVar r_ignore2( "r_ignore2", "0", CVAR_RENDERER, "used for random debugging without defining new vars" );
Expand Down
4 changes: 4 additions & 0 deletions renderer/draw_arb2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ static progDef_t progs[MAX_GLPROGS] = {
{ GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION_DIRECT, "interaction_direct.vfp" },
{ GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION_DIRECT, "interaction_direct.vfp" },

// SteveL #3878: Particle softening applied by the engine
{ GL_VERTEX_PROGRAM_ARB, VPROG_SOFT_PARTICLE, "soft_particle.vfp" },
{ GL_FRAGMENT_PROGRAM_ARB, FPROG_SOFT_PARTICLE, "soft_particle.vfp" },

// additional programs can be dynamically specified in materials
};

Expand Down
108 changes: 105 additions & 3 deletions renderer/draw_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,9 +586,10 @@ 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.
Only parameters 0..3 were in use befre #3877. Now I've used a new parameter 4 for the
Only parameters 0..3 were in use before #3877. Now I've used a new parameter 4 for the
size of _currentDepth. It's needed throughout, including by light interactions, and its
size might in theory differ from _currentRender.
Parameters 5 and 6 are used by soft particles #3878. Note these can be freely reused by different draw calls.
==================
*/
void RB_SetProgramEnvironment()
Expand Down Expand Up @@ -761,6 +762,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;

Expand All @@ -777,7 +781,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 );
}

Expand All @@ -803,6 +808,8 @@ 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;
Expand Down Expand Up @@ -885,6 +892,101 @@ 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 ) )
{
// 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 any
// shader program in a particle stage will be used instead of the particle softener programs about to be
// applied in this block. Contains some code repetition from above block, but that's better than intertwining
// the two sections.
// Repeated code -->
if ( tr.backEndRenderer != BE_ARB2 || r_skipNewAmbient.GetBool() ) {
continue;
}
qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), (void *)&ac->color );
qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() ); //~Check: do we need these?
qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() );
qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() );
qglEnableClientState( GL_COLOR_ARRAY );
qglEnableVertexAttribArrayARB( 9 );
qglEnableVertexAttribArrayARB( 10 );
qglEnableClientState( GL_NORMAL_ARRAY );
// <-- end repeated code
GL_State( pStage->drawStateBits | GLS_DEPTHFUNC_ALWAYS ); // Disable depth clipping. The fragment program will
// handle it to allow overdraw.

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

// 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, 5, 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
}
qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 6, parm );

// draw it
RB_DrawElementsWithCounters( tri );

GL_SelectTexture( 1 );
globalImages->BindNull();
GL_SelectTexture( 0 );
globalImages->BindNull();

// Repeated code -->
qglDisable( GL_VERTEX_PROGRAM_ARB );
qglDisable( GL_FRAGMENT_PROGRAM_ARB );

qglDisableClientState( GL_COLOR_ARRAY );
qglDisableVertexAttribArrayARB( 9 );
qglDisableVertexAttribArrayARB( 10 );
qglDisableClientState( GL_NORMAL_ARRAY );
// <-- end repeated code
continue;
}

//--------------------------
//
Expand Down Expand Up @@ -983,7 +1085,7 @@ 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 ( !soft_particle && ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) ) {
RB_LeaveDepthHack();
}
}
Expand Down
Loading

0 comments on commit cf14f50

Please sign in to comment.