News
DirectX
Links
Contact Me

In Association with Amazon.com
In Association with Amazon.ca

$5 via PayPal


Computed Alpha Channel Tutorial



Computed Alpha Channel

The code to load our texture is the same as our Alpha Transparency lesson's code, so I won't show it again. After the image has been loaded (in InitScene) we call our process_alpha() procedure to generate an alpha channel for our texture.

process_alpha() determines the texture format we have and then calls the appropriate procedure to do the actual texture processing.

// Function:process_alpha
// Whazzit:Scans through a texture setting its alpha component to the same value as the
//         red component.  Our image is grayscale so red == blue == green.  You'd get
//         some funky effects if you loaded a non-grayscale image since only the red
//         would control alpha.
void process_alpha(void){
HRESULT hr;
D3DSURFACE_DESC surf_desc;
D3DLOCKED_RECT rect;

   //We use GetLevelDesc to obtain the width and height of the texture.  We could
   //hard-code the values, but that's bad programming practice.
   hr=g_texture->GetLevelDesc(0,&surf_desc);
   if(FAILED(hr)){
      FatalError(hr,"Error getting surface description");
   }

   //After the texture is locked, the pBits member of the rect structure will point to
   //the actual data bits.
   hr=g_texture->LockRect(0,     //Level 0, the only one since we didn't use mipmaps
                          &rect, //This will be filled with info if the lock suceeds
                          NULL,  //Lock the whole texture
                          D3DLOCK_NOSYSLOCK); //This allows our debugger to keep running

   if(FAILED(hr)){
      FatalError(hr,"Error locking texture");
   }


   //Let's see what texture format we have.  We requested 32-bit ARGB, but it's not
   //necessarily what we got.
   switch(surf_desc.Format){
      case D3DFMT_A8R8G8B8:   //32-bit ARGB, what we requested
         process_alphaA8R8G8B8(surf_desc.Width,surf_desc.Height,&rect);
         break;
      case D3DFMT_A4R4G4B4:   //16-bit ARGB, not ideal, but not bad
         process_alphaA4R4G4B4(surf_desc.Width,surf_desc.Height,&rect);
         break;
      case D3DFMT_R8G8B8:     //These 3 formats have no alpha channel
      case D3DFMT_R5G6B5:     //Hopefully we'd never be given this
      case D3DFMT_R3G3B2:
         g_texture->UnlockRect(0);
         FatalError("Texture had no alpha channel, aborting");
         break;
      default:    //Default handler.  Other formats (like 1-bit alpha) aren't
                  //suitable for this example, so we bail out and tell the user 'why'.
         g_texture->UnlockRect(0);
         FatalError("Your video card does not support a texture format with sufficent alpha precision.");
         break;
   };

   g_texture->UnlockRect(0);

}
// Function:process_alphaA8R8G8B8
// Whazzit:This processes our texture if it's 32-bit ARGB.  This is the ideal format.
//         It's easy and fast to process with a full 8-bits of precision for the
//         alpha channel.
void process_alphaA8R8G8B8(DWORD p_width,DWORD p_height,D3DLOCKED_RECT *p_rect){
DWORD x,y;
DWORD pitch_diff;

//When we lock our texture, we will get a pointer to our 32-bit ARGB data.  Note that
//because of the byte ordering on Intel we would specify a 32-bit value as 0xAARRGGBB
//But our structure is laid out in reverse order BGRA.  Those wacky Intel-ians.
struct my_colour{
   unsigned char blue;
   unsigned char green;
   unsigned char red;
   unsigned char alpha;
} *col;


   //Sometimes extra space needs to be allocated for each 'row' of texture data.
   //The width is how wide the data is per row, the pitch is how much is actually allocated.
   //The pitch will always be at least as big as the width, but may be larger if the driver
   //reqires data to be on a specific memory alignment boundary.
   //
   //pitch_diff is the amount we have to add to skip the non-data space to reach the next line
   pitch_diff=(p_rect->Pitch/4) - p_width;

   //Using a pointer to 'my_colour' simplifies our dealings with the various colour components
   col=(my_colour *)p_rect->pBits;

   //Now we loop through the whole texture setting the alpha component equal to the red component.
   //Since our image was grayscale, we could have used the blue or green instead of red and it
   //would have made no difference.
   for(y=0;y < p_height;y++){
      for(x=0;x < p_width; x++){
         col->alpha=col->red;
         col++;
      }
      //Add pitch_diff to skip to the next line.
      col+=pitch_diff;
   }

}
// Function:process_alphaA4R4G4B4
// Whazzit:This processes our texture if it's 16-bit ARGB.  Though it lacks the
//         precision of the 32-bit ARGB, it's still pretty good and it takes up
//         1/2 of the memory.
void process_alphaA4R4G4B4(DWORD p_width,DWORD p_height,D3DLOCKED_RECT *p_rect){
DWORD x,y;
DWORD pitch_diff;

//With this texture format, we have 4 bits for each of the alpha, red, green, and blue
//channels.
struct my_colour{
   unsigned char blue:4;
   unsigned char green:4;
   unsigned char red:4;
   unsigned char alpha:4;
}*col;

   //Sometimes extra space needs to be allocated for each 'row' of texture data.
   //The width is how wide the data is per row, the pitch is how much is actually allocated.
   //The pitch will always be at least as big as the width, but may be larger if the driver
   //reqires data to be on a specific memory alignment boundary.
   //
   //pitch_diff is the amount we have to add to skip the non-data space to reach the next line
   pitch_diff=(p_rect->Pitch/2) - p_width;

   //Using a pointer to 'my_colour' simplifies our dealings with the various colour components
   col=(my_colour *)p_rect->pBits;

   //Now we loop through the whole texture setting the alpha component equal to the red component.
   //Since our image was grayscale, we could have used the blue or green instead of red and it
   //would have made no difference.
   for(y=0;y < p_height;y++){
      for(x=0;x < p_width; x++){
         col->alpha=col->red;
         col++;
      }
      //Add pitch_diff to skip to the next line.
      col+=pitch_diff;
   }


}