geometryCacheFile.cpp

//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

//
// File Name: geometryCacheFile.cpp
//
// Description : An interface used for reading cache file data, storing it 
// and converting it to ASCII. See geometryCacheFile.h for file format info.
//

// Project includes
//
#include <geometryCacheFile.h>
#include <geometryCacheBlockBase.h>
#include <geometryCacheBlockStringData.h>
#include <geometryCacheBlockIntData.h>
#include <geometryCacheBlockDVAData.h>
#include <geometryCacheBlockFVAData.h>

// Maya includes
//
#include <maya/flib.h>
#include <maya/MString.h>
#include <maya/MGlobal.h>

// Other includes
//
#include <fstream>

#if defined (OSMac_)
#include <stdlib.h>
#else
#include <malloc.h>
#endif

//
// Methods
//

geometryCacheFile::geometryCacheFile( const MString& fileName, MIffFile* iffFile )
        :cacheFileName( fileName )
//
// Description : ( public method )
//              Constructor
//
{       
        readStatus = false;
        iffFilePtr = iffFile;
}

geometryCacheFile::~geometryCacheFile()
//
// Description : ( public method )
//              Destructor
//
{
        // Free all the pointers in the blockList.
        // Start from the back of the list, delete the pointer returned then 
        // pop it off the stack.
        //
        while( blockList.size() )
        {       
                // Get current pointer
                //
                geometryCacheBlockBase * block = blockList.back();

                delete block;

                // Pop the back item of the stack
        //
                blockList.pop_back();
        }
        
        // Close the cache file
        //
        iffFilePtr->close();
}

const MString& geometryCacheFile::fileName()
//
// Description : ( public method )
//              Returns the file name
//
{
        return cacheFileName;
}

const bool& geometryCacheFile::isRead()
//
// Description : ( public method )
//              Indicates if the file has been read
//
{
        return readStatus;
}

bool geometryCacheFile::readCacheFiles()
//
// Description : ( public method )
//              Read the cache file
//
{       
        MStatus status = MS::kSuccess;

        // Attempt to open the file
        //
        status = iffFilePtr->open( cacheFileName );
        if( !status ) return false;

        // Proceed if the file is open
        //
        if( iffFilePtr->isActive() ) {
                // Read the Header
                //
                readStatus      = readHeaderGroup( status );
                if( !readStatus ) return false;

                // Read all the channel groups
                //
                do {
                        // Read the next channel group
                        //
                        readStatus = readChannelGroup( status );
                        if( !readStatus ) return false;

                } while ( status == MS::kSuccess );

        } else
                // If file failed to open
                //
                return false;

        return true;
}

bool geometryCacheFile::convertToAscii()
//
// Description : ( public method )
//              Convert the file to Ascii
//
{
        // Generate an output file name by changing the file name extention to txt
        //
        int loc = cacheFileName.rindex('.');
        MString outputFileName = cacheFileName.substring(0, loc-1);
        outputFileName += ".txt";

        // Create an output file steam to flush our data to ascii
        //
        std::ofstream oFile( outputFileName.asChar() );
        if( !oFile.bad() ) 
        {
                // Create an iterator to iterate through the blockList
                //
                cacheBlockIterator blockIt;

                // Write out all the blocks in the blockList
                //
                for( blockIt = blockList.begin();
                        blockIt != blockList.end();
                        blockIt++ )
                {
                        // Get the current block
                        //
                        geometryCacheBlockBase* block = *blockIt;
                        
                        // OutputToAscii
                        //
                        block->outputToAscii( oFile );
                }
        } else
                // If output file stream could not open the file
                //
                return false;

        // Output a message to indicate that the file has been converted
        //
        MGlobal::displayInfo( "Converted file \"" +
                                                        cacheFileName +
                                                        "\" to file \"" +
                                                        outputFileName + 
                                                        "\"" );
        return true;
}

