前面详细介绍了压缩纹理dds的各种格式DXT1~DXT5,下面来详细介绍一下怎么具体使用压缩纹理。
【一】怎么创建dds文件:
1、photoshop插件导出的方式,通过把dds.8bi拷贝到插件格式目录中即可。
2、directx 的Texture tool也可以实现dds文件的创建和修改转换等功能。
注意:一般需要将纹理大小修改成2的指数倍才能执行转换。
【二】怎么读取dds文件:
参考下面的代码:
bool DDSFile::readHeader(Stream &s)
{
U32 tmp;
// Read the FOURCC
s.read(&tmp);
int a = 1;
if(tmp != MakeFourCC('D', 'D', 'S', ' '))
{
Con::errorf("DDSFile::readHeader - unexpected magic number, wanted 'DDS '!");
return false;
}
// Read the size of the header.
s.read(&tmp);
if(tmp != 124)
{
Con::errorf("DDSFile::readHeader - incorrect header size. Expected 124 bytes.");
return false;
}
// Read some flags...
U32 ddsdFlags;
s.read(&ddsdFlags);
// "Always include DDSD_CAPS, DDSD_PIXELFORMAT, DDSD_WIDTH, DDSD_HEIGHT."
if(!(ddsdFlags & (DDSDCaps | DDSDPixelFormat | DDSDWidth | DDSDHeight)))
{
Con::errorf("DDSFile::readHeader - incorrect surface description flags.");
return false;
}
// Read height and width (always present)
s.read(&mHeight);
s.read(&mWidth);
// Read pitch or linear size.
// First make sure we have valid flags (either linear size or pitch).
if((ddsdFlags & (DDSDLinearSize | DDSDPitch)) == (DDSDLinearSize | DDSDPitch))
{
// Both are invalid!
Con::errorf("DDSFile::readHeader - encountered both DDSD_LINEARSIZE and DDSD_PITCH!");
return false;
}
// Ok, some flags are set, so let's do some reading.
s.read(&mPitchOrLinearSize);
if(ddsdFlags & DDSDLinearSize)
{
mFlags.set(LinearSizeFlag);
}
else if (ddsdFlags & DDSDPitch)
{
mFlags.set(PitchSizeFlag);
}
else
{
// Neither set! This appears to be depressingly common.
// Con::warnf("DDSFile::readHeader - encountered neither DDSD_LINEARSIZE nor DDSD_PITCH!");
}
// Do we need to read depth? If so, we are a volume texture!
s.read(&mDepth);
if(ddsdFlags & DDSDDepth)
{
mFlags.set(VolumeFlag);
}
else
{
// Wipe it if the flag wasn't set!
mDepth = 0;
}
// Deal with mips!
s.read(&mMipMapCount);
if(ddsdFlags & DDSDMipMapCount)
{
mFlags.set(MipMapsFlag);
}
else
{
// Wipe it if the flag wasn't set!
mMipMapCount = 1;
}
// Deal with 11 DWORDS of reserved space (this reserved space brought to
// you by DirectDraw and the letters F and U).
for(U32 i=0; i<11; i++)
s.read(&tmp);
// Now we're onto the pixel format!
s.read(&tmp);
if(tmp != 32)
{
Con::errorf("DDSFile::readHeader - pixel format chunk has unexpected size!");
return false;
}
U32 ddpfFlags;
s.read(&ddpfFlags);
// Read the next few values so we can deal with them all in one go.
U32 pfFourCC, pfBitCount, pfRMask, pfGMask, pfBMask, pfAlphaMask;
s.read(&pfFourCC);
s.read(&pfBitCount);
s.read(&pfRMask);
s.read(&pfGMask);
s.read(&pfBMask);
s.read(&pfAlphaMask);
// Sanity check flags...
if(!(ddpfFlags & (DDPFRGB | DDPFFourCC)))
{
Con::errorf("DDSFile::readHeader - incoherent pixel flags, neither RGB nor FourCC!");
return false;
}
// For now let's just dump the header info.
if(ddpfFlags & DDPFRGB)
{
mFlags.set(RGBData);
//Con::printf("RGB Pixel format of DDS:");
//Con::printf(" bitcount = %d (16, 24, 32)", pfBitCount);
mBytesPerPixel = pfBitCount / 8;
//Con::printf(" red mask = %x", pfRMask);
//Con::printf(" green mask = %x", pfGMask);
//Con::printf(" blue mask = %x", pfBMask);
mHasAlpha = false;
if(ddpfFlags & DDPFAlphaPixels)
{
mHasAlpha = true;
//Con::printf(" alpha mask = %x", pfAlphaMask);
}
else
{
//Con::printf(" no alpha.");
}
// Try to match a format.
if(mHasAlpha)
{
// If it has alpha it is one of...
// GFXFormatR8G8B8A8
// GFXFormatR5G5B5A1
// GFXFormatA8
if(pfBitCount == 32)
mFormat = GFXFormatR8G8B8A8;
else if(pfBitCount == 16)
mFormat = GFXFormatR5G5B5A1;
else if(pfBitCount == 8)
mFormat = GFXFormatA8;
else
{
Con::errorf("DDSFile::readHeader - unable to match alpha RGB format!");
return false;
}
}
else
{
// Otherwise it is one of...
// GFXFormatR8G8B8
// GFXFormatR8G8B8X8
// GFXFormatR5G6B5
// GFXFormatP8
// GFXFormatL8
if(pfBitCount == 24)
mFormat = GFXFormatR8G8B8;
else if(pfBitCount == 32)
mFormat = GFXFormatR8G8B8X8;
else if(pfBitCount == 16)
mFormat = GFXFormatR5G6B5;
else if(pfBitCount == 8)
{
// Either palette or luminance... And DDS doesn't support palette.
mFormat = GFXFormatL8;
}
else
{
Con::errorf("DDSFile::readHeader - unable to match non-alpha RGB format!");
return false;
}
}
// Sweet, all done.
}
else if (ddpfFlags & DDPFFourCC)
{
mFlags.set(CompressedData);
/* Con::printf("FourCC Pixel format of DDS:");
Con::printf(" fourcc = '%c%c%c%c'", ((U8*)&pfFourCC)[0], ((U8*)&pfFourCC)[1], ((U8*)&pfFourCC)[2], ((U8*)&pfFourCC)[3]); */
// Ok, make a format determination.
switch(pfFourCC)
{
case FOURCC_DXT1:
mFormat = GFXFormatDXT1;
break;
case FOURCC_DXT2:
mFormat = GFXFormatDXT2;
break;
case FOURCC_DXT3:
mFormat = GFXFormatDXT3;
break;
case FOURCC_DXT4:
mFormat = GFXFormatDXT4;
break;
case FOURCC_DXT5:
mFormat = GFXFormatDXT5;
break;
default:
Con::errorf("DDSFile::readHeader - unknown fourcc = '%c%c%c%c'", ((U8*)&pfFourCC)[0], ((U8*)&pfFourCC)[1], ((U8*)&pfFourCC)[2], ((U8*)&pfFourCC)[3]);
break;
}
}
// Deal with final caps bits... Is this really necessary?
U32 caps1, caps2;
s.read(&caps1);
s.read(&caps2);
s.read(&tmp);
s.read(&tmp); // More icky reserved space.
// Screw caps1.
// if(!(caps1 & DDSCAPS_TEXTURE)))
// {
// }
// Caps2 has cubemap/volume info. Care about that.
if(caps2 & DDSCAPS2Cubemap)
{
mFlags.set(CubeMapFlag);
}
// MS has ANOTHER reserved word here. This one particularly sucks.
s.read(&tmp);
return true;
}
bool DDSFile::read(Stream &s)
{
if(!readHeader(s))
{
Con::errorf("DDSFile::read - error reading header!");
return false;
}
// At this point we know what sort of image we contain. So we should
// allocate some buffers, and read it in.
// How many surfaces are we talking about?
if(mFlags.test(CubeMapFlag))
{
// Do something with cubemaps.
}
else if (mFlags.test(VolumeFlag))
{
// Do something with volume
}
else
{
// It's a plain old texture.
// First allocate a SurfaceData to stick this in.
mSurfaces.push_back(new SurfaceData());
// Load the main image.
mSurfaces.last()->addNextMip(this, s, mHeight, mWidth, 0);
// Load however many mips there are.
for(S32 i=1; i<mMipMapCount; i++)
mSurfaces.last()->addNextMip(this, s, mHeight, mWidth, i);
// Ok, we're done.
}
return true;
}
void DDSFile::SurfaceData::addNextMip(DDSFile *dds, Stream &s, U32 height, U32 width, U32 mipLevel)
{
U32 size = dds->getSurfaceSize(height, width, mipLevel);
mMips.push_back(new U8[size]);
if(!s.read(size, mMips.last()))
Con::errorf("DDSFile::SurfaceData::addNextMip - failed to read mip!");
}
【三】怎么上传dds到d3d纹理:
参考下面的代码,及directX中的Using Compressed Textures (Direct3D 9)目录:
/// Load a texture from a proper DDSFile instance.
bool GFXD3D9TextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds)
{
PROFILE_START(GFXD3DTexMan_loadTexture);
GFXD3D9TextureObject *texture = static_cast<GFXD3D9TextureObject*>(aTexture);
// Check with profiler to see if we can do automatic mipmap generation.
bool supportsAutoMips = GFX->getCardProfiler()->queryProfile("autoMipMapLevel", true);
// Settings for mipmap generation
U32 maxDownloadMip = dds->mMipMapCount;
U32 nbMipMapLevel = dds->mMipMapCount;
if(supportsAutoMips && false) // Off it goes!
{
maxDownloadMip = 1;
nbMipMapLevel = aTexture->mMipLevels;
}
// Fill the texture...
U32 i = 0;
while( i < maxDownloadMip)
{
PROFILE_START(GFXD3DTexMan_loadSurface);
U32 width = dds->getWidth(i);
U32 height = dds->getHeight(i);
RECT rect;
rect.left = 0;
rect.right = width;
rect.top = 0;
rect.bottom = height;
LPDIRECT3DSURFACE9 surf = NULL;
D3D9Assert(texture->get2DTex()->GetSurfaceLevel( i, &surf ), "Failed to get surface");
if (surf == NULL)
{
i++;
continue;
}
D3DSURFACE_DESC desc;
surf->GetDesc(&desc);
D3D9Assert( GFXD3DX.D3DXLoadSurfaceFromMemory( surf, NULL, NULL,
(void*)((U8*)(dds->mSurfaces[0]->mMips[i])),
GFXD3D9TextureFormat[dds->mFormat], dds->getPitch(i),
NULL, &rect,
#ifdef TORQUE_OS_XENON
false, 0, 0, // Unique to Xenon -pw
#endif
D3DX_FILTER_NONE, 0 ), "Failed to load surface" );
surf->Release();
++i;
PROFILE_END();
}
PROFILE_END();
return true;
}
【四】d3d怎么切换mipmap:
对d3d的托管纹理都是自动管理的,当然mipmap的切换也是硬件自动完成的。