1 | |
2 | // |
3 | // This source file is part of appleseed. |
4 | // Visit http://appleseedhq.net/ for additional information and resources. |
5 | // |
6 | // This software is released under the MIT license. |
7 | // |
8 | // Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited |
9 | // Copyright (c) 2014-2017 Francois Beaune, The appleseedhq Organization |
10 | // |
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy |
12 | // of this software and associated documentation files (the "Software"), to deal |
13 | // in the Software without restriction, including without limitation the rights |
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
15 | // copies of the Software, and to permit persons to whom the Software is |
16 | // furnished to do so, subject to the following conditions: |
17 | // |
18 | // The above copyright notice and this permission notice shall be included in |
19 | // all copies or substantial portions of the Software. |
20 | // |
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
27 | // THE SOFTWARE. |
28 | // |
29 | |
30 | #ifndef APPLESEED_FOUNDATION_IMAGE_TILE_H |
31 | #define APPLESEED_FOUNDATION_IMAGE_TILE_H |
32 | |
33 | // appleseed.foundation headers. |
34 | #include "foundation/image/pixel.h" |
35 | #include "foundation/platform/types.h" |
36 | |
37 | // appleseed.main headers. |
38 | #include "main/dllsymbol.h" |
39 | |
40 | // Standard headers. |
41 | #include <cassert> |
42 | #include <cstddef> |
43 | #include <cstring> |
44 | |
45 | namespace foundation |
46 | { |
47 | |
48 | // |
49 | // A tile, as a 2D array of pixels. |
50 | // |
51 | |
52 | class APPLESEED_DLLSYMBOL Tile |
53 | { |
54 | public: |
55 | // Construct a new tile. The content of the tile is left undefined. |
56 | Tile( |
57 | const size_t width, // tile width, in pixels |
58 | const size_t height, // tile height, in pixels |
59 | const size_t channel_count, // number of channels |
60 | const PixelFormat pixel_format, // pixel format |
61 | uint8* storage = 0); // if provided, use this memory for pixel storage |
62 | |
63 | // Construct a tile by converting an existing tile to a given pixel format. |
64 | Tile( |
65 | const Tile& tile, // source tile |
66 | const PixelFormat pixel_format, // new pixel format |
67 | uint8* storage = 0); // if provided, use this memory for pixel storage |
68 | |
69 | // Construct a tile by converting an existing tile to a given pixel format, |
70 | // and allowing reordering, replication and deletion of channels. |
71 | Tile( |
72 | const Tile& tile, // source tile |
73 | const PixelFormat pixel_format, // new pixel format |
74 | const size_t* shuffle_table, // channel shuffling table |
75 | uint8* storage = 0); // if provided, use this memory for pixel storage |
76 | |
77 | // Copy constructor. |
78 | Tile(const Tile& rhs); |
79 | |
80 | // Destructor. |
81 | ~Tile(); |
82 | |
83 | // Like foundation::IUnknown::release() but without introducing a virtual function table. |
84 | void release(); |
85 | |
86 | // Return the size (in bytes) of this object in memory. |
87 | size_t get_memory_size() const; |
88 | |
89 | // Tile properties. |
90 | PixelFormat get_pixel_format() const; |
91 | size_t get_width() const; |
92 | size_t get_height() const; |
93 | size_t get_channel_count() const; // number of channels in one pixel |
94 | size_t get_pixel_count() const; // number of pixels |
95 | size_t get_size() const; // size in bytes of the pixel array |
96 | |
97 | // Return a pointer to the tile' storage. |
98 | uint8* get_storage() const; |
99 | |
100 | // Direct access to a given pixel. |
101 | uint8* pixel( |
102 | const size_t i) const; |
103 | uint8* pixel( |
104 | const size_t x, |
105 | const size_t y) const; |
106 | |
107 | // Direct access to a given component of a given pixel. |
108 | uint8* component( |
109 | const size_t i, |
110 | const size_t c) const; |
111 | uint8* component( |
112 | const size_t x, |
113 | const size_t y, |
114 | const size_t c) const; |
115 | |
116 | // Structured write access to a given pixel, with automatic pixel format conversion. |
117 | template <typename T> |
118 | void set_pixel( |
119 | const size_t i, |
120 | const T components[]); |
121 | template <typename T> |
122 | void set_pixel( |
123 | const size_t x, |
124 | const size_t y, |
125 | const T components[]); |
126 | template <typename Color> |
127 | void set_pixel( |
128 | const size_t i, |
129 | const Color& color); |
130 | template <typename Color> |
131 | void set_pixel( |
132 | const size_t x, |
133 | const size_t y, |
134 | const Color& color); |
135 | |
136 | // Structured write access to a given component of a given pixel. |
137 | template <typename T> |
138 | void set_component( |
139 | const size_t i, |
140 | const size_t c, |
141 | const T value); |
142 | template <typename T> |
143 | void set_component( |
144 | const size_t x, |
145 | const size_t y, |
146 | const size_t c, |
147 | const T value); |
148 | |
149 | // Structured read access to a given pixel, with automatic pixel format conversion. |
150 | template <typename T> |
151 | void get_pixel( |
152 | const size_t i, |
153 | T components[]) const; |
154 | template <typename T> |
155 | void get_pixel( |
156 | const size_t x, |
157 | const size_t y, |
158 | T components[]) const; |
159 | template <typename Color> |
160 | void get_pixel( |
161 | const size_t i, |
162 | Color& color) const; |
163 | template <typename Color> |
164 | void get_pixel( |
165 | const size_t x, |
166 | const size_t y, |
167 | Color& color) const; |
168 | |
169 | // Structured read access to a given component of a given pixel. |
170 | template <typename T> |
171 | T get_component( |
172 | const size_t i, |
173 | const size_t c) const; |
174 | template <typename T> |
175 | T get_component( |
176 | const size_t x, |
177 | const size_t y, |
178 | const size_t c) const; |
179 | |
180 | // Set all pixels to a given color. |
181 | template <typename Color> |
182 | void clear(const Color& color); |
183 | |
184 | // Copy the contents of another tile of equal dimensions and number of channels |
185 | // (but possibly using a different pixel format). |
186 | void copy(const Tile& rhs); |
187 | |
188 | protected: |
189 | const size_t m_width; // tile width, in pixels |
190 | const size_t m_height; // tile height, in pixels |
191 | const size_t m_channel_count; // number of channels per pixel |
192 | const PixelFormat m_pixel_format; // pixel format |
193 | const size_t m_pixel_count; // total number of pixels |
194 | const size_t m_channel_size; // size in bytes of one channel |
195 | const size_t m_pixel_size; // size in bytes of one pixel |
196 | const size_t m_array_size; // size in bytes of the pixel array |
197 | uint8* m_pixel_array; // pixel array |
198 | bool m_own_storage; // does the tile own the memory used for pixel storage? |
199 | }; |
200 | |
201 | |
202 | // |
203 | // Tile class implementation. |
204 | // |
205 | |
206 | inline PixelFormat Tile::get_pixel_format() const |
207 | { |
208 | return m_pixel_format; |
209 | } |
210 | |
211 | inline size_t Tile::get_width() const |
212 | { |
213 | return m_width; |
214 | } |
215 | |
216 | inline size_t Tile::get_height() const |
217 | { |
218 | return m_height; |
219 | } |
220 | |
221 | inline size_t Tile::get_channel_count() const |
222 | { |
223 | return m_channel_count; |
224 | } |
225 | |
226 | inline size_t Tile::get_pixel_count() const |
227 | { |
228 | return m_pixel_count; |
229 | } |
230 | |
231 | inline size_t Tile::get_size() const |
232 | { |
233 | return m_array_size; |
234 | } |
235 | |
236 | inline uint8* Tile::get_storage() const |
237 | { |
238 | return m_pixel_array; |
239 | } |
240 | |
241 | inline uint8* Tile::pixel( |
242 | const size_t i) const |
243 | { |
244 | assert(i < m_pixel_count); |
245 | |
246 | const size_t index = i * m_pixel_size; |
247 | assert(index < m_array_size); |
248 | |
249 | return m_pixel_array + index; |
250 | } |
251 | |
252 | inline uint8* Tile::pixel( |
253 | const size_t x, |
254 | const size_t y) const |
255 | { |
256 | assert(x < m_width); |
257 | assert(y < m_height); |
258 | |
259 | return pixel(y * m_width + x); |
260 | } |
261 | |
262 | inline uint8* Tile::component( |
263 | const size_t i, |
264 | const size_t c) const |
265 | { |
266 | return pixel(i) + c * m_channel_size; |
267 | } |
268 | |
269 | inline uint8* Tile::component( |
270 | const size_t x, |
271 | const size_t y, |
272 | const size_t c) const |
273 | { |
274 | return pixel(x, y) + c * m_channel_size; |
275 | } |
276 | |
277 | template <typename T> |
278 | inline void Tile::set_pixel( |
279 | const size_t i, |
280 | const T components[]) |
281 | { |
282 | Pixel::convert_to_format( |
283 | components, // source begin |
284 | components + m_channel_count, // source end |
285 | 1, // source stride |
286 | m_pixel_format, // destination format |
287 | pixel(i), // destination |
288 | 1); // destination stride |
289 | } |
290 | |
291 | template <typename T> |
292 | inline void Tile::set_pixel( |
293 | const size_t x, |
294 | const size_t y, |
295 | const T components[]) |
296 | { |
297 | assert(x < m_width); |
298 | assert(y < m_height); |
299 | |
300 | set_pixel<T>(y * m_width + x, components); |
301 | } |
302 | |
303 | template <typename Color> |
304 | inline void Tile::set_pixel( |
305 | const size_t i, |
306 | const Color& color) |
307 | { |
308 | assert(sizeof(Color) == m_channel_count * sizeof(color[0])); |
309 | |
310 | set_pixel(i, &color[0]); |
311 | } |
312 | |
313 | template <typename Color> |
314 | inline void Tile::set_pixel( |
315 | const size_t x, |
316 | const size_t y, |
317 | const Color& color) |
318 | { |
319 | assert(sizeof(Color) == m_channel_count * sizeof(color[0])); |
320 | |
321 | set_pixel(x, y, &color[0]); |
322 | } |
323 | |
324 | template <typename T> |
325 | inline void Tile::set_component( |
326 | const size_t i, |
327 | const size_t c, |
328 | const T value) |
329 | { |
330 | Pixel::convert_to_format( |
331 | &value, // source begin |
332 | &value + 1, // source end |
333 | 1, // source stride |
334 | m_pixel_format, // destination format |
335 | component(i, c), // destination |
336 | 1); // destination stride |
337 | } |
338 | |
339 | template <typename T> |
340 | inline void Tile::set_component( |
341 | const size_t x, |
342 | const size_t y, |
343 | const size_t c, |
344 | const T value) |
345 | { |
346 | assert(x < m_width); |
347 | assert(y < m_height); |
348 | |
349 | set_component(y * m_width + x, c, value); |
350 | } |
351 | |
352 | template <typename T> |
353 | inline void Tile::get_pixel( |
354 | const size_t i, |
355 | T components[]) const |
356 | { |
357 | const uint8* src = pixel(i); |
358 | |
359 | Pixel::convert_from_format( |
360 | m_pixel_format, // source format |
361 | src, // source begin |
362 | src + m_pixel_size, // source end |
363 | 1, // source stride |
364 | components, // destination |
365 | 1); // destination stride |
366 | } |
367 | |
368 | template <typename T> |
369 | inline void Tile::get_pixel( |
370 | const size_t x, |
371 | const size_t y, |
372 | T components[]) const |
373 | { |
374 | assert(x < m_width); |
375 | assert(y < m_height); |
376 | |
377 | get_pixel<T>(y * m_width + x, components); |
378 | } |
379 | |
380 | template <typename Color> |
381 | inline void Tile::get_pixel( |
382 | const size_t i, |
383 | Color& color) const |
384 | { |
385 | assert(sizeof(Color) == m_channel_count * sizeof(color[0])); |
386 | |
387 | get_pixel(i, &color[0]); |
388 | } |
389 | |
390 | template <typename Color> |
391 | inline void Tile::get_pixel( |
392 | const size_t x, |
393 | const size_t y, |
394 | Color& color) const |
395 | { |
396 | assert(sizeof(Color) == m_channel_count * sizeof(color[0])); |
397 | |
398 | get_pixel(x, y, &color[0]); |
399 | } |
400 | |
401 | template <typename T> |
402 | inline T Tile::get_component( |
403 | const size_t i, |
404 | const size_t c) const |
405 | { |
406 | const uint8* src = component(i, c); |
407 | |
408 | T value; |
409 | Pixel::convert_from_format( |
410 | m_pixel_format, // source format |
411 | src, // source begin |
412 | src + m_channel_size, // source end |
413 | 1, // source stride |
414 | &value, // destination |
415 | 1); // destination stride |
416 | |
417 | return value; |
418 | } |
419 | |
420 | template <typename T> |
421 | inline T Tile::get_component( |
422 | const size_t x, |
423 | const size_t y, |
424 | const size_t c) const |
425 | { |
426 | assert(x < m_width); |
427 | assert(y < m_height); |
428 | |
429 | return get_component<T>(y * m_width + x, c); |
430 | } |
431 | |
432 | template <typename Color> |
433 | inline void Tile::clear(const Color& color) |
434 | { |
435 | assert(sizeof(Color) == m_channel_count * sizeof(color[0])); |
436 | |
437 | // Set first pixel of first row. |
438 | uint8* base = pixel(0, 0); |
439 | Pixel::convert_to_format( |
440 | &color[0], // source begin |
441 | &color[0] + m_channel_count, // source end |
442 | 1, // source stride |
443 | m_pixel_format, // destination format |
444 | base, // destination |
445 | 1); // destination stride |
446 | |
447 | // Set remaining pixels of first row. |
448 | uint8* dest = base + m_pixel_size; |
449 | for (size_t i = 1; i < m_width; ++i) |
450 | { |
451 | std::memcpy(dest, base, m_pixel_size); |
452 | dest += m_pixel_size; |
453 | } |
454 | |
455 | // Set remaining rows. |
456 | const size_t row_size = m_width * m_pixel_size; |
457 | for (size_t i = 1; i < m_height; ++i) |
458 | { |
459 | std::memcpy(dest, base, row_size); |
460 | dest += row_size; |
461 | } |
462 | } |
463 | |
464 | } // namespace foundation |
465 | |
466 | #endif // !APPLESEED_FOUNDATION_IMAGE_TILE_H |
467 | |