386 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			386 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
///////////////////////////////////////////////////////////////////////////
 | 
						|
//
 | 
						|
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
 | 
						|
// Digital Ltd. LLC
 | 
						|
//
 | 
						|
// All rights reserved.
 | 
						|
//
 | 
						|
// Redistribution and use in source and binary forms, with or without
 | 
						|
// modification, are permitted provided that the following conditions are
 | 
						|
// met:
 | 
						|
// *       Redistributions of source code must retain the above copyright
 | 
						|
// notice, this list of conditions and the following disclaimer.
 | 
						|
// *       Redistributions in binary form must reproduce the above
 | 
						|
// copyright notice, this list of conditions and the following disclaimer
 | 
						|
// in the documentation and/or other materials provided with the
 | 
						|
// distribution.
 | 
						|
// *       Neither the name of Industrial Light & Magic nor the names of
 | 
						|
// its contributors may be used to endorse or promote products derived
 | 
						|
// from this software without specific prior written permission.
 | 
						|
//
 | 
						|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
						|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
						|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
						|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
						|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
//
 | 
						|
///////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
//
 | 
						|
//	class TileOffsets
 | 
						|
//
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
 | 
						|
#include <ImfTileOffsets.h>
 | 
						|
#include <ImfXdr.h>
 | 
						|
#include <ImfIO.h>
 | 
						|
#include "Iex.h"
 | 
						|
 | 
						|
namespace Imf {
 | 
						|
 | 
						|
 | 
						|
TileOffsets::TileOffsets (LevelMode mode,
 | 
						|
              int numXLevels, int numYLevels,
 | 
						|
              const int *numXTiles, const int *numYTiles)
 | 
						|
:
 | 
						|
    _mode (mode),
 | 
						|
    _numXLevels (numXLevels),
 | 
						|
    _numYLevels (numYLevels)
 | 
						|
{
 | 
						|
    switch (_mode)
 | 
						|
    {
 | 
						|
      case ONE_LEVEL:
 | 
						|
      case MIPMAP_LEVELS:
 | 
						|
 | 
						|
        _offsets.resize (_numXLevels);
 | 
						|
 | 
						|
        for (unsigned int l = 0; l < _offsets.size(); ++l)
 | 
						|
        {
 | 
						|
            _offsets[l].resize (numYTiles[l]);
 | 
						|
 | 
						|
            for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
 | 
						|
        {
 | 
						|
                _offsets[l][dy].resize (numXTiles[l]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      case RIPMAP_LEVELS:
 | 
						|
 | 
						|
        _offsets.resize (_numXLevels * _numYLevels);
 | 
						|
 | 
						|
        for (unsigned int ly = 0; ly < _numYLevels; ++ly)
 | 
						|
        {
 | 
						|
            for (unsigned int lx = 0; lx < _numXLevels; ++lx)
 | 
						|
            {
 | 
						|
                int l = ly * _numXLevels + lx;
 | 
						|
                _offsets[l].resize (numYTiles[ly]);
 | 
						|
 | 
						|
                for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
 | 
						|
                {
 | 
						|
                    _offsets[l][dy].resize (numXTiles[lx]);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool
 | 
						|
TileOffsets::anyOffsetsAreInvalid () const
 | 
						|
{
 | 
						|
    for (unsigned int l = 0; l < _offsets.size(); ++l)
 | 
						|
    for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
 | 
						|
        for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
 | 
						|
        if (_offsets[l][dy][dx] <= 0)
 | 
						|
            return true;
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
TileOffsets::findTiles (IStream &is)
 | 
						|
{
 | 
						|
    for (unsigned int l = 0; l < _offsets.size(); ++l)
 | 
						|
    {
 | 
						|
    for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
 | 
						|
    {
 | 
						|
        for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
 | 
						|
        {
 | 
						|
        Int64 tileOffset = is.tellg();
 | 
						|
 | 
						|
        int tileX;
 | 
						|
        Xdr::read <StreamIO> (is, tileX);
 | 
						|
 | 
						|
        int tileY;
 | 
						|
        Xdr::read <StreamIO> (is, tileY);
 | 
						|
 | 
						|
        int levelX;
 | 
						|
        Xdr::read <StreamIO> (is, levelX);
 | 
						|
 | 
						|
        int levelY;
 | 
						|
        Xdr::read <StreamIO> (is, levelY);
 | 
						|
 | 
						|
        int dataSize;
 | 
						|
        Xdr::read <StreamIO> (is, dataSize);
 | 
						|
 | 
						|
        Xdr::skip <StreamIO> (is, dataSize);
 | 
						|
 | 
						|
        if (!isValidTile(tileX, tileY, levelX, levelY))
 | 
						|
            return;
 | 
						|
 | 
						|
        operator () (tileX, tileY, levelX, levelY) = tileOffset;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
TileOffsets::reconstructFromFile (IStream &is)
 | 
						|
{
 | 
						|
    //
 | 
						|
    // Try to reconstruct a missing tile offset table by sequentially
 | 
						|
    // scanning through the file, and recording the offsets in the file
 | 
						|
    // of the tiles we find.
 | 
						|
    //
 | 
						|
 | 
						|
    Int64 position = is.tellg();
 | 
						|
 | 
						|
    try
 | 
						|
    {
 | 
						|
    findTiles (is);
 | 
						|
    }
 | 
						|
    catch (...)
 | 
						|
    {
 | 
						|
        //
 | 
						|
        // Suppress all exceptions.  This function is called only to
 | 
						|
    // reconstruct the tile offset table for incomplete files,
 | 
						|
    // and exceptions are likely.
 | 
						|
        //
 | 
						|
    }
 | 
						|
 | 
						|
    is.clear();
 | 
						|
    is.seekg (position);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
TileOffsets::readFrom (IStream &is, bool &complete)
 | 
						|
{
 | 
						|
    //
 | 
						|
    // Read in the tile offsets from the file's tile offset table
 | 
						|
    //
 | 
						|
 | 
						|
    for (unsigned int l = 0; l < _offsets.size(); ++l)
 | 
						|
    for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
 | 
						|
        for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
 | 
						|
        Xdr::read <StreamIO> (is, _offsets[l][dy][dx]);
 | 
						|
 | 
						|
    //
 | 
						|
    // Check if any tile offsets are invalid.
 | 
						|
    //
 | 
						|
    // Invalid offsets mean that the file is probably incomplete
 | 
						|
    // (the offset table is the last thing written to the file).
 | 
						|
    // Either some process is still busy writing the file, or
 | 
						|
    // writing the file was aborted.
 | 
						|
    //
 | 
						|
    // We should still be able to read the existing parts of the
 | 
						|
    // file.  In order to do this, we have to make a sequential
 | 
						|
    // scan over the scan tile to reconstruct the tile offset
 | 
						|
    // table.
 | 
						|
    //
 | 
						|
 | 
						|
    if (anyOffsetsAreInvalid())
 | 
						|
    {
 | 
						|
    complete = false;
 | 
						|
    reconstructFromFile (is);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
    complete = true;
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
Int64
 | 
						|
TileOffsets::writeTo (OStream &os) const
 | 
						|
{
 | 
						|
    //
 | 
						|
    // Write the tile offset table to the file, and
 | 
						|
    // return the position of the start of the table
 | 
						|
    // in the file.
 | 
						|
    //
 | 
						|
 | 
						|
    Int64 pos = os.tellp();
 | 
						|
 | 
						|
    if (pos == -1)
 | 
						|
    Iex::throwErrnoExc ("Cannot determine current file position (%T).");
 | 
						|
 | 
						|
    for (unsigned int l = 0; l < _offsets.size(); ++l)
 | 
						|
    for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
 | 
						|
        for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
 | 
						|
        Xdr::write <StreamIO> (os, _offsets[l][dy][dx]);
 | 
						|
 | 
						|
    return pos;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool
 | 
						|
TileOffsets::isEmpty () const
 | 
						|
{
 | 
						|
    for (unsigned int l = 0; l < _offsets.size(); ++l)
 | 
						|
    for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
 | 
						|
        for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
 | 
						|
        if (_offsets[l][dy][dx] != 0)
 | 
						|
            return false;
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool
 | 
						|
TileOffsets::isValidTile (int dx, int dy, int lx, int ly) const
 | 
						|
{
 | 
						|
    switch (_mode)
 | 
						|
    {
 | 
						|
      case ONE_LEVEL:
 | 
						|
 | 
						|
        if (lx == 0 &&
 | 
						|
        ly == 0 &&
 | 
						|
        _offsets.size() > 0 &&
 | 
						|
            _offsets[0].size() > dy &&
 | 
						|
            _offsets[0][dy].size() > dx)
 | 
						|
    {
 | 
						|
            return true;
 | 
						|
    }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      case MIPMAP_LEVELS:
 | 
						|
 | 
						|
        if (lx < _numXLevels &&
 | 
						|
        ly < _numYLevels &&
 | 
						|
            _offsets.size() > lx &&
 | 
						|
            _offsets[lx].size() > dy &&
 | 
						|
            _offsets[lx][dy].size() > dx)
 | 
						|
    {
 | 
						|
            return true;
 | 
						|
    }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      case RIPMAP_LEVELS:
 | 
						|
 | 
						|
        if (lx < _numXLevels &&
 | 
						|
        ly < _numYLevels &&
 | 
						|
            _offsets.size() > lx + ly * _numXLevels &&
 | 
						|
            _offsets[lx + ly * _numXLevels].size() > dy &&
 | 
						|
            _offsets[lx + ly * _numXLevels][dy].size() > dx)
 | 
						|
    {
 | 
						|
            return true;
 | 
						|
    }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
Int64 &
 | 
						|
TileOffsets::operator () (int dx, int dy, int lx, int ly)
 | 
						|
{
 | 
						|
    //
 | 
						|
    // Looks up the value of the tile with tile coordinate (dx, dy)
 | 
						|
    // and level number (lx, ly) in the _offsets array, and returns
 | 
						|
    // the cooresponding offset.
 | 
						|
    //
 | 
						|
 | 
						|
    switch (_mode)
 | 
						|
    {
 | 
						|
      case ONE_LEVEL:
 | 
						|
 | 
						|
        return _offsets[0][dy][dx];
 | 
						|
        break;
 | 
						|
 | 
						|
      case MIPMAP_LEVELS:
 | 
						|
 | 
						|
        return _offsets[lx][dy][dx];
 | 
						|
        break;
 | 
						|
 | 
						|
      case RIPMAP_LEVELS:
 | 
						|
 | 
						|
        return _offsets[lx + ly * _numXLevels][dy][dx];
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
 | 
						|
        throw Iex::ArgExc ("Unknown LevelMode format.");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
Int64 &
 | 
						|
TileOffsets::operator () (int dx, int dy, int l)
 | 
						|
{
 | 
						|
    return operator () (dx, dy, l, l);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
const Int64 &
 | 
						|
TileOffsets::operator () (int dx, int dy, int lx, int ly) const
 | 
						|
{
 | 
						|
    //
 | 
						|
    // Looks up the value of the tile with tile coordinate (dx, dy)
 | 
						|
    // and level number (lx, ly) in the _offsets array, and returns
 | 
						|
    // the cooresponding offset.
 | 
						|
    //
 | 
						|
 | 
						|
    switch (_mode)
 | 
						|
    {
 | 
						|
      case ONE_LEVEL:
 | 
						|
 | 
						|
        return _offsets[0][dy][dx];
 | 
						|
        break;
 | 
						|
 | 
						|
      case MIPMAP_LEVELS:
 | 
						|
 | 
						|
        return _offsets[lx][dy][dx];
 | 
						|
        break;
 | 
						|
 | 
						|
      case RIPMAP_LEVELS:
 | 
						|
 | 
						|
        return _offsets[lx + ly * _numXLevels][dy][dx];
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
 | 
						|
        throw Iex::ArgExc ("Unknown LevelMode format.");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
const Int64 &
 | 
						|
TileOffsets::operator () (int dx, int dy, int l) const
 | 
						|
{
 | 
						|
    return operator () (dx, dy, l, l);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
} // namespace Imf
 |