// must match ptype_t values
particletype_t particletype[pt_total] =
{
- {0, 0, false}, // pt_dead
+ {PBLEND_INVALID, PARTICLE_INVALID, false}, //pt_dead (should never happen)
{PBLEND_ALPHA, PARTICLE_BILLBOARD, false}, //pt_alphastatic
{PBLEND_ADD, PARTICLE_BILLBOARD, false}, //pt_static
{PBLEND_ADD, PARTICLE_SPARK, false}, //pt_spark
cvar_t cl_particles_smoke_alphafade = {CVAR_SAVE, "cl_particles_smoke_alphafade", "0.55", "brightness fade per second"};
cvar_t cl_particles_sparks = {CVAR_SAVE, "cl_particles_sparks", "1", "enables sparks (used by multiple effects)"};
cvar_t cl_particles_bubbles = {CVAR_SAVE, "cl_particles_bubbles", "1", "enables bubbles (used by multiple effects)"};
-cvar_t cl_particles_novis = {CVAR_SAVE, "cl_particles_novis", "0", "turn off PVS culling of particles"};
+cvar_t cl_particles_visculling = {CVAR_SAVE, "cl_particles_visculling", "0", "perform a costly check if each particle is visible before drawing"};
cvar_t cl_decals = {CVAR_SAVE, "cl_decals", "1", "enables decals (bullet holes, blood, etc)"};
+cvar_t cl_decals_visculling = {CVAR_SAVE, "cl_decals_visculling", "1", "perform a very cheap check if each decal is visible before drawing"};
cvar_t cl_decals_time = {CVAR_SAVE, "cl_decals_time", "20", "how long before decals start to fade away"};
cvar_t cl_decals_fadetime = {CVAR_SAVE, "cl_decals_fadetime", "1", "how long decals take to fade away"};
Cvar_RegisterVariable (&cl_particles_smoke_alphafade);
Cvar_RegisterVariable (&cl_particles_sparks);
Cvar_RegisterVariable (&cl_particles_bubbles);
- Cvar_RegisterVariable (&cl_particles_novis);
+ Cvar_RegisterVariable (&cl_particles_visculling);
Cvar_RegisterVariable (&cl_decals);
+ Cvar_RegisterVariable (&cl_decals_visculling);
Cvar_RegisterVariable (&cl_decals_time);
Cvar_RegisterVariable (&cl_decals_fadetime);
}
decal->color[1] = ((((color1 >> 8) & 0xFF) * l1 + ((color2 >> 8) & 0xFF) * l2) >> 8) & 0xFF;
decal->color[2] = ((((color1 >> 0) & 0xFF) * l1 + ((color2 >> 0) & 0xFF) * l2) >> 8) & 0xFF;
decal->owner = hitent;
+ decal->clusterindex = -1000; // no vis culling unless we're sure
if (hitent)
{
// these relative things are only used to regenerate p->org and p->vel if decal->owner is not world (0)
Matrix4x4_Transform(&cl.entities[decal->owner].render.inversematrix, org, decal->relativeorigin);
Matrix4x4_Transform3x3(&cl.entities[decal->owner].render.inversematrix, normal, decal->relativenormal);
}
+ else
+ {
+ if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.PointInLeaf)
+ {
+ mleaf_t *leaf = r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, decal->org);
+ if(leaf)
+ decal->clusterindex = leaf->clusterindex;
+ }
+ }
}
void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, float alpha, int texnum, int color1, int color2)
{
matrix4x4_t tempmatrix;
Matrix4x4_CreateFromQuakeEntity(&tempmatrix, originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, light[3]);
- r_refdef.scene.templights[r_refdef.scene.numlights].corona_currentalpha = -1;
R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, light, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights++];
}
// glowing entity
// called by CL_LinkNetworkEntity
Matrix4x4_Scale(&tempmatrix, info->lightradiusstart, 1);
- r_refdef.scene.templights[r_refdef.scene.numlights].corona_currentalpha = -1;
R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, info->lightcolor, -1, info->lightcubemapnum > 0 ? va("cubemaps/%i", info->lightcubemapnum) : NULL, info->lightshadow, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights++];
}
// we invert it again during the blendfunc to make it work...
#ifndef DUMPPARTICLEFONT
- particlefonttexture = loadtextureimage(particletexturepool, "particles/particlefont.tga", false, TEXF_ALPHA | TEXF_PRECACHE, true);
+ particlefonttexture = loadtextureimage(particletexturepool, "particles/particlefont.tga", false, TEXF_ALPHA | TEXF_PRECACHE | TEXF_FORCELINEAR, true);
if (!particlefonttexture)
#endif
{
Image_WriteTGABGRA ("particles/particlefont.tga", PARTICLEFONTSIZE, PARTICLEFONTSIZE, particletexturedata);
#endif
- particlefonttexture = R_LoadTexture2D(particletexturepool, "particlefont", PARTICLEFONTSIZE, PARTICLEFONTSIZE, particletexturedata, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
+ particlefonttexture = R_LoadTexture2D(particletexturepool, "particlefont", PARTICLEFONTSIZE, PARTICLEFONTSIZE, particletexturedata, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
Mem_Free(particletexturedata);
}
}
#ifndef DUMPPARTICLEFONT
- particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_PRECACHE, true);
+ particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_PRECACHE | TEXF_FORCELINEAR, true);
if (!particletexture[tex_beam].texture)
#endif
{
#ifdef DUMPPARTICLEFONT
Image_WriteTGABGRA ("particles/nexbeam.tga", 64, 64, &data2[0][0][0]);
#endif
- particletexture[tex_beam].texture = R_LoadTexture2D(particletexturepool, "nexbeam", 16, 64, &data2[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE, NULL);
+ particletexture[tex_beam].texture = R_LoadTexture2D(particletexturepool, "nexbeam", 16, 64, &data2[0][0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
}
particletexture[tex_beam].s1 = 0;
particletexture[tex_beam].t1 = 0;
goto killdecal;
}
+ if(cl_decals_visculling.integer && decal->clusterindex > -1000 && !CHECKPVSBIT(r_refdef.viewcache.world_pvsbits, decal->clusterindex))
+ continue;
+
if (DotProduct(r_refdef.view.origin, decal->normal) > DotProduct(decal->org, decal->normal) && VectorDistance2(decal->org, r_refdef.view.origin) < drawdist2 * (decal->size * decal->size))
- {
- if(!cl_particles_novis.integer)
- if (!r_refdef.viewcache.world_novis)
- if(r_refdef.scene.worldmodel->brush.PointInLeaf)
- {
- mleaf_t *leaf = r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, decal->org);
- if(leaf)
- if(!CHECKPVSBIT(r_refdef.viewcache.world_pvsbits, leaf->clusterindex))
- continue;
- }
R_MeshQueue_AddTransparent(decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL);
- }
continue;
killdecal:
decal->typeindex = 0;
c4f[3] = p->alpha * colormultiplier[3];
switch (blendmode)
{
+ case PBLEND_INVALID:
case PBLEND_INVMOD:
case PBLEND_ADD:
// additive and modulate can just fade out in fog (this is correct)
tex = &particletexture[p->texnum];
switch(p->orientation)
{
+ case PARTICLE_INVALID:
case PARTICLE_BILLBOARD:
VectorScale(r_refdef.view.left, -size * p->stretch, right);
VectorScale(r_refdef.view.up, size, up);
}
// now render batches of particles based on blendmode and texture
- blendmode = -1;
+ blendmode = PBLEND_INVALID;
texture = NULL;
GL_LockArrays(0, numsurfaces*4);
batchstart = 0;
case PBLEND_ALPHA:
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
+ case PBLEND_INVALID:
case PBLEND_ADD:
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
break;
R_MeshQueue_AddTransparent(p->org, R_DrawParticle_TransparentCallback, NULL, i, NULL);
break;
default:
- if(!cl_particles_novis.integer)
+ if(cl_particles_visculling.integer)
if (!r_refdef.viewcache.world_novis)
- if(r_refdef.scene.worldmodel->brush.PointInLeaf)
+ if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.PointInLeaf)
{
mleaf_t *leaf = r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, p->org);
if(leaf)