Page 1 of 1

El-Cheapo Fullbrights

Posted: Sun Aug 14, 2011 9:13 pm
by mh
This one ain't a copy and paste tutorial.

So, here's a way of using the same texture object for fullbrights as you use for the main texture. Neat for saving on texture memory, faster loading times, and may run faster if your hardware is able to figure out that it can cache the result of a texture lookup and reuse it rather than needing to do a second texture lookup.

I'm assuming that you've got multitexture and a minimum of 3 TMUs available. If neither of these apply you can still get the texture memory saving but you'll need to figure out the blend modes for yourself.

You'll also need to do more work yourself if you've got external textures or a legit use for BSP or MDL textures with an alpha channel.

On to the info.

First thing is that we build a second copy of d_8to24table; this one has an alpha channel of 0 for entries below 224 but it keeps the same r, g and b. Entries 224 and above are the same as your regular d_8to24table.

Then we use that as the palette when uploading a texture that has fullbright colours in it.

Finally when rendering, we set up our texture environment for these textures like so:

Code: Select all

// diffuse - regular texture
glActiveTexture (GL_TEXTURE0);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

// lightmap - optionally use GL_RGB_SCALE for overbrighting
glActiveTexture (GL_TEXTURE1);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

// fullbright
glActiveTexture (GL_TEXTURE2);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
Now we just bind the regular texture to both TMU 0 and 2, the lightmap to TMU1, and draw. That's it. The GL_DECAL environment will give you the following result:

Code: Select all

(tex * lm) * (1.0f - tex.a) + (fb.a * tex.rgb)
Which is exactly what we need for fullbrights - areas covered by fullbright pixels are replaced by them, areas not so covered are left alone. Result.

Posted: Sun Aug 14, 2011 10:36 pm
by metlslime
Nice.

Posted: Sat Aug 20, 2011 7:25 am
by Baker
Make a d_8to32table with colors 224 and greater will have alpha of 1.

Upload all textures with any fullbright pixels as 4 bytes per color (RGBA, BGRA, whatever).

Turn on ALPHA_TEST during fullbright drawing pass.

No need to maintain a fullbright texture at all. No fullbright texture to upload. No multiple tables to maintain.

Just a thought.

Re: El-Cheapo Fullbrights

Posted: Sat Aug 20, 2011 10:56 am
by leileilol
mh wrote:this one has an alpha channel of 0 for entries below 224 but it keeps the same r, g and b. Entries 224 and above are the same as your regular d_8to24table.
The end byte of colormap.lmp stores the number of fullbright ranges so you should just be able to 256 - that for the base instead of hardcoding it up to 224 colors.

Re: El-Cheapo Fullbrights

Posted: Sat Aug 20, 2011 2:19 pm
by mh
leileilol wrote:
mh wrote:this one has an alpha channel of 0 for entries below 224 but it keeps the same r, g and b. Entries 224 and above are the same as your regular d_8to24table.
The end byte of colormap.lmp stores the number of fullbright ranges so you should just be able to 256 - that for the base instead of hardcoding it up to 224 colors.
It's also possible to scan down each column and check for colour changes. If there are none - it's fullbright.

Problem 1 there is that column 0 in ID1 is all black so that will also register as fullbright.

Problem 2 is that a mod can contain a weird colormap, with some columns possibly having an inverted range.

A variation of this trick can handle fullbrights and regular textures in a single pass without needing to even do any state changes between them. Use the same state for both.

Big problem occurs with coloured light and overbrighting. It's sometimes the case that the final combination with the fullbright comes out darker than if the fullbright was not used. You can see this at the red arrows pointing to the e1 entry in the start map. Solution is to calculate both and take the max, but that needs a shader.

Another idea is to upload the colormap as a texture, upload the raw palette indexes for each texture (using a GL_INTENSITY formatm you'd also need to use the 8-bit mipmap and resample functions, and GL_NEAREST_MIPMAP_NEAREST for the min filter), then do some dependent texture lookups in a shader. That would give you an almost exact match to how software Quake looked. A neat thing about that too is that - if you weren't bothered about coloured light - you can pack all 4 lightstyles into a BGRA texture. So a lookup on the main texture gives you the s texcoord, a lookup on the lightmap gives you the t, then use those for a third lookup on the colormap texture. Like I said though - needs shaders, and I'm not certain of how it would interact with dynamic lights.

Posted: Mon Aug 22, 2011 7:42 pm
by metlslime
Just wanted to mention, that some of the proposed ideas could add complexity when supporting external textures. Most (or all?) external textures were authored to use additive blending rather than alpha blending, which means if your pipeline is set up for alpha blending you will need a special case for external textures. (this is why i switched to additive for all fullbrights in the last version of fitzquake, so that the renderer doesn't have to care where the texture came from.)

On the other hand a special case could be worth it if it means the main path can be really fast.

Re: El-Cheapo Fullbrights

Posted: Mon Aug 22, 2011 11:08 pm
by mh
mh wrote:You'll also need to do more work yourself if you've got external textures or a legit use for BSP or MDL textures with an alpha channel.
;)

Simplest approach is to just calculate the light blend as normal, then take the max of that and the fullbright image as the final fragment colour. That also deals with situations where the fullbright colour is going to be darker than the normal light blend - this happens in a few places in ID1 maps.

Image
Image

I guess you couldn't do it with the fixed pipeline though...

The "use the same texture" approach is ideally suited to situations where you might be memory-limited, in which case having it not work with external textures is the least of your worries. If you're already memory-limited with a few extra 64x64 textures, I guess that loading loads of 512x512 textures is not something you're going to be wildly interested in.