public override object Decode( Stream input, Stream output, params object[] args )
{
int filePos = 0;
// Read 4 character code
{
byte[] filetype = new byte[sizeof(uint)];
filePos += input.Read( filetype, filePos, sizeof ( uint ) );
uint fileType = 0;
IntPtr ptr = Memory.PinObject( fileType );
FlipEndian( ptr, sizeof(uint), 1);
Memory.UnpinObject( fileType );
if (new FourCC('D', 'D', 'S', ' ') != fileType)
{
throw new AxiomException("This is not a DDS file!");
}
}
/* // Read header in full
DDSHeader header;
stream->read(&header, sizeof(DDSHeader));
// Endian flip if required, all 32-bit values
flipEndian(&header, 4, sizeof(DDSHeader) / 4);
// Check some sizes
if (header.size != DDS_HEADER_SIZE)
{
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
"DDS header size mismatch!", "DDSCodec::decode");
}
if (header.pixelFormat.size != DDS_PIXELFORMAT_SIZE)
{
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
"DDS header size mismatch!", "DDSCodec::decode");
}
ImageData* imgData = OGRE_NEW ImageData();
MemoryDataStreamPtr output;
imgData->depth = 1; // (deal with volume later)
imgData->width = header.width;
imgData->height = header.height;
size_t numFaces = 1; // assume one face until we know otherwise
if (header.caps.caps1 & DDSCAPS_MIPMAP)
{
imgData->num_mipmaps = static_cast<ushort>(header.mipMapCount - 1);
}
else
{
imgData->num_mipmaps = 0;
}
imgData->flags = 0;
bool decompressDXT = false;
// Figure out basic image type
if (header.caps.caps2 & DDSCAPS2_CUBEMAP)
{
imgData->flags |= IF_CUBEMAP;
numFaces = 6;
}
else if (header.caps.caps2 & DDSCAPS2_VOLUME)
{
imgData->flags |= IF_3D_TEXTURE;
imgData->depth = header.depth;
}
// Pixel format
PixelFormat sourceFormat = PF_UNKNOWN;
if (header.pixelFormat.flags & DDPF_FOURCC)
{
sourceFormat = convertFourCCFormat(header.pixelFormat.fourCC);
}
else
{
sourceFormat = convertPixelFormat(header.pixelFormat.rgbBits,
header.pixelFormat.redMask, header.pixelFormat.greenMask,
header.pixelFormat.blueMask,
header.pixelFormat.flags & DDPF_ALPHAPIXELS ?
header.pixelFormat.alphaMask : 0);
}
if (PixelUtil::isCompressed(sourceFormat))
{
if (!Root::getSingleton().getRenderSystem()->getCapabilities()
->hasCapability(RSC_TEXTURE_COMPRESSION_DXT))
{
// We'll need to decompress
decompressDXT = true;
// Convert format
switch (sourceFormat)
{
case PF_DXT1:
// source can be either 565 or 5551 depending on whether alpha present
// unfortunately you have to read a block to figure out which
// Note that we upgrade to 32-bit pixel formats here, even
// though the source is 16-bit; this is because the interpolated
// values will benefit from the 32-bit results, and the source
// from which the 16-bit samples are calculated may have been
// 32-bit so can benefit from this.
DXTColourBlock block;
stream->read(&block, sizeof(DXTColourBlock));
flipEndian(&(block.colour_0), sizeof(uint16), 1);
flipEndian(&(block.colour_1), sizeof(uint16), 1);
// skip back since we'll need to read this again
stream->skip(0 - sizeof(DXTColourBlock));
// colour_0 <= colour_1 means transparency in DXT1
if (block.colour_0 <= block.colour_1)
{
imgData->format = PF_BYTE_RGBA;
}
else
{
imgData->format = PF_BYTE_RGB;
}
break;
case PF_DXT2:
case PF_DXT3:
case PF_DXT4:
case PF_DXT5:
// full alpha present, formats vary only in encoding
imgData->format = PF_BYTE_RGBA;
break;
default:
// all other cases need no special format handling
break;
}
}
else
{
// Use original format
imgData->format = sourceFormat;
// Keep DXT data compressed
imgData->flags |= IF_COMPRESSED;
}
}
else // not compressed
{
// Don't test against DDPF_RGB since greyscale DDS doesn't set this
// just derive any other kind of format
imgData->format = sourceFormat;
}
// Calculate total size from number of mipmaps, faces and size
imgData->size = Image::calculateSize(imgData->num_mipmaps, numFaces,
imgData->width, imgData->height, imgData->depth, imgData->format);
// Bind output buffer
output.bind(OGRE_NEW MemoryDataStream(imgData->size));
// Now deal with the data
void* destPtr = output->getPtr();
// all mips for a face, then each face
for(size_t i = 0; i < numFaces; ++i)
{
size_t width = imgData->width;
size_t height = imgData->height;
size_t depth = imgData->depth;
for(size_t mip = 0; mip <= imgData->num_mipmaps; ++mip)
{
size_t dstPitch = width * PixelUtil::getNumElemBytes(imgData->format);
if (PixelUtil::isCompressed(sourceFormat))
{
// Compressed data
if (decompressDXT)
{
DXTColourBlock col;
DXTInterpolatedAlphaBlock iAlpha;
DXTExplicitAlphaBlock eAlpha;
// 4x4 block of decompressed colour
ColourValue tempColours[16];
size_t destBpp = PixelUtil::getNumElemBytes(imgData->format);
size_t sx = std::min(width, (size_t)4);
size_t sy = std::min(height, (size_t)4);
size_t destPitchMinus4 = dstPitch - destBpp * sx;
// slices are done individually
for(size_t z = 0; z < depth; ++z)
{
// 4x4 blocks in x/y
for (size_t y = 0; y < height; y += 4)
{
for (size_t x = 0; x < width; x += 4)
{
if (sourceFormat == PF_DXT2 ||
sourceFormat == PF_DXT3)
{
// explicit alpha
stream->read(&eAlpha, sizeof(DXTExplicitAlphaBlock));
flipEndian(eAlpha.alphaRow, sizeof(uint16), 4);
unpackDXTAlpha(eAlpha, tempColours) ;
}
else if (sourceFormat == PF_DXT4 ||
sourceFormat == PF_DXT5)
{
// interpolated alpha
stream->read(&iAlpha, sizeof(DXTInterpolatedAlphaBlock));
flipEndian(&(iAlpha.alpha_0), sizeof(uint16), 1);
flipEndian(&(iAlpha.alpha_1), sizeof(uint16), 1);
unpackDXTAlpha(iAlpha, tempColours) ;
}
// always read colour
stream->read(&col, sizeof(DXTColourBlock));
flipEndian(&(col.colour_0), sizeof(uint16), 1);
flipEndian(&(col.colour_1), sizeof(uint16), 1);
unpackDXTColour(sourceFormat, col, tempColours);
// write 4x4 block to uncompressed version
for (size_t by = 0; by < sy; ++by)
{
for (size_t bx = 0; bx < sx; ++bx)
{
PixelUtil::packColour(tempColours[by*4+bx],
imgData->format, destPtr);
destPtr = static_cast<void*>(
static_cast<uchar*>(destPtr) + destBpp);
}
// advance to next row
destPtr = static_cast<void*>(
static_cast<uchar*>(destPtr) + destPitchMinus4);
}
// next block. Our dest pointer is 4 lines down
// from where it started
if (x + 4 >= width)
{
// Jump back to the start of the line
destPtr = static_cast<void*>(
static_cast<uchar*>(destPtr) - destPitchMinus4);
}
else
{
// Jump back up 4 rows and 4 pixels to the
// right to be at the next block to the right
destPtr = static_cast<void*>(
static_cast<uchar*>(destPtr) - dstPitch * sy + destBpp * sx);
}
}
}
}
}
else
{
// load directly
// DDS format lies! sizeOrPitch is not always set for DXT!!
size_t dxtSize = PixelUtil::getMemorySize(width, height, depth, imgData->format);
stream->read(destPtr, dxtSize);
destPtr = static_cast<void*>(static_cast<uchar*>(destPtr) + dxtSize);
}
}
else
{
// Final data - trim incoming pitch
size_t srcPitch;
if (header.flags & DDSD_PITCH)
{
srcPitch = header.sizeOrPitch /
std::max((size_t)1, mip * 2);
}
else
{
// assume same as final pitch
srcPitch = dstPitch;
}
assert (dstPitch <= srcPitch);
long srcAdvance = static_cast<long>(srcPitch) - static_cast<long>(dstPitch);
for (size_t z = 0; z < imgData->depth; ++z)
{
for (size_t y = 0; y < imgData->height; ++y)
{
stream->read(destPtr, dstPitch);
if (srcAdvance > 0)
stream->skip(srcAdvance);
destPtr = static_cast<void*>(static_cast<uchar*>(destPtr) + dstPitch);
}
}
}
/// Next mip
if(width!=1) width /= 2;
if(height!=1) height /= 2;
if(depth!=1) depth /= 2;
}
}
DecodeResult ret;
ret.first = output;
ret.second = CodecDataPtr(imgData);
return ret;*/
return null;
}