Game Development Community

[beta 3] Adding DDS luminance texture support [code]

by Manoel Neto · in Torque 3D Professional · 03/27/2011 (9:25 am) · 3 replies

Here's code to add support for properly loading luminance DDS formats: GFXFormatL8, GFXFormatL16, GFXFormatL8A8 and GFXFormatL4A4. These are very useful when you have pre-generated textures that don't use all 4 RGBA channels (like lookup tables, etc).

(T3D has L8 and L16 registered as proper formats, but failed loading DDS files using those formats since they don't have RGB flags).

First, we'll add L8A8 and L4A4:

In Engine/source/gfx/gfxEnums.h, in the GFXFormat enum add the lines marked with "NEW!" comments:

// 8 bit texture formats...
   GFXFormatA8 = 0,// first in group...
   GFXFormatL8,
   GFXFormatA4L4,//<--- NEW!

// 16 bit texture formats...
   GFXFormatR5G6B5,// first in group...
   GFXFormatR5G5B5A1,
   GFXFormatR5G5B5X1,
   GFXFormatA8L8,//<--- NEW!
   GFXFormatL16,

In Engine/source/gfx/D3D9/pc/gfxD3D9EnumTranslate.pc.cpp, in GFXD3D9EnumTranslate::init(), add these:
GFXD3D9TextureFormat[GFXFormatR32F] = D3DFMT_R32F;
GFXD3D9TextureFormat[GFXFormatA8L8] = D3DFMT_A8L8; //<--- NEW!
GFXD3D9TextureFormat[GFXFormatA4L4] = D3DFMT_A4L4; //<--- NEW!
GFXD3D9TextureFormat[GFXFormatA8] = D3DFMT_A8;

In Engine/source/gfx/gfxAPI.cpp, add these:
{ GFXFormatR5G5B5X1, "GFXFormatR5G5B5X1" },
   { GFXFormatA8L8, "GFXFormatA8L8" }, //<--- NEW!
   { GFXFormatA4L4, "GFXFormatA4L4" }, //<--- NEW!
   { GFXFormatA8, "GFXFormatA8" },

In Engine/source/gfx/gfxFormatUtils.cpp, add:
GFXFormatInfo::Data( 1,    false, false, false ),   // GFXFormatL8
   GFXFormatInfo::Data( 1,    true,  false, false ),   // GFXFormatA4L4 <--- NEW!

   // 16 bit texture formats...
   GFXFormatInfo::Data( 2,    false, false, false ),   // GFXFormatR5G6B5
   GFXFormatInfo::Data( 2,    true,  false, false ),   // GFXFormatR5G5B5A1
   GFXFormatInfo::Data( 2,    false, false, false ),   // GFXFormatR5G5B5X1
   GFXFormatInfo::Data( 2,    true,  false, false ),   // GFXFormatA8L8 <--- NEW!
   GFXFormatInfo::Data( 2,    false, false, false ),   // GFXFormatL16

And in Engine/source/gfx/gfxStringEnumTranslate.cpp, add:
GFX_STRING_ASSIGN_MACRO( GFXStringTextureFormat, GFXFormatR5G5B5X1 );
   GFX_STRING_ASSIGN_MACRO( GFXStringTextureFormat, GFXFormatA8L8 ); //<--- NEW!
   GFX_STRING_ASSIGN_MACRO( GFXStringTextureFormat, GFXFormatA4L4 ); //<--- NEW!
   GFX_STRING_ASSIGN_MACRO( GFXStringTextureFormat, GFXFormatA8 );

Now let's teach DDSLoader how to load them. Open Engine/source/gfx/bitmap/ddsLoader.cpp. Lines marked with "CHANGE!" were modified (check the surrounding lines to see where they are).
enum DDSPixelFormatFlags
{
   DDPFAlphaPixels   = 0x00000001,
   DDPFFourCC        = 0x00000004,
   DDPFRGB           = 0x00000040, // <--- CHANGE
   DDPFLUMINANCE     = 0x00020000  // <--- NEW!
};
if(!(ddpfFlags & (DDPFRGB | DDPFFourCC | DDPFLUMINANCE))) //<--- CHANGE!   
   {
      Con::errorf("DDSFile::readHeader - incoherent pixel flags, neither RGB nor FourCC!");
      return false;
   }

Before this:
if(ddpfFlags & DDPFRGB)
Add this:
// New luminance code!
   if(ddpfFlags & DDPFLUMINANCE)
   {
      mFlags.set(RGBData);

      mBytesPerPixel = pfBitCount / 8;      

      bool hasAlpha = ddpfFlags & DDPFAlphaPixels;

      mHasTransparency = hasAlpha;

      // Try to match a format.
      if(hasAlpha)
      {
         // If it has alpha it is one of...
         // GFXFormatA8L8
         // GFXFormatA4L4

         if(pfBitCount == 16)
            mFormat = GFXFormatA8L8;
         else if(pfBitCount == 8)
            mFormat = GFXFormatA4L4;
         else
         {
            Con::errorf("DDSFile::readHeader - unable to match alpha Luminance format!");
            return false;
         }
      }
      else
      {
         // Otherwise it is one of...
         // GFXFormatL16
         // GFXFormatL8

         if(pfBitCount == 16)
            mFormat = GFXFormatL16;
         else if(pfBitCount == 8)
            mFormat = GFXFormatL8;
         else
         {
            Con::errorf("DDSFile::readHeader - unable to match non-alpha Luminance format!");
            return false;
         }
      }
   }

And finally, let's fix a bug/limitation in Engine/source/gfx/D3D9/gfxD3D9TextureManager.cpp:

Replace this:
if ( dds->getSurfacePitch( i ) != lockedRect.Pitch )
 {
	Con::errorf( "GFXD3D9TextureManager - pitch mismatch on DDS load" );

	surf->UnlockRect();
	surf->Release();

	return false;
 }

By this:
if ( dds->getSurfacePitch( i ) != lockedRect.Pitch )
 {
	AssertFatal( dds->mSurfaces.size() > 0, "Assumption failed. DDSFile has no surfaces." );
	
	// Do a row-by-row copy
	U32 srcPitch = dds->getSurfacePitch( i );
	U32 srcHeight = dds->getHeight();
	U8* srcBytes = dds->mSurfaces[0]->mMips[i];
	U8* dstBytes = (U8*)lockedRect.pBits;
	for (U32 i = 0; i<srcHeight; i++)          
	{
	   dMemcpy( dstBytes, srcBytes, srcPitch );
	   dstBytes += lockedRect.Pitch;
	   srcBytes += srcPitch;
	}           
	surf->UnlockRect();
	surf->Release();

	return true;
 }
(This is the correct way to handle pitch mistmatch).

#1
03/29/2011 (4:04 pm)
Thanks! THREED-1530
#2
04/02/2011 (2:10 am)
Merged... this will be in T3D 1.1 final.
#3
04/02/2011 (2:18 am)
ty (both of you)