Blender V4.3
COM_MemoryBuffer.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
7#include "COM_BufferArea.h"
8#include "COM_BufferRange.h"
10#include "COM_Enums.h"
11
12#include "BLI_math_base.hh"
13#include "BLI_math_interp.hh"
14#include "BLI_math_vector.h"
16#include "BLI_rect.h"
17
18#include <cstdint>
19#include <cstring>
20
22struct ImBuf;
23
24namespace blender::compositor {
25
27 Clip,
28 Extend,
29 Repeat,
30};
31
36 public:
45
54
55 private:
59 DataType datatype_;
60
64 rcti rect_;
65
69 float *buffer_;
70
75 uint8_t num_channels_;
76
80 bool is_a_single_elem_;
81
85 bool owns_data_;
86
88 int to_positive_x_stride_;
89
91 int to_positive_y_stride_;
92
93 public:
97 MemoryBuffer(DataType data_type, int width, int height);
98
102 MemoryBuffer(DataType data_type, const rcti &rect, bool is_a_single_elem = false);
103
109 float *buffer, int num_channels, int width, int height, bool is_a_single_elem = false);
110
115 MemoryBuffer(float *buffer, int num_channels, const rcti &rect, bool is_a_single_elem = false);
116
120 MemoryBuffer(const MemoryBuffer &src);
121
126
131 bool is_a_single_elem() const
132 {
133 return is_a_single_elem_;
134 }
135
136 float &operator[](int index)
137 {
138 BLI_assert(is_a_single_elem_ ? index < num_channels_ :
140 return buffer_[index];
141 }
142
143 const float &operator[](int index) const
144 {
145 BLI_assert(is_a_single_elem_ ? index < num_channels_ :
147 return buffer_[index];
148 }
149
153 intptr_t get_coords_offset(int x, int y) const
154 {
155 return ((intptr_t)y - rect_.ymin) * row_stride + ((intptr_t)x - rect_.xmin) * elem_stride;
156 }
157
161 float *get_elem(int x, int y)
162 {
163 BLI_assert(has_coords(x, y));
164 return buffer_ + get_coords_offset(x, y);
165 }
166
170 const float *get_elem(int x, int y) const
171 {
172 BLI_assert(has_coords(x, y));
173 return buffer_ + get_coords_offset(x, y);
174 }
175
179 const float *get_elem_clamped(int x, int y) const
180 {
181 const int clamped_x = math::clamp(x, 0, this->get_width() - 1);
182 const int clamped_y = math::clamp(y, 0, this->get_height() - 1);
183 return buffer_ + get_coords_offset(clamped_x, clamped_y);
184 }
185
186 void read_elem(int x, int y, float *out) const
187 {
188 memcpy(out, get_elem(x, y), get_elem_bytes_len());
189 }
190
191 void read_elem_clamped(int x, int y, float *out) const
192 {
193 memcpy(out, get_elem_clamped(x, y), get_elem_bytes_len());
194 }
195
196 void read_elem_checked(int x, int y, float *out) const
197 {
198 if (!has_coords(x, y)) {
199 clear_elem(out);
200 }
201 else {
202 read_elem(x, y, out);
203 }
204 }
205
206 void read_elem_checked(float x, float y, float *out) const
207 {
208 read_elem_checked(floor_x(x), floor_y(y), out);
209 }
210
211 /* Equivalent to the GLSL texture() function with bilinear interpolation and extended boundary
212 * conditions. The coordinates are thus expected to have half-pixels offsets. A float4 is always
213 * returned regardless of the number of channels of the buffer, the remaining channels will be
214 * initialized with the template float4(0, 0, 0, 1). */
216 {
217 if (is_a_single_elem_) {
218 float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);
219 memcpy(result, buffer_, get_elem_bytes_len());
220 return result;
221 }
222
223 const int2 size = int2(get_width(), get_height());
224 const float2 texel_coordinates = (coordinates * float2(size)) - 0.5f;
225
226 float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);
228 buffer_, result, size.x, size.y, num_channels_, texel_coordinates.x, texel_coordinates.y);
229 return result;
230 }
231
232 /* Equivalent to the GLSL texture() function with nearest interpolation and extended boundary
233 * conditions. The coordinates are thus expected to have half-pixels offsets. A float4 is always
234 * returned regardless of the number of channels of the buffer, the remaining channels will be
235 * initialized with the template float4(0, 0, 0, 1). */
237 {
238 if (is_a_single_elem_) {
239 float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);
240 memcpy(result, buffer_, get_elem_bytes_len());
241 return result;
242 }
243
244 const int2 size = int2(get_width(), get_height());
245 const float2 texel_coordinates = coordinates * float2(size);
246
247 float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);
249 buffer_, result, size.x, size.y, num_channels_, texel_coordinates.x, texel_coordinates.y);
250 return result;
251 }
252
253 void read_elem_bilinear(float x, float y, float *out) const
254 {
255 read(out, x, y, PixelSampler::Bilinear);
256 }
257
258 void read_elem_bicubic_bspline(float x, float y, float *out) const
259 {
260 if (is_a_single_elem_) {
261 memcpy(out, buffer_, get_elem_bytes_len());
262 return;
263 }
264
266 out,
267 this->get_width(),
268 this->get_height(),
269 num_channels_,
270 get_relative_x(x),
271 get_relative_y(y));
272 }
273
274 void read_elem_sampled(float x, float y, PixelSampler sampler, float *out) const
275 {
276 read(out, x, y, sampler);
277 }
278
280 float x, float y, float dx[2], float dy[2], bool extend_boundary, float *out) const;
281
285 float &get_value(int x, int y, int channel)
286 {
287 BLI_assert(has_coords(x, y) && channel >= 0 && channel < num_channels_);
288 return buffer_[get_coords_offset(x, y) + channel];
289 }
290
294 const float &get_value(int x, int y, int channel) const
295 {
296 BLI_assert(has_coords(x, y) && channel >= 0 && channel < num_channels_);
297 return buffer_[get_coords_offset(x, y) + channel];
298 }
299
303 const float *get_row_end(int y) const
304 {
305 BLI_assert(has_y(y));
306 return buffer_ + (is_a_single_elem() ? num_channels_ : get_coords_offset(get_width(), y));
307 }
308
314 {
315 return is_a_single_elem() ? 1 : get_width();
316 }
317
323 {
324 return is_a_single_elem() ? 1 : get_height();
325 }
326
328 {
329 return num_channels_;
330 }
331
333 {
334 return num_channels_ * sizeof(float);
335 }
336
341 {
342 return BufferRange<float>(buffer_, 0, buffer_len(), elem_stride);
343 }
344
346 {
347 return BufferRange<const float>(buffer_, 0, buffer_len(), elem_stride);
348 }
349
351 {
352 return BufferArea<float>(buffer_, get_width(), area, elem_stride);
353 }
354
356 {
357 return BufferArea<const float>(buffer_, get_width(), area, elem_stride);
358 }
359
362
367 float *get_buffer()
368 {
369 return buffer_;
370 }
371
376 MemoryBuffer *inflate() const;
377
378 inline void wrap_pixel(float &x,
379 float &y,
380 MemoryBufferExtend extend_x,
381 MemoryBufferExtend extend_y) const
382 {
383 const float w = (float)get_width();
384 const float h = (float)get_height();
385 x = x - rect_.xmin;
386 y = y - rect_.ymin;
387
388 switch (extend_x) {
390 break;
392 if (x < 0) {
393 x = 0.0f;
394 }
395 if (x >= w) {
396 x = w - 1;
397 }
398 break;
400 x = floored_fmod(x, w);
401 break;
402 }
403
404 switch (extend_y) {
406 break;
408 if (y < 0) {
409 y = 0.0f;
410 }
411 if (y >= h) {
412 y = h - 1;
413 }
414 break;
416 y = floored_fmod(y, h);
417 break;
418 }
419
420 x = x + rect_.xmin;
421 y = y + rect_.ymin;
422 }
423
424 inline void read(float *result,
425 float x,
426 float y,
430 {
431 /* Extend is completely ignored for constants. This may need to be fixed in the future. */
432 if (is_a_single_elem_) {
433 memcpy(result, buffer_, get_elem_bytes_len());
434 return;
435 }
436
437 this->wrap_pixel(x, y, extend_x, extend_y);
438
440 read_elem_checked(int(floorf(x + 0.5f)), int(floorf(y + 0.5f)), result);
441 return;
442 }
443
444 x = get_relative_x(x);
445 y = get_relative_y(y);
446 const float w = get_width();
447 const float h = get_height();
448
449 /* Compute (linear interpolation) intersection with Clip. */
450 float mult = 1.0f;
451 if (extend_x == MemoryBufferExtend::Clip) {
452 mult = std::min(x + 1.0f, w - x);
453 }
454 if (extend_y == MemoryBufferExtend::Clip) {
455 mult = std::min(mult, std::min(y + 1.0f, h - y));
456 }
457 if (mult <= 0.0f) {
458 clear_elem(result);
459 return;
460 }
461
463 /* Sample using Extend or Repeat. */
465 result,
466 w,
467 h,
468 num_channels_,
469 x,
470 y,
471 extend_x == MemoryBufferExtend::Repeat,
472 extend_y == MemoryBufferExtend::Repeat);
473 }
474 else { /* #PixelSampler::Bicubic */
475 /* Sample using Extend (Repeat is not implemented by `interpolate_cubic_bspline`). */
476 math::interpolate_cubic_bspline_fl(buffer_, result, w, h, num_channels_, x, y);
477 }
478
479 /* Multiply by Clip intersection. */
480 if (mult < 1.0f) {
481 for (int i = 0; i < num_channels_; ++i) {
482 result[i] *= mult;
483 }
484 }
485 }
486 void write_pixel(int x, int y, const float color[4]);
487 void add_pixel(int x, int y, const float color[4]);
488 inline void read_bilinear(float *result,
489 float x,
490 float y,
493 {
494 float u = x;
495 float v = y;
496 this->wrap_pixel(u, v, extend_x, extend_y);
497 if ((extend_x != MemoryBufferExtend::Repeat && (u < 0.0f || u >= get_width())) ||
499 {
500 copy_vn_fl(result, num_channels_, 0.0f);
501 return;
502 }
503 if (is_a_single_elem_) {
504 memcpy(result, buffer_, sizeof(float) * num_channels_);
505 }
506 else {
508 result,
509 get_width(),
510 get_height(),
511 num_channels_,
512 u,
513 v,
514 extend_x == MemoryBufferExtend::Repeat,
515 extend_y == MemoryBufferExtend::Repeat);
516 }
517 }
518
522 void apply_processor(ColormanageProcessor &processor, const rcti area);
523
524 void copy_from(const MemoryBuffer *src, const rcti &area);
525 void copy_from(const MemoryBuffer *src, const rcti &area, int to_x, int to_y);
526 void copy_from(const MemoryBuffer *src,
527 const rcti &area,
528 int channel_offset,
529 int elem_size,
530 int to_channel_offset);
531 void copy_from(const MemoryBuffer *src,
532 const rcti &area,
533 int channel_offset,
534 int elem_size,
535 int to_x,
536 int to_y,
537 int to_channel_offset);
538 void copy_from(const uchar *src, const rcti &area);
539 void copy_from(const uchar *src,
540 const rcti &area,
541 int channel_offset,
542 int elem_size,
543 int elem_stride,
544 int row_stride,
545 int to_channel_offset);
546 void copy_from(const uchar *src,
547 const rcti &area,
548 int channel_offset,
549 int elem_size,
550 int elem_stride,
551 int row_stride,
552 int to_x,
553 int to_y,
554 int to_channel_offset);
555 void copy_from(const struct ImBuf *src,
556 const rcti &area,
557 bool ensure_premultiplied = false,
558 bool ensure_linear_space = false);
559 void copy_from(const struct ImBuf *src,
560 const rcti &area,
561 int channel_offset,
562 int elem_size,
563 int to_channel_offset,
564 bool ensure_premultiplied = false,
565 bool ensure_linear_space = false);
566 void copy_from(const struct ImBuf *src,
567 const rcti &src_area,
568 int channel_offset,
569 int elem_size,
570 int to_x,
571 int to_y,
572 int to_channel_offset,
573 bool ensure_premultiplied = false,
574 bool ensure_linear_space = false);
575
576 void fill(const rcti &area, const float *value);
577 void fill(const rcti &area, int channel_offset, const float *value, int value_size);
585 void fill_from(const MemoryBuffer &src);
586
590 const rcti &get_rect() const
591 {
592 return rect_;
593 }
594
598 const int get_width() const
599 {
600 return BLI_rcti_size_x(&rect_);
601 }
602
606 const int get_height() const
607 {
608 return BLI_rcti_size_y(&rect_);
609 }
610
614 void clear();
615
616 float get_max_value() const;
617 float get_max_value(const rcti &rect) const;
618
619 private:
620 void set_strides();
621 const int64_t buffer_len() const
622 {
624 }
625
626 void clear_elem(float *out) const
627 {
628 memset(out, 0, num_channels_ * sizeof(float));
629 }
630
631 template<typename T> T get_relative_x(T x) const
632 {
633 return x - rect_.xmin;
634 }
635
636 template<typename T> T get_relative_y(T y) const
637 {
638 return y - rect_.ymin;
639 }
640
641 template<typename T> bool has_coords(T x, T y) const
642 {
643 return has_x(x) && has_y(y);
644 }
645
646 template<typename T> bool has_x(T x) const
647 {
648 return x >= rect_.xmin && x < rect_.xmax;
649 }
650
651 template<typename T> bool has_y(T y) const
652 {
653 return y >= rect_.ymin && y < rect_.ymax;
654 }
655
656 /* Fast `floor(..)` functions. The caller should check result is within buffer bounds.
657 * It `ceil(..)` in near cases and when given coordinate
658 * is negative and less than buffer rect `min - 1`. */
659 int floor_x(float x) const
660 {
661 return (int)(x + to_positive_x_stride_) - to_positive_x_stride_;
662 }
663
664 int floor_y(float y) const
665 {
666 return (int)(y + to_positive_y_stride_) - to_positive_y_stride_;
667 }
668
669 void copy_single_elem_from(const MemoryBuffer *src,
670 int channel_offset,
671 int elem_size,
672 int to_channel_offset);
673 void copy_rows_from(const MemoryBuffer *src, const rcti &src_area, int to_x, int to_y);
674 void copy_elems_from(const MemoryBuffer *src,
675 const rcti &area,
676 int channel_offset,
677 int elem_size,
678 int to_x,
679 int to_y,
680 int to_channel_offset);
681
682#ifdef WITH_CXX_GUARDEDALLOC
683 MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryBuffer")
684#endif
685};
686
687} // namespace blender::compositor
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE float floored_fmod(float f, float n)
void copy_vn_fl(float *array_tar, int size, float val)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
unsigned char uchar
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
SIMD_FORCE_INLINE void mult(const btTransform &t1, const btTransform &t2)
Set the current transform as the value of the product of two transforms.
Definition btTransform.h:76
a MemoryBuffer contains access to the data
const rcti & get_rect() const
get the rect of this MemoryBuffer
void copy_from(const struct ImBuf *src, const rcti &area, bool ensure_premultiplied=false, bool ensure_linear_space=false)
const float * get_elem_clamped(int x, int y) const
void read_elem_checked(int x, int y, float *out) const
float & get_value(int x, int y, int channel)
void read(float *result, float x, float y, PixelSampler sampler=PixelSampler::Nearest, MemoryBufferExtend extend_x=MemoryBufferExtend::Clip, MemoryBufferExtend extend_y=MemoryBufferExtend::Clip) const
void copy_from(const struct ImBuf *src, const rcti &src_area, int channel_offset, int elem_size, int to_x, int to_y, int to_channel_offset, bool ensure_premultiplied=false, bool ensure_linear_space=false)
void copy_from(const MemoryBuffer *src, const rcti &area)
BufferArea< float > get_buffer_area(const rcti &area)
BufferArea< const float > get_buffer_area(const rcti &area) const
const float & get_value(int x, int y, int channel) const
void read_elem_checked(float x, float y, float *out) const
const int get_width() const
get the width of this MemoryBuffer
const float * get_elem(int x, int y) const
intptr_t get_coords_offset(int x, int y) const
const float & operator[](int index) const
const int get_height() const
get the height of this MemoryBuffer
BufferRange< const float > as_range() const
void write_pixel(int x, int y, const float color[4])
float * get_buffer()
get the data of this MemoryBuffer
void read_elem_bicubic_bspline(float x, float y, float *out) const
void read_elem_bilinear(float x, float y, float *out) const
float4 texture_nearest_extend(float2 coordinates) const
void read_elem(int x, int y, float *out) const
void fill(const rcti &area, const float *value)
const float * get_row_end(int y) const
void fill_from(const MemoryBuffer &src)
add the content from other_buffer to this MemoryBuffer
void wrap_pixel(float &x, float &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y) const
void read_bilinear(float *result, float x, float y, MemoryBufferExtend extend_x=MemoryBufferExtend::Clip, MemoryBufferExtend extend_y=MemoryBufferExtend::Clip) const
MemoryBuffer(DataType data_type, int width, int height)
construct new temporarily MemoryBuffer for a width and height.
void read_elem_clamped(int x, int y, float *out) const
void read_elem_filtered(float x, float y, float dx[2], float dy[2], bool extend_boundary, float *out) const
void copy_from(const struct ImBuf *src, const rcti &area, int channel_offset, int elem_size, int to_channel_offset, bool ensure_premultiplied=false, bool ensure_linear_space=false)
void apply_processor(ColormanageProcessor &processor, const rcti area)
Apply a color processor on the given area.
void add_pixel(int x, int y, const float color[4])
void read_elem_sampled(float x, float y, PixelSampler sampler, float *out) const
float4 texture_bilinear_extend(float2 coordinates) const
BuffersIterator< float > iterate_with(Span< MemoryBuffer * > inputs)
void clear()
clear the buffer. Make all pixels black transparent.
local_group_size(16, 16) .push_constant(Type local_group_size(16, 16) .push_constant(Type input_tx sampler(1, ImageType::FLOAT_2D, "matte_tx") .image(0
#define floorf(x)
draw_view in_light_buf[] float
DataType
possible data types for sockets
Definition COM_defines.h:21
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
T clamp(const T &a, const T &min, const T &max)
void interpolate_nearest_fl(const float *buffer, float *output, int width, int height, int components, float u, float v)
float4 interpolate_bilinear_wrap_fl(const float *buffer, int width, int height, float u, float v)
float4 interpolate_cubic_bspline_fl(const float *buffer, int width, int height, float u, float v)
float4 interpolate_bilinear_fl(const float *buffer, int width, int height, float u, float v)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
__int64 int64_t
Definition stdint.h:89
_W64 int intptr_t
Definition stdint.h:118
unsigned char uint8_t
Definition stdint.h:78
int ymin
int ymax
int xmin
int xmax