diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h index 9e240537daf..4d95bda41f9 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.h +++ b/source/blender/compositor/intern/COM_MemoryBuffer.h @@ -194,11 +194,26 @@ class MemoryBuffer { return buffer_ + get_coords_offset(x, y); } + /** + * Get buffer element at given coordinates, clamped to border. + */ + const float *get_elem_clamped(int x, int y) const + { + const int clamped_x = math::clamp(x, 0, this->get_width() - 1); + const int clamped_y = math::clamp(y, 0, this->get_height() - 1); + return buffer_ + get_coords_offset(clamped_x, clamped_y); + } + void read_elem(int x, int y, float *out) const { memcpy(out, get_elem(x, y), get_elem_bytes_len()); } + void read_elem_clamped(int x, int y, float *out) const + { + memcpy(out, get_elem_clamped(x, y), get_elem_bytes_len()); + } + void read_elem_checked(int x, int y, float *out) const { if (!has_coords(x, y)) { diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index d6f1643a288..82c002e1852 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -9,6 +9,7 @@ #include "BLI_ghash.h" #include "BLI_hash.hh" +#include "BLI_math_base.hh" #include "BLI_rect.h" #include "BLI_span.hh" #include "BLI_threads.h" @@ -591,6 +592,14 @@ class NodeOperation { execute_pixel(result, x, y, chunk_data); } + inline void read_clamped(float result[4], int x, int y, void *chunk_data) + { + execute_pixel(result, + math::clamp(x, 0, int(this->get_width()) - 1), + math::clamp(y, 0, int(this->get_height()) - 1), + chunk_data); + } + virtual void *initialize_tile_data(rcti * /*rect*/) { return 0; diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.cc b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc index aba12b781c7..43313de77a0 100644 --- a/source/blender/compositor/operations/COM_BilateralBlurOperation.cc +++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc @@ -34,12 +34,7 @@ void BilateralBlurOperation::execute_pixel(float output[4], int x, int y, void * float temp_color[4]; float blur_color[4]; float blur_divider; - float space = space_; float sigmacolor = data_->sigma_color; - int minx = floor(x - space); - int maxx = ceil(x + space); - int miny = floor(y - space); - int maxy = ceil(y + space); float delta_color; input_determinator_program_->read(determinator_reference_color, x, y, data); @@ -49,17 +44,17 @@ void BilateralBlurOperation::execute_pixel(float output[4], int x, int y, void * * using gaussian bell for weights. Also sigma_color doesn't seem to be * used correct at all. */ - for (int yi = miny; yi < maxy; yi += QualityStepHelper::get_step()) { - for (int xi = minx; xi < maxx; xi += QualityStepHelper::get_step()) { + for (int yi = -radius_; yi <= radius_; yi += QualityStepHelper::get_step()) { + for (int xi = -radius_; xi <= radius_; xi += QualityStepHelper::get_step()) { /* Read determinator. */ - input_determinator_program_->read(determinator, xi, yi, data); + input_determinator_program_->read_clamped(determinator, x + xi, y + yi, data); delta_color = (fabsf(determinator_reference_color[0] - determinator[0]) + fabsf(determinator_reference_color[1] - determinator[1]) + /* Do not take the alpha channel into account. */ fabsf(determinator_reference_color[2] - determinator[2])); if (delta_color < sigmacolor) { /* Add this to the blur. */ - input_color_program_->read(temp_color, xi, yi, data); + input_color_program_->read_clamped(temp_color, x + xi, y + yi, data); add_v4_v4(blur_color, temp_color); blur_divider += 1.0f; } @@ -87,7 +82,7 @@ bool BilateralBlurOperation::determine_depending_area_of_interest( rcti *input, ReadBufferOperation *read_operation, rcti *output) { rcti new_input; - int add = ceil(space_) + 1; + int add = radius_ + 1; new_input.xmax = input->xmax + (add); new_input.xmin = input->xmin - (add); @@ -101,7 +96,7 @@ void BilateralBlurOperation::get_area_of_interest(const int /*input_idx*/, const rcti &output_area, rcti &r_input_area) { - const int add = ceil(space_) + 1; + const int add = radius_ + 1; r_input_area.xmax = output_area.xmax + (add); r_input_area.xmin = output_area.xmin - (add); @@ -117,8 +112,9 @@ struct PixelCursor { const float *determ_reference_color; float temp_color[4]; float *out; - int min_x, max_x; - int min_y, max_y; + int radius; + int x; + int y; }; static void blur_pixel(PixelCursor &p) @@ -130,16 +126,16 @@ static void blur_pixel(PixelCursor &p) * using gaussian bell for weights. Also sigma_color doesn't seem to be * used correct at all. */ - for (int yi = p.min_y; yi < p.max_y; yi += p.step) { - for (int xi = p.min_x; xi < p.max_x; xi += p.step) { - p.input_determinator->read(p.temp_color, xi, yi); + for (int yi = -p.radius; yi <= p.radius; yi += p.step) { + for (int xi = -p.radius; xi <= p.radius; xi += p.step) { + p.input_determinator->read_elem_clamped(p.x + xi, p.y + yi, p.temp_color); /* Do not take the alpha channel into account. */ const float delta_color = (fabsf(p.determ_reference_color[0] - p.temp_color[0]) + fabsf(p.determ_reference_color[1] - p.temp_color[1]) + fabsf(p.determ_reference_color[2] - p.temp_color[2])); if (delta_color < p.sigma_color) { /* Add this to the blur. */ - p.input_color->read(p.temp_color, xi, yi); + p.input_color->read_elem_clamped(p.x + xi, p.y + yi, p.temp_color); add_v4_v4(p.out, p.temp_color); blur_divider += 1.0f; } @@ -161,22 +157,17 @@ void BilateralBlurOperation::update_memory_buffer_partial(MemoryBuffer *output, PixelCursor p = {}; p.step = QualityStepHelper::get_step(); p.sigma_color = data_->sigma_color; + p.radius = radius_; p.input_color = inputs[0]; p.input_determinator = inputs[1]; - const float space = space_; for (int y = area.ymin; y < area.ymax; y++) { p.out = output->get_elem(area.xmin, y); - /* This will be used as the reference color for the determinator. */ - p.determ_reference_color = p.input_determinator->get_elem(area.xmin, y); - p.min_y = floor(y - space); - p.max_y = ceil(y + space); + p.y = y; for (int x = area.xmin; x < area.xmax; x++) { - p.min_x = floor(x - space); - p.max_x = ceil(x + space); - + p.x = x; + /* This will be used as the reference color for the determinator. */ + p.determ_reference_color = p.input_determinator->get_elem(x, y); blur_pixel(p); - - p.determ_reference_color += p.input_determinator->elem_stride; p.out += output->elem_stride; } } diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.h b/source/blender/compositor/operations/COM_BilateralBlurOperation.h index a85b613b4b5..4661d07444b 100644 --- a/source/blender/compositor/operations/COM_BilateralBlurOperation.h +++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.h @@ -4,6 +4,8 @@ #pragma once +#include "BLI_math_base.hh" + #include "COM_MultiThreadedOperation.h" #include "COM_QualityStepHelper.h" @@ -14,7 +16,7 @@ class BilateralBlurOperation : public MultiThreadedOperation, public QualityStep SocketReader *input_color_program_; SocketReader *input_determinator_program_; NodeBilateralBlurData *data_; - float space_; + int radius_; public: BilateralBlurOperation(); @@ -41,7 +43,7 @@ class BilateralBlurOperation : public MultiThreadedOperation, public QualityStep void set_data(NodeBilateralBlurData *data) { data_ = data; - space_ = data->sigma_space + data->iter; + radius_ = int(math::ceil(data->sigma_space + data->iter)); } void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;