ddsFloatReader.cpp
#include <maya/MPxImageFile.h>
#include <maya/MImageFileInfo.h>
#include <maya/MImage.h>
#include <maya/MFnPlugin.h>
#include <maya/MStringArray.h>
#include <maya/MIOStream.h>
#if _WIN32
#pragma warning( disable : 4290 ) // Disable STL warnings.
#endif
#include "ddsFloatReader.h"
#include <math.h>
using namespace dds_Float_Reader;
MString kImageFormatName( "DDS Float");
class ddsFloatReader : public MPxImageFile
{
public:
ddsFloatReader();
virtual ~ddsFloatReader();
static void* creator();
virtual MStatus open( MString pathname, MImageFileInfo* info);
virtual MStatus load( MImage& image, unsigned int idx);
virtual MStatus close();
protected:
unsigned int fWidth;
unsigned int fHeight;
unsigned int fNumChannels;
unsigned int fBytesPerPixel;
FILE *fInputFile;
DDS_HEADER fHeader;
};
ddsFloatReader::ddsFloatReader()
: fWidth(0),
fHeight(0),
fNumChannels(0),
fBytesPerPixel(0),
fInputFile(NULL)
{
}
ddsFloatReader::~ddsFloatReader()
{
close();
}
MStatus ddsFloatReader::close()
{
fWidth = 0;
fHeight = 0;
fNumChannels = 0;
fBytesPerPixel = 0;
if (fInputFile != NULL)
fclose(fInputFile);
fInputFile = NULL;
return MS::kSuccess;
}
void * ddsFloatReader::creator()
{
return new ddsFloatReader();
}
inline void swap_endian(void *val)
{
#if defined(OSMac_)
unsigned int *ival = (unsigned int *)val;
*ival = ((*ival >> 24) & 0x000000ff) |
((*ival >> 8) & 0x0000ff00) |
((*ival << 8) & 0x00ff0000) |
((*ival << 24) & 0xff000000);
#endif
}
inline void swap_endian_half(void *val)
{
#if defined(OSMac_)
unsigned short *ival = (unsigned short *)val;
*ival = ((*ival >> 8) & 255) |
((*ival << 8) & 65280);
#endif
}
const double two_pow_neg14 = pow(2.0, -14.0);
inline float halfToFloat(unsigned short val)
{
float outValue = 0.0f;
#if defined(OSMac_)
swap_endian_half( &val );
#endif
double h_mantissa = (float) (val & 1023);
double h_exponent = (float) ((val >> 10) & 31);
unsigned int i_sign = (val >> 15) & 1; ;
double h_sign = (i_sign == 0) ? 1.0 : -1.0;
if (h_exponent != 30.0)
{
outValue = (float) (h_sign * pow(2.0, h_exponent-15.0) * ( 1.0 + ( h_mantissa / 1024.0 )));
}
else
{
outValue = (float) ( h_sign * pow(2.0, two_pow_neg14) * ( h_mantissa / 1024.0 ) );
}
return outValue;
}
MStatus ddsFloatReader::open( MString filename, MImageFileInfo* info)
{
#if _WIN32
if ( ( fInputFile = fopen( filename.asChar(), "rb" ) ) == NULL )
#else
if ( ( fInputFile = fopen( filename.asChar(), "r" ) ) == NULL )
#endif
{
return MS::kFailure;
}
if ( fread( &fHeader, 1, sizeof(DDS_HEADER), fInputFile) == sizeof(DDS_HEADER) )
{
swap_endian(&fHeader.fCapabilities.dwCaps2);
if (( (fHeader.fCapabilities.dwCaps2) & DDSCAPS2_CUBEMAP_FLAG ) ||
( (fHeader.fCapabilities.dwCaps2) & DDSCAPS2_VOLUME_FLAG ))
{
close();
return MS::kFailure;
}
swap_endian(&fHeader.fWidth);
swap_endian(&fHeader.fHeight);
fWidth = fHeader.fWidth;
fHeight = fHeader.fHeight;
fNumChannels = 0;
if (fWidth==0 || fHeight==0)
{
close();
return MS::kFailure;
}
swap_endian(& fHeader.fFormat.fFlags );
if (fHeader.fFormat.fFlags & DDS_FOURCC_FLAG)
{
swap_endian(&fHeader.fFormat.fPixelFormat);
bool supportedFormat = true;
switch (fHeader.fFormat.fPixelFormat)
{
case DDS_R16F:
fNumChannels = 1;
fBytesPerPixel = 2;
break;
case DDS_G16R16F:
fNumChannels = 2;
fBytesPerPixel = 4;
break;
case DDS_A16B16G16R16F:
fNumChannels = 4;
fBytesPerPixel = 8;
break;
case DDS_R32F:
fNumChannels = 1;
fBytesPerPixel = 4;
break;
case DDS_G32R32F:
fNumChannels = 2;
fBytesPerPixel = 8;
break;
case DDS_A32B32G32R32F:
fNumChannels = 4;
fBytesPerPixel = 16;
break;
default:
supportedFormat = false;
break;
}
if (!supportedFormat)
{
close();
return MS::kFailure;
}
}
else
{
close();
return MS::kFailure;
}
if (info)
{
info->numberOfImages( 1 );
info->width( fWidth );
info->height( fHeight );
info->channels( fNumChannels );
info->hasAlpha( fNumChannels == 4 );
info->hasMipMaps( false );
info->imageType( MImageFileInfo::kImageTypeColor );
info->hardwareType( MImageFileInfo::kHwTexture2D );
info->pixelType( MImage::kFloat );
}
}
return MS::kSuccess;
}
MStatus ddsFloatReader::load( MImage& image, unsigned int imageNumber)
{
MStatus loaded = MS::kFailure;
bool isHalfType = false;
switch (fHeader.fFormat.fPixelFormat)
{
case DDS_R16F:
isHalfType = true;
break;
case DDS_G16R16F:
isHalfType = true;
break;
case DDS_A16B16G16R16F:
isHalfType = true;
break;
default:
break;
}
image.create( fWidth, fHeight, fNumChannels, MImage::kFloat);
float* outputBuffer = image.floatPixels();
float *inputFloatBuffer = NULL;
unsigned short *inputIntBuffer = NULL;
if (!isHalfType)
{
inputFloatBuffer = new float[fWidth * fNumChannels];
}
else
inputIntBuffer= new unsigned short[fWidth * fNumChannels];
if ((!inputFloatBuffer && !inputIntBuffer) || !outputBuffer)
{
if (inputFloatBuffer)
{
delete inputFloatBuffer;
inputFloatBuffer = NULL;
}
if (inputIntBuffer)
{
delete inputIntBuffer;
inputIntBuffer = NULL;
}
close();
return MS::kFailure;
}
if (isHalfType)
{
unsigned int x,y;
float *outPtr = outputBuffer;
outPtr += (fHeight-1) * (fWidth * fNumChannels);
for (y=0; y<fHeight; y++)
{
unsigned int numBytes = fWidth * fBytesPerPixel;
fread( inputIntBuffer, 1, numBytes, fInputFile);
unsigned short *inPtr = inputIntBuffer;
for (x=0; x<fWidth * fNumChannels; x++)
{
float outValue = halfToFloat(*inPtr);
*(outPtr + x) = outValue;
inPtr++;
}
outPtr -= (fWidth * fNumChannels);
}
loaded = MS::kSuccess;
}
else
{
unsigned int x,y;
float *outPtr = outputBuffer;
outPtr += (fHeight-1) * (fWidth * fNumChannels);
for (y=0; y<fHeight; y++)
{
unsigned int numBytes = fWidth * fBytesPerPixel;
fread( inputFloatBuffer, 1, numBytes, fInputFile);
#if defined(OSMac_)
unsigned int *bPtr = (unsigned int *)inputFloatBuffer;
unsigned int b;
for (b=0; b<numBytes / 4; b++)
{
swap_endian( bPtr );
bPtr++;
}
#endif
float *inPtr = inputFloatBuffer;
for (x=0; x<fWidth * fNumChannels; x++)
{
*(outPtr + x) = *inPtr;
inPtr++;
}
outPtr -= (fWidth * fNumChannels);
}
loaded = MS::kSuccess;
}
if (inputFloatBuffer)
{
delete inputFloatBuffer;
inputFloatBuffer = NULL;
}
close();
return loaded;
}
MStatus initializePlugin( MObject obj )
{
MFnPlugin plugin( obj, PLUGIN_COMPANY, "8.0", "Any" );
MStringArray extensions;
extensions.append( "dds");
CHECK_MSTATUS( plugin.registerImageFile(
kImageFormatName,
ddsFloatReader::creator,
extensions));
return MS::kSuccess;
}
MStatus uninitializePlugin( MObject obj )
{
MFnPlugin plugin( obj );
CHECK_MSTATUS( plugin.deregisterImageFile( kImageFormatName ) );
return MS::kSuccess;
}