bool geometryCacheFile::readHeaderGroup( MStatus& status )
//
// Description : ( private method )
//              Read the Header group CACH. 
//              The header of every disk cache file consists of these tags
//
//              CACH    ( header group )
//              VRSN    ( version )
//              STIM    ( startTime in ticks )
//              ETIM    ( endTime in ticks )
//
{
        MIffTag tmpTag;
        MIffTag cachTag;

        status = iffFilePtr->beginReadGroup( tmpTag, cachTag );
        if( status ) {
                if( cachTag == MIffTag('C', 'A', 'C', 'H') ) {
                        // Store a "CACH" tag into the blockList
                        //
                        storeCacheBlock( "CACH" );

                        // Read the header version
                        //
                        readStatus = readHeaderVersion();
                        if( !readStatus ) return false;

                        // Read the Time Range
                        //
                        readStatus = readHeaderTimeRange();
                        if( !readStatus ) return false;

                        // Store an ending "/CACH" tag into the blockList
                        //
                        storeCacheBlock( "/CACH" );
                }               
        }
        iffFilePtr->endReadGroup();

        return true;
}

bool geometryCacheFile::readHeaderVersion()
//
// Description : ( private method )
//              Read and store the cache file version from the VRSN block.
//
{
        MStatus status = MS::kSuccess;
        MIffTag tmpTag;
        unsigned int byteCount;
    
        status = iffFilePtr->beginGet( tmpTag, (unsigned *)&byteCount );
        if( !status ) return false;

        char *tmpName = (char*)alloca(sizeof(char)* (byteCount+1));
        //pointers allocated by alloca are from the stack and automatically freed when
        //the function exits.  Do not free explicitly.

        if( tmpName && tmpTag == MIffTag('V', 'R', 'S', 'N') ) {
                // read the data from the block
                //
                iffFilePtr->get( tmpName, byteCount, &status);
                if( !status ) return false;

                // Store the cache file version in the blockList
                //
                storeCacheBlock( "VRSN", tmpName );

                status = iffFilePtr->endGet();
                if( !status ) return false;
        }

        return true;
}

bool geometryCacheFile::readHeaderTimeRange()
//
// Description : ( private method )
//              Read and store the start and end time from the STIM and ETIM blocks.
//              The data from these blocks are only used for multiple cache files.
//              If the cache file is a single cache file, then the values will only be 
//              from 0 to 1.
//
{
        MStatus status = MS::kSuccess;
        MIffTag tmpTag;
        unsigned int byteCount;
        
#if (!defined BYTE_ORDER) || (BYTE_ORDER == BIG_ENDIAN)
        const int *startTime = (int *)iffFilePtr->getChunk( 
                                                                tmpTag, 
                                                                (unsigned int *)&byteCount );  
        if(     startTime == NULL ||
                !(tmpTag == MIffTag ('S', 'T', 'I', 'M')) || 
                byteCount != sizeof(int) )
                return false;

        // Store the start time in the blockList
        //
        storeCacheBlock( "STIM", *startTime );

        const int *endTime = (int *)iffFilePtr->getChunk( 
                                                                tmpTag, 
                                                                (unsigned int *)&byteCount );  
        if(     endTime == NULL ||
                !(tmpTag == MIffTag('E', 'T', 'I', 'M')) ||
                byteCount != sizeof(int) )
                return false;                           

        // Store the end time in the blockList
        //
        storeCacheBlock( "ETIM", *endTime );
#else
        const int *startTime = (int *)iffFilePtr->getChunk( tmpTag, (unsigned int *)&byteCount );  
        if(     startTime == NULL ||
                // There is no != operator for MIffTag
                !(tmpTag == MIffTag ('S', 'T', 'I', 'M')) ||
                byteCount != sizeof(int) )
                return false;

        // Store the start time in the blockList
        //
        storeCacheBlock( "STIM", FLswapword(*startTime) );

        const int *endTime = (int *)iffFilePtr->getChunk( tmpTag, (unsigned int *)&byteCount );  
        if(     endTime == NULL ||
                !(tmpTag == MIffTag('E', 'T', 'I', 'M')) ||
                byteCount != sizeof(int) )
                return false;

        // Store the end time in the blockList
        //
        storeCacheBlock( "ETIM", FLswapword(*endTime) );
#endif
        return true;
}

