1///////////////////////////////////////////////////////////////////////////
2//
3// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
4// Digital Ltd. LLC
5//
6// All rights reserved.
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11// *       Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// *       Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17// *       Neither the name of Industrial Light & Magic nor the names of
18// its contributors may be used to endorse or promote products derived
19// from this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32//
33///////////////////////////////////////////////////////////////////////////
34
35
36//-----------------------------------------------------------------------------
37//
38//	Miscellaneous stuff related to tiled files
39//
40//-----------------------------------------------------------------------------
41
42#include <ImfTiledMisc.h>
43#include "Iex.h"
44#include <ImfMisc.h>
45#include <ImfChannelList.h>
46
47
48namespace Imf {
49
50using Imath::Box2i;
51using Imath::V2i;
52
53
54int
55levelSize (int min, int max, int l, LevelRoundingMode rmode)
56{
57    if (l < 0)
58	throw Iex::ArgExc ("Argument not in valid range.");
59
60    int a = max - min + 1;
61    int b = (1 << l);
62    int size = a / b;
63
64    if (rmode == ROUND_UP && size * b < a)
65	size += 1;
66
67    return std::max (size, 1);
68}
69
70
71Box2i
72dataWindowForLevel (const TileDescription &tileDesc,
73		    int minX, int maxX,
74		    int minY, int maxY,
75		    int lx, int ly)
76{
77    V2i levelMin = V2i (minX, minY);
78
79    V2i levelMax = levelMin +
80		   V2i (levelSize (minX, maxX, lx, tileDesc.roundingMode) - 1,
81			levelSize (minY, maxY, ly, tileDesc.roundingMode) - 1);
82
83    return Box2i(levelMin, levelMax);
84}
85
86
87Box2i
88dataWindowForTile (const TileDescription &tileDesc,
89		   int minX, int maxX,
90		   int minY, int maxY,
91		   int dx, int dy,
92		   int lx, int ly)
93{
94    V2i tileMin = V2i (minX + dx * tileDesc.xSize,
95		       minY + dy * tileDesc.ySize);
96
97    V2i tileMax = tileMin + V2i (tileDesc.xSize - 1, tileDesc.ySize - 1);
98
99    V2i levelMax = dataWindowForLevel
100		       (tileDesc, minX, maxX, minY, maxY, lx, ly).max;
101
102    tileMax = V2i (std::min (tileMax[0], levelMax[0]),
103		   std::min (tileMax[1], levelMax[1]));
104
105    return Box2i (tileMin, tileMax);
106}
107
108
109size_t
110calculateBytesPerPixel (const Header &header)
111{
112    const ChannelList &channels = header.channels();
113
114    size_t bytesPerPixel = 0;
115
116    for (ChannelList::ConstIterator c = channels.begin();
117	 c != channels.end();
118	 ++c)
119    {
120	bytesPerPixel += pixelTypeSize (c.channel().type);
121    }
122
123    return bytesPerPixel;
124}
125
126
127namespace {
128
129int
130floorLog2 (int x)
131{
132    //
133    // For x > 0, floorLog2(y) returns floor(log(x)/log(2)).
134    //
135
136    int y = 0;
137
138    while (x > 1)
139    {
140	y +=  1;
141	x >>= 1;
142    }
143
144    return y;
145}
146
147
148int
149ceilLog2 (int x)
150{
151    //
152    // For x > 0, ceilLog2(y) returns ceil(log(x)/log(2)).
153    //
154
155    int y = 0;
156    int r = 0;
157
158    while (x > 1)
159    {
160	if (x & 1)
161	    r = 1;
162
163	y +=  1;
164	x >>= 1;
165    }
166
167    return y + r;
168}
169
170
171int
172roundLog2 (int x, LevelRoundingMode rmode)
173{
174    return (rmode == ROUND_DOWN)? floorLog2 (x): ceilLog2 (x);
175}
176
177
178int
179calculateNumXLevels (const TileDescription& tileDesc,
180		     int minX, int maxX,
181		     int minY, int maxY)
182{
183    int num = 0;
184
185    switch (tileDesc.mode)
186    {
187      case ONE_LEVEL:
188
189	num = 1;
190	break;
191
192      case MIPMAP_LEVELS:
193
194	{
195	  int w = maxX - minX + 1;
196	  int h = maxY - minY + 1;
197	  num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1;
198	}
199        break;
200
201      case RIPMAP_LEVELS:
202
203	{
204	  int w = maxX - minX + 1;
205	  num = roundLog2 (w, tileDesc.roundingMode) + 1;
206	}
207	break;
208
209      default:
210
211	throw Iex::ArgExc ("Unknown LevelMode format.");
212    }
213
214    return num;
215}
216
217
218int
219calculateNumYLevels (const TileDescription& tileDesc,
220		     int minX, int maxX,
221		     int minY, int maxY)
222{
223    int num = 0;
224
225    switch (tileDesc.mode)
226    {
227      case ONE_LEVEL:
228
229	num = 1;
230	break;
231
232      case MIPMAP_LEVELS:
233
234	{
235	  int w = maxX - minX + 1;
236	  int h = maxY - minY + 1;
237	  num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1;
238	}
239        break;
240
241      case RIPMAP_LEVELS:
242
243	{
244	  int h = maxY - minY + 1;
245	  num = roundLog2 (h, tileDesc.roundingMode) + 1;
246	}
247	break;
248
249      default:
250
251	throw Iex::ArgExc ("Unknown LevelMode format.");
252    }
253
254    return num;
255}
256
257
258void
259calculateNumTiles (int *numTiles,
260		   int numLevels,
261		   int min, int max,
262		   int size,
263		   LevelRoundingMode rmode)
264{
265    for (int i = 0; i < numLevels; i++)
266    {
267	numTiles[i] = (levelSize (min, max, i, rmode) + size - 1) / size;
268    }
269}
270
271} // namespace
272
273
274void
275precalculateTileInfo (const TileDescription& tileDesc,
276		      int minX, int maxX,
277		      int minY, int maxY,
278		      int *&numXTiles, int *&numYTiles,
279		      int &numXLevels, int &numYLevels)
280{
281    numXLevels = calculateNumXLevels(tileDesc, minX, maxX, minY, maxY);
282    numYLevels = calculateNumYLevels(tileDesc, minX, maxX, minY, maxY);
283
284    numXTiles = new int[numXLevels];
285    numYTiles = new int[numYLevels];
286
287    calculateNumTiles (numXTiles,
288		       numXLevels,
289		       minX, maxX,
290		       tileDesc.xSize,
291		       tileDesc.roundingMode);
292
293    calculateNumTiles (numYTiles,
294		       numYLevels,
295		       minY, maxY,
296		       tileDesc.ySize,
297		       tileDesc.roundingMode);
298}
299
300
301} // namespace Imf
302