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_ICANVAS_H |
31 | #define APPLESEED_FOUNDATION_IMAGE_ICANVAS_H |
32 | |
33 | // appleseed.foundation headers. |
34 | #include "foundation/core/concepts/noncopyable.h" |
35 | #include "foundation/image/canvasproperties.h" |
36 | #include "foundation/image/pixel.h" |
37 | #include "foundation/image/tile.h" |
38 | #include "foundation/math/scalar.h" |
39 | #include "foundation/platform/types.h" |
40 | |
41 | // appleseed.main headers. |
42 | #include "main/dllsymbol.h" |
43 | |
44 | // Standard headers. |
45 | #include <cassert> |
46 | #include <cstddef> |
47 | |
48 | namespace foundation |
49 | { |
50 | |
51 | // |
52 | // Canvas interface. |
53 | // |
54 | |
55 | class APPLESEED_DLLSYMBOL ICanvas |
56 | : public NonCopyable |
57 | { |
58 | public: |
59 | // Destructor. |
60 | virtual ~ICanvas() {} |
61 | |
62 | // Access canvas properties. |
63 | virtual const CanvasProperties& properties() const = 0; |
64 | |
65 | // Direct access to a given tile. |
66 | virtual Tile& tile( |
67 | const size_t tile_x, |
68 | const size_t tile_y) = 0; |
69 | virtual const Tile& tile( |
70 | const size_t tile_x, |
71 | const size_t tile_y) const = 0; |
72 | |
73 | // Direct access to a given pixel. |
74 | uint8* pixel( |
75 | const size_t x, |
76 | const size_t y); |
77 | const uint8* pixel( |
78 | const size_t x, |
79 | const size_t y) const; |
80 | |
81 | // Structured write access to a given pixel, with automatic pixel format conversion. |
82 | template <typename Color> |
83 | void set_pixel( |
84 | const size_t x, |
85 | const size_t y, |
86 | const Color& color); |
87 | template <typename T> |
88 | void set_pixel( |
89 | const size_t x, |
90 | const size_t y, |
91 | const T components[]); |
92 | |
93 | // Structured read access to a given pixel, with automatic pixel format conversion. |
94 | template <typename Color> |
95 | void get_pixel( |
96 | const size_t x, |
97 | const size_t y, |
98 | Color& color) const; |
99 | template <typename T> |
100 | void get_pixel( |
101 | const size_t x, |
102 | const size_t y, |
103 | T components[]) const; |
104 | |
105 | // Set all pixels to a given color. |
106 | // This causes all tiles to be accessed, and created if necessary. |
107 | template <typename Color> |
108 | void clear(const Color& color); |
109 | }; |
110 | |
111 | |
112 | // |
113 | // ICanvas class implementation. |
114 | // |
115 | |
116 | inline uint8* ICanvas::pixel( |
117 | const size_t x, |
118 | const size_t y) |
119 | { |
120 | // Retrieve canvas properties. |
121 | const CanvasProperties& props = properties(); |
122 | |
123 | assert(x < props.m_canvas_width); |
124 | assert(y < props.m_canvas_height); |
125 | |
126 | // Compute the coordinates of the tile containing the pixel (x, y). |
127 | const size_t tile_x = truncate<size_t>(x * props.m_rcp_tile_width); |
128 | const size_t tile_y = truncate<size_t>(y * props.m_rcp_tile_height); |
129 | assert(tile_x < props.m_tile_count_x); |
130 | assert(tile_y < props.m_tile_count_y); |
131 | |
132 | // Retrieve the tile. |
133 | Tile& t = tile(tile_x, tile_y); |
134 | |
135 | // Compute the tile space coordinates of the pixel (x, y). |
136 | const size_t pixel_x = x - tile_x * props.m_tile_width; |
137 | const size_t pixel_y = y - tile_y * props.m_tile_height; |
138 | assert(pixel_x < t.get_width()); |
139 | assert(pixel_y < t.get_height()); |
140 | |
141 | // Access the pixel. |
142 | return t.pixel(pixel_x, pixel_y); |
143 | } |
144 | |
145 | inline const uint8* ICanvas::pixel( |
146 | const size_t x, |
147 | const size_t y) const |
148 | { |
149 | // Retrieve canvas properties. |
150 | const CanvasProperties& props = properties(); |
151 | |
152 | assert(x < props.m_canvas_width); |
153 | assert(y < props.m_canvas_height); |
154 | |
155 | // Compute the coordinates of the tile containing the pixel (x, y). |
156 | const size_t tile_x = truncate<size_t>(x * props.m_rcp_tile_width); |
157 | const size_t tile_y = truncate<size_t>(y * props.m_rcp_tile_height); |
158 | assert(tile_x < props.m_tile_count_x); |
159 | assert(tile_y < props.m_tile_count_y); |
160 | |
161 | // Retrieve the tile. |
162 | const Tile& t = tile(tile_x, tile_y); |
163 | |
164 | // Compute the tile space coordinates of the pixel (x, y). |
165 | const size_t pixel_x = x - tile_x * props.m_tile_width; |
166 | const size_t pixel_y = y - tile_y * props.m_tile_height; |
167 | assert(pixel_x < t.get_width()); |
168 | assert(pixel_y < t.get_height()); |
169 | |
170 | // Access the pixel. |
171 | return t.pixel(pixel_x, pixel_y); |
172 | } |
173 | |
174 | // Check that the number of channels in a pixel value matches the number of channels in the tile. |
175 | #define FOUNDATION_CHECK_PIXEL_SIZE(color) \ |
176 | assert(sizeof(Color) == props.m_channel_count * sizeof(color[0])) |
177 | |
178 | template <typename Color> |
179 | inline void ICanvas::set_pixel( |
180 | const size_t x, |
181 | const size_t y, |
182 | const Color& color) |
183 | { |
184 | const CanvasProperties& props = properties(); |
185 | |
186 | FOUNDATION_CHECK_PIXEL_SIZE(color); |
187 | |
188 | Pixel::convert_to_format( |
189 | &color[0], // source begin |
190 | &color[0] + props.m_channel_count, // source end |
191 | 1, // source stride |
192 | props.m_pixel_format, // destination format |
193 | pixel(x, y), // destination |
194 | 1); // destination stride |
195 | } |
196 | |
197 | template <typename T> |
198 | inline void ICanvas::set_pixel( |
199 | const size_t x, |
200 | const size_t y, |
201 | const T components[]) |
202 | { |
203 | const CanvasProperties& props = properties(); |
204 | |
205 | Pixel::convert_to_format( |
206 | components, // source begin |
207 | components + props.m_channel_count, // source end |
208 | 1, // source stride |
209 | props.m_pixel_format, // destination format |
210 | pixel(x, y), // destination |
211 | 1); // destination stride |
212 | } |
213 | |
214 | template <typename Color> |
215 | inline void ICanvas::get_pixel( |
216 | const size_t x, |
217 | const size_t y, |
218 | Color& color) const |
219 | { |
220 | const CanvasProperties& props = properties(); |
221 | |
222 | FOUNDATION_CHECK_PIXEL_SIZE(color); |
223 | |
224 | const uint8* src = pixel(x, y); |
225 | |
226 | Pixel::convert_from_format( |
227 | props.m_pixel_format, // source format |
228 | src, // source begin |
229 | src + props.m_pixel_size, // source end |
230 | 1, // source stride |
231 | &color[0], // destination |
232 | 1); // destination stride |
233 | } |
234 | |
235 | template <typename T> |
236 | inline void ICanvas::get_pixel( |
237 | const size_t x, |
238 | const size_t y, |
239 | T components[]) const |
240 | { |
241 | const CanvasProperties& props = properties(); |
242 | const uint8* src = pixel(x, y); |
243 | |
244 | Pixel::convert_from_format( |
245 | props.m_pixel_format, // source format |
246 | src, // source begin |
247 | src + props.m_pixel_size, // source end |
248 | 1, // source stride |
249 | components, // destination |
250 | 1); // destination stride |
251 | } |
252 | |
253 | template <typename Color> |
254 | inline void ICanvas::clear(const Color& color) |
255 | { |
256 | const CanvasProperties& props = properties(); |
257 | |
258 | FOUNDATION_CHECK_PIXEL_SIZE(color); |
259 | |
260 | for (size_t ty = 0; ty < props.m_tile_count_y; ++ty) |
261 | { |
262 | for (size_t tx = 0; tx < props.m_tile_count_x; ++tx) |
263 | tile(tx, ty).clear(color); |
264 | } |
265 | } |
266 | |
267 | #undef FOUNDATION_CHECK_PIXEL_SIZE |
268 | |
269 | } // namespace foundation |
270 | |
271 | #endif // !APPLESEED_FOUNDATION_IMAGE_ICANVAS_H |
272 | |