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
48namespace foundation
49{
50
51//
52// Canvas interface.
53//
54
55class 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
116inline 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
145inline 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
178template <typename Color>
179inline 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
197template <typename T>
198inline 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
214template <typename Color>
215inline 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
235template <typename T>
236inline 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
253template <typename Color>
254inline 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