bool geometryCacheFile::readChannelGroup( MStatus& groupStatus )
//
// Description : ( private method )
//              Read the channel group MYCH.
//              The channel group can consist of these following tags
//
//              MYCH    ( time group )
//              TIME    ( time in ticks )
//              CHNM    ( channel name )
//              SIZE    ( size )
//              DVCA    ( geometry point data )
//
{
        MIffTag mychTag;
        MIffTag tmpTag;
        unsigned int byteCount;

        groupStatus = iffFilePtr->beginReadGroup(tmpTag, mychTag);
        if( groupStatus == MS::kSuccess ) {
                if( mychTag == MIffTag('M', 'Y', 'C', 'H')) {
                        // Store the "MYCH" group in the blockList
                        //
                        storeCacheBlock( "MYCH" );

                        // Get the next tag
                        //
                        MStatus stat = iffFilePtr->beginGet(tmpTag, (unsigned *)&byteCount);
                        if (!stat) return false;

                        // If the tag is TIME, then this is a single file cache file
                        // Read the time chunk before the channel name chunk
                        //
                        if( tmpTag == MIffTag('T', 'I', 'M', 'E') )
                        {
                                // Read channel time
                                //
                                readStatus = readChannelTime();
                                if ( !readStatus ) return false;

                                // End Get
                                //
                                stat = iffFilePtr->endGet();
                                if (!stat) return false;
                        }

                        // Read Channel
                        //
                        MStatus channelStatus = MS::kSuccess;
                        do {
                                // Read channel name, size and data
                                //
                                readStatus = readChannel( channelStatus );
                                if( !readStatus ) return false;

                        } while ( channelStatus == MS::kSuccess );

                        // Store the ending "/MYCH" in the blockList
                        //
                        storeCacheBlock( "/MYCH" );
                }
        } 
        iffFilePtr->endReadGroup();
        return readStatus;
}

bool geometryCacheFile::readChannelTime()
//
// Description : ( private method )
//              Read and store the channel time from the TIME block.
//
{
        MIffTag tmpTag;
        unsigned int byteCount;

        const int *tmpNum =     (int*) iffFilePtr->getChunk( tmpTag, (unsigned *)&byteCount );
        if( tmpNum && 
                tmpTag == MIffTag('T', 'I', 'M', 'E') && 
                byteCount == sizeof(int)) {
#if (!defined BYTE_ORDER) || (BYTE_ORDER == BIG_ENDIAN)
                // Store the channel time in the blockList
                //
                storeCacheBlock( "TIME", *tmpNum );
#else
                // Store the channel time in the blockList
                //
                storeCacheBlock( "TIME", FLswapword(*tmpNum) );
#endif          
        } 
        return true;
}

bool geometryCacheFile::readChannel( MStatus& channelStatus )
//
// Description : ( private method )
//              Read and store the channel data.
//
{
        readStatus = readChannelName( channelStatus );
        if( !readStatus ) return false;

        // If channelStatus is not MS::Success then this means that there is no
        // more channel data to read.  Return from function.
        //
        if( !channelStatus ) return true;

        readStatus = readChannelData();
        if( !readStatus ) return false;

        return true;
}
bool geometryCacheFile::readChannelName( MStatus& channelStatus )
//
// Description : ( private method )
//              Read and store the channel name from the CHNM block.
//
{
        MStatus lStatus;
        unsigned int byteCount;
        MIffTag chnmTag;
        
        channelStatus = iffFilePtr->beginGet( chnmTag, (unsigned *)&byteCount );
        if( channelStatus == MS::kSuccess ) {
                char *tmpName = (char*)alloca(sizeof(char)* (byteCount+1));
                //pointers allocated by alloca are from the stack and automatically freed when
                //the function exits.  Do not free explicitly.

                if( tmpName && chnmTag == MIffTag('C', 'H', 'N', 'M') ) {
                        iffFilePtr->get( tmpName, byteCount, &lStatus);
                        if( !lStatus ) return false;
                        MString channelName = tmpName;

                        // Store the channel name in the blockList
                        //
                        storeCacheBlock( "CHNM", channelName );
                } else return false;
        } 
        iffFilePtr->endGet();
        return true;
}

