From 8278ad3dfb326359f4f8196dc375d952d43c93c7 Mon Sep 17 00:00:00 2001 From: Manuel Castilla Date: Wed, 13 Oct 2021 23:02:15 +0200 Subject: Fix T90799: Box/Ellipse Mask node masking is off-centered This is especially noticeable when using the default center with full width and height as some borders are masked by 1 pixel. The relative coordinates are now calculated respect the last ones instead of the dimensions for centering, and the limits are inclusive to mask more accurately. --- .../compositor/operations/COM_BoxMaskOperation.cc | 28 +++++++++++----------- .../operations/COM_EllipseMaskOperation.cc | 16 ++++++------- 2 files changed, 22 insertions(+), 22 deletions(-) (limited to 'source/blender/compositor') diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cc b/source/blender/compositor/operations/COM_BoxMaskOperation.cc index adfe7fcd87a..c79179a3e0a 100644 --- a/source/blender/compositor/operations/COM_BoxMaskOperation.cc +++ b/source/blender/compositor/operations/COM_BoxMaskOperation.cc @@ -48,8 +48,8 @@ void BoxMaskOperation::execute_pixel_sampled(float output[4], float input_mask[4]; float input_value[4]; - float rx = x / this->get_width(); - float ry = y / this->get_height(); + float rx = x / MAX2(this->get_width() - 1.0f, FLT_EPSILON); + float ry = y / MAX2(this->get_height() - 1.0f, FLT_EPSILON); const float dy = (ry - data_->y) / aspect_ratio_; const float dx = rx - data_->x; @@ -59,10 +59,10 @@ void BoxMaskOperation::execute_pixel_sampled(float output[4], input_mask_->read_sampled(input_mask, x, y, sampler); input_value_->read_sampled(input_value, x, y, sampler); - float half_height = data_->height / 2.0f; - float half_width = data_->width / 2.0f; - bool inside = (rx > data_->x - half_width && rx < data_->x + half_width && - ry > data_->y - half_height && ry < data_->y + half_height); + float half_height = data_->height / 2.0f + FLT_EPSILON; + float half_width = data_->width / 2.0f + FLT_EPSILON; + bool inside = (rx >= data_->x - half_width && rx <= data_->x + half_width && + ry >= data_->y - half_height && ry <= data_->y + half_height); switch (mask_type_) { case CMP_NODE_MASKTYPE_ADD: @@ -144,20 +144,20 @@ void BoxMaskOperation::apply_mask(MemoryBuffer *output, Span inputs, MaskFunc mask_func) { - const float op_w = this->get_width(); - const float op_h = this->get_height(); - const float half_w = data_->width / 2.0f; - const float half_h = data_->height / 2.0f; + const float op_last_x = MAX2(this->get_width() - 1.0f, FLT_EPSILON); + const float op_last_y = MAX2(this->get_height() - 1.0f, FLT_EPSILON); + const float half_w = data_->width / 2.0f + FLT_EPSILON; + const float half_h = data_->height / 2.0f + FLT_EPSILON; for (BuffersIterator it = output->iterate_with(inputs, area); !it.is_end(); ++it) { - const float op_ry = it.y / op_h; + const float op_ry = it.y / op_last_y; const float dy = (op_ry - data_->y) / aspect_ratio_; - const float op_rx = it.x / op_w; + const float op_rx = it.x / op_last_x; const float dx = op_rx - data_->x; const float rx = data_->x + (cosine_ * dx + sine_ * dy); const float ry = data_->y + (-sine_ * dx + cosine_ * dy); - const bool inside = (rx > data_->x - half_w && rx < data_->x + half_w && - ry > data_->y - half_h && ry < data_->y + half_h); + const bool inside = (rx >= data_->x - half_w && rx <= data_->x + half_w && + ry >= data_->y - half_h && ry <= data_->y + half_h); const float *mask = it.in(0); const float *value = it.in(1); *it.out = mask_func(inside, mask, value); diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc index 19497c38131..a051e06d15e 100644 --- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc +++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc @@ -48,8 +48,8 @@ void EllipseMaskOperation::execute_pixel_sampled(float output[4], float input_mask[4]; float input_value[4]; - float rx = x / this->get_width(); - float ry = y / this->get_height(); + float rx = x / MAX2(this->get_width() - 1.0f, FLT_EPSILON); + float ry = y / MAX2(this->get_height() - 1.0f, FLT_EPSILON); const float dy = (ry - data_->y) / aspect_ratio_; const float dx = rx - data_->x; @@ -68,7 +68,7 @@ void EllipseMaskOperation::execute_pixel_sampled(float output[4], sy *= sy; const float ty = half_height * half_height; - bool inside = ((sx / tx) + (sy / ty)) < 1.0f; + bool inside = ((sx / tx) + (sy / ty)) <= (1.0f + FLT_EPSILON); switch (mask_type_) { case CMP_NODE_MASKTYPE_ADD: @@ -152,20 +152,20 @@ void EllipseMaskOperation::apply_mask(MemoryBuffer *output, { const MemoryBuffer *input_mask = inputs[0]; const MemoryBuffer *input_value = inputs[1]; - const float op_w = this->get_width(); - const float op_h = this->get_height(); + const float op_last_x = MAX2(this->get_width() - 1.0f, FLT_EPSILON); + const float op_last_y = MAX2(this->get_height() - 1.0f, FLT_EPSILON); const float half_w = data_->width / 2.0f; const float half_h = data_->height / 2.0f; const float tx = half_w * half_w; const float ty = half_h * half_h; for (int y = area.ymin; y < area.ymax; y++) { - const float op_ry = y / op_h; + const float op_ry = y / op_last_y; const float dy = (op_ry - data_->y) / aspect_ratio_; float *out = output->get_elem(area.xmin, y); const float *mask = input_mask->get_elem(area.xmin, y); const float *value = input_value->get_elem(area.xmin, y); for (int x = area.xmin; x < area.xmax; x++) { - const float op_rx = x / op_w; + const float op_rx = x / op_last_x; const float dx = op_rx - data_->x; const float rx = data_->x + (cosine_ * dx + sine_ * dy); const float ry = data_->y + (-sine_ * dx + cosine_ * dy); @@ -173,7 +173,7 @@ void EllipseMaskOperation::apply_mask(MemoryBuffer *output, sx *= sx; float sy = ry - data_->y; sy *= sy; - const bool inside = ((sx / tx) + (sy / ty)) < 1.0f; + const bool inside = ((sx / tx) + (sy / ty)) <= (1.0f + FLT_EPSILON); out[0] = mask_func(inside, mask, value); mask += input_mask->elem_stride; -- cgit v1.2.3