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 #include <algorithm> // for std::max()
47
48
49 namespace Imf {
50
51 using Imath::Box2i;
52 using Imath::V2i;
53
54
55 int
levelSize(int min,int max,int l,LevelRoundingMode rmode)56 levelSize (int min, int max, int l, LevelRoundingMode rmode)
57 {
58 if (l < 0)
59 throw Iex::ArgExc ("Argument not in valid range.");
60
61 int a = max - min + 1;
62 int b = (1 << l);
63 int size = a / b;
64
65 if (rmode == ROUND_UP && size * b < a)
66 size += 1;
67
68 return std::max (size, 1);
69 }
70
71
72 Box2i
dataWindowForLevel(const TileDescription & tileDesc,int minX,int maxX,int minY,int maxY,int lx,int ly)73 dataWindowForLevel (const TileDescription &tileDesc,
74 int minX, int maxX,
75 int minY, int maxY,
76 int lx, int ly)
77 {
78 V2i levelMin = V2i (minX, minY);
79
80 V2i levelMax = levelMin +
81 V2i (levelSize (minX, maxX, lx, tileDesc.roundingMode) - 1,
82 levelSize (minY, maxY, ly, tileDesc.roundingMode) - 1);
83
84 return Box2i(levelMin, levelMax);
85 }
86
87
88 Box2i
dataWindowForTile(const TileDescription & tileDesc,int minX,int maxX,int minY,int maxY,int dx,int dy,int lx,int ly)89 dataWindowForTile (const TileDescription &tileDesc,
90 int minX, int maxX,
91 int minY, int maxY,
92 int dx, int dy,
93 int lx, int ly)
94 {
95 V2i tileMin = V2i (minX + dx * tileDesc.xSize,
96 minY + dy * tileDesc.ySize);
97
98 V2i tileMax = tileMin + V2i (tileDesc.xSize - 1, tileDesc.ySize - 1);
99
100 V2i levelMax = dataWindowForLevel
101 (tileDesc, minX, maxX, minY, maxY, lx, ly).max;
102
103 tileMax = V2i (std::min (tileMax[0], levelMax[0]),
104 std::min (tileMax[1], levelMax[1]));
105
106 return Box2i (tileMin, tileMax);
107 }
108
109
110 size_t
calculateBytesPerPixel(const Header & header)111 calculateBytesPerPixel (const Header &header)
112 {
113 const ChannelList &channels = header.channels();
114
115 size_t bytesPerPixel = 0;
116
117 for (ChannelList::ConstIterator c = channels.begin();
118 c != channels.end();
119 ++c)
120 {
121 bytesPerPixel += pixelTypeSize (c.channel().type);
122 }
123
124 return bytesPerPixel;
125 }
126
127
128 namespace {
129
130 int
floorLog2(int x)131 floorLog2 (int x)
132 {
133 //
134 // For x > 0, floorLog2(y) returns floor(log(x)/log(2)).
135 //
136
137 int y = 0;
138
139 while (x > 1)
140 {
141 y += 1;
142 x >>= 1;
143 }
144
145 return y;
146 }
147
148
149 int
ceilLog2(int x)150 ceilLog2 (int x)
151 {
152 //
153 // For x > 0, ceilLog2(y) returns ceil(log(x)/log(2)).
154 //
155
156 int y = 0;
157 int r = 0;
158
159 while (x > 1)
160 {
161 if (x & 1)
162 r = 1;
163
164 y += 1;
165 x >>= 1;
166 }
167
168 return y + r;
169 }
170
171
172 int
roundLog2(int x,LevelRoundingMode rmode)173 roundLog2 (int x, LevelRoundingMode rmode)
174 {
175 return (rmode == ROUND_DOWN)? floorLog2 (x): ceilLog2 (x);
176 }
177
178
179 int
calculateNumXLevels(const TileDescription & tileDesc,int minX,int maxX,int minY,int maxY)180 calculateNumXLevels (const TileDescription& tileDesc,
181 int minX, int maxX,
182 int minY, int maxY)
183 {
184 int num = 0;
185
186 switch (tileDesc.mode)
187 {
188 case ONE_LEVEL:
189
190 num = 1;
191 break;
192
193 case MIPMAP_LEVELS:
194
195 {
196 int w = maxX - minX + 1;
197 int h = maxY - minY + 1;
198 num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1;
199 }
200 break;
201
202 case RIPMAP_LEVELS:
203
204 {
205 int w = maxX - minX + 1;
206 num = roundLog2 (w, tileDesc.roundingMode) + 1;
207 }
208 break;
209
210 default:
211
212 throw Iex::ArgExc ("Unknown LevelMode format.");
213 }
214
215 return num;
216 }
217
218
219 int
calculateNumYLevels(const TileDescription & tileDesc,int minX,int maxX,int minY,int maxY)220 calculateNumYLevels (const TileDescription& tileDesc,
221 int minX, int maxX,
222 int minY, int maxY)
223 {
224 int num = 0;
225
226 switch (tileDesc.mode)
227 {
228 case ONE_LEVEL:
229
230 num = 1;
231 break;
232
233 case MIPMAP_LEVELS:
234
235 {
236 int w = maxX - minX + 1;
237 int h = maxY - minY + 1;
238 num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1;
239 }
240 break;
241
242 case RIPMAP_LEVELS:
243
244 {
245 int h = maxY - minY + 1;
246 num = roundLog2 (h, tileDesc.roundingMode) + 1;
247 }
248 break;
249
250 default:
251
252 throw Iex::ArgExc ("Unknown LevelMode format.");
253 }
254
255 return num;
256 }
257
258
259 void
calculateNumTiles(int * numTiles,int numLevels,int min,int max,int size,LevelRoundingMode rmode)260 calculateNumTiles (int *numTiles,
261 int numLevels,
262 int min, int max,
263 int size,
264 LevelRoundingMode rmode)
265 {
266 for (int i = 0; i < numLevels; i++)
267 {
268 numTiles[i] = (levelSize (min, max, i, rmode) + size - 1) / size;
269 }
270 }
271
272 } // namespace
273
274
275 void
precalculateTileInfo(const TileDescription & tileDesc,int minX,int maxX,int minY,int maxY,int * & numXTiles,int * & numYTiles,int & numXLevels,int & numYLevels)276 precalculateTileInfo (const TileDescription& tileDesc,
277 int minX, int maxX,
278 int minY, int maxY,
279 int *&numXTiles, int *&numYTiles,
280 int &numXLevels, int &numYLevels)
281 {
282 numXLevels = calculateNumXLevels(tileDesc, minX, maxX, minY, maxY);
283 numYLevels = calculateNumYLevels(tileDesc, minX, maxX, minY, maxY);
284
285 numXTiles = new int[numXLevels];
286 numYTiles = new int[numYLevels];
287
288 calculateNumTiles (numXTiles,
289 numXLevels,
290 minX, maxX,
291 tileDesc.xSize,
292 tileDesc.roundingMode);
293
294 calculateNumTiles (numYTiles,
295 numYLevels,
296 minY, maxY,
297 tileDesc.ySize,
298 tileDesc.roundingMode);
299 }
300
301
302 } // namespace Imf
303