压缩纹理(续)

前面详细介绍了压缩纹理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的切换也是硬件自动完成的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值