bool geometryCacheFile::readChannelData()
//
// Description : ( private method )
//              Read and store the channel size and geometry point data from the SIZE
//              and DVCA or FVCA blocks.
//
{
    MIffTag tmpTag;
        unsigned int byteCount;
        uint size;

        // Read the channel size
        //
        const int *tmpNum = (int*) iffFilePtr->getChunk(tmpTag, (unsigned *)&byteCount);
        if( tmpNum && 
                tmpTag == MIffTag('S', 'I', 'Z', 'E') && 
                byteCount == sizeof(int)) 
        {
#if (!defined BYTE_ORDER) || (BYTE_ORDER == BIG_ENDIAN)
                        size = *tmpNum;
#else
                        size = FLswapword(*tmpNum);
#endif
                // Store the channel size in the blockList
                //
                storeCacheBlock( "SIZE", size );
        } else return false;

        // Read the channel data
        //
        if( size ) {
                const void *tmpVec = (double*) iffFilePtr->getChunk(tmpTag, (unsigned *)&byteCount);

                if( tmpVec && 
                        tmpTag == MIffTag('D', 'V', 'C', 'A') &&
                        size * sizeof(double)*3 == byteCount )
                {
                        double *tmpVecDbl = (double*) tmpVec;
                        double *dataArray = new double[size*3];
#if (!defined BYTE_ORDER) || (BYTE_ORDER == BIG_ENDIAN)
                        memcpy(dataArray, tmpVec, byteCount);
#else
                        for(unsigned int i = 0; i < size*3; i++) {
                                FLswapdouble(tmpVecDbl[i], &(dataArray[i]));
                        }
#endif          
                        // Store the channel geometry points in the blockList
                        //
                        storeCacheBlock( "DVCA", dataArray, size );
                        delete [] dataArray;
                } else if( tmpVec && 
                                   tmpTag == MIffTag('F', 'V', 'C', 'A') &&
                                   size * sizeof(float)*3 == byteCount ) {
                        float *tmpVecFlt = (float*) tmpVec;
                        float *dataArray = new float[size*3];
#if (!defined BYTE_ORDER) || (BYTE_ORDER == BIG_ENDIAN)
                        memcpy(dataArray, tmpVec, byteCount);
#else
                        for(unsigned int i = 0; i < size*3; i++) {
                                FLswapfloat(tmpVecFlt[i], &(dataArray[i]));
                        }
#endif          
                        // Store the channel geometry points in the blockList
                        //
                        storeCacheBlock( "FVCA", dataArray, size );
                        delete [] dataArray;
                } else {
                        return false;
                }
        }
        return true;
}

void geometryCacheFile::storeCacheBlock( const MString& tag )
//
// Description : ( private method )
//              Stores the specified data into the blockList.
//
{
        blockList.push_back( new geometryCacheBlockBase( tag ) );
}

void geometryCacheFile::storeCacheBlock( const MString& tag, const int& value )
//
// Description : ( private method )
//              Stores the specified data into the blockList.
//
{
        blockList.push_back( new geometryCacheBlockIntData( tag, value ) );
}

void geometryCacheFile::storeCacheBlock( const MString& tag, const MString& value  )
//
// Description : ( private method )
//              Stores the specified data into the blockList.
//
{
        blockList.push_back( new geometryCacheBlockStringData( tag, value ) );
}

void geometryCacheFile::storeCacheBlock( const MString& tag, const double* value, const uint& size )
//
// Description : ( private method )
//              Stores the specified data into the blockList.
//
{
        blockList.push_back( new geometryCacheBlockDVAData( tag, value, size ) );
}


void geometryCacheFile::storeCacheBlock( const MString& tag, const float* value, const uint& size )
//
// Description : ( private method )
//              Stores the specified data into the blockList.
//
{
        blockList.push_back( new geometryCacheBlockFVAData( tag, value, size ) );
}

Autodesk® Maya® 2009 © 1997-2008 Autodesk, Inc. All rights reserved. Generated with doxygen 1.5.6