From 9099ef25ee4e06d40d6f81088e3e799229a7fdc9 Mon Sep 17 00:00:00 2001 From: havoc Date: Fri, 19 Nov 2010 13:42:14 +0000 Subject: [PATCH 1/1] particle rendering now uses premultiplied alpha (texture is automatically converted on load, however dds may need to be DXT4 rather than DXT5 now) this should give an fps boost git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10613 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_particles.c | 82 ++++++++++++++++++++++++-------------------------- gl_textures.c | 15 +++++++++ r_textures.h | 4 ++- 3 files changed, 58 insertions(+), 43 deletions(-) diff --git a/cl_particles.c b/cl_particles.c index d706a1f2..955a5791 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -1994,7 +1994,7 @@ static void R_InitParticleTexture (void) // we invert it again during the blendfunc to make it work... #ifndef DUMPPARTICLEFONT - decalskinframe = R_SkinFrame_LoadExternal("particles/particlefont.tga", TEXF_ALPHA | TEXF_FORCELINEAR, false); + decalskinframe = R_SkinFrame_LoadExternal("particles/particlefont.tga", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, false); if (decalskinframe) { particlefonttexture = decalskinframe->base; @@ -2139,7 +2139,7 @@ static void R_InitParticleTexture (void) Image_WriteTGABGRA ("particles/particlefont.tga", PARTICLEFONTSIZE, PARTICLEFONTSIZE, particletexturedata); #endif - decalskinframe = R_SkinFrame_LoadInternalBGRA("particlefont", TEXF_ALPHA | TEXF_FORCELINEAR, particletexturedata, PARTICLEFONTSIZE, PARTICLEFONTSIZE); + decalskinframe = R_SkinFrame_LoadInternalBGRA("particlefont", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, particletexturedata, PARTICLEFONTSIZE, PARTICLEFONTSIZE); particlefonttexture = decalskinframe->base; Mem_Free(particletexturedata); @@ -2158,7 +2158,7 @@ static void R_InitParticleTexture (void) } #ifndef DUMPPARTICLEFONT - particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR, true, r_texture_convertsRGB_particles.integer != 0); + particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, r_texture_convertsRGB_particles.integer != 0); if (!particletexture[tex_beam].texture) #endif { @@ -2181,7 +2181,7 @@ static void R_InitParticleTexture (void) #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_ALPHA | TEXF_FORCELINEAR, -1, NULL); + particletexture[tex_beam].texture = R_LoadTexture2D(particletexturepool, "nexbeam", 16, 64, &data2[0][0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, -1, NULL); } particletexture[tex_beam].s1 = 0; particletexture[tex_beam].t1 = 0; @@ -2241,7 +2241,7 @@ static void R_InitParticleTexture (void) Con_Printf("particles/particlefont.txt: texnum %i outside valid range (0 to %i)\n", i, MAX_PARTICLETEXTURES); continue; } - particletexture[i].texture = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR, false)->base; + particletexture[i].texture = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, false)->base; particletexture[i].s1 = s1; particletexture[i].t1 = t1; particletexture[i].s2 = s2; @@ -2495,15 +2495,15 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh palpha = p->alpha; if(dofade && p->orientation != PARTICLE_VBEAM && p->orientation != PARTICLE_HBEAM) palpha *= min(1, (DotProduct(p->org, r_refdef.view.forward) - minparticledist_start) / (minparticledist_end - minparticledist_start)); + alpha = palpha * colormultiplier[3]; + // ensure alpha multiplier saturates properly + if (alpha > 1.0f) + alpha = 1.0f; switch (blendmode) { case PBLEND_INVALID: case PBLEND_INVMOD: - alpha = palpha * colormultiplier[3]; - // ensure alpha multiplier saturates properly - if (alpha > 1.0f) - alpha = 1.0f; // additive and modulate can just fade out in fog (this is correct) if (r_refdef.fogenabled) alpha *= RSurf_FogVertex(p->org); @@ -2512,13 +2512,9 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh c4f[0] = p->color[0] * alpha; c4f[1] = p->color[1] * alpha; c4f[2] = p->color[2] * alpha; - c4f[3] = 1; + c4f[3] = 0; break; case PBLEND_ADD: - alpha = palpha * colormultiplier[3]; - // ensure alpha multiplier saturates properly - if (alpha > 1.0f) - alpha = 1.0f; // additive and modulate can just fade out in fog (this is correct) if (r_refdef.fogenabled) alpha *= RSurf_FogVertex(p->org); @@ -2526,13 +2522,13 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh c4f[0] = p->color[0] * colormultiplier[0] * alpha; c4f[1] = p->color[1] * colormultiplier[1] * alpha; c4f[2] = p->color[2] * colormultiplier[2] * alpha; - c4f[3] = 1; + c4f[3] = 0; break; case PBLEND_ALPHA: - c4f[0] = p->color[0] * colormultiplier[0]; - c4f[1] = p->color[1] * colormultiplier[1]; - c4f[2] = p->color[2] * colormultiplier[2]; - c4f[3] = palpha * colormultiplier[3]; + c4f[0] = alpha * p->color[0] * colormultiplier[0]; + c4f[1] = alpha * p->color[1] * colormultiplier[1]; + c4f[2] = alpha * p->color[2] * colormultiplier[2]; + c4f[3] = alpha; // note: lighting is not cheap! if (particletype[p->typeindex].lighting) { @@ -2683,36 +2679,38 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh { p = cl.particles + surfacelist[surfacelistindex]; - if (blendmode != p->blendmode) - { - blendmode = (pblend_t)p->blendmode; - switch(blendmode) - { - 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; - case PBLEND_INVMOD: - GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - break; - } - } if (texture != particletexture[p->texnum].texture) { texture = particletexture[p->texnum].texture; R_SetupShader_Generic(texture, NULL, GL_MODULATE, 1); } - // iterate until we find a change in settings - batchstart = surfacelistindex++; - for (;surfacelistindex < numsurfaces;surfacelistindex++) + if (p->blendmode == PBLEND_INVMOD) { - p = cl.particles + surfacelist[surfacelistindex]; - if (blendmode != p->blendmode || texture != particletexture[p->texnum].texture) - break; + // inverse modulate blend - group these + GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + // iterate until we find a change in settings + batchstart = surfacelistindex++; + for (;surfacelistindex < numsurfaces;surfacelistindex++) + { + p = cl.particles + surfacelist[surfacelistindex]; + if (p->blendmode != PBLEND_INVMOD || texture != particletexture[p->texnum].texture) + break; + } + } + else + { + // additive or alpha blend - group these + // (we can group these because we premultiplied the texture alpha) + GL_BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + // iterate until we find a change in settings + batchstart = surfacelistindex++; + for (;surfacelistindex < numsurfaces;surfacelistindex++) + { + p = cl.particles + surfacelist[surfacelistindex]; + if (p->blendmode == PBLEND_INVMOD || texture != particletexture[p->texnum].texture) + break; + } } batchcount = surfacelistindex - batchstart; diff --git a/gl_textures.c b/gl_textures.c index 455924b6..192568fa 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -1119,6 +1119,21 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) prevbuffer = colorconvertbuffer; } + if (glt->flags & TEXF_RGBMULTIPLYBYALPHA) + { + // multiply RGB channels by A channel before uploading + int alpha; + for (i = 0;i < width*height*depth*4;i += 4) + { + alpha = prevbuffer[i+3]; + colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8; + colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8; + colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8; + colorconvertbuffer[i+3] = alpha; + } + prevbuffer = colorconvertbuffer; + } + // scale up to a power of 2 size (if appropriate) if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) { diff --git a/r_textures.h b/r_textures.h index 433066a7..8732ca2e 100644 --- a/r_textures.h +++ b/r_textures.h @@ -6,6 +6,8 @@ #define TEXF_ALPHA 0x00000001 // mipmapped #define TEXF_MIPMAP 0x00000002 +// multiply RGB by A channel before uploading +#define TEXF_RGBMULTIPLYBYALPHA 0x00000004 // indicates texture coordinates should be clamped rather than wrapping #define TEXF_CLAMP 0x00000020 // indicates texture should be uploaded using GL_NEAREST or GL_NEAREST_MIPMAP_NEAREST mode @@ -31,7 +33,7 @@ // indicates the texture will be used as a render target (D3D hint) #define TEXF_RENDERTARGET 0x0010000 // used for checking if textures mismatch -#define TEXF_IMPORTANTBITS (TEXF_ALPHA | TEXF_MIPMAP | TEXF_CLAMP | TEXF_FORCENEAREST | TEXF_FORCELINEAR | TEXF_PICMIP | TEXF_COMPRESS | TEXF_COMPARE | TEXF_LOWPRECISION | TEXF_RENDERTARGET) +#define TEXF_IMPORTANTBITS (TEXF_ALPHA | TEXF_MIPMAP | TEXF_RGBMULTIPLYBYALPHA | TEXF_CLAMP | TEXF_FORCENEAREST | TEXF_FORCELINEAR | TEXF_PICMIP | TEXF_COMPRESS | TEXF_COMPARE | TEXF_LOWPRECISION | TEXF_RENDERTARGET) typedef enum textype_e { -- 2.39.2