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
157 pixel_map(pixel_map const &other) = delete;
158
159 [[nodiscard]] pixel_map copy() const noexcept
160 {
161 if (_self_allocated) {
162 auto r = pixel_map(_width, _height);
163
164 for (ssize_t y = 0; y != _height; ++y) {
165 ttlet src_row = (*this)[y];
166 auto dst_row = r[y];
167 for (ssize_t x = 0; x != _width; ++x) {
168 dst_row[x] = src_row[x];
169 }
170 }
171
172 r._hash = _hash;
173 return r;
174 } else {
175 return submap(0, 0, _width, _height);
176 }
177 }
178
179 pixel_map(pixel_map &&other) noexcept :
180 _pixels(other._pixels),
181 _width(other._width),
182 _height(other._height),
183 _stride(other._stride),
184 _hash(other._hash),
185 _self_allocated(other._self_allocated)
186 {
187 tt_axiom(this != &other);
188 other._self_allocated = false;
189 }
190
191 [[nodiscard]] operator bool() const noexcept
192 {
193 return _pixels != nullptr;
194 }
195
196 [[nodiscard]] ssize_t width() const noexcept
197 {
198 return _width;
199 }
200
201 [[nodiscard]] ssize_t height() const noexcept
202 {
203 return _height;
204 }
205
206 [[nodiscard]] ssize_t stride() const noexcept
207 {
208 return _stride;
209 }
210
211 [[nodiscard]] size_t hash() const noexcept
212 {
213 return _hash;
214 }
215
218 pixel_map &operator=(pixel_map const &other) = delete;
219
220 pixel_map &operator=(pixel_map &&other) noexcept
221 {
222 // Self assignment is allowed.
223 if (_self_allocated) {
224 delete[] _pixels;
225 }
226 _pixels = other._pixels;
227 _width = other._width;
228 _height = other._height;
229 _stride = other._stride;
230 _hash = other._hash;
231 _self_allocated = other._self_allocated;
232 other._self_allocated = false;
233 return *this;
234 }
235
236 extent2 extent() const noexcept
237 {
238 return {narrow_cast<float>(_width), narrow_cast<float>(_height)};
239 }
240
248 pixel_map submap(ssize_t x, ssize_t y, ssize_t width, ssize_t height) const noexcept
249 {
250 tt_axiom((x >= 0) && (y >= 0));
251 tt_assert((x + width <= _width) && (y + height <= _height));
252
253 ttlet offset = y * _stride + x;
254
255 auto r = pixel_map{_pixels + offset, width, height, _stride};
256 r._hash = (width == _width && height == _height) ? _hash : 0;
257 return r;
258 }
259
260 pixel_map submap(aarectangle rectangle) const noexcept
261 {
262 tt_axiom(round(rectangle) == rectangle);
263 return submap(
264 narrow_cast<ssize_t>(rectangle.left()),
265 narrow_cast<ssize_t>(rectangle.bottom()),
266 narrow_cast<ssize_t>(rectangle.width()),
267 narrow_cast<ssize_t>(rectangle.height()));
268 }
269
270 pixel_row<T> const operator[](ssize_t rowNr) const noexcept
271 {
272 return {_pixels + (rowNr * _stride), _width};
273 }
274
275 pixel_row<T> operator[](ssize_t rowNr) noexcept
276 {
277 return {_pixels + (rowNr * _stride), _width};
278 }
279
280 pixel_row<T> const at(ssize_t rowNr) const noexcept
281 {
282 tt_assert(rowNr < _height);
283 return (*this)[rowNr];
284 }
285
286 pixel_row<T> at(ssize_t rowNr) noexcept
287 {
288 tt_assert(rowNr < _height);
289 return (*this)[rowNr];
290 }
291
295 void update_hash() noexcept
296 {
297 size_t h = hash_mix(_width, _height);
298 for (ssize_t row_nr = 0; row_nr != _height; ++row_nr) {
299 ttlet &row = (*this)[row_nr];
300 for (ssize_t col_nr = 0; col_nr != _width; ++col_nr) {
301 h = hash_mix(h, row[col_nr]);
302 }
303 }
304 _hash = h;
305 }
306
307private:
310 T *_pixels;
311
314 ssize_t _width;
315
318 ssize_t _height;
319
323 ssize_t _stride;
324
327 size_t _hash;
328
331 bool _self_allocated;
332};
333
334template<typename T>
335void copy(pixel_map<T> const &src, pixel_map<T> &dst) noexcept
336{
337 ssize_t width = std::min(src.width(), dst.width());
338 ssize_t height = std::min(src.height(), dst.height());
339
340 for (ssize_t y = 0; y != height; ++y) {
341 ttlet src_row = src[y];
342 auto dst_row = dst[y];
343 for (ssize_t x = 0; x != width; ++x) {
344 dst_row[x] = src_row[x];
345 }
346 }
347}
348
349template<int KERNEL_SIZE, typename KERNEL>
350void horizontalFilterRow(pixel_row<uint8_t> row, KERNEL kernel) noexcept;
351
352template<int KERNEL_SIZE, typename T, typename KERNEL>
353void horizontalFilter(pixel_map<T> &pixels, KERNEL kernel) noexcept;
354
357template<typename T>
358void fill(pixel_map<T> &dst) noexcept;
359
362template<typename T>
363void fill(pixel_map<T> &dst, T color) noexcept;
364
367template<typename T>
368void rotate90(pixel_map<T> &dst, pixel_map<T> const &src) noexcept;
369
372template<typename T>
373void rotate270(pixel_map<T> &dst, pixel_map<T> const &src) noexcept;
374
377void mergeMaximum(pixel_map<uint8_t> &dst, pixel_map<uint8_t> const &src) noexcept;
378
384template<typename T>
385inline void makeTransparentBorder(pixel_map<T> &pixel_map) noexcept;
386
387} // 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:248
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(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:295
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)=delete
Disallowing copying so that life-time of selfAllocated pixels is easy to understand.
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
pixel_map(pixel_map const &other)=delete
Disallowing copying so that life-time of selfAllocated pixels is easy to understand.
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)