Automatic water transparency

Discuss anything not covered by any of the other categories.
Post Reply
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Automatic water transparency

Post by Baker »

Ok ... QuakeSrc.org is dead so I can't dig for the answer ...

I'd like to detect whether or not a map is vised for transparent water in the engine and then store that so r_wateralpha is automatically ignored if r_novis 0.

And at the moment archive.org isn't even working so I can't see if it was a standard tutorial.

Is there any engine with a living web site with a simple implementation of this? If I recall, Tomaz Quake had this but I can't find the source code anywhere (that isn't a dead site).
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

A simple way of doing this, when you're building your texturechains for the world is:

1) Keep a global r_renderflags variable, which is initialized to 0 at the start of each frame.
2) In R_RecursiveWorldNode, bitwise-OR it with a flag indicating if a SURF_UNDERWATER surf has been seen.
3) Also bitwise-OR it with another flag indicating if an above-water surf has been seen (if (!(surf-flags & SURF_UNDERWATER))).
4) When it comes to time to draw your water, check the r_renderflags. If both flags are present, you can switch on translucent water, otherwise don't.

I've run through this solution on all of the e1 maps, several other ID1 maps, some hipnotic and some custom maps, and it's been good for all of them. The nice thing is that it's effectively "for free", and doesn't involve any load-time processing.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Hey MH! I found the code in JoeQuake 0.15 and in Vengeance R2 and it looks like you were the author.
/*
=================
Mod_DetectWaterTrans

detect if a model has been vised for translucent water
=================
*/
qboolean Mod_DetectWaterTrans (model_t *mod)
{
int i, j;
byte *vis;
mleaf_t *leaf;
msurface_t **surf;

// no visdata
if (!mod->visdata)
return true;

for (i = 0 ; i < mod->numleafs ; i++)
{
// leaf 0 is the solid leaf, leafs go to numleafs + 1
leaf = &mod->leafs[i+1];

// not interested in these leafs
if (leaf->contents >= CONTENTS_EMPTY || leaf->contents == CONTENTS_SOLID || leaf->contents == CONTENTS_SKY)
continue;

// check marksurfaces for a water texture
surf = leaf->firstmarksurface;

for (j = 0 ; j < leaf->nummarksurfaces ; j++, surf++)
{
// bad surf/texinfo/texture (some old maps have this from a bad qbsp)
if (!surf || !(*surf) || !(*surf)->texinfo || !(*surf)->texinfo->texture)
continue;

// not interested in teleports
if (!ISTELETEX((*surf)->texinfo->texture->name))
goto LeafOK;
}

// no water/etc textures here
continue;

LeafOK:
// get the decompressed vis
vis = Mod_DecompressVis (leaf->compressed_vis, mod);

// check the other leafs
for (j = 0 ; j < mod->numleafs ; j++)
{
// in the PVS
if (vis[j>>3] & (1 << (j & 7)))
{
mleaf_t *visleaf = &mod->leafs[j + 1];

// the leaf we hit originally was under water/slime/lava, and a
// leaf in it's pvs is above water/slime/lava.
if (visleaf->contents == CONTENTS_EMPTY)
return true;
}
}
}

// found nothing
return false;
}
But I tried it and it didn't seem to work for me. Any ideas? Vengeance R2 has the word "BROKEN" in the notes.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

Yup, that was one of mine.

I don't recommend it, it's far from 100% reliable. The method I described above is much much better.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

mh wrote:Yup, that was one of mine.

I don't recommend it, it's far from 100% reliable. The method I described above is much much better.
I'll try the method you described and give it a shot.

I'm a little weak on the .bsp (hence my apprehension), but I think you've described enough that I think I can do it. I would really love to have this feature.

Thank you for your help.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

It works perfect with the few tests I've done. :D :D
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Post by r00k »

Works like a champ...

Code: Select all

int r_renderflags;
#define RF_UNDERWATER	2
#define RF_ABOVEWATER	4

void R_DrawWaterSurfaces (void)
//...
if ((r_novis.value == 0) && (!((r_renderflags & RF_UNDERWATER) && (r_renderflags & RF_ABOVEWATER))))
     alpha = 1;

void R_RecursiveWorldNode (mnode_t *node, int clipflags)
//...
if (surf->flags & SURF_UNDERWATER)
	r_renderflags |= RF_UNDERWATER;
else
	r_renderflags |= RF_ABOVEWATER;

void R_DrawWorld (void)
//..
r_renderflags = 0;
Can you explain WHY this works? Are all "leaf"s set to SURF_UNDERWATER by default at loadtime, and unset in the model->visdata?
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

Take a look in Mod_LoadLeafs. There's a check at the end of it which runs through all leafs, checks the contents member, then sets the SURF_UNDERWATER flag for marksurfaces.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Post Reply