|
Packit |
c2c737 |
///////////////////////////////////////////////////////////////////////////
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
|
|
Packit |
c2c737 |
// Digital Ltd. LLC
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// All rights reserved.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Redistribution and use in source and binary forms, with or without
|
|
Packit |
c2c737 |
// modification, are permitted provided that the following conditions are
|
|
Packit |
c2c737 |
// met:
|
|
Packit |
c2c737 |
// * Redistributions of source code must retain the above copyright
|
|
Packit |
c2c737 |
// notice, this list of conditions and the following disclaimer.
|
|
Packit |
c2c737 |
// * Redistributions in binary form must reproduce the above
|
|
Packit |
c2c737 |
// copyright notice, this list of conditions and the following disclaimer
|
|
Packit |
c2c737 |
// in the documentation and/or other materials provided with the
|
|
Packit |
c2c737 |
// distribution.
|
|
Packit |
c2c737 |
// * Neither the name of Industrial Light & Magic nor the names of
|
|
Packit |
c2c737 |
// its contributors may be used to endorse or promote products derived
|
|
Packit |
c2c737 |
// from this software without specific prior written permission.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
c2c737 |
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
c2c737 |
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
Packit |
c2c737 |
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
Packit |
c2c737 |
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
Packit |
c2c737 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
Packit |
c2c737 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
Packit |
c2c737 |
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
Packit |
c2c737 |
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
Packit |
c2c737 |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
c2c737 |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
///////////////////////////////////////////////////////////////////////////
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//-----------------------------------------------------------------------------
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Miscellaneous stuff related to tiled files
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
//-----------------------------------------------------------------------------
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
#include <ImfTiledMisc.h>
|
|
Packit |
c2c737 |
#include "Iex.h"
|
|
Packit |
c2c737 |
#include <ImfMisc.h>
|
|
Packit |
c2c737 |
#include <ImfChannelList.h>
|
|
Packit |
c2c737 |
#include <ImfTileDescription.h>
|
|
Packit |
c2c737 |
#include <algorithm>
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
#include "ImfNamespace.h"
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
using IMATH_NAMESPACE::Box2i;
|
|
Packit |
c2c737 |
using IMATH_NAMESPACE::V2i;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int
|
|
Packit |
c2c737 |
levelSize (int min, int max, int l, LevelRoundingMode rmode)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
if (l < 0)
|
|
Packit |
c2c737 |
throw IEX_NAMESPACE::ArgExc ("Argument not in valid range.");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int a = max - min + 1;
|
|
Packit |
c2c737 |
int b = (1 << l);
|
|
Packit |
c2c737 |
int size = a / b;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (rmode == ROUND_UP && size * b < a)
|
|
Packit |
c2c737 |
size += 1;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
return std::max (size, 1);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
Box2i
|
|
Packit |
c2c737 |
dataWindowForLevel (const TileDescription &tileDesc,
|
|
Packit |
c2c737 |
int minX, int maxX,
|
|
Packit |
c2c737 |
int minY, int maxY,
|
|
Packit |
c2c737 |
int lx, int ly)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
V2i levelMin = V2i (minX, minY);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
V2i levelMax = levelMin +
|
|
Packit |
c2c737 |
V2i (levelSize (minX, maxX, lx, tileDesc.roundingMode) - 1,
|
|
Packit |
c2c737 |
levelSize (minY, maxY, ly, tileDesc.roundingMode) - 1);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
return Box2i(levelMin, levelMax);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
Box2i
|
|
Packit |
c2c737 |
dataWindowForTile (const TileDescription &tileDesc,
|
|
Packit |
c2c737 |
int minX, int maxX,
|
|
Packit |
c2c737 |
int minY, int maxY,
|
|
Packit |
c2c737 |
int dx, int dy,
|
|
Packit |
c2c737 |
int lx, int ly)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
V2i tileMin = V2i (minX + dx * tileDesc.xSize,
|
|
Packit |
c2c737 |
minY + dy * tileDesc.ySize);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
V2i tileMax = tileMin + V2i (tileDesc.xSize - 1, tileDesc.ySize - 1);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
V2i levelMax = dataWindowForLevel
|
|
Packit |
c2c737 |
(tileDesc, minX, maxX, minY, maxY, lx, ly).max;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
tileMax = V2i (std::min (tileMax[0], levelMax[0]),
|
|
Packit |
c2c737 |
std::min (tileMax[1], levelMax[1]));
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
return Box2i (tileMin, tileMax);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
size_t
|
|
Packit |
c2c737 |
calculateBytesPerPixel (const Header &header)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
const ChannelList &channels = header.channels();
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
size_t bytesPerPixel = 0;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
for (ChannelList::ConstIterator c = channels.begin();
|
|
Packit |
c2c737 |
c != channels.end();
|
|
Packit |
c2c737 |
++c)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
bytesPerPixel += pixelTypeSize (c.channel().type);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
return bytesPerPixel;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void
|
|
Packit |
c2c737 |
calculateBytesPerLine (const Header &header,
|
|
Packit |
c2c737 |
char* sampleCountBase,
|
|
Packit |
c2c737 |
int sampleCountXStride,
|
|
Packit |
c2c737 |
int sampleCountYStride,
|
|
Packit |
c2c737 |
int minX, int maxX,
|
|
Packit |
c2c737 |
int minY, int maxY,
|
|
Packit |
c2c737 |
std::vector<int>& xOffsets,
|
|
Packit |
c2c737 |
std::vector<int>& yOffsets,
|
|
Packit |
c2c737 |
std::vector<Int64>& bytesPerLine)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
const ChannelList &channels = header.channels();
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int pos = 0;
|
|
Packit |
c2c737 |
for (ChannelList::ConstIterator c = channels.begin();
|
|
Packit |
c2c737 |
c != channels.end();
|
|
Packit |
c2c737 |
++c, ++pos)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
int xOffset = xOffsets[pos];
|
|
Packit |
c2c737 |
int yOffset = yOffsets[pos];
|
|
Packit |
c2c737 |
int i = 0;
|
|
Packit |
c2c737 |
for (int y = minY - yOffset; y <= maxY - yOffset; y++, i++)
|
|
Packit |
c2c737 |
for (int x = minX - xOffset; x <= maxX - xOffset; x++)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
bytesPerLine[i] += sampleCount(sampleCountBase,
|
|
Packit |
c2c737 |
sampleCountXStride,
|
|
Packit |
c2c737 |
sampleCountYStride,
|
|
Packit |
c2c737 |
x, y)
|
|
Packit |
c2c737 |
* pixelTypeSize (c.channel().type);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
namespace {
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int
|
|
Packit |
c2c737 |
floorLog2 (int x)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// For x > 0, floorLog2(y) returns floor(log(x)/log(2)).
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int y = 0;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
while (x > 1)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
y += 1;
|
|
Packit |
c2c737 |
x >>= 1;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
return y;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int
|
|
Packit |
c2c737 |
ceilLog2 (int x)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// For x > 0, ceilLog2(y) returns ceil(log(x)/log(2)).
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int y = 0;
|
|
Packit |
c2c737 |
int r = 0;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
while (x > 1)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
if (x & 1)
|
|
Packit |
c2c737 |
r = 1;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
y += 1;
|
|
Packit |
c2c737 |
x >>= 1;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
return y + r;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int
|
|
Packit |
c2c737 |
roundLog2 (int x, LevelRoundingMode rmode)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
return (rmode == ROUND_DOWN)? floorLog2 (x): ceilLog2 (x);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int
|
|
Packit |
c2c737 |
calculateNumXLevels (const TileDescription& tileDesc,
|
|
Packit |
c2c737 |
int minX, int maxX,
|
|
Packit |
c2c737 |
int minY, int maxY)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
int num = 0;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
switch (tileDesc.mode)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
case ONE_LEVEL:
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
num = 1;
|
|
Packit |
c2c737 |
break;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
case MIPMAP_LEVELS:
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
int w = maxX - minX + 1;
|
|
Packit |
c2c737 |
int h = maxY - minY + 1;
|
|
Packit |
c2c737 |
num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
break;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
case RIPMAP_LEVELS:
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
int w = maxX - minX + 1;
|
|
Packit |
c2c737 |
num = roundLog2 (w, tileDesc.roundingMode) + 1;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
break;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
default:
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
return num;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int
|
|
Packit |
c2c737 |
calculateNumYLevels (const TileDescription& tileDesc,
|
|
Packit |
c2c737 |
int minX, int maxX,
|
|
Packit |
c2c737 |
int minY, int maxY)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
int num = 0;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
switch (tileDesc.mode)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
case ONE_LEVEL:
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
num = 1;
|
|
Packit |
c2c737 |
break;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
case MIPMAP_LEVELS:
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
int w = maxX - minX + 1;
|
|
Packit |
c2c737 |
int h = maxY - minY + 1;
|
|
Packit |
c2c737 |
num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
break;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
case RIPMAP_LEVELS:
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
int h = maxY - minY + 1;
|
|
Packit |
c2c737 |
num = roundLog2 (h, tileDesc.roundingMode) + 1;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
break;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
default:
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
return num;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void
|
|
Packit |
c2c737 |
calculateNumTiles (int *numTiles,
|
|
Packit |
c2c737 |
int numLevels,
|
|
Packit |
c2c737 |
int min, int max,
|
|
Packit |
c2c737 |
int size,
|
|
Packit |
c2c737 |
LevelRoundingMode rmode)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
for (int i = 0; i < numLevels; i++)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
numTiles[i] = (levelSize (min, max, i, rmode) + size - 1) / size;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
} // namespace
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void
|
|
Packit |
c2c737 |
precalculateTileInfo (const TileDescription& tileDesc,
|
|
Packit |
c2c737 |
int minX, int maxX,
|
|
Packit |
c2c737 |
int minY, int maxY,
|
|
Packit |
c2c737 |
int *&numXTiles, int *&numYTiles,
|
|
Packit |
c2c737 |
int &numXLevels, int &numYLevels)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
numXLevels = calculateNumXLevels(tileDesc, minX, maxX, minY, maxY);
|
|
Packit |
c2c737 |
numYLevels = calculateNumYLevels(tileDesc, minX, maxX, minY, maxY);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
numXTiles = new int[numXLevels];
|
|
Packit |
c2c737 |
numYTiles = new int[numYLevels];
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
calculateNumTiles (numXTiles,
|
|
Packit |
c2c737 |
numXLevels,
|
|
Packit |
c2c737 |
minX, maxX,
|
|
Packit |
c2c737 |
tileDesc.xSize,
|
|
Packit |
c2c737 |
tileDesc.roundingMode);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
calculateNumTiles (numYTiles,
|
|
Packit |
c2c737 |
numYLevels,
|
|
Packit |
c2c737 |
minY, maxY,
|
|
Packit |
c2c737 |
tileDesc.ySize,
|
|
Packit |
c2c737 |
tileDesc.roundingMode);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int
|
|
Packit |
c2c737 |
getTiledChunkOffsetTableSize(const Header& header)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Save the dataWindow information
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
const Box2i &dataWindow = header.dataWindow();
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Precompute level and tile information.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int* numXTiles;
|
|
Packit |
c2c737 |
int* numYTiles;
|
|
Packit |
c2c737 |
int numXLevels;
|
|
Packit |
c2c737 |
int numYLevels;
|
|
Packit |
c2c737 |
precalculateTileInfo (header.tileDescription(),
|
|
Packit |
c2c737 |
dataWindow.min.x, dataWindow.max.x,
|
|
Packit |
c2c737 |
dataWindow.min.y, dataWindow.max.y,
|
|
Packit |
c2c737 |
numXTiles, numYTiles,
|
|
Packit |
c2c737 |
numXLevels, numYLevels);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Calculate lineOffsetSize.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
int lineOffsetSize = 0;
|
|
Packit |
c2c737 |
const TileDescription &desc = header.tileDescription();
|
|
Packit |
c2c737 |
switch (desc.mode)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
case ONE_LEVEL:
|
|
Packit |
c2c737 |
case MIPMAP_LEVELS:
|
|
Packit |
c2c737 |
for (int i = 0; i < numXLevels; i++)
|
|
Packit |
c2c737 |
lineOffsetSize += numXTiles[i] * numYTiles[i];
|
|
Packit |
c2c737 |
break;
|
|
Packit |
c2c737 |
case RIPMAP_LEVELS:
|
|
Packit |
c2c737 |
for (int i = 0; i < numXLevels; i++)
|
|
Packit |
c2c737 |
for (int j = 0; j < numYLevels; j++)
|
|
Packit |
c2c737 |
lineOffsetSize += numXTiles[i] * numYTiles[j];
|
|
Packit |
c2c737 |
break;
|
|
Packit |
c2c737 |
case NUM_LEVELMODES :
|
|
Packit |
c2c737 |
throw IEX_NAMESPACE::LogicExc("Bad level mode getting chunk offset table size");
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
delete[] numXTiles;
|
|
Packit |
c2c737 |
delete[] numYTiles;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
return lineOffsetSize;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
|