Game Development Community

Using SubmergeTextures for Water & Lava

by Cisor · 03/29/2004 (11:04 am) · 0 comments

Ok, below follows a no bells-and-whistles resource to expose the existing lava functionality for water.

The resource assumes the following:

1) If you are using submerge textures, whatever colour you want is in the textures. Hence no background colour will be applied.
2) If you are using submergeTexture1, submergeTexture0 is also specified.
3) If no submergeTexture is specified (or it doesn't exist as specified in the waterblock) the default water/lava colour is used as hardcoded in game.cc.

Possible enhancements:

1) The ability to specify the background colour.
2) The ability to use both background color and textures.
3) The ability to use more than two textures.
4) Renaming the underlava.h and .cc to be something more meaningfull like submerge.h .cc.

In view of the TSE upgrade to the waterblock I didn't think it worthwhile to do the enhancements above, although they should be quite trivial to do.

First: BACK UP THE FOLLOWING FILES:

game.cc
underlava.h
underlava.cc

Second: In underlava.h,

find ...
#ifndef _MPOINT_H_
#include "math/mPoint.h"
#endif

and include the below after that...
// included color - MJC
#ifndef _COLOR_H_
#include "core/color.h"
#endif

then find...
void render()

and replace with...
void render(ColorF color); // changed MJC to accept color

Third: In underlava.cc,

find...
void UnderLavaFX::render()

and comment out the whole routine, replacing it with the routine below...
void UnderLavaFX::render(ColorF color) // changed MJC to pass color
{
   init();

   glMatrixMode(GL_MODELVIEW);
   glPushMatrix();
   glLoadIdentity();
   glMatrixMode(GL_PROJECTION);
   glPushMatrix();
   glLoadIdentity();

   glEnable(GL_TEXTURE_2D);
   TextureHandle submergeTex = WaterBlock::getSubmergeTexture(0); // uncommented MJC
   glBindTexture(GL_TEXTURE_2D, submergeTex.getGLName()); // changed MJC

   glEnable(GL_BLEND);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   glDepthMask(GL_FALSE);
   glColor4f(color.red,color.green,color.blue,color.alpha); // changed MJC
   // begin MJC to do submerge color
   if(!submergeTex) { 
	   glBegin(GL_TRIANGLE_FAN);
	   glVertex3f(-1, -1, 0);
	   glVertex3f(-1,  1, 0);
	   glVertex3f( 1,  1, 0);
	   glVertex3f( 1, -1, 0);
	   glEnd();
   }
   // end MJC
   if( submergeTex ) // changed MJC
   {
      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

      // render layer 1
      for( U32 i=0; i<mNumPoints.y; i++ )
      {
         renderRow( i, mNumPoints.y-1, mNumPoints.x-1 );
      }
   }
   
   // give second layer a different phase
   mWave[0].velocity += 10.0;

   submergeTex = WaterBlock::getSubmergeTexture(1); // uncommented MJC

   if( submergeTex ) // changed MJC
   {
      glBindTexture(GL_TEXTURE_2D, submergeTex.getGLName());

      // render layer 2
      for( U32 i=0; i<mNumPoints.y; i++ )
      {
         renderRow( i, mNumPoints.y-1, mNumPoints.x-1 );
      }
   }

   glDepthMask(GL_TRUE);
   glDisable(GL_TEXTURE_2D);
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   glDisable(GL_BLEND);
   
   glMatrixMode(GL_PROJECTION);
   glPopMatrix();
   glMatrixMode(GL_MODELVIEW);
   glPopMatrix();
}

As you can see I've commented the sections I've changed.

Fourth: In game.cc, in routine void GameRenderFilters(const CameraQuery& camq),

find...
if (WaterBlock::isWater(WaterBlock::mSubmergedType))
         {
            // view filter for camera below the water surface
            glMatrixMode(GL_MODELVIEW);
            glPushMatrix();
            glLoadIdentity();
            glMatrixMode(GL_PROJECTION);
            glPushMatrix();
            glLoadIdentity();

            glDisable(GL_TEXTURE_2D);
            glDepthMask(GL_FALSE);
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glColor4f(.2, .6, .6, .3);
            glBegin(GL_TRIANGLE_FAN);
            glVertex3f(-1, -1, 0);
            glVertex3f(-1,  1, 0);
            glVertex3f( 1,  1, 0);
            glVertex3f( 1, -1, 0);
            glEnd();         
            glDisable(GL_BLEND);
            glBlendFunc(GL_ONE, GL_ZERO);
            glDepthMask(GL_TRUE);

            glMatrixMode(GL_PROJECTION);
            glPopMatrix();
            glMatrixMode(GL_MODELVIEW);
            glPopMatrix();
         }
         else if (WaterBlock::isLava(WaterBlock::mSubmergedType))
         {
	 gLavaFX.render();
         }

and replace with...
if (WaterBlock::isWater(WaterBlock::mSubmergedType))
         {
             // view filter for camera below the water surface
/* begin MJC
	glMatrixMode(GL_MODELVIEW);
            glPushMatrix();
            glLoadIdentity();
            glMatrixMode(GL_PROJECTION);
            glPushMatrix();
            glLoadIdentity();

            glDisable(GL_TEXTURE_2D);
            glDepthMask(GL_FALSE);
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glColor4f(.2, .6, .6, .3);
            glBegin(GL_TRIANGLE_FAN);
            glVertex3f(-1, -1, 0);
            glVertex3f(-1,  1, 0);
            glVertex3f( 1,  1, 0);
            glVertex3f( 1, -1, 0);
            glEnd();         
            glDisable(GL_BLEND);
            glBlendFunc(GL_ONE, GL_ZERO);
            glDepthMask(GL_TRUE);

            glMatrixMode(GL_PROJECTION);
            glPopMatrix();
            glMatrixMode(GL_MODELVIEW);
            glPopMatrix();
end MJC */
	 // added MJC to send colour and use submerge textures
	 ColorF waterFilterColor(0.2, 0.6, 0.6, 0.6);
	 gLavaFX.render(waterFilterColor);
          }
         else if (WaterBlock::isLava(WaterBlock::mSubmergedType))
         {
             // added MJC to send lava colour
	 ColorF lavaFilterColor(1.0, 1.0, 1.0, 0.5);
	 gLavaFX.render(lavaFilterColor);
         }

Since game.cc is currently using the USEOLDFILTERS setting, that's actually is all that is required to make this work, but for sake of completeness, you can make the changes below as well to ensure that the NEWFILTERS section will also work.

Fifth: Still in game.cc, and routine void GameRenderFilters(const CameraQuery& camq),

find...
F32 invincible       = 0.f; ColorF invincibleFilterColor(0.f, 0.f, 1.f, 0.f);

and after that insert...
ColorF lavaFilterColor(1.0, 1.0, 1.0, 0.5);

Sixth: Still in game.cc, and routine void GameRenderFilters(const CameraQuery& camq),

find...
if(addWaterFilter)
      {
         Xcolor         = ( Xcolor * ( 1 - waterFilterColor.alpha ) ) + ( waterFilterColor * waterFilterColor.alpha );
         Xcolor.alpha   =   Xcolor.alpha * ( 1 - waterFilterColor.alpha  );
      }

and comment it out...
/* begin MJC
      if(addWaterFilter)
      {
         Xcolor         = ( Xcolor * ( 1 - waterFilterColor.alpha ) ) + ( waterFilterColor * waterFilterColor.alpha );
         Xcolor.alpha   =   Xcolor.alpha * ( 1 - waterFilterColor.alpha  );
      }
end MJC */

Seventh and last: Still in game.cc, and routine void GameRenderFilters(const CameraQuery& camq),

find...
// if were under lava, apply appropriate texture
      if( addLavaFilter )
      {
         gLavaFX.render();
      }

and replace with...
// added MJC to use submerge textures for water and to 
      // send colour
      if( addWaterFilter )
     {
        gLavaFX.render(waterFilterColor);
     }
     // end added MJC
     // if were under lava, apply appropriate texture
     if( addLavaFilter )
     {
        // changed MJC to send colour
        gLavaFX.render(lavaFilterColor);
     }

And that's it! Do a full-rebuild and you should be good to go.

PS: A note about the textures - make sure they wrap properly else you get unseemly seams.
Also, for water, blue or grayscale hazemaps work quite well.

Enjoy!