HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
pixel_map.hpp
1// Copyright Take Vos 2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6#include "required.hpp"
7#include "hash.hpp"
8#include "geometry/axis_aligned_rectangle.hpp"
9#include "geometry/extent.hpp"
10#include <algorithm>
11#include <cassert>
12#include <span>
13#include <string>
14#include <vector>
15
16namespace tt {
17
20template<typename T>
21class pixel_row {
22public:
23 pixel_row(T *pixels, ssize_t width) noexcept : _pixels(pixels), _width(width) {}
24
25 [[nodiscard]] ssize_t width() const noexcept
26 {
27 return _width;
28 }
29
32 [[nodiscard]] T const *data() const noexcept
33 {
34 return _pixels;
35 }
36
39 [[nodiscard]] T *data() noexcept
40 {
41 return _pixels;
42 }
43
48 [[nodiscard]] T const &operator[](ssize_t columnNr) const noexcept
49 {
50 return _pixels[columnNr];
51 }
52
57 [[nodiscard]] T &operator[](ssize_t columnNr) noexcept
58 {
59 return _pixels[columnNr];
60 }
61
68 [[nodiscard]] T const &at(ssize_t columnNr) const noexcept
69 {
70 tt_assert(columnNr >= 0 && columnNr < _width);
71 return _pixels[columnNr];
72 }
73
80 [[nodiscard]] T &at(ssize_t columnNr) noexcept
81 {
82 tt_assert(columnNr >= 0 && columnNr < _width);
83 return _pixels[columnNr];
84 }
85
86private:
89 T *_pixels;
90
93 ssize_t _width;
94};
95
100template<typename T>
102public:
105 pixel_map() noexcept : _pixels(nullptr), _width(0), _height(0), _stride(0), _hash(0), _self_allocated(true) {}
106
113 pixel_map(T *pixels, ssize_t width, ssize_t height, ssize_t stride) noexcept :
114 _pixels(pixels), _width(width), _height(height), _stride(stride), _hash(0), _self_allocated(false)
115 {
116 tt_assert(_stride >= _width);
117 tt_assert(_width >= 0);
118 tt_assert(_height >= 0);
119
120 if (pixels == nullptr) {
121 _self_allocated = true;
122 _pixels = new T[_height * _stride];
123 }
124 }
125
132 pixel_map(T *pixels, ssize_t width, ssize_t height) noexcept : pixel_map(pixels, width, height, width) {}
133
139 pixel_map(ssize_t width, ssize_t height, ssize_t stride) noexcept : pixel_map(nullptr, width, height, stride) {}
140
146 pixel_map(ssize_t width, ssize_t height) noexcept : pixel_map(nullptr, width, height, width) {}
147
148 ~pixel_map()
149 {
150 if (_self_allocated) {
151 delete[] _pixels;
152 }
153 }
154
160 pixel_map(pixel_map const &other) noexcept :
161 _pixels(other._pixels),
162 _width(other._width),
163 _height(other._height),
164 _stride(other._stride),
165 _hash(other._hash),
166 _self_allocated(other._self_allocated)
167 {
168 if (_self_allocated) {
169 _pixels = new T[_height * _stride];
170
171 for (ssize_t y = 0; y != _height; ++y) {
172 ttlet src_row = other[y];
173 auto dst_row = (*this)[y];
174 for (ssize_t x = 0; x != _width; ++x) {
175 dst_row[x] = src_row[x];
176 }
177 }
178 }
179 }
180
181 pixel_map(pixel_map &&other) noexcept :
182 _pixels(other._pixels),
183 _width(other._width),
184 _height(other._height),
185 _stride(other._stride),
186 _hash(other._hash),
187 _self_allocated(other._self_allocated)
188 {
189 tt_axiom(this != &other);
190 other._self_allocated = false;
191 }
192
193 [[nodiscard]] operator bool() const noexcept
194 {
195 return _pixels != nullptr;
196 }
197
198 [[nodiscard]] ssize_t width() const noexcept
199 {
200 return _width;
201 }
202
203 [[nodiscard]] ssize_t height() const noexcept
204 {
205 return _height;
206 }
207
208 [[nodiscard]] ssize_t stride() const noexcept
209 {
210 return _stride;
211 }
212
213 [[nodiscard]] size_t hash() const noexcept
214 {
215 return _hash;
216 }
217
221 {
222 tt_return_on_self_assignment(other);
223
224 _pixels = other._pixels;
225 _width = other._width;
226 _height = other._height;
227 _stride = other._stride;
228 _hash = other._hash;
229 _self_allocated = other._self_allocated;
230
231 if (_self_allocated) {
232 _pixels = new T[_height * _stride];
233
234 for (ssize_t y = 0; y != _height; ++y) {
235 ttlet src_row = other[y];
236 auto dst_row = (*this)[y];
237 for (ssize_t x = 0; x != _width; ++x) {
238 dst_row[x] = src_row[x];
239 }
240 }
241 }
242 return *this;
243 }
244
245 pixel_map &operator=(pixel_map &&other) noexcept
246 {
247 // Self assignment is allowed.
248 if (_self_allocated) {
249 delete[] _pixels;
250 }
251 _pixels = other._pixels;
252 _width = other._width;
253 _height = other._height;
254 _stride = other._stride;
255 _hash = other._hash;
256 _self_allocated = other._self_allocated;
257 other._self_allocated = false;
258 return *this;
259 }
260
261 extent2 extent() const noexcept
262 {
263 return {narrow_cast<float>(_width), narrow_cast<float>(_height)};
264 }
265
273 pixel_map submap(ssize_t x, ssize_t y, ssize_t width, ssize_t height) const noexcept
274 {
275 tt_axiom((x >= 0) && (y >= 0));
276 tt_assert((x + width <= _width) && (y + height <= _height));
277
278 ttlet offset = y * _stride + x;
279
280 auto r = pixel_map{_pixels + offset, width, height, _stride};
281 r._hash = (width == _width && height == _height) ? _hash : 0;
282 return r;
283 }
284
285 pixel_map submap(aarectangle rectangle) const noexcept
286 {
287 tt_axiom(round(rectangle) == rectangle);
288 return submap(
289 narrow_cast<ssize_t>(rectangle.left()),
290 narrow_cast<ssize_t>(rectangle.bottom()),
291 narrow_cast<ssize_t>(rectangle.width()),
292 narrow_cast<ssize_t>(rectangle.height()));
293 }
294
295 pixel_row<T> const operator[](ssize_t rowNr) const noexcept
296 {
297 return {_pixels + (rowNr * _stride), _width};
298 }
299
300 pixel_row<T> operator[](ssize_t rowNr) noexcept
301 {
302 return {_pixels + (rowNr * _stride), _width};
303 }
304
305 pixel_row<T> const at(ssize_t rowNr) const noexcept
306 {
307 tt_assert(rowNr < _height);
308 return (*this)[rowNr];
309 }
310
311 pixel_row<T> at(ssize_t rowNr) noexcept
312 {
313 tt_assert(rowNr < _height);
314 return (*this)[rowNr];
315 }
316
320 void update_hash() noexcept
321 {
322 size_t h = hash_mix(_width, _height);
323 for (ssize_t row_nr = 0; row_nr != _height; ++row_nr) {
324 ttlet &row = (*this)[row_nr];
325 for (ssize_t col_nr = 0; col_nr != _width; ++col_nr) {
326 h = hash_mix(h, row[col_nr]);
327 }
328 }
329 _hash = h;
330 }
331
332private:
335 T *_pixels;
336
339 ssize_t _width;
340
343 ssize_t _height;
344
348 ssize_t _stride;
349
352 size_t _hash;
353
356 bool _self_allocated;
357};
358
359template<typename T>
360void copy(pixel_map<T> const &src, pixel_map<T> &dst) noexcept
361{
362 ssize_t width = std::min(src.width(), dst.width());
363 ssize_t height = std::min(src.height(), dst.height());
364
365 for (ssize_t y = 0; y != height; ++y) {
366 ttlet src_row = src[y];
367 auto dst_row = dst[y];
368 for (ssize_t x = 0; x != width; ++x) {
369 dst_row[x] = src_row[x];
370 }
371 }
372}
373
374template<int KERNEL_SIZE, typename KERNEL>
375void horizontalFilterRow(pixel_row<uint8_t> row, KERNEL kernel) noexcept;
376
377template<int KERNEL_SIZE, typename T, typename KERNEL>
378void horizontalFilter(pixel_map<T> &pixels, KERNEL kernel) noexcept;
379
382template<typename T>
383void fill(pixel_map<T> &dst) noexcept;
384
387template<typename T>
388void fill(pixel_map<T> &dst, T color) noexcept;
389
392template<typename T>
393void rotate90(pixel_map<T> &dst, pixel_map<T> const &src) noexcept;
394
397template<typename T>
398void rotate270(pixel_map<T> &dst, pixel_map<T> const &src) noexcept;
399
402void mergeMaximum(pixel_map<uint8_t> &dst, pixel_map<uint8_t> const &src) noexcept;
403
409template<typename T>
410inline void makeTransparentBorder(pixel_map<T> &pixel_map) noexcept;
411
412} // namespace tt
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:20
Class which represents an rectangle.
Definition rectangle.hpp:16
A 2D canvas of pixels.
Definition pixel_map.hpp:101
pixel_map submap(ssize_t x, ssize_t y, ssize_t width, ssize_t height) const noexcept
Get a (smaller) view of the map.
Definition pixel_map.hpp:273
pixel_map(T *pixels, ssize_t width, ssize_t height) noexcept
Construct an pixel-map from memory received from an API.
Definition pixel_map.hpp:132
pixel_map(pixel_map const &other) noexcept
Copy constructor of other.
Definition pixel_map.hpp:160
pixel_map(ssize_t width, ssize_t height) noexcept
Construct an pixel-map from memory received from an API.
Definition pixel_map.hpp:146
void update_hash() noexcept
Update the hash value of the pixmap.
Definition pixel_map.hpp:320
pixel_map() noexcept
Construct an empty pixel-map.
Definition pixel_map.hpp:105
pixel_map(ssize_t width, ssize_t height, ssize_t stride) noexcept
Construct an pixel-map from memory received from an API.
Definition pixel_map.hpp:139
pixel_map & operator=(pixel_map const &other)
Disallowing copying so that life-time of selfAllocated pixels is easy to understand.
Definition pixel_map.hpp:220
pixel_map(T *pixels, ssize_t width, ssize_t height, ssize_t stride) noexcept
Construct an pixel-map from memory received from an API.
Definition pixel_map.hpp:113
A row of pixels.
Definition pixel_map.hpp:21
T const * data() const noexcept
Get a pointer to the pixel data.
Definition pixel_map.hpp:32
T const & operator[](ssize_t columnNr) const noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:48
T * data() noexcept
Get a pointer to the pixel data.
Definition pixel_map.hpp:39
T const & at(ssize_t columnNr) const noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:68
T & at(ssize_t columnNr) noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:80
T & operator[](ssize_t columnNr) noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:57
T fill(T... args)
T min(T... args)