diff options
Diffstat (limited to 'source/blender/compositor/operations')
103 files changed, 1095 insertions, 620 deletions
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cc b/source/blender/compositor/operations/COM_BlurBaseOperation.cc index 058b422c4a5..412632e2e22 100644 --- a/source/blender/compositor/operations/COM_BlurBaseOperation.cc +++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cc @@ -212,31 +212,30 @@ void BlurBaseOperation::updateSize() this->m_sizeavailable = true; } -void BlurBaseOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void BlurBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { if (!m_extend_bounds) { - NodeOperation::determineResolution(resolution, preferredResolution); + NodeOperation::determine_canvas(preferred_area, r_area); return; } switch (execution_model_) { case eExecutionModel::Tiled: { - NodeOperation::determineResolution(resolution, preferredResolution); - resolution[0] += 2 * m_size * m_data.sizex; - resolution[1] += 2 * m_size * m_data.sizey; + NodeOperation::determine_canvas(preferred_area, r_area); + r_area.xmax += 2 * m_size * m_data.sizex; + r_area.ymax += 2 * m_size * m_data.sizey; break; } case eExecutionModel::FullFrame: { /* Setting a modifier ensures all non main inputs have extended bounds as preferred - * resolution, avoiding unnecessary resolution conversions that would hide constant + * canvas, avoiding unnecessary canvas conversions that would hide constant * operations. */ - set_determined_resolution_modifier([=](unsigned int res[2]) { + set_determined_canvas_modifier([=](rcti &canvas) { /* Rounding to even prevents jiggling in backdrop while switching size values. */ - res[0] += round_to_even(2 * m_size * m_data.sizex); - res[1] += round_to_even(2 * m_size * m_data.sizey); + canvas.xmax += round_to_even(2 * m_size * m_data.sizex); + canvas.ymax += round_to_even(2 * m_size * m_data.sizey); }); - NodeOperation::determineResolution(resolution, preferredResolution); + NodeOperation::determine_canvas(preferred_area, r_area); break; } } @@ -251,7 +250,7 @@ void BlurBaseOperation::get_area_of_interest(const int input_idx, r_input_area = output_area; break; case 1: - r_input_area = use_variable_size_ ? output_area : COM_SINGLE_ELEM_AREA; + r_input_area = use_variable_size_ ? output_area : COM_CONSTANT_INPUT_AREA_OF_INTEREST; break; } } diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.h b/source/blender/compositor/operations/COM_BlurBaseOperation.h index 78b1e919aa6..9ab9bf5a173 100644 --- a/source/blender/compositor/operations/COM_BlurBaseOperation.h +++ b/source/blender/compositor/operations/COM_BlurBaseOperation.h @@ -85,8 +85,7 @@ class BlurBaseOperation : public MultiThreadedOperation, public QualityStepHelpe int get_blur_size(eDimension dim) const; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; virtual void get_area_of_interest(int input_idx, const rcti &output_area, diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cc b/source/blender/compositor/operations/COM_BokehBlurOperation.cc index f2a43b7dbca..93482dd2a54 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.cc +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cc @@ -34,7 +34,7 @@ constexpr int SIZE_INPUT_INDEX = 3; BokehBlurOperation::BokehBlurOperation() { this->addInputSocket(DataType::Color); - this->addInputSocket(DataType::Color, ResizeMode::None); + this->addInputSocket(DataType::Color, ResizeMode::Align); this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Color); @@ -266,31 +266,30 @@ void BokehBlurOperation::updateSize() this->m_sizeavailable = true; } -void BokehBlurOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void BokehBlurOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { if (!m_extend_bounds) { - NodeOperation::determineResolution(resolution, preferredResolution); + NodeOperation::determine_canvas(preferred_area, r_area); return; } switch (execution_model_) { case eExecutionModel::Tiled: { - NodeOperation::determineResolution(resolution, preferredResolution); - const float max_dim = MAX2(resolution[0], resolution[1]); - resolution[0] += 2 * this->m_size * max_dim / 100.0f; - resolution[1] += 2 * this->m_size * max_dim / 100.0f; + NodeOperation::determine_canvas(preferred_area, r_area); + const float max_dim = MAX2(BLI_rcti_size_x(&r_area), BLI_rcti_size_y(&r_area)); + r_area.xmax += 2 * this->m_size * max_dim / 100.0f; + r_area.ymax += 2 * this->m_size * max_dim / 100.0f; break; } case eExecutionModel::FullFrame: { - set_determined_resolution_modifier([=](unsigned int res[2]) { - const float max_dim = MAX2(res[0], res[1]); + set_determined_canvas_modifier([=](rcti &canvas) { + const float max_dim = MAX2(BLI_rcti_size_x(&canvas), BLI_rcti_size_y(&canvas)); /* Rounding to even prevents image jiggling in backdrop while switching size values. */ float add_size = round_to_even(2 * this->m_size * max_dim / 100.0f); - res[0] += add_size; - res[1] += add_size; + canvas.xmax += add_size; + canvas.ymax += add_size; }); - NodeOperation::determineResolution(resolution, preferredResolution); + NodeOperation::determine_canvas(preferred_area, r_area); break; } } @@ -312,17 +311,14 @@ void BokehBlurOperation::get_area_of_interest(const int input_idx, } case BOKEH_INPUT_INDEX: { NodeOperation *bokeh_input = getInputOperation(BOKEH_INPUT_INDEX); - r_input_area.xmin = 0; - r_input_area.xmax = bokeh_input->getWidth(); - r_input_area.ymin = 0; - r_input_area.ymax = bokeh_input->getHeight(); + r_input_area = bokeh_input->get_canvas(); break; } case BOUNDING_BOX_INPUT_INDEX: r_input_area = output_area; break; case SIZE_INPUT_INDEX: { - r_input_area = COM_SINGLE_ELEM_AREA; + r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST; break; } } diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.h b/source/blender/compositor/operations/COM_BokehBlurOperation.h index 59c14305393..84f5a8293ba 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.h @@ -80,8 +80,7 @@ class BokehBlurOperation : public MultiThreadedOperation, public QualityStepHelp this->m_extend_bounds = extend_bounds; } - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; void update_memory_buffer_partial(MemoryBuffer *output, diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.cc b/source/blender/compositor/operations/COM_BokehImageOperation.cc index bd5b25b5af8..5c9c8b36ee0 100644 --- a/source/blender/compositor/operations/COM_BokehImageOperation.cc +++ b/source/blender/compositor/operations/COM_BokehImageOperation.cc @@ -145,11 +145,13 @@ void BokehImageOperation::deinitExecution() } } -void BokehImageOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) +void BokehImageOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - resolution[0] = COM_BLUR_BOKEH_PIXELS; - resolution[1] = COM_BLUR_BOKEH_PIXELS; + BLI_rcti_init(&r_area, + preferred_area.xmin, + preferred_area.xmin + COM_BLUR_BOKEH_PIXELS, + preferred_area.ymin, + preferred_area.ymin + COM_BLUR_BOKEH_PIXELS); } } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.h b/source/blender/compositor/operations/COM_BokehImageOperation.h index 2527233fabd..f7fec5d71a5 100644 --- a/source/blender/compositor/operations/COM_BokehImageOperation.h +++ b/source/blender/compositor/operations/COM_BokehImageOperation.h @@ -128,8 +128,7 @@ class BokehImageOperation : public MultiThreadedOperation { * \brief determine the resolution of this operation. currently fixed at [COM_BLUR_BOKEH_PIXELS, * COM_BLUR_BOKEH_PIXELS] \param resolution: \param preferredResolution: */ - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; /** * \brief set the node data diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cc b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc index 7457ac9e227..a573a9d7eed 100644 --- a/source/blender/compositor/operations/COM_CalculateMeanOperation.cc +++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc @@ -27,7 +27,7 @@ namespace blender::compositor { CalculateMeanOperation::CalculateMeanOperation() { - this->addInputSocket(DataType::Color, ResizeMode::None); + this->addInputSocket(DataType::Color, ResizeMode::Align); this->addOutputSocket(DataType::Value); this->m_imageReader = nullptr; this->m_iscalculated = false; @@ -165,11 +165,7 @@ void CalculateMeanOperation::get_area_of_interest(int input_idx, rcti &r_input_area) { BLI_assert(input_idx == 0); - NodeOperation *operation = getInputOperation(input_idx); - r_input_area.xmin = 0; - r_input_area.ymin = 0; - r_input_area.xmax = operation->getWidth(); - r_input_area.ymax = operation->getHeight(); + r_input_area = get_input_operation(input_idx)->get_canvas(); } void CalculateMeanOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output), diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc index aee8c0d52e8..0b6590ae4c7 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc +++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc @@ -40,7 +40,7 @@ ColorBalanceASCCDLOperation::ColorBalanceASCCDLOperation() this->addOutputSocket(DataType::Color); this->m_inputValueOperation = nullptr; this->m_inputColorOperation = nullptr; - this->setResolutionInputSocketIndex(1); + this->set_canvas_input_index(1); flags.can_be_constant = true; } diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc index 674cb79a238..c658ecd6394 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc +++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc @@ -45,7 +45,7 @@ ColorBalanceLGGOperation::ColorBalanceLGGOperation() this->addOutputSocket(DataType::Color); this->m_inputValueOperation = nullptr; this->m_inputColorOperation = nullptr; - this->setResolutionInputSocketIndex(1); + this->set_canvas_input_index(1); flags.can_be_constant = true; } diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cc b/source/blender/compositor/operations/COM_ColorCurveOperation.cc index 646238460ba..364b310945e 100644 --- a/source/blender/compositor/operations/COM_ColorCurveOperation.cc +++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cc @@ -37,7 +37,7 @@ ColorCurveOperation::ColorCurveOperation() this->m_inputBlackProgram = nullptr; this->m_inputWhiteProgram = nullptr; - this->setResolutionInputSocketIndex(1); + this->set_canvas_input_index(1); } void ColorCurveOperation::initExecution() { @@ -139,7 +139,7 @@ ConstantLevelColorCurveOperation::ConstantLevelColorCurveOperation() this->m_inputFacProgram = nullptr; this->m_inputImageProgram = nullptr; - this->setResolutionInputSocketIndex(1); + this->set_canvas_input_index(1); } void ConstantLevelColorCurveOperation::initExecution() { diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc index fb9e2e43c60..f7466b5db34 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cc +++ b/source/blender/compositor/operations/COM_CompositorOperation.cc @@ -236,8 +236,7 @@ void CompositorOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(outp depth_buf.copy_from(inputs[2], area); } -void CompositorOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void CompositorOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area) { int width = this->m_rd->xsch * this->m_rd->size / 100; int height = this->m_rd->ysch * this->m_rd->size / 100; @@ -254,13 +253,19 @@ void CompositorOperation::determineResolution(unsigned int resolution[2], RE_ReleaseResult(re); } - preferredResolution[0] = width; - preferredResolution[1] = height; - - NodeOperation::determineResolution(resolution, preferredResolution); - - resolution[0] = width; - resolution[1] = height; + rcti local_preferred; + BLI_rcti_init(&local_preferred, 0, width, 0, height); + + switch (execution_model_) { + case eExecutionModel::Tiled: + NodeOperation::determine_canvas(local_preferred, r_area); + r_area = local_preferred; + break; + case eExecutionModel::FullFrame: + set_determined_canvas_modifier([&](rcti &canvas) { canvas = local_preferred; }); + NodeOperation::determine_canvas(local_preferred, r_area); + break; + } } } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h index 66367ec8bae..6eb96e01b47 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.h +++ b/source/blender/compositor/operations/COM_CompositorOperation.h @@ -115,8 +115,7 @@ class CompositorOperation : public MultiThreadedOperation { { return eCompositorPriority::Medium; } - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void setUseAlphaInput(bool value) { this->m_useAlphaInput = value; diff --git a/source/blender/compositor/operations/COM_ConstantOperation.cc b/source/blender/compositor/operations/COM_ConstantOperation.cc index 33d51cca432..c127860a89c 100644 --- a/source/blender/compositor/operations/COM_ConstantOperation.cc +++ b/source/blender/compositor/operations/COM_ConstantOperation.cc @@ -22,14 +22,14 @@ namespace blender::compositor { ConstantOperation::ConstantOperation() { - needs_resolution_to_get_constant_ = false; + needs_canvas_to_get_constant_ = false; flags.is_constant_operation = true; flags.is_fullframe_operation = true; } bool ConstantOperation::can_get_constant_elem() const { - return !needs_resolution_to_get_constant_ || this->flags.is_resolution_set; + return !needs_canvas_to_get_constant_ || this->flags.is_canvas_set; } void ConstantOperation::update_memory_buffer(MemoryBuffer *output, diff --git a/source/blender/compositor/operations/COM_ConstantOperation.h b/source/blender/compositor/operations/COM_ConstantOperation.h index 31b8d30254b..d44d1939424 100644 --- a/source/blender/compositor/operations/COM_ConstantOperation.h +++ b/source/blender/compositor/operations/COM_ConstantOperation.h @@ -31,7 +31,7 @@ namespace blender::compositor { */ class ConstantOperation : public NodeOperation { protected: - bool needs_resolution_to_get_constant_; + bool needs_canvas_to_get_constant_; public: ConstantOperation(); diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cc b/source/blender/compositor/operations/COM_ConvertOperation.cc index 9a3733dda5b..7b2721ebbb2 100644 --- a/source/blender/compositor/operations/COM_ConvertOperation.cc +++ b/source/blender/compositor/operations/COM_ConvertOperation.cc @@ -587,7 +587,7 @@ CombineChannelsOperation::CombineChannelsOperation() this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Color); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->m_inputChannel1Operation = nullptr; this->m_inputChannel2Operation = nullptr; this->m_inputChannel3Operation = nullptr; diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc index 11a077229fd..807223fd45f 100644 --- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc +++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc @@ -29,7 +29,7 @@ ConvolutionFilterOperation::ConvolutionFilterOperation() this->addInputSocket(DataType::Color); this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Color); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->m_inputOperation = nullptr; this->flags.complex = true; } diff --git a/source/blender/compositor/operations/COM_CropOperation.cc b/source/blender/compositor/operations/COM_CropOperation.cc index 12833660fcb..6ac30c22ad1 100644 --- a/source/blender/compositor/operations/COM_CropOperation.cc +++ b/source/blender/compositor/operations/COM_CropOperation.cc @@ -23,7 +23,7 @@ namespace blender::compositor { CropBaseOperation::CropBaseOperation() { - this->addInputSocket(DataType::Color, ResizeMode::None); + this->addInputSocket(DataType::Color, ResizeMode::Align); this->addOutputSocket(DataType::Color); this->m_inputOperation = nullptr; this->m_settings = nullptr; @@ -142,13 +142,12 @@ void CropImageOperation::get_area_of_interest(const int input_idx, r_input_area.ymin = output_area.ymin + this->m_ymin; } -void CropImageOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void CropImageOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - NodeOperation::determineResolution(resolution, preferredResolution); + NodeOperation::determine_canvas(preferred_area, r_area); updateArea(); - resolution[0] = this->m_xmax - this->m_xmin; - resolution[1] = this->m_ymax - this->m_ymin; + r_area.xmax = r_area.xmin + (m_xmax - m_xmin); + r_area.ymax = r_area.ymin + (m_ymax - m_ymin); } void CropImageOperation::executePixelSampled(float output[4], diff --git a/source/blender/compositor/operations/COM_CropOperation.h b/source/blender/compositor/operations/COM_CropOperation.h index 57caa4e5834..a156727402b 100644 --- a/source/blender/compositor/operations/COM_CropOperation.h +++ b/source/blender/compositor/operations/COM_CropOperation.h @@ -66,8 +66,7 @@ class CropImageOperation : public CropBaseOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cc b/source/blender/compositor/operations/COM_DenoiseOperation.cc index 0c660e0b723..f8a575acc3a 100644 --- a/source/blender/compositor/operations/COM_DenoiseOperation.cc +++ b/source/blender/compositor/operations/COM_DenoiseOperation.cc @@ -153,10 +153,7 @@ void DenoiseBaseOperation::get_area_of_interest(const int UNUSED(input_idx), const rcti &UNUSED(output_area), rcti &r_input_area) { - r_input_area.xmin = 0; - r_input_area.xmax = this->getWidth(); - r_input_area.ymin = 0; - r_input_area.ymax = this->getHeight(); + r_input_area = this->get_canvas(); } DenoiseOperation::DenoiseOperation() diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.cc b/source/blender/compositor/operations/COM_DespeckleOperation.cc index 19bd7b2af6f..df637ee6709 100644 --- a/source/blender/compositor/operations/COM_DespeckleOperation.cc +++ b/source/blender/compositor/operations/COM_DespeckleOperation.cc @@ -29,7 +29,7 @@ DespeckleOperation::DespeckleOperation() this->addInputSocket(DataType::Color); this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Color); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->m_inputOperation = nullptr; this->flags.complex = true; } diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cc b/source/blender/compositor/operations/COM_DilateErodeOperation.cc index 28b40021cd9..b7fd714ba5b 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.cc +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc @@ -783,7 +783,8 @@ static void step_update_memory_buffer(MemoryBuffer *output, start = half_window + (i - 1) * window + 1; for (int y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { - result.get_value(x, y + start + area.ymin, 0) = selector(temp[y], temp[y + window - 1]); + result.get_value(x + area.xmin, y + start + area.ymin, 0) = selector(temp[y], + temp[y + window - 1]); } } } diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc index 102025ed915..e69124205d0 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc @@ -152,10 +152,7 @@ void DirectionalBlurOperation::get_area_of_interest(const int input_idx, { BLI_assert(input_idx == 0); UNUSED_VARS_NDEBUG(input_idx); - r_input_area.xmin = 0; - r_input_area.xmax = this->getWidth(); - r_input_area.ymin = 0; - r_input_area.ymax = this->getHeight(); + r_input_area = this->get_canvas(); } void DirectionalBlurOperation::update_memory_buffer_partial(MemoryBuffer *output, diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cc b/source/blender/compositor/operations/COM_DisplaceOperation.cc index a4c01fda7ca..d08ff60d5d0 100644 --- a/source/blender/compositor/operations/COM_DisplaceOperation.cc +++ b/source/blender/compositor/operations/COM_DisplaceOperation.cc @@ -211,10 +211,7 @@ void DisplaceOperation::get_area_of_interest(const int input_idx, { switch (input_idx) { case 0: { - r_input_area.xmin = 0; - r_input_area.ymin = 0; - r_input_area.xmax = getInputOperation(input_idx)->getWidth(); - r_input_area.ymax = getInputOperation(input_idx)->getHeight(); + r_input_area = getInputOperation(input_idx)->get_canvas(); break; } case 1: { diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc index e1c531bd49e..712b61be805 100644 --- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc +++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc @@ -138,10 +138,7 @@ void DisplaceSimpleOperation::get_area_of_interest(const int input_idx, { switch (input_idx) { case 0: { - r_input_area.xmin = 0; - r_input_area.ymin = 0; - r_input_area.xmax = getInputOperation(input_idx)->getWidth(); - r_input_area.ymax = getInputOperation(input_idx)->getHeight(); + r_input_area = get_input_operation(input_idx)->get_canvas(); break; } default: { diff --git a/source/blender/compositor/operations/COM_DotproductOperation.cc b/source/blender/compositor/operations/COM_DotproductOperation.cc index 875b161e208..aa18ff1e827 100644 --- a/source/blender/compositor/operations/COM_DotproductOperation.cc +++ b/source/blender/compositor/operations/COM_DotproductOperation.cc @@ -25,7 +25,7 @@ DotproductOperation::DotproductOperation() this->addInputSocket(DataType::Vector); this->addInputSocket(DataType::Vector); this->addOutputSocket(DataType::Value); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->m_input1Operation = nullptr; this->m_input2Operation = nullptr; flags.can_be_constant = true; diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc index 55ae19ad194..d112334b749 100644 --- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc +++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc @@ -1399,10 +1399,7 @@ void DoubleEdgeMaskOperation::get_area_of_interest(int UNUSED(input_idx), const rcti &UNUSED(output_area), rcti &r_input_area) { - r_input_area.xmax = this->getWidth(); - r_input_area.xmin = 0; - r_input_area.ymax = this->getHeight(); - r_input_area.ymin = 0; + r_input_area = this->get_canvas(); } void DoubleEdgeMaskOperation::update_memory_buffer(MemoryBuffer *output, diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc index eb1fd98a590..bf6eee6d3f9 100644 --- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc +++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc @@ -162,13 +162,13 @@ void EllipseMaskOperation::apply_mask(MemoryBuffer *output, const float half_h = this->m_data->height / 2.0f; const float tx = half_w * half_w; const float ty = half_h * half_h; - for (const int y : YRange(area)) { + for (int y = area.ymin; y < area.ymax; y++) { const float op_ry = y / op_h; const float dy = (op_ry - this->m_data->y) / m_aspectRatio; 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 (const int x : XRange(area)) { + for (int x = area.xmin; x < area.xmax; x++) { const float op_rx = x / op_w; const float dx = op_rx - this->m_data->x; const float rx = this->m_data->x + (m_cosine * dx + m_sine * dy); diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc index e0fc45811cb..f45b77c6ebc 100644 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc @@ -271,10 +271,7 @@ void FastGaussianBlurOperation::get_area_of_interest(const int input_idx, { switch (input_idx) { case IMAGE_INPUT_INDEX: - r_input_area.xmin = 0; - r_input_area.xmax = getWidth(); - r_input_area.ymin = 0; - r_input_area.ymax = getHeight(); + r_input_area = this->get_canvas(); break; default: BlurBaseOperation::get_area_of_interest(input_idx, output_area, r_input_area); @@ -411,10 +408,7 @@ void FastGaussianBlurValueOperation::get_area_of_interest(const int UNUSED(input const rcti &UNUSED(output_area), rcti &r_input_area) { - r_input_area.xmin = 0; - r_input_area.xmax = getWidth(); - r_input_area.ymin = 0; - r_input_area.ymax = getHeight(); + r_input_area = this->get_canvas(); } void FastGaussianBlurValueOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output), diff --git a/source/blender/compositor/operations/COM_FlipOperation.cc b/source/blender/compositor/operations/COM_FlipOperation.cc index d0dc6c0b570..2d8865e41e0 100644 --- a/source/blender/compositor/operations/COM_FlipOperation.cc +++ b/source/blender/compositor/operations/COM_FlipOperation.cc @@ -22,9 +22,9 @@ namespace blender::compositor { FlipOperation::FlipOperation() { - this->addInputSocket(DataType::Color); + this->addInputSocket(DataType::Color, ResizeMode::None); this->addOutputSocket(DataType::Color); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->m_inputOperation = nullptr; this->m_flipX = true; this->m_flipY = false; @@ -75,6 +75,24 @@ bool FlipOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void FlipOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) +{ + NodeOperation::determine_canvas(preferred_area, r_area); + if (execution_model_ == eExecutionModel::FullFrame) { + rcti input_area = r_area; + if (m_flipX) { + const int width = BLI_rcti_size_x(&input_area) - 1; + r_area.xmax = (width - input_area.xmin) + 1; + r_area.xmin = (width - input_area.xmax) + 1; + } + if (m_flipY) { + const int height = BLI_rcti_size_y(&input_area) - 1; + r_area.ymax = (height - input_area.ymin) + 1; + r_area.ymin = (height - input_area.ymax) + 1; + } + } +} + void FlipOperation::get_area_of_interest(const int input_idx, const rcti &output_area, rcti &r_input_area) @@ -84,7 +102,7 @@ void FlipOperation::get_area_of_interest(const int input_idx, if (this->m_flipX) { const int w = (int)this->getWidth() - 1; r_input_area.xmax = (w - output_area.xmin) + 1; - r_input_area.xmin = (w - output_area.xmax) - 1; + r_input_area.xmin = (w - output_area.xmax) + 1; } else { r_input_area.xmin = output_area.xmin; @@ -93,7 +111,7 @@ void FlipOperation::get_area_of_interest(const int input_idx, if (this->m_flipY) { const int h = (int)this->getHeight() - 1; r_input_area.ymax = (h - output_area.ymin) + 1; - r_input_area.ymin = (h - output_area.ymax) - 1; + r_input_area.ymin = (h - output_area.ymax) + 1; } else { r_input_area.ymin = output_area.ymin; @@ -106,10 +124,12 @@ void FlipOperation::update_memory_buffer_partial(MemoryBuffer *output, Span<MemoryBuffer *> inputs) { const MemoryBuffer *input_img = inputs[0]; + const int input_offset_x = input_img->get_rect().xmin; + const int input_offset_y = input_img->get_rect().ymin; for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { const int nx = this->m_flipX ? ((int)this->getWidth() - 1) - it.x : it.x; const int ny = this->m_flipY ? ((int)this->getHeight() - 1) - it.y : it.y; - input_img->read_elem(nx, ny, it.out); + input_img->read_elem(input_offset_x + nx, input_offset_y + ny, it.out); } } diff --git a/source/blender/compositor/operations/COM_FlipOperation.h b/source/blender/compositor/operations/COM_FlipOperation.h index dba7f82c341..963996a5b0d 100644 --- a/source/blender/compositor/operations/COM_FlipOperation.h +++ b/source/blender/compositor/operations/COM_FlipOperation.h @@ -46,6 +46,7 @@ class FlipOperation : public MultiThreadedOperation { this->m_flipY = flipY; } + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cc b/source/blender/compositor/operations/COM_GlareBaseOperation.cc index 90755d9f27a..cd4607b1dde 100644 --- a/source/blender/compositor/operations/COM_GlareBaseOperation.cc +++ b/source/blender/compositor/operations/COM_GlareBaseOperation.cc @@ -26,6 +26,8 @@ GlareBaseOperation::GlareBaseOperation() this->addInputSocket(DataType::Color); this->addOutputSocket(DataType::Color); this->m_settings = nullptr; + flags.is_fullframe_operation = true; + is_output_rendered_ = false; } void GlareBaseOperation::initExecution() { @@ -69,4 +71,36 @@ bool GlareBaseOperation::determineDependingAreaOfInterest(rcti * /*input*/, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void GlareBaseOperation::get_area_of_interest(const int input_idx, + const rcti &UNUSED(output_area), + rcti &r_input_area) +{ + BLI_assert(input_idx == 0); + UNUSED_VARS_NDEBUG(input_idx); + r_input_area.xmin = 0; + r_input_area.xmax = this->getWidth(); + r_input_area.ymin = 0; + r_input_area.ymax = this->getHeight(); +} + +void GlareBaseOperation::update_memory_buffer(MemoryBuffer *output, + const rcti &UNUSED(area), + Span<MemoryBuffer *> inputs) +{ + if (!is_output_rendered_) { + MemoryBuffer *input = inputs[0]; + const bool is_input_inflated = input->is_a_single_elem(); + if (is_input_inflated) { + input = input->inflate(); + } + + this->generateGlare(output->getBuffer(), input, m_settings); + is_output_rendered_ = true; + + if (is_input_inflated) { + delete input; + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.h b/source/blender/compositor/operations/COM_GlareBaseOperation.h index 6dac6f5ecc7..5ca240a9e66 100644 --- a/source/blender/compositor/operations/COM_GlareBaseOperation.h +++ b/source/blender/compositor/operations/COM_GlareBaseOperation.h @@ -49,6 +49,8 @@ class GlareBaseOperation : public SingleThreadedOperation { */ NodeGlare *m_settings; + bool is_output_rendered_; + public: /** * Initialize the execution @@ -68,6 +70,14 @@ class GlareBaseOperation : public SingleThreadedOperation { ReadBufferOperation *readOperation, rcti *output) override; + void get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) final; + + void update_memory_buffer(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) final; + protected: GlareBaseOperation(); diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cc b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc index 1d3402f5b7b..1bf7cf5ae07 100644 --- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cc +++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc @@ -30,12 +30,13 @@ GlareThresholdOperation::GlareThresholdOperation() this->m_inputProgram = nullptr; } -void GlareThresholdOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void GlareThresholdOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - NodeOperation::determineResolution(resolution, preferredResolution); - resolution[0] = resolution[0] / (1 << this->m_settings->quality); - resolution[1] = resolution[1] / (1 << this->m_settings->quality); + NodeOperation::determine_canvas(preferred_area, r_area); + const int width = BLI_rcti_size_x(&r_area) / (1 << this->m_settings->quality); + const int height = BLI_rcti_size_y(&r_area) / (1 << this->m_settings->quality); + r_area.xmax = r_area.xmin + width; + r_area.ymax = r_area.ymin + height; } void GlareThresholdOperation::initExecution() @@ -70,4 +71,24 @@ void GlareThresholdOperation::deinitExecution() this->m_inputProgram = nullptr; } +void GlareThresholdOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const float threshold = this->m_settings->threshold; + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *color = it.in(0); + if (IMB_colormanagement_get_luminance(color) >= threshold) { + it.out[0] = color[0] - threshold; + it.out[1] = color[1] - threshold; + it.out[2] = color[2] - threshold; + + CLAMP3_MIN(it.out, 0.0f); + } + else { + zero_v3(it.out); + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.h b/source/blender/compositor/operations/COM_GlareThresholdOperation.h index a6e971dada7..44f2d717c0e 100644 --- a/source/blender/compositor/operations/COM_GlareThresholdOperation.h +++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.h @@ -18,12 +18,12 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_light_types.h" namespace blender::compositor { -class GlareThresholdOperation : public NodeOperation { +class GlareThresholdOperation : public MultiThreadedOperation { private: /** * \brief Cached reference to the inputProgram @@ -58,8 +58,10 @@ class GlareThresholdOperation : public NodeOperation { this->m_settings = settings; } - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ImageOperation.cc b/source/blender/compositor/operations/COM_ImageOperation.cc index e78d389410f..ff389093f5a 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.cc +++ b/source/blender/compositor/operations/COM_ImageOperation.cc @@ -112,17 +112,14 @@ void BaseImageOperation::deinitExecution() } } -void BaseImageOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) +void BaseImageOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area) { ImBuf *stackbuf = getImBuf(); - resolution[0] = 0; - resolution[1] = 0; + r_area = COM_AREA_NONE; if (stackbuf) { - resolution[0] = stackbuf->x; - resolution[1] = stackbuf->y; + BLI_rcti_init(&r_area, 0, stackbuf->x, 0, stackbuf->y); } BKE_image_release_ibuf(this->m_image, stackbuf, nullptr); @@ -222,7 +219,7 @@ void ImageDepthOperation::executePixelSampled(float output[4], output[0] = 0.0f; } else { - int offset = y * this->m_width + x; + int offset = y * getWidth() + x; output[0] = this->m_depthBuffer[offset]; } } diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h index f8b4239c9f8..e2fdfbf6f81 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.h +++ b/source/blender/compositor/operations/COM_ImageOperation.h @@ -54,8 +54,7 @@ class BaseImageOperation : public MultiThreadedOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; virtual ImBuf *getImBuf(); diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cc b/source/blender/compositor/operations/COM_InpaintOperation.cc index 5e76c41752c..5d440dd7d76 100644 --- a/source/blender/compositor/operations/COM_InpaintOperation.cc +++ b/source/blender/compositor/operations/COM_InpaintOperation.cc @@ -293,10 +293,7 @@ void InpaintSimpleOperation::get_area_of_interest(const int input_idx, { BLI_assert(input_idx == 0); UNUSED_VARS_NDEBUG(input_idx); - r_input_area.xmin = 0; - r_input_area.xmax = this->getWidth(); - r_input_area.ymin = 0; - r_input_area.ymax = this->getHeight(); + r_input_area = this->get_canvas(); } void InpaintSimpleOperation::update_memory_buffer(MemoryBuffer *output, diff --git a/source/blender/compositor/operations/COM_InvertOperation.cc b/source/blender/compositor/operations/COM_InvertOperation.cc index 4f71a1d0d1d..d406b809c7a 100644 --- a/source/blender/compositor/operations/COM_InvertOperation.cc +++ b/source/blender/compositor/operations/COM_InvertOperation.cc @@ -29,7 +29,7 @@ InvertOperation::InvertOperation() this->m_inputColorProgram = nullptr; this->m_color = true; this->m_alpha = false; - setResolutionInputSocketIndex(1); + set_canvas_input_index(1); this->flags.can_be_constant = true; } void InvertOperation::initExecution() diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc index c00aafc19a2..b4840926d55 100644 --- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc @@ -303,11 +303,9 @@ void KeyingScreenOperation::deinitializeTileData(rcti * /*rect*/, void *data) MEM_freeN(tile_data); } -void KeyingScreenOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) +void KeyingScreenOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - resolution[0] = 0; - resolution[1] = 0; + r_area = COM_AREA_NONE; if (this->m_movieClip) { MovieClipUser user = {0}; @@ -317,9 +315,9 @@ void KeyingScreenOperation::determineResolution(unsigned int resolution[2], BKE_movieclip_user_set_frame(&user, clip_frame); BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height); - - resolution[0] = width; - resolution[1] = height; + r_area = preferred_area; + r_area.xmax = r_area.xmin + width; + r_area.ymax = r_area.ymin + height; } } diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.h b/source/blender/compositor/operations/COM_KeyingScreenOperation.h index 0bc47dbea30..7a7dda27710 100644 --- a/source/blender/compositor/operations/COM_KeyingScreenOperation.h +++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.h @@ -57,8 +57,7 @@ class KeyingScreenOperation : public MultiThreadedOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; TriangulationData *buildVoronoiTriangulation(); diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cc b/source/blender/compositor/operations/COM_MapUVOperation.cc index ad047c619f8..ba38e583b30 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.cc +++ b/source/blender/compositor/operations/COM_MapUVOperation.cc @@ -23,12 +23,12 @@ namespace blender::compositor { MapUVOperation::MapUVOperation() { - this->addInputSocket(DataType::Color, ResizeMode::None); + this->addInputSocket(DataType::Color, ResizeMode::Align); this->addInputSocket(DataType::Vector); this->addOutputSocket(DataType::Color); this->m_alpha = 0.0f; this->flags.complex = true; - setResolutionInputSocketIndex(1); + set_canvas_input_index(UV_INPUT_INDEX); this->m_inputUVProgram = nullptr; this->m_inputColorProgram = nullptr; @@ -36,11 +36,11 @@ MapUVOperation::MapUVOperation() void MapUVOperation::init_data() { - NodeOperation *image_input = get_input_operation(0); + NodeOperation *image_input = get_input_operation(IMAGE_INPUT_INDEX); image_width_ = image_input->getWidth(); image_height_ = image_input->getHeight(); - NodeOperation *uv_input = get_input_operation(1); + NodeOperation *uv_input = get_input_operation(UV_INPUT_INDEX); uv_width_ = uv_input->getWidth(); uv_height_ = uv_input->getHeight(); } @@ -205,14 +205,11 @@ void MapUVOperation::get_area_of_interest(const int input_idx, rcti &r_input_area) { switch (input_idx) { - case 0: { - r_input_area.xmin = 0; - r_input_area.xmax = image_width_; - r_input_area.ymin = 0; - r_input_area.ymax = image_height_; + case IMAGE_INPUT_INDEX: { + r_input_area = get_input_operation(IMAGE_INPUT_INDEX)->get_canvas(); break; } - case 1: { + case UV_INPUT_INDEX: { r_input_area = output_area; expand_area_for_sampler(r_input_area, PixelSampler::Bilinear); break; @@ -224,7 +221,7 @@ void MapUVOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output), const rcti &UNUSED(area), Span<MemoryBuffer *> inputs) { - const MemoryBuffer *uv_input = inputs[1]; + const MemoryBuffer *uv_input = inputs[UV_INPUT_INDEX]; uv_input_read_fn_ = [=](float x, float y, float *out) { uv_input->read_elem_bilinear(x, y, out); }; @@ -234,7 +231,7 @@ void MapUVOperation::update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> inputs) { - const MemoryBuffer *input_image = inputs[0]; + const MemoryBuffer *input_image = inputs[IMAGE_INPUT_INDEX]; for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { float xy[2] = {(float)it.x, (float)it.y}; float uv[2]; diff --git a/source/blender/compositor/operations/COM_MapUVOperation.h b/source/blender/compositor/operations/COM_MapUVOperation.h index 65fbcb461c9..49c6689f700 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.h +++ b/source/blender/compositor/operations/COM_MapUVOperation.h @@ -24,6 +24,8 @@ namespace blender::compositor { class MapUVOperation : public MultiThreadedOperation { private: + static constexpr int IMAGE_INPUT_INDEX = 0; + static constexpr int UV_INPUT_INDEX = 1; /** * Cached reference to the inputProgram */ diff --git a/source/blender/compositor/operations/COM_MaskOperation.cc b/source/blender/compositor/operations/COM_MaskOperation.cc index 84992f23924..65b89a8c79a 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.cc +++ b/source/blender/compositor/operations/COM_MaskOperation.cc @@ -109,22 +109,15 @@ void MaskOperation::deinitExecution() } } -void MaskOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void MaskOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { if (this->m_maskWidth == 0 || this->m_maskHeight == 0) { - NodeOperation::determineResolution(resolution, preferredResolution); + r_area = COM_AREA_NONE; } else { - unsigned int nr[2]; - - nr[0] = this->m_maskWidth; - nr[1] = this->m_maskHeight; - - NodeOperation::determineResolution(resolution, nr); - - resolution[0] = this->m_maskWidth; - resolution[1] = this->m_maskHeight; + r_area = preferred_area; + r_area.xmax = r_area.xmin + m_maskWidth; + r_area.ymax = r_area.ymin + m_maskHeight; } } diff --git a/source/blender/compositor/operations/COM_MaskOperation.h b/source/blender/compositor/operations/COM_MaskOperation.h index 81e344c0451..cc7eb0c022c 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.h +++ b/source/blender/compositor/operations/COM_MaskOperation.h @@ -54,8 +54,7 @@ class MaskOperation : public MultiThreadedOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; public: MaskOperation(); diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cc b/source/blender/compositor/operations/COM_MathBaseOperation.cc index 2256dce011b..d3fb83caf7c 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cc +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cc @@ -51,22 +51,19 @@ void MathBaseOperation::deinitExecution() this->m_inputValue3Operation = nullptr; } -void MathBaseOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void MathBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { NodeOperationInput *socket; - unsigned int tempPreferredResolution[2] = {0, 0}; - unsigned int tempResolution[2]; - + rcti temp_area; socket = this->getInputSocket(0); - socket->determineResolution(tempResolution, tempPreferredResolution); - if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { - this->setResolutionInputSocketIndex(0); + const bool determined = socket->determine_canvas(COM_AREA_NONE, temp_area); + if (determined) { + this->set_canvas_input_index(0); } else { - this->setResolutionInputSocketIndex(1); + this->set_canvas_input_index(1); } - NodeOperation::determineResolution(resolution, preferredResolution); + NodeOperation::determine_canvas(preferred_area, r_area); } void MathBaseOperation::clampIfNeeded(float *color) diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h index d2da05db68e..0188eb50fa8 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.h +++ b/source/blender/compositor/operations/COM_MathBaseOperation.h @@ -75,8 +75,7 @@ class MathBaseOperation : public MultiThreadedOperation { /** * Determine resolution */ - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void setUseClamp(bool value) { diff --git a/source/blender/compositor/operations/COM_MixOperation.cc b/source/blender/compositor/operations/COM_MixOperation.cc index 77ecbf60356..895d32e6fee 100644 --- a/source/blender/compositor/operations/COM_MixOperation.cc +++ b/source/blender/compositor/operations/COM_MixOperation.cc @@ -66,29 +66,27 @@ void MixBaseOperation::executePixelSampled(float output[4], float x, float y, Pi output[3] = inputColor1[3]; } -void MixBaseOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void MixBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { NodeOperationInput *socket; - unsigned int tempPreferredResolution[2] = {0, 0}; - unsigned int tempResolution[2]; + rcti temp_area; socket = this->getInputSocket(1); - socket->determineResolution(tempResolution, tempPreferredResolution); - if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { - this->setResolutionInputSocketIndex(1); + bool determined = socket->determine_canvas(COM_AREA_NONE, temp_area); + if (determined) { + this->set_canvas_input_index(1); } else { socket = this->getInputSocket(2); - socket->determineResolution(tempResolution, tempPreferredResolution); - if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { - this->setResolutionInputSocketIndex(2); + determined = socket->determine_canvas(COM_AREA_NONE, temp_area); + if (determined) { + this->set_canvas_input_index(2); } else { - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); } } - NodeOperation::determineResolution(resolution, preferredResolution); + NodeOperation::determine_canvas(preferred_area, r_area); } void MixBaseOperation::deinitExecution() @@ -111,7 +109,7 @@ void MixBaseOperation::update_memory_buffer_partial(MemoryBuffer *output, p.value_stride = input_value->elem_stride; p.color1_stride = input_color1->elem_stride; p.color2_stride = input_color2->elem_stride; - for (const int y : YRange(area)) { + for (int y = area.ymin; y < area.ymax; y++) { p.out = output->get_elem(area.xmin, y); p.row_end = p.out + width * output->elem_stride; p.value = input_value->get_elem(area.xmin, y); diff --git a/source/blender/compositor/operations/COM_MixOperation.h b/source/blender/compositor/operations/COM_MixOperation.h index 7ef9d78d58f..fabbea422eb 100644 --- a/source/blender/compositor/operations/COM_MixOperation.h +++ b/source/blender/compositor/operations/COM_MixOperation.h @@ -87,8 +87,7 @@ class MixBaseOperation : public MultiThreadedOperation { */ void deinitExecution() override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void setUseValueAlphaMultiply(const bool value) { diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc index e36e93984fb..aed91d4d46e 100644 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc @@ -29,8 +29,9 @@ MovieClipAttributeOperation::MovieClipAttributeOperation() this->m_framenumber = 0; this->m_attribute = MCA_X; this->m_invert = false; - needs_resolution_to_get_constant_ = true; + needs_canvas_to_get_constant_ = true; is_value_calculated_ = false; + stabilization_resolution_socket_ = nullptr; } void MovieClipAttributeOperation::initExecution() @@ -42,7 +43,7 @@ void MovieClipAttributeOperation::initExecution() void MovieClipAttributeOperation::calc_value() { - BLI_assert(this->get_flags().is_resolution_set); + BLI_assert(this->get_flags().is_canvas_set); is_value_calculated_ = true; if (this->m_clip == nullptr) { return; @@ -53,8 +54,17 @@ void MovieClipAttributeOperation::calc_value() scale = 1.0f; angle = 0.0f; int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber); - BKE_tracking_stabilization_data_get( - this->m_clip, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle); + NodeOperation &stabilization_operation = + stabilization_resolution_socket_ ? + stabilization_resolution_socket_->getLink()->getOperation() : + *this; + BKE_tracking_stabilization_data_get(this->m_clip, + clip_framenr, + stabilization_operation.getWidth(), + stabilization_operation.getHeight(), + loc, + &scale, + &angle); switch (this->m_attribute) { case MCA_SCALE: this->m_value = scale; @@ -87,11 +97,9 @@ void MovieClipAttributeOperation::executePixelSampled(float output[4], output[0] = this->m_value; } -void MovieClipAttributeOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void MovieClipAttributeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; + r_area = preferred_area; } const float *MovieClipAttributeOperation::get_constant_elem() diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h index 28c39d4dad3..50680653aea 100644 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h @@ -42,6 +42,7 @@ class MovieClipAttributeOperation : public ConstantOperation { bool m_invert; MovieClipAttribute m_attribute; bool is_value_calculated_; + NodeOperationInput *stabilization_resolution_socket_; public: /** @@ -55,8 +56,7 @@ class MovieClipAttributeOperation : public ConstantOperation { * The inner loop of this operation. */ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; const float *get_constant_elem() override; @@ -77,6 +77,14 @@ class MovieClipAttributeOperation : public ConstantOperation { this->m_invert = invert; } + /** + * Set an operation socket which input will be used to get the resolution for stabilization. + */ + void set_socket_input_resolution_for_stabilization(NodeOperationInput *input_socket) + { + stabilization_resolution_socket_ = input_socket; + } + private: void calc_value(); }; diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cc b/source/blender/compositor/operations/COM_MovieClipOperation.cc index e520b928edf..1ca33b12432 100644 --- a/source/blender/compositor/operations/COM_MovieClipOperation.cc +++ b/source/blender/compositor/operations/COM_MovieClipOperation.cc @@ -71,19 +71,13 @@ void MovieClipBaseOperation::deinitExecution() } } -void MovieClipBaseOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) +void MovieClipBaseOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area) { - resolution[0] = 0; - resolution[1] = 0; - + r_area = COM_AREA_NONE; if (this->m_movieClip) { int width, height; - BKE_movieclip_get_size(this->m_movieClip, this->m_movieClipUser, &width, &height); - - resolution[0] = width; - resolution[1] = height; + BLI_rcti_init(&r_area, 0, width, 0, height); } } diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.h b/source/blender/compositor/operations/COM_MovieClipOperation.h index 0a0c4c00f81..465ccd4fc00 100644 --- a/source/blender/compositor/operations/COM_MovieClipOperation.h +++ b/source/blender/compositor/operations/COM_MovieClipOperation.h @@ -41,8 +41,7 @@ class MovieClipBaseOperation : public MultiThreadedOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; public: MovieClipBaseOperation(); diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc index d3424959061..49f43d2c1a7 100644 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc @@ -29,15 +29,14 @@ MovieDistortionOperation::MovieDistortionOperation(bool distortion) { this->addInputSocket(DataType::Color); this->addOutputSocket(DataType::Color); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->m_inputOperation = nullptr; this->m_movieClip = nullptr; this->m_apply = distortion; } -void MovieDistortionOperation::initExecution() +void MovieDistortionOperation::init_data() { - this->m_inputOperation = this->getInputSocketReader(0); if (this->m_movieClip) { MovieTracking *tracking = &this->m_movieClip->tracking; MovieClipUser clipUser = {0}; @@ -49,10 +48,10 @@ void MovieDistortionOperation::initExecution() float delta[2]; rcti full_frame; full_frame.xmin = full_frame.ymin = 0; - full_frame.xmax = this->m_width; - full_frame.ymax = this->m_height; + full_frame.xmax = this->getWidth(); + full_frame.ymax = this->getHeight(); BKE_tracking_max_distortion_delta_across_bound( - tracking, this->m_width, this->m_height, &full_frame, !this->m_apply, delta); + tracking, this->getWidth(), this->getHeight(), &full_frame, !this->m_apply, delta); /* 5 is just in case we didn't hit real max of distortion in * BKE_tracking_max_undistortion_delta_across_bound @@ -60,15 +59,25 @@ void MovieDistortionOperation::initExecution() m_margin[0] = delta[0] + 5; m_margin[1] = delta[1] + 5; - this->m_distortion = BKE_tracking_distortion_new( - tracking, calibration_width, calibration_height); this->m_calibration_width = calibration_width; this->m_calibration_height = calibration_height; this->m_pixel_aspect = tracking->camera.pixel_aspect; } else { m_margin[0] = m_margin[1] = 0; - this->m_distortion = nullptr; + } +} + +void MovieDistortionOperation::initExecution() +{ + m_inputOperation = this->getInputSocketReader(0); + if (m_movieClip) { + MovieTracking *tracking = &m_movieClip->tracking; + m_distortion = BKE_tracking_distortion_new( + tracking, m_calibration_width, m_calibration_height); + } + else { + m_distortion = nullptr; } } @@ -89,8 +98,8 @@ void MovieDistortionOperation::executePixelSampled(float output[4], if (this->m_distortion != nullptr) { /* float overscan = 0.0f; */ const float pixel_aspect = this->m_pixel_aspect; - const float w = (float)this->m_width /* / (1 + overscan) */; - const float h = (float)this->m_height /* / (1 + overscan) */; + const float w = (float)this->getWidth() /* / (1 + overscan) */; + const float h = (float)this->getHeight() /* / (1 + overscan) */; const float aspx = w / (float)this->m_calibration_width; const float aspy = h / (float)this->m_calibration_height; float in[2]; @@ -152,8 +161,8 @@ void MovieDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output /* `float overscan = 0.0f;` */ const float pixel_aspect = this->m_pixel_aspect; - const float w = (float)this->m_width /* `/ (1 + overscan)` */; - const float h = (float)this->m_height /* `/ (1 + overscan)` */; + const float w = (float)this->getWidth() /* `/ (1 + overscan)` */; + const float h = (float)this->getHeight() /* `/ (1 + overscan)` */; const float aspx = w / (float)this->m_calibration_width; const float aspy = h / (float)this->m_calibration_height; float xy[2]; diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.h b/source/blender/compositor/operations/COM_MovieDistortionOperation.h index 69c2f9c269c..abf0553b75b 100644 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.h +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.h @@ -44,6 +44,7 @@ class MovieDistortionOperation : public MultiThreadedOperation { MovieDistortionOperation(bool distortion); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + void init_data() override; void initExecution() override; void deinitExecution() override; diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cc b/source/blender/compositor/operations/COM_NormalizeOperation.cc index c3e72d2575f..7d79b375b45 100644 --- a/source/blender/compositor/operations/COM_NormalizeOperation.cc +++ b/source/blender/compositor/operations/COM_NormalizeOperation.cc @@ -133,11 +133,7 @@ void NormalizeOperation::get_area_of_interest(const int UNUSED(input_idx), const rcti &UNUSED(output_area), rcti &r_input_area) { - NodeOperation *input = get_input_operation(0); - r_input_area.xmin = 0; - r_input_area.xmax = input->getWidth(); - r_input_area.ymin = 0; - r_input_area.ymax = input->getHeight(); + r_input_area = get_input_operation(0)->get_canvas(); } void NormalizeOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output), diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc index 5b6f650d40e..d436b00a6e3 100644 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc @@ -86,8 +86,8 @@ void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filenam /* prepare the file with all the channels */ - if (IMB_exr_begin_write( - exrhandle, filename, width, height, this->m_format->exr_codec, nullptr) == 0) { + if (!IMB_exr_begin_write( + exrhandle, filename, width, height, this->m_format->exr_codec, nullptr)) { printf("Error Writing Singlelayer Multiview Openexr\n"); IMB_exr_close(exrhandle); } @@ -200,8 +200,7 @@ void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename /* prepare the file with all the channels for the header */ StampData *stamp_data = createStampData(); - if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, stamp_data) == - 0) { + if (!IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, stamp_data)) { printf("Error Writing Multilayer Multiview Openexr\n"); IMB_exr_close(exrhandle); BKE_stamp_data_free(stamp_data); diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc index 402d29893a4..79be95bb686 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cc +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc @@ -339,7 +339,7 @@ OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(const Scene * this->m_exr_codec = exr_codec; this->m_exr_half_float = exr_half_float; this->m_viewName = viewName; - this->setResolutionInputSocketIndex(RESOLUTION_INPUT_ANY); + this->set_canvas_input_index(RESOLUTION_INPUT_ANY); } void OutputOpenExrMultiLayerOperation::add_layer(const char *name, diff --git a/source/blender/compositor/operations/COM_PixelateOperation.cc b/source/blender/compositor/operations/COM_PixelateOperation.cc index 94827cd1b02..4fc238bc094 100644 --- a/source/blender/compositor/operations/COM_PixelateOperation.cc +++ b/source/blender/compositor/operations/COM_PixelateOperation.cc @@ -24,7 +24,7 @@ PixelateOperation::PixelateOperation(DataType datatype) { this->addInputSocket(datatype); this->addOutputSocket(datatype); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->m_inputOperation = nullptr; } diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc index d2a06ddd7c4..65cd08456ef 100644 --- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc +++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc @@ -209,15 +209,13 @@ void *PlaneCornerPinMaskOperation::initializeTileData(rcti *rect) return data; } -void PlaneCornerPinMaskOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void PlaneCornerPinMaskOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { if (execution_model_ == eExecutionModel::FullFrame) { - /* Determine inputs resolution. */ - PlaneDistortMaskOperation::determineResolution(resolution, preferredResolution); + /* Determine input canvases. */ + PlaneDistortMaskOperation::determine_canvas(preferred_area, r_area); } - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; + r_area = preferred_area; } void PlaneCornerPinMaskOperation::get_area_of_interest(const int UNUSED(input_idx), @@ -225,7 +223,7 @@ void PlaneCornerPinMaskOperation::get_area_of_interest(const int UNUSED(input_id rcti &r_input_area) { /* All corner inputs are used as constants. */ - r_input_area = COM_SINGLE_ELEM_AREA; + r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST; } /* ******** PlaneCornerPinWarpImageOperation ******** */ @@ -322,7 +320,7 @@ void PlaneCornerPinWarpImageOperation::get_area_of_interest(const int input_idx, } else { /* Corner inputs are used as constants. */ - r_input_area = COM_SINGLE_ELEM_AREA; + r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST; } } diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h index 2831e937147..7b3917923d2 100644 --- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h +++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h @@ -43,8 +43,7 @@ class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation { void *initializeTileData(rcti *rect) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; }; diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc index ccabb3cf11c..31ef41789fd 100644 --- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc +++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc @@ -73,7 +73,7 @@ BLI_INLINE void warpCoord(float x, float y, float matrix[3][3], float uv[2], flo PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation() : PlaneDistortBaseOperation() { - this->addInputSocket(DataType::Color, ResizeMode::None); + this->addInputSocket(DataType::Color, ResizeMode::Align); this->addOutputSocket(DataType::Color); this->m_pixelReader = nullptr; this->flags.complex = true; @@ -196,10 +196,7 @@ void PlaneDistortWarpImageOperation::get_area_of_interest(const int input_idx, } /* TODO: figure out the area needed for warping and EWA filtering. */ - r_input_area.xmin = 0; - r_input_area.ymin = 0; - r_input_area.xmax = get_input_operation(0)->getWidth(); - r_input_area.ymax = get_input_operation(0)->getHeight(); + r_input_area = get_input_operation(0)->get_canvas(); /* Old implementation but resulting coordinates are way out of input operation bounds and in some * cases the area result may incorrectly cause cropping. */ diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc index bf24f843ca2..7226a133a52 100644 --- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc +++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc @@ -83,19 +83,17 @@ void PlaneTrackCommon::readCornersFromTrack(float corners[4][2], float frame) } } -void PlaneTrackCommon::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) +void PlaneTrackCommon::determine_canvas(const rcti &preferred_area, rcti &r_area) { - resolution[0] = 0; - resolution[1] = 0; - + r_area = COM_AREA_NONE; if (this->m_movieClip) { int width, height; MovieClipUser user = {0}; BKE_movieclip_user_set_frame(&user, this->m_framenumber); BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height); - resolution[0] = width; - resolution[1] = height; + r_area = preferred_area; + r_area.xmax = r_area.xmin + width; + r_area.ymax = r_area.ymin + height; } } diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.h b/source/blender/compositor/operations/COM_PlaneTrackOperation.h index d2027755162..60845aac514 100644 --- a/source/blender/compositor/operations/COM_PlaneTrackOperation.h +++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.h @@ -41,7 +41,7 @@ class PlaneTrackCommon { * implementation classes must make wrappers to use these methods, see below. */ void read_and_calculate_corners(PlaneDistortBaseOperation *distort_op); - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determine_canvas(const rcti &preferred_area, rcti &r_area); public: PlaneTrackCommon(); @@ -77,13 +77,13 @@ class PlaneTrackMaskOperation : public PlaneDistortMaskOperation, public PlaneTr void initExecution() override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override + void determine_canvas(const rcti &preferred_area, rcti &r_area) override { - PlaneTrackCommon::determineResolution(resolution, preferredResolution); + PlaneTrackCommon::determine_canvas(preferred_area, r_area); - unsigned int temp[2]; - NodeOperation::determineResolution(temp, resolution); + rcti unused; + rcti &preferred = r_area; + NodeOperation::determine_canvas(preferred, unused); } }; @@ -98,12 +98,13 @@ class PlaneTrackWarpImageOperation : public PlaneDistortWarpImageOperation, void initExecution() override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override + void determine_canvas(const rcti &preferred_area, rcti &r_area) override { - PlaneTrackCommon::determineResolution(resolution, preferredResolution); - unsigned int temp[2]; - NodeOperation::determineResolution(temp, resolution); + PlaneTrackCommon::determine_canvas(preferred_area, r_area); + + rcti unused; + rcti &preferred = r_area; + NodeOperation::determine_canvas(preferred, unused); } }; diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cc b/source/blender/compositor/operations/COM_PreviewOperation.cc index fa8b5ffcabf..34520264d54 100644 --- a/source/blender/compositor/operations/COM_PreviewOperation.cc +++ b/source/blender/compositor/operations/COM_PreviewOperation.cc @@ -41,7 +41,7 @@ PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings, const unsigned int defaultHeight) { - this->addInputSocket(DataType::Color, ResizeMode::None); + this->addInputSocket(DataType::Color, ResizeMode::Align); this->m_preview = nullptr; this->m_outputBuffer = nullptr; this->m_input = nullptr; @@ -130,14 +130,14 @@ bool PreviewOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } -void PreviewOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) +void PreviewOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area) { /* Use default preview resolution as preferred ensuring it has size so that * generated inputs (which don't have resolution on their own) are displayed */ BLI_assert(this->m_defaultWidth > 0 && this->m_defaultHeight > 0); - unsigned int previewPreferredRes[2] = {this->m_defaultWidth, this->m_defaultHeight}; - NodeOperation::determineResolution(resolution, previewPreferredRes); + rcti local_preferred; + BLI_rcti_init(&local_preferred, 0, m_defaultWidth, 0, m_defaultHeight); + NodeOperation::determine_canvas(local_preferred, r_area); /* If resolution is 0 there are two possible scenarios: * - Either node is not connected at all @@ -148,8 +148,8 @@ void PreviewOperation::determineResolution(unsigned int resolution[2], * The latter case would only happen if an input doesn't set any resolution ignoring output * preferred resolution. In such case preview size will be 0 too. */ - int width = resolution[0]; - int height = resolution[1]; + int width = BLI_rcti_size_x(&r_area); + int height = BLI_rcti_size_y(&r_area); this->m_divider = 0.0f; if (width > 0 && height > 0) { if (width > height) { @@ -162,8 +162,7 @@ void PreviewOperation::determineResolution(unsigned int resolution[2], width = width * this->m_divider; height = height * this->m_divider; - resolution[0] = width; - resolution[1] = height; + BLI_rcti_init(&r_area, r_area.xmin, r_area.xmin + width, r_area.ymin, r_area.ymin + height); } eCompositorPriority PreviewOperation::getRenderPriority() const diff --git a/source/blender/compositor/operations/COM_PreviewOperation.h b/source/blender/compositor/operations/COM_PreviewOperation.h index 05dae9c4dd8..4bd0f07d882 100644 --- a/source/blender/compositor/operations/COM_PreviewOperation.h +++ b/source/blender/compositor/operations/COM_PreviewOperation.h @@ -58,8 +58,7 @@ class PreviewOperation : public MultiThreadedOperation { eCompositorPriority getRenderPriority() const override; void executeRegion(rcti *rect, unsigned int tileNumber) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc index fcab5dd5751..2982f59a019 100644 --- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc +++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc @@ -131,13 +131,30 @@ void ProjectorLensDistortionOperation::updateDispersion() this->unlockMutex(); } +void ProjectorLensDistortionOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) +{ + switch (execution_model_) { + case eExecutionModel::FullFrame: { + set_determined_canvas_modifier([=](rcti &canvas) { + /* Ensure screen space. */ + BLI_rcti_translate(&canvas, -canvas.xmin, -canvas.ymin); + }); + break; + } + default: + break; + } + + NodeOperation::determine_canvas(preferred_area, r_area); +} + void ProjectorLensDistortionOperation::get_area_of_interest(const int input_idx, const rcti &output_area, rcti &r_input_area) { if (input_idx == 1) { /* Dispersion input is used as constant only. */ - r_input_area = COM_SINGLE_ELEM_AREA; + r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST; return; } diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h index 7c7626bf271..b42fa3a361c 100644 --- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h +++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h @@ -62,6 +62,7 @@ class ProjectorLensDistortionOperation : public MultiThreadedOperation { void updateDispersion(); + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cc b/source/blender/compositor/operations/COM_ReadBufferOperation.cc index d35d2516f16..599370751bb 100644 --- a/source/blender/compositor/operations/COM_ReadBufferOperation.cc +++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cc @@ -36,16 +36,17 @@ void *ReadBufferOperation::initializeTileData(rcti * /*rect*/) return m_buffer; } -void ReadBufferOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void ReadBufferOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { if (this->m_memoryProxy != nullptr) { WriteBufferOperation *operation = this->m_memoryProxy->getWriteBufferOperation(); - operation->determineResolution(resolution, preferredResolution); - operation->setResolution(resolution); + operation->determine_canvas(preferred_area, r_area); + operation->set_canvas(r_area); /** \todo may not occur! But does with blur node. */ if (this->m_memoryProxy->getExecutor()) { + uint resolution[2] = {static_cast<uint>(BLI_rcti_size_x(&r_area)), + static_cast<uint>(BLI_rcti_size_y(&r_area))}; this->m_memoryProxy->getExecutor()->setResolution(resolution); } diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.h b/source/blender/compositor/operations/COM_ReadBufferOperation.h index 8b96b961a43..02f6eccd246 100644 --- a/source/blender/compositor/operations/COM_ReadBufferOperation.h +++ b/source/blender/compositor/operations/COM_ReadBufferOperation.h @@ -43,8 +43,7 @@ class ReadBufferOperation : public NodeOperation { return this->m_memoryProxy; } - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void *initializeTileData(rcti *rect) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cc b/source/blender/compositor/operations/COM_RenderLayersProg.cc index 72e2c92c9cf..2ac551ffe6f 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cc +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc @@ -196,15 +196,13 @@ void RenderLayersProg::deinitExecution() } } -void RenderLayersProg::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) +void RenderLayersProg::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area) { Scene *sce = this->getScene(); Render *re = (sce) ? RE_GetSceneRender(sce) : nullptr; RenderResult *rr = nullptr; - resolution[0] = 0; - resolution[1] = 0; + r_area = COM_AREA_NONE; if (re) { rr = RE_AcquireResultRead(re); @@ -215,8 +213,7 @@ void RenderLayersProg::determineResolution(unsigned int resolution[2], if (view_layer) { RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name); if (rl) { - resolution[0] = rl->rectx; - resolution[1] = rl->recty; + BLI_rcti_init(&r_area, 0, rl->rectx, 0, rl->recty); } } } diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h index dd76a56d645..b499afd45df 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.h +++ b/source/blender/compositor/operations/COM_RenderLayersProg.h @@ -73,8 +73,7 @@ class RenderLayersProg : public MultiThreadedOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; /** * retrieve the reference to the float buffer of the renderer. diff --git a/source/blender/compositor/operations/COM_RotateOperation.cc b/source/blender/compositor/operations/COM_RotateOperation.cc index e3c482c15cb..9e26c93feac 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.cc +++ b/source/blender/compositor/operations/COM_RotateOperation.cc @@ -25,10 +25,10 @@ namespace blender::compositor { RotateOperation::RotateOperation() { - this->addInputSocket(DataType::Color); - this->addInputSocket(DataType::Value); + this->addInputSocket(DataType::Color, ResizeMode::None); + this->addInputSocket(DataType::Value, ResizeMode::None); this->addOutputSocket(DataType::Color); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->m_imageSocket = nullptr; this->m_degreeSocket = nullptr; this->m_doDegree2RadConversion = false; @@ -36,6 +36,21 @@ RotateOperation::RotateOperation() sampler_ = PixelSampler::Bilinear; } +void RotateOperation::get_rotation_center(const rcti &area, float &r_x, float &r_y) +{ + r_x = (BLI_rcti_size_x(&area) - 1) / 2.0; + r_y = (BLI_rcti_size_y(&area) - 1) / 2.0; +} + +void RotateOperation::get_rotation_offset(const rcti &input_canvas, + const rcti &rotate_canvas, + float &r_offset_x, + float &r_offset_y) +{ + r_offset_x = (BLI_rcti_size_x(&input_canvas) - BLI_rcti_size_x(&rotate_canvas)) / 2.0f; + r_offset_y = (BLI_rcti_size_y(&input_canvas) - BLI_rcti_size_y(&rotate_canvas)) / 2.0f; +} + void RotateOperation::get_area_rotation_bounds(const rcti &area, const float center_x, const float center_y, @@ -48,14 +63,14 @@ void RotateOperation::get_area_rotation_bounds(const rcti &area, const float dxmax = area.xmax - center_x; const float dymax = area.ymax - center_y; - const float x1 = center_x + (cosine * dxmin + sine * dymin); - const float x2 = center_x + (cosine * dxmax + sine * dymin); - const float x3 = center_x + (cosine * dxmin + sine * dymax); - const float x4 = center_x + (cosine * dxmax + sine * dymax); - const float y1 = center_y + (-sine * dxmin + cosine * dymin); - const float y2 = center_y + (-sine * dxmax + cosine * dymin); - const float y3 = center_y + (-sine * dxmin + cosine * dymax); - const float y4 = center_y + (-sine * dxmax + cosine * dymax); + const float x1 = center_x + (cosine * dxmin + (-sine) * dymin); + const float x2 = center_x + (cosine * dxmax + (-sine) * dymin); + const float x3 = center_x + (cosine * dxmin + (-sine) * dymax); + const float x4 = center_x + (cosine * dxmax + (-sine) * dymax); + const float y1 = center_y + (sine * dxmin + cosine * dymin); + const float y2 = center_y + (sine * dxmax + cosine * dymin); + const float y3 = center_y + (sine * dxmin + cosine * dymax); + const float y4 = center_y + (sine * dxmax + cosine * dymax); const float minx = MIN2(x1, MIN2(x2, MIN2(x3, x4))); const float maxx = MAX2(x1, MAX2(x2, MAX2(x3, x4))); const float miny = MIN2(y1, MIN2(y2, MIN2(y3, y4))); @@ -67,10 +82,56 @@ void RotateOperation::get_area_rotation_bounds(const rcti &area, r_bounds.ymax = ceil(maxy); } +void RotateOperation::get_area_rotation_bounds_inverted(const rcti &area, + const float center_x, + const float center_y, + const float sine, + const float cosine, + rcti &r_bounds) +{ + get_area_rotation_bounds(area, center_x, center_y, -sine, cosine, r_bounds); +} + +void RotateOperation::get_rotation_area_of_interest(const rcti &input_canvas, + const rcti &rotate_canvas, + const float sine, + const float cosine, + const rcti &output_area, + rcti &r_input_area) +{ + float center_x, center_y; + get_rotation_center(input_canvas, center_x, center_y); + + float rotate_offset_x, rotate_offset_y; + get_rotation_offset(input_canvas, rotate_canvas, rotate_offset_x, rotate_offset_y); + + r_input_area = output_area; + BLI_rcti_translate(&r_input_area, rotate_offset_x, rotate_offset_y); + get_area_rotation_bounds_inverted(r_input_area, center_x, center_y, sine, cosine, r_input_area); +} + +void RotateOperation::get_rotation_canvas(const rcti &input_canvas, + const float sine, + const float cosine, + rcti &r_canvas) +{ + float center_x, center_y; + get_rotation_center(input_canvas, center_x, center_y); + + rcti rot_bounds; + get_area_rotation_bounds(input_canvas, center_x, center_y, sine, cosine, rot_bounds); + + float offset_x, offset_y; + get_rotation_offset(input_canvas, rot_bounds, offset_x, offset_y); + r_canvas = rot_bounds; + BLI_rcti_translate(&r_canvas, -offset_x, -offset_y); +} + void RotateOperation::init_data() { - this->m_centerX = (getWidth() - 1) / 2.0; - this->m_centerY = (getHeight() - 1) / 2.0; + if (execution_model_ == eExecutionModel::Tiled) { + get_rotation_center(get_canvas(), m_centerX, m_centerY); + } } void RotateOperation::initExecution() @@ -94,11 +155,7 @@ inline void RotateOperation::ensureDegree() this->m_degreeSocket->readSampled(degree, 0, 0, PixelSampler::Nearest); break; case eExecutionModel::FullFrame: - NodeOperation *degree_op = getInputOperation(DEGREE_INPUT_INDEX); - const bool is_constant_degree = degree_op->get_flags().is_constant_operation; - degree[0] = is_constant_degree ? - static_cast<ConstantOperation *>(degree_op)->get_constant_elem()[0] : - 0.0f; + degree[0] = get_input_operation(DEGREE_INPUT_INDEX)->get_constant_value_default(0.0f); break; } @@ -159,18 +216,40 @@ bool RotateOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void RotateOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) +{ + if (execution_model_ == eExecutionModel::Tiled) { + NodeOperation::determine_canvas(preferred_area, r_area); + return; + } + + const bool image_determined = + getInputSocket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area); + if (image_determined) { + rcti input_canvas = r_area; + rcti unused; + getInputSocket(DEGREE_INPUT_INDEX)->determine_canvas(input_canvas, unused); + + ensureDegree(); + + get_rotation_canvas(input_canvas, m_sine, m_cosine, r_area); + } +} + void RotateOperation::get_area_of_interest(const int input_idx, const rcti &output_area, rcti &r_input_area) { if (input_idx == DEGREE_INPUT_INDEX) { - /* Degrees input is always used as constant. */ - r_input_area = COM_SINGLE_ELEM_AREA; + r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST; return; } ensureDegree(); - get_area_rotation_bounds(output_area, m_centerX, m_centerY, m_sine, m_cosine, r_input_area); + + const rcti &input_image_canvas = get_input_operation(IMAGE_INPUT_INDEX)->get_canvas(); + get_rotation_area_of_interest( + input_image_canvas, this->get_canvas(), m_sine, m_cosine, output_area, r_input_area); expand_area_for_sampler(r_input_area, sampler_); } @@ -178,13 +257,20 @@ void RotateOperation::update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> inputs) { - ensureDegree(); const MemoryBuffer *input_img = inputs[IMAGE_INPUT_INDEX]; + + NodeOperation *image_op = get_input_operation(IMAGE_INPUT_INDEX); + float center_x, center_y; + get_rotation_center(image_op->get_canvas(), center_x, center_y); + float rotate_offset_x, rotate_offset_y; + get_rotation_offset( + image_op->get_canvas(), this->get_canvas(), rotate_offset_x, rotate_offset_y); + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { - float x = it.x; - float y = it.y; - rotate_coords(x, y, m_centerX, m_centerY, m_sine, m_cosine); - input_img->read_elem_sampled(x, y, sampler_, it.out); + float x = rotate_offset_x + it.x + canvas_.xmin; + float y = rotate_offset_y + it.y + canvas_.ymin; + rotate_coords(x, y, center_x, center_y, m_sine, m_cosine); + input_img->read_elem_sampled(x - canvas_.xmin, y - canvas_.ymin, sampler_, it.out); } } diff --git a/source/blender/compositor/operations/COM_RotateOperation.h b/source/blender/compositor/operations/COM_RotateOperation.h index f0de699f9ce..76f203cfbc0 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.h +++ b/source/blender/compositor/operations/COM_RotateOperation.h @@ -29,8 +29,10 @@ class RotateOperation : public MultiThreadedOperation { SocketReader *m_imageSocket; SocketReader *m_degreeSocket; + /* TODO(manzanilla): to be removed with tiled implementation. */ float m_centerX; float m_centerY; + float m_cosine; float m_sine; bool m_doDegree2RadConversion; @@ -49,12 +51,33 @@ class RotateOperation : public MultiThreadedOperation { y = center_y + (-sine * dx + cosine * dy); } + static void get_rotation_center(const rcti &area, float &r_x, float &r_y); + static void get_rotation_offset(const rcti &input_canvas, + const rcti &rotate_canvas, + float &r_offset_x, + float &r_offset_y); static void get_area_rotation_bounds(const rcti &area, const float center_x, const float center_y, const float sine, const float cosine, rcti &r_bounds); + static void get_area_rotation_bounds_inverted(const rcti &area, + const float center_x, + const float center_y, + const float sine, + const float cosine, + rcti &r_bounds); + static void get_rotation_area_of_interest(const rcti &input_canvas, + const rcti &rotate_canvas, + const float sine, + const float cosine, + const rcti &output_area, + rcti &r_input_area); + static void get_rotation_canvas(const rcti &input_canvas, + const float sine, + const float cosine, + rcti &r_canvas); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, @@ -80,6 +103,8 @@ class RotateOperation : public MultiThreadedOperation { void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> inputs) override; + + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc index 0161b837915..dbd8faf0f1d 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cc +++ b/source/blender/compositor/operations/COM_ScaleOperation.cc @@ -38,17 +38,21 @@ BaseScaleOperation::BaseScaleOperation() m_variable_size = false; } +void BaseScaleOperation::set_scale_canvas_max_size(Size2f size) +{ + max_scale_canvas_size_ = size; +} + ScaleOperation::ScaleOperation() : ScaleOperation(DataType::Color) { } ScaleOperation::ScaleOperation(DataType data_type) : BaseScaleOperation() { - this->addInputSocket(data_type); + this->addInputSocket(data_type, ResizeMode::None); this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); this->addOutputSocket(data_type); - this->setResolutionInputSocketIndex(0); this->m_inputOperation = nullptr; this->m_inputXOperation = nullptr; this->m_inputYOperation = nullptr; @@ -64,34 +68,52 @@ float ScaleOperation::get_constant_scale(const int input_op_idx, const float fac return 1.0f; } -float ScaleOperation::get_constant_scale_x() +float ScaleOperation::get_constant_scale_x(const float width) +{ + return get_constant_scale(X_INPUT_INDEX, get_relative_scale_x_factor(width)); +} + +float ScaleOperation::get_constant_scale_y(const float height) { - return get_constant_scale(1, get_relative_scale_x_factor()); + return get_constant_scale(Y_INPUT_INDEX, get_relative_scale_y_factor(height)); } -float ScaleOperation::get_constant_scale_y() +bool ScaleOperation::is_scaling_variable() { - return get_constant_scale(2, get_relative_scale_y_factor()); + return !get_input_operation(X_INPUT_INDEX)->get_flags().is_constant_operation || + !get_input_operation(Y_INPUT_INDEX)->get_flags().is_constant_operation; } -void ScaleOperation::scale_area( - rcti &rect, float center_x, float center_y, float scale_x, float scale_y) +void ScaleOperation::scale_area(rcti &area, float relative_scale_x, float relative_scale_y) { - rect.xmin = scale_coord(rect.xmin, center_x, scale_x); - rect.xmax = scale_coord(rect.xmax, center_x, scale_x); - rect.ymin = scale_coord(rect.ymin, center_y, scale_y); - rect.ymax = scale_coord(rect.ymax, center_y, scale_y); + const rcti src_area = area; + const float center_x = BLI_rcti_size_x(&area) / 2.0f; + const float center_y = BLI_rcti_size_y(&area) / 2.0f; + area.xmin = floorf(scale_coord(area.xmin, center_x, relative_scale_x)); + area.xmax = ceilf(scale_coord(area.xmax, center_x, relative_scale_x)); + area.ymin = floorf(scale_coord(area.ymin, center_y, relative_scale_y)); + area.ymax = ceilf(scale_coord(area.ymax, center_y, relative_scale_y)); + + float scale_offset_x, scale_offset_y; + ScaleOperation::get_scale_offset(src_area, area, scale_offset_x, scale_offset_y); + BLI_rcti_translate(&area, -scale_offset_x, -scale_offset_y); } -void ScaleOperation::scale_area(rcti &rect, float scale_x, float scale_y) +void ScaleOperation::clamp_area_size_max(rcti &area, Size2f max_size) { - scale_area(rect, m_centerX, m_centerY, scale_x, scale_y); + + if (BLI_rcti_size_x(&area) > max_size.x) { + area.xmax = area.xmin + max_size.x; + } + if (BLI_rcti_size_y(&area) > max_size.y) { + area.ymax = area.ymin + max_size.y; + } } void ScaleOperation::init_data() { - m_centerX = getWidth() / 2.0f; - m_centerY = getHeight() / 2.0f; + canvas_center_x_ = canvas_.xmin + getWidth() / 2.0f; + canvas_center_y_ = canvas_.ymin + getHeight() / 2.0f; } void ScaleOperation::initExecution() @@ -108,18 +130,52 @@ void ScaleOperation::deinitExecution() this->m_inputYOperation = nullptr; } +void ScaleOperation::get_scale_offset(const rcti &input_canvas, + const rcti &scale_canvas, + float &r_scale_offset_x, + float &r_scale_offset_y) +{ + r_scale_offset_x = (BLI_rcti_size_x(&input_canvas) - BLI_rcti_size_x(&scale_canvas)) / 2.0f; + r_scale_offset_y = (BLI_rcti_size_y(&input_canvas) - BLI_rcti_size_y(&scale_canvas)) / 2.0f; +} + +void ScaleOperation::get_scale_area_of_interest(const rcti &input_canvas, + const rcti &scale_canvas, + const float relative_scale_x, + const float relative_scale_y, + const rcti &output_area, + rcti &r_input_area) +{ + const float scale_center_x = BLI_rcti_size_x(&input_canvas) / 2.0f; + const float scale_center_y = BLI_rcti_size_y(&input_canvas) / 2.0f; + float scale_offset_x, scale_offset_y; + ScaleOperation::get_scale_offset(input_canvas, scale_canvas, scale_offset_x, scale_offset_y); + + r_input_area.xmin = floorf( + scale_coord_inverted(output_area.xmin + scale_offset_x, scale_center_x, relative_scale_x)); + r_input_area.xmax = ceilf( + scale_coord_inverted(output_area.xmax + scale_offset_x, scale_center_x, relative_scale_x)); + r_input_area.ymin = floorf( + scale_coord_inverted(output_area.ymin + scale_offset_y, scale_center_y, relative_scale_y)); + r_input_area.ymax = ceilf( + scale_coord_inverted(output_area.ymax + scale_offset_y, scale_center_y, relative_scale_y)); +} + void ScaleOperation::get_area_of_interest(const int input_idx, const rcti &output_area, rcti &r_input_area) { r_input_area = output_area; - if (input_idx != 0 || m_variable_size) { + if (input_idx != 0 || is_scaling_variable()) { return; } - float scale_x = get_constant_scale_x(); - float scale_y = get_constant_scale_y(); - scale_area(r_input_area, scale_x, scale_y); + NodeOperation *image_op = get_input_operation(IMAGE_INPUT_INDEX); + const float scale_x = get_constant_scale_x(image_op->getWidth()); + const float scale_y = get_constant_scale_y(image_op->getHeight()); + + get_scale_area_of_interest( + image_op->get_canvas(), this->get_canvas(), scale_x, scale_y, output_area, r_input_area); expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler); } @@ -127,18 +183,70 @@ void ScaleOperation::update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> inputs) { - const MemoryBuffer *input_img = inputs[0]; - MemoryBuffer *input_x = inputs[1]; - MemoryBuffer *input_y = inputs[2]; - const float scale_x_factor = get_relative_scale_x_factor(); - const float scale_y_factor = get_relative_scale_y_factor(); + NodeOperation *input_image_op = get_input_operation(IMAGE_INPUT_INDEX); + const int input_image_width = input_image_op->getWidth(); + const int input_image_height = input_image_op->getHeight(); + const float scale_x_factor = get_relative_scale_x_factor(input_image_width); + const float scale_y_factor = get_relative_scale_y_factor(input_image_height); + const float scale_center_x = input_image_width / 2.0f; + const float scale_center_y = input_image_height / 2.0f; + float from_scale_offset_x, from_scale_offset_y; + ScaleOperation::get_scale_offset( + input_image_op->get_canvas(), this->get_canvas(), from_scale_offset_x, from_scale_offset_y); + + const MemoryBuffer *input_image = inputs[IMAGE_INPUT_INDEX]; + MemoryBuffer *input_x = inputs[X_INPUT_INDEX]; + MemoryBuffer *input_y = inputs[Y_INPUT_INDEX]; BuffersIterator<float> it = output->iterate_with({input_x, input_y}, area); for (; !it.is_end(); ++it) { const float rel_scale_x = *it.in(0) * scale_x_factor; const float rel_scale_y = *it.in(1) * scale_y_factor; - const float scaled_x = scale_coord(it.x, m_centerX, rel_scale_x); - const float scaled_y = scale_coord(it.y, m_centerY, rel_scale_y); - input_img->read_elem_sampled(scaled_x, scaled_y, (PixelSampler)m_sampler, it.out); + const float scaled_x = scale_coord_inverted( + from_scale_offset_x + canvas_.xmin + it.x, scale_center_x, rel_scale_x); + const float scaled_y = scale_coord_inverted( + from_scale_offset_y + canvas_.ymin + it.y, scale_center_y, rel_scale_y); + + input_image->read_elem_sampled( + scaled_x - canvas_.xmin, scaled_y - canvas_.ymin, (PixelSampler)m_sampler, it.out); + } +} + +void ScaleOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) +{ + if (execution_model_ == eExecutionModel::Tiled) { + NodeOperation::determine_canvas(preferred_area, r_area); + return; + } + + const bool image_determined = + getInputSocket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area); + if (image_determined) { + rcti image_canvas = r_area; + rcti unused; + NodeOperationInput *x_socket = getInputSocket(X_INPUT_INDEX); + NodeOperationInput *y_socket = getInputSocket(Y_INPUT_INDEX); + x_socket->determine_canvas(image_canvas, unused); + y_socket->determine_canvas(image_canvas, unused); + if (is_scaling_variable()) { + /* Do not scale canvas. */ + return; + } + + /* Determine scaled canvas. */ + const float input_width = BLI_rcti_size_x(&r_area); + const float input_height = BLI_rcti_size_y(&r_area); + const float scale_x = get_constant_scale_x(input_width); + const float scale_y = get_constant_scale_y(input_height); + scale_area(r_area, scale_x, scale_y); + const Size2f max_scale_size = {MAX2(input_width, max_scale_canvas_size_.x), + MAX2(input_height, max_scale_canvas_size_.y)}; + clamp_area_size_max(r_area, max_scale_size); + + /* Re-determine canvases of x and y constant inputs with scaled canvas as preferred. */ + get_input_operation(X_INPUT_INDEX)->unset_canvas(); + get_input_operation(Y_INPUT_INDEX)->unset_canvas(); + x_socket->determine_canvas(r_area, unused); + y_socket->determine_canvas(r_area, unused); } } @@ -166,8 +274,8 @@ void ScaleRelativeOperation::executePixelSampled(float output[4], const float scx = scaleX[0]; const float scy = scaleY[0]; - float nx = this->m_centerX + (x - this->m_centerX) / scx; - float ny = this->m_centerY + (y - this->m_centerY) / scy; + float nx = this->canvas_center_x_ + (x - this->canvas_center_x_) / scx; + float ny = this->canvas_center_y_ + (y - this->canvas_center_y_) / scy; this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); } @@ -186,10 +294,10 @@ bool ScaleRelativeOperation::determineDependingAreaOfInterest(rcti *input, const float scx = scaleX[0]; const float scy = scaleY[0]; - newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / scx + 1; - newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / scx - 1; - newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / scy + 1; - newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / scy - 1; + newInput.xmax = this->canvas_center_x_ + (input->xmax - this->canvas_center_x_) / scx + 1; + newInput.xmin = this->canvas_center_x_ + (input->xmin - this->canvas_center_x_) / scx - 1; + newInput.ymax = this->canvas_center_y_ + (input->ymax - this->canvas_center_y_) / scy + 1; + newInput.ymin = this->canvas_center_y_ + (input->ymin - this->canvas_center_y_) / scy - 1; } else { newInput.xmax = this->getWidth(); @@ -222,8 +330,8 @@ void ScaleAbsoluteOperation::executePixelSampled(float output[4], float relativeXScale = scx / width; float relativeYScale = scy / height; - float nx = this->m_centerX + (x - this->m_centerX) / relativeXScale; - float ny = this->m_centerY + (y - this->m_centerY) / relativeYScale; + float nx = this->canvas_center_x_ + (x - this->canvas_center_x_) / relativeXScale; + float ny = this->canvas_center_y_ + (y - this->canvas_center_y_) / relativeYScale; this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); } @@ -248,10 +356,14 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, float relateveXScale = scx / width; float relateveYScale = scy / height; - newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / relateveXScale; - newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / relateveXScale; - newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / relateveYScale; - newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / relateveYScale; + newInput.xmax = this->canvas_center_x_ + + (input->xmax - this->canvas_center_x_) / relateveXScale; + newInput.xmin = this->canvas_center_x_ + + (input->xmin - this->canvas_center_x_) / relateveXScale; + newInput.ymax = this->canvas_center_y_ + + (input->ymax - this->canvas_center_y_) / relateveYScale; + newInput.ymin = this->canvas_center_y_ + + (input->ymin - this->canvas_center_y_) / relateveYScale; } else { newInput.xmax = this->getWidth(); @@ -267,16 +379,17 @@ ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation() { this->addInputSocket(DataType::Color, ResizeMode::None); this->addOutputSocket(DataType::Color); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->m_inputOperation = nullptr; this->m_is_offset = false; } -void ScaleFixedSizeOperation::init_data() +void ScaleFixedSizeOperation::init_data(const rcti &input_canvas) { - const NodeOperation *input_op = getInputOperation(0); - this->m_relX = input_op->getWidth() / (float)this->m_newWidth; - this->m_relY = input_op->getHeight() / (float)this->m_newHeight; + const int input_width = BLI_rcti_size_x(&input_canvas); + const int input_height = BLI_rcti_size_y(&input_canvas); + this->m_relX = input_width / (float)this->m_newWidth; + this->m_relY = input_height / (float)this->m_newHeight; /* *** all the options below are for a fairly special case - camera framing *** */ if (this->m_offsetX != 0.0f || this->m_offsetY != 0.0f) { @@ -294,8 +407,8 @@ void ScaleFixedSizeOperation::init_data() if (this->m_is_aspect) { /* apply aspect from clip */ - const float w_src = input_op->getWidth(); - const float h_src = input_op->getHeight(); + const float w_src = input_width; + const float h_src = input_height; /* destination aspect is already applied from the camera frame */ const float w_dst = this->m_newWidth; @@ -310,12 +423,32 @@ void ScaleFixedSizeOperation::init_data() const float div = asp_src / asp_dst; this->m_relX /= div; this->m_offsetX += ((w_src - (w_src * div)) / (w_src / w_dst)) / 2.0f; + if (m_is_crop && execution_model_ == eExecutionModel::FullFrame) { + int fit_width = m_newWidth * div; + if (fit_width > max_scale_canvas_size_.x) { + fit_width = max_scale_canvas_size_.x; + } + + const int added_width = fit_width - m_newWidth; + m_newWidth += added_width; + m_offsetX += added_width / 2.0f; + } } else { /* fit Y */ const float div = asp_dst / asp_src; this->m_relY /= div; this->m_offsetY += ((h_src - (h_src * div)) / (h_src / h_dst)) / 2.0f; + if (m_is_crop && execution_model_ == eExecutionModel::FullFrame) { + int fit_height = m_newHeight * div; + if (fit_height > max_scale_canvas_size_.y) { + fit_height = max_scale_canvas_size_.y; + } + + const int added_height = fit_height - m_newHeight; + m_newHeight += added_height; + m_offsetY += added_height / 2.0f; + } } this->m_is_offset = true; @@ -366,15 +499,26 @@ bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input, return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } -void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) +void ScaleFixedSizeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - unsigned int nr[2]; - nr[0] = this->m_newWidth; - nr[1] = this->m_newHeight; - BaseScaleOperation::determineResolution(resolution, nr); - resolution[0] = this->m_newWidth; - resolution[1] = this->m_newHeight; + rcti local_preferred = preferred_area; + local_preferred.xmax = local_preferred.xmin + m_newWidth; + local_preferred.ymax = local_preferred.ymin + m_newHeight; + rcti input_canvas; + const bool input_determined = getInputSocket(0)->determine_canvas(local_preferred, input_canvas); + if (input_determined) { + init_data(input_canvas); + r_area = input_canvas; + if (execution_model_ == eExecutionModel::FullFrame) { + r_area.xmin /= m_relX; + r_area.ymin /= m_relY; + r_area.xmin += m_offsetX; + r_area.ymin += m_offsetY; + } + + r_area.xmax = r_area.xmin + m_newWidth; + r_area.ymax = r_area.ymin + m_newHeight; + } } void ScaleFixedSizeOperation::get_area_of_interest(const int input_idx, @@ -383,10 +527,11 @@ void ScaleFixedSizeOperation::get_area_of_interest(const int input_idx, { BLI_assert(input_idx == 0); UNUSED_VARS_NDEBUG(input_idx); - r_input_area.xmax = (output_area.xmax - m_offsetX) * this->m_relX; - r_input_area.xmin = (output_area.xmin - m_offsetX) * this->m_relX; - r_input_area.ymax = (output_area.ymax - m_offsetY) * this->m_relY; - r_input_area.ymin = (output_area.ymin - m_offsetY) * this->m_relY; + + r_input_area.xmax = ceilf((output_area.xmax - m_offsetX) * this->m_relX); + r_input_area.xmin = floorf((output_area.xmin - m_offsetX) * this->m_relX); + r_input_area.ymax = ceilf((output_area.ymax - m_offsetY) * this->m_relY); + r_input_area.ymin = floorf((output_area.ymin - m_offsetY) * this->m_relY); expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler); } @@ -399,14 +544,17 @@ void ScaleFixedSizeOperation::update_memory_buffer_partial(MemoryBuffer *output, BuffersIterator<float> it = output->iterate_with({}, area); if (this->m_is_offset) { for (; !it.is_end(); ++it) { - const float nx = (it.x - this->m_offsetX) * this->m_relX; - const float ny = (it.y - this->m_offsetY) * this->m_relY; - input_img->read_elem_sampled(nx, ny, sampler, it.out); + const float nx = (canvas_.xmin + it.x - this->m_offsetX) * this->m_relX; + const float ny = (canvas_.ymin + it.y - this->m_offsetY) * this->m_relY; + input_img->read_elem_sampled(nx - canvas_.xmin, ny - canvas_.ymin, sampler, it.out); } } else { for (; !it.is_end(); ++it) { - input_img->read_elem_sampled(it.x * this->m_relX, it.y * this->m_relY, sampler, it.out); + input_img->read_elem_sampled((canvas_.xmin + it.x) * this->m_relX - canvas_.xmin, + (canvas_.ymin + it.y) * this->m_relY - canvas_.ymin, + sampler, + it.out); } } } diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h index 65762d1ce62..746e490d900 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.h +++ b/source/blender/compositor/operations/COM_ScaleOperation.h @@ -24,6 +24,9 @@ namespace blender::compositor { class BaseScaleOperation : public MultiThreadedOperation { public: + static constexpr float DEFAULT_MAX_SCALE_CANVAS_SIZE = 12000; + + public: void setSampler(PixelSampler sampler) { this->m_sampler = (int)sampler; @@ -33,6 +36,8 @@ class BaseScaleOperation : public MultiThreadedOperation { m_variable_size = variable_size; }; + void set_scale_canvas_max_size(Size2f size); + protected: BaseScaleOperation(); @@ -41,20 +46,26 @@ class BaseScaleOperation : public MultiThreadedOperation { return (m_sampler == -1) ? sampler : (PixelSampler)m_sampler; } + Size2f max_scale_canvas_size_ = {DEFAULT_MAX_SCALE_CANVAS_SIZE, DEFAULT_MAX_SCALE_CANVAS_SIZE}; int m_sampler; + /* TODO(manzanilla): to be removed with tiled implementation. */ bool m_variable_size; }; class ScaleOperation : public BaseScaleOperation { public: - static constexpr float MIN_SCALE = 0.0001f; + static constexpr float MIN_RELATIVE_SCALE = 0.0001f; protected: + static constexpr int IMAGE_INPUT_INDEX = 0; + static constexpr int X_INPUT_INDEX = 1; + static constexpr int Y_INPUT_INDEX = 2; + SocketReader *m_inputOperation; SocketReader *m_inputXOperation; SocketReader *m_inputYOperation; - float m_centerX; - float m_centerY; + float canvas_center_x_; + float canvas_center_y_; public: ScaleOperation(); @@ -62,9 +73,28 @@ class ScaleOperation : public BaseScaleOperation { static float scale_coord(const float coord, const float center, const float relative_scale) { - return center + (coord - center) / MAX2(relative_scale, MIN_SCALE); + return center + (coord - center) * MAX2(relative_scale, MIN_RELATIVE_SCALE); } - static void scale_area(rcti &rect, float center_x, float center_y, float scale_x, float scale_y); + + static float scale_coord_inverted(const float coord, + const float center, + const float relative_scale) + { + return center + (coord - center) / MAX2(relative_scale, MIN_RELATIVE_SCALE); + } + + static void get_scale_offset(const rcti &input_canvas, + const rcti &scale_canvas, + float &r_scale_offset_x, + float &r_scale_offset_y); + static void scale_area(rcti &area, float relative_scale_x, float relative_scale_y); + static void get_scale_area_of_interest(const rcti &input_canvas, + const rcti &scale_canvas, + const float relative_scale_x, + const float relative_scale_y, + const rcti &output_area, + rcti &r_input_area); + static void clamp_area_size_max(rcti &area, Size2f max_size); void init_data() override; void initExecution() override; @@ -75,15 +105,17 @@ class ScaleOperation : public BaseScaleOperation { const rcti &area, Span<MemoryBuffer *> inputs) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; + protected: - virtual float get_relative_scale_x_factor() = 0; - virtual float get_relative_scale_y_factor() = 0; + virtual float get_relative_scale_x_factor(float width) = 0; + virtual float get_relative_scale_y_factor(float height) = 0; private: + bool is_scaling_variable(); float get_constant_scale(int input_op_idx, float factor); - float get_constant_scale_x(); - float get_constant_scale_y(); - void scale_area(rcti &rect, float scale_x, float scale_y); + float get_constant_scale_x(float width); + float get_constant_scale_y(float height); }; class ScaleRelativeOperation : public ScaleOperation { @@ -94,11 +126,13 @@ class ScaleRelativeOperation : public ScaleOperation { ReadBufferOperation *readOperation, rcti *output) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - float get_relative_scale_x_factor() override + + float get_relative_scale_x_factor(float UNUSED(width)) override { return 1.0f; } - float get_relative_scale_y_factor() override + + float get_relative_scale_y_factor(float UNUSED(height)) override { return 1.0f; } @@ -110,13 +144,15 @@ class ScaleAbsoluteOperation : public ScaleOperation { ReadBufferOperation *readOperation, rcti *output) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - float get_relative_scale_x_factor() override + + float get_relative_scale_x_factor(float width) override { - return 1.0f / getWidth(); + return 1.0f / width; } - float get_relative_scale_y_factor() override + + float get_relative_scale_y_factor(float height) override { - return 1.0f / getHeight(); + return 1.0f / height; } }; @@ -141,11 +177,9 @@ class ScaleFixedSizeOperation : public BaseScaleOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void init_data() override; void initExecution() override; void deinitExecution() override; void setNewWidth(int width) @@ -174,6 +208,9 @@ class ScaleFixedSizeOperation : public BaseScaleOperation { void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> inputs) override; + + private: + void init_data(const rcti &input_canvas); }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc index 628da686a42..21d9210bdac 100644 --- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc +++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc @@ -382,13 +382,30 @@ void ScreenLensDistortionOperation::updateVariables(float distortion, float disp mul_v3_v3fl(m_k4, m_k, 4.0f); } +void ScreenLensDistortionOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) +{ + switch (execution_model_) { + case eExecutionModel::FullFrame: { + set_determined_canvas_modifier([=](rcti &canvas) { + /* Ensure screen space. */ + BLI_rcti_translate(&canvas, -canvas.xmin, -canvas.ymin); + }); + break; + } + default: + break; + } + + NodeOperation::determine_canvas(preferred_area, r_area); +} + void ScreenLensDistortionOperation::get_area_of_interest(const int input_idx, const rcti &UNUSED(output_area), rcti &r_input_area) { if (input_idx != 0) { /* Dispersion and distortion inputs are used as constants only. */ - r_input_area = COM_SINGLE_ELEM_AREA; + r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST; } /* XXX the original method of estimating the area-of-interest does not work @@ -398,10 +415,7 @@ void ScreenLensDistortionOperation::get_area_of_interest(const int input_idx, */ #if 1 NodeOperation *image = getInputOperation(0); - r_input_area.xmax = image->getWidth(); - r_input_area.xmin = 0; - r_input_area.ymax = image->getHeight(); - r_input_area.ymin = 0; + r_input_area = image->get_canvas(); #else /* Original method in tiled implementation. */ rcti newInput; diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h index 616fc8883b0..93681b2f934 100644 --- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h +++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h @@ -86,6 +86,7 @@ class ScreenLensDistortionOperation : public MultiThreadedOperation { ReadBufferOperation *readOperation, rcti *output) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cc b/source/blender/compositor/operations/COM_SetColorOperation.cc index dbe45fa60db..1e7a950e727 100644 --- a/source/blender/compositor/operations/COM_SetColorOperation.cc +++ b/source/blender/compositor/operations/COM_SetColorOperation.cc @@ -34,11 +34,9 @@ void SetColorOperation::executePixelSampled(float output[4], copy_v4_v4(output, this->m_color); } -void SetColorOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void SetColorOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; + r_area = preferred_area; } } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetColorOperation.h b/source/blender/compositor/operations/COM_SetColorOperation.h index f546d5e7668..34ea35bdcbc 100644 --- a/source/blender/compositor/operations/COM_SetColorOperation.h +++ b/source/blender/compositor/operations/COM_SetColorOperation.h @@ -83,8 +83,7 @@ class SetColorOperation : public ConstantOperation { */ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cc b/source/blender/compositor/operations/COM_SetValueOperation.cc index ef43cf64653..b7c50f94887 100644 --- a/source/blender/compositor/operations/COM_SetValueOperation.cc +++ b/source/blender/compositor/operations/COM_SetValueOperation.cc @@ -34,11 +34,9 @@ void SetValueOperation::executePixelSampled(float output[4], output[0] = this->m_value; } -void SetValueOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void SetValueOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; + r_area = preferred_area; } } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetValueOperation.h b/source/blender/compositor/operations/COM_SetValueOperation.h index 726624c1c6a..e72652450a9 100644 --- a/source/blender/compositor/operations/COM_SetValueOperation.h +++ b/source/blender/compositor/operations/COM_SetValueOperation.h @@ -54,8 +54,8 @@ class SetValueOperation : public ConstantOperation { * The inner loop of this operation. */ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cc b/source/blender/compositor/operations/COM_SetVectorOperation.cc index 7b8cf44048c..3e8514f1f59 100644 --- a/source/blender/compositor/operations/COM_SetVectorOperation.cc +++ b/source/blender/compositor/operations/COM_SetVectorOperation.cc @@ -37,11 +37,9 @@ void SetVectorOperation::executePixelSampled(float output[4], output[2] = vector_.z; } -void SetVectorOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void SetVectorOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; + r_area = preferred_area; } } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.h b/source/blender/compositor/operations/COM_SetVectorOperation.h index 41fd06659d6..920ea8051e4 100644 --- a/source/blender/compositor/operations/COM_SetVectorOperation.h +++ b/source/blender/compositor/operations/COM_SetVectorOperation.h @@ -84,8 +84,7 @@ class SetVectorOperation : public ConstantOperation { */ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void setVector(const float vector[3]) { diff --git a/source/blender/compositor/operations/COM_SplitOperation.cc b/source/blender/compositor/operations/COM_SplitOperation.cc index b2a50e2c740..47b2bbb7e94 100644 --- a/source/blender/compositor/operations/COM_SplitOperation.cc +++ b/source/blender/compositor/operations/COM_SplitOperation.cc @@ -67,16 +67,14 @@ void SplitOperation::executePixelSampled(float output[4], } } -void SplitOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void SplitOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - unsigned int tempPreferredResolution[2] = {0, 0}; - unsigned int tempResolution[2]; + rcti unused_area; - this->getInputSocket(0)->determineResolution(tempResolution, tempPreferredResolution); - this->setResolutionInputSocketIndex((tempResolution[0] && tempResolution[1]) ? 0 : 1); + const bool determined = this->getInputSocket(0)->determine_canvas(COM_AREA_NONE, unused_area); + this->set_canvas_input_index(determined ? 0 : 1); - NodeOperation::determineResolution(resolution, preferredResolution); + NodeOperation::determine_canvas(preferred_area, r_area); } void SplitOperation::update_memory_buffer_partial(MemoryBuffer *output, diff --git a/source/blender/compositor/operations/COM_SplitOperation.h b/source/blender/compositor/operations/COM_SplitOperation.h index 2d09d2a07dc..f923c9f8b7a 100644 --- a/source/blender/compositor/operations/COM_SplitOperation.h +++ b/source/blender/compositor/operations/COM_SplitOperation.h @@ -35,8 +35,7 @@ class SplitOperation : public MultiThreadedOperation { void initExecution() override; void deinitExecution() override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void setSplitPercentage(float splitPercentage) { this->m_splitPercentage = splitPercentage; diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cc b/source/blender/compositor/operations/COM_SunBeamsOperation.cc index ad96e3a02ba..494506389c5 100644 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.cc +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cc @@ -25,7 +25,7 @@ SunBeamsOperation::SunBeamsOperation() { this->addInputSocket(DataType::Color); this->addOutputSocket(DataType::Color); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->flags.complex = true; } diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc index c8e0844d35f..c06e3ac7cb0 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.cc +++ b/source/blender/compositor/operations/COM_TextureOperation.cc @@ -72,34 +72,20 @@ void TextureBaseOperation::deinitExecution() NodeOperation::deinitExecution(); } -void TextureBaseOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void TextureBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - switch (execution_model_) { - case eExecutionModel::Tiled: { - if (preferredResolution[0] == 0 || preferredResolution[1] == 0) { - int width = this->m_rd->xsch * this->m_rd->size / 100; - int height = this->m_rd->ysch * this->m_rd->size / 100; - resolution[0] = width; - resolution[1] = height; - } - else { - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; - } - break; - } - case eExecutionModel::FullFrame: { - /* Determine inputs resolutions. */ - unsigned int temp[2]; - NodeOperation::determineResolution(temp, preferredResolution); - - /* We don't use inputs resolutions because they are only used as parameters, not image data. - */ - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; - break; - } + r_area = preferred_area; + if (BLI_rcti_is_empty(&preferred_area)) { + int width = this->m_rd->xsch * this->m_rd->size / 100; + int height = this->m_rd->ysch * this->m_rd->size / 100; + r_area.xmax = preferred_area.xmin + width; + r_area.ymax = preferred_area.ymin + height; + } + + if (execution_model_ == eExecutionModel::FullFrame) { + /* Determine inputs. */ + rcti temp; + NodeOperation::determine_canvas(r_area, temp); } } diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h index 1e95cb270d0..5bc21da1f96 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.h +++ b/source/blender/compositor/operations/COM_TextureOperation.h @@ -46,8 +46,7 @@ class TextureBaseOperation : public MultiThreadedOperation { /** * Determine the output resolution. */ - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; /** * Constructor diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cc b/source/blender/compositor/operations/COM_TonemapOperation.cc index 20da468eeb1..cb671c54abe 100644 --- a/source/blender/compositor/operations/COM_TonemapOperation.cc +++ b/source/blender/compositor/operations/COM_TonemapOperation.cc @@ -28,7 +28,7 @@ namespace blender::compositor { TonemapOperation::TonemapOperation() { - this->addInputSocket(DataType::Color, ResizeMode::None); + this->addInputSocket(DataType::Color, ResizeMode::Align); this->addOutputSocket(DataType::Color); this->m_imageReader = nullptr; this->m_data = nullptr; @@ -160,11 +160,7 @@ void TonemapOperation::get_area_of_interest(const int input_idx, rcti &r_input_area) { BLI_assert(input_idx == 0); - NodeOperation *operation = getInputOperation(input_idx); - r_input_area.xmin = 0; - r_input_area.ymin = 0; - r_input_area.xmax = operation->getWidth(); - r_input_area.ymax = operation->getHeight(); + r_input_area = get_input_operation(input_idx)->get_canvas(); } struct Luminance { diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cc b/source/blender/compositor/operations/COM_TrackPositionOperation.cc index 0f4be16a620..1929c578177 100644 --- a/source/blender/compositor/operations/COM_TrackPositionOperation.cc +++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cc @@ -157,11 +157,9 @@ const float *TrackPositionOperation::get_constant_elem() return &track_position_; } -void TrackPositionOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void TrackPositionOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; + r_area = preferred_area; } } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.h b/source/blender/compositor/operations/COM_TrackPositionOperation.h index f716bd97737..a47d3e03ed4 100644 --- a/source/blender/compositor/operations/COM_TrackPositionOperation.h +++ b/source/blender/compositor/operations/COM_TrackPositionOperation.h @@ -53,8 +53,7 @@ class TrackPositionOperation : public ConstantOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; public: TrackPositionOperation(); diff --git a/source/blender/compositor/operations/COM_TransformOperation.cc b/source/blender/compositor/operations/COM_TransformOperation.cc index 2feaa0ae16d..5f6e9ed4d21 100644 --- a/source/blender/compositor/operations/COM_TransformOperation.cc +++ b/source/blender/compositor/operations/COM_TransformOperation.cc @@ -27,55 +27,40 @@ namespace blender::compositor { TransformOperation::TransformOperation() { - addInputSocket(DataType::Color); - addInputSocket(DataType::Value); - addInputSocket(DataType::Value); - addInputSocket(DataType::Value); - addInputSocket(DataType::Value); + addInputSocket(DataType::Color, ResizeMode::None); + addInputSocket(DataType::Value, ResizeMode::None); + addInputSocket(DataType::Value, ResizeMode::None); + addInputSocket(DataType::Value, ResizeMode::None); + addInputSocket(DataType::Value, ResizeMode::None); addOutputSocket(DataType::Color); translate_factor_x_ = 1.0f; translate_factor_y_ = 1.0f; convert_degree_to_rad_ = false; sampler_ = PixelSampler::Bilinear; invert_ = false; + max_scale_canvas_size_ = {ScaleOperation::DEFAULT_MAX_SCALE_CANVAS_SIZE, + ScaleOperation::DEFAULT_MAX_SCALE_CANVAS_SIZE}; +} + +void TransformOperation::set_scale_canvas_max_size(Size2f size) +{ + max_scale_canvas_size_ = size; } void TransformOperation::init_data() { - /* Translation. */ - translate_x_ = 0; - NodeOperation *x_op = getInputOperation(X_INPUT_INDEX); - if (x_op->get_flags().is_constant_operation) { - translate_x_ = static_cast<ConstantOperation *>(x_op)->get_constant_elem()[0] * - translate_factor_x_; - } - translate_y_ = 0; - NodeOperation *y_op = getInputOperation(Y_INPUT_INDEX); - if (y_op->get_flags().is_constant_operation) { - translate_y_ = static_cast<ConstantOperation *>(y_op)->get_constant_elem()[0] * - translate_factor_y_; - } - /* Scaling. */ - scale_center_x_ = getWidth() / 2.0; - scale_center_y_ = getHeight() / 2.0; - constant_scale_ = 1.0f; - NodeOperation *scale_op = getInputOperation(SCALE_INPUT_INDEX); - if (scale_op->get_flags().is_constant_operation) { - constant_scale_ = static_cast<ConstantOperation *>(scale_op)->get_constant_elem()[0]; - } + translate_x_ = get_input_operation(X_INPUT_INDEX)->get_constant_value_default(0.0f) * + translate_factor_x_; + translate_y_ = get_input_operation(Y_INPUT_INDEX)->get_constant_value_default(0.0f) * + translate_factor_y_; - /* Rotation. */ - rotate_center_x_ = (getWidth() - 1.0) / 2.0; - rotate_center_y_ = (getHeight() - 1.0) / 2.0; - NodeOperation *degree_op = getInputOperation(DEGREE_INPUT_INDEX); - const bool is_constant_degree = degree_op->get_flags().is_constant_operation; - const float degree = is_constant_degree ? - static_cast<ConstantOperation *>(degree_op)->get_constant_elem()[0] : - 0.0f; + const float degree = get_input_operation(DEGREE_INPUT_INDEX)->get_constant_value_default(0.0f); const double rad = convert_degree_to_rad_ ? DEG2RAD((double)degree) : degree; rotate_cosine_ = cos(rad); rotate_sine_ = sin(rad); + + scale_ = get_input_operation(SCALE_INPUT_INDEX)->get_constant_value_default(1.0f); } void TransformOperation::get_area_of_interest(const int input_idx, @@ -84,26 +69,41 @@ void TransformOperation::get_area_of_interest(const int input_idx, { switch (input_idx) { case IMAGE_INPUT_INDEX: { - BLI_rcti_translate(&r_input_area, translate_x_, translate_y_); - ScaleOperation::scale_area( - r_input_area, scale_center_x_, scale_center_y_, constant_scale_, constant_scale_); - RotateOperation::get_area_rotation_bounds(r_input_area, - rotate_center_x_, - rotate_center_y_, - rotate_sine_, - rotate_cosine_, - r_input_area); + NodeOperation *image_op = get_input_operation(IMAGE_INPUT_INDEX); + const rcti &image_canvas = image_op->get_canvas(); + if (invert_) { + /* Scale -> Rotate -> Translate. */ + r_input_area = output_area; + BLI_rcti_translate(&r_input_area, -translate_x_, -translate_y_); + RotateOperation::get_rotation_area_of_interest(scale_canvas_, + rotate_canvas_, + rotate_sine_, + rotate_cosine_, + r_input_area, + r_input_area); + ScaleOperation::get_scale_area_of_interest( + image_canvas, scale_canvas_, scale_, scale_, r_input_area, r_input_area); + } + else { + /* Translate -> Rotate -> Scale. */ + ScaleOperation::get_scale_area_of_interest( + rotate_canvas_, scale_canvas_, scale_, scale_, output_area, r_input_area); + RotateOperation::get_rotation_area_of_interest(translate_canvas_, + rotate_canvas_, + rotate_sine_, + rotate_cosine_, + r_input_area, + r_input_area); + BLI_rcti_translate(&r_input_area, -translate_x_, -translate_y_); + } expand_area_for_sampler(r_input_area, sampler_); break; } case X_INPUT_INDEX: case Y_INPUT_INDEX: - case DEGREE_INPUT_INDEX: { - r_input_area = COM_SINGLE_ELEM_AREA; - break; - } + case DEGREE_INPUT_INDEX: case SCALE_INPUT_INDEX: { - r_input_area = output_area; + r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST; break; } } @@ -114,8 +114,7 @@ void TransformOperation::update_memory_buffer_partial(MemoryBuffer *output, Span<MemoryBuffer *> inputs) { const MemoryBuffer *input_img = inputs[IMAGE_INPUT_INDEX]; - MemoryBuffer *input_scale = inputs[SCALE_INPUT_INDEX]; - BuffersIterator<float> it = output->iterate_with({input_scale}, area); + BuffersIterator<float> it = output->iterate_with({}, area); if (invert_) { transform_inverted(it, input_img); } @@ -124,31 +123,111 @@ void TransformOperation::update_memory_buffer_partial(MemoryBuffer *output, } } +void TransformOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) +{ + const bool image_determined = + getInputSocket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area); + if (image_determined) { + rcti image_canvas = r_area; + rcti unused; + getInputSocket(X_INPUT_INDEX)->determine_canvas(image_canvas, unused); + getInputSocket(Y_INPUT_INDEX)->determine_canvas(image_canvas, unused); + getInputSocket(DEGREE_INPUT_INDEX)->determine_canvas(image_canvas, unused); + getInputSocket(SCALE_INPUT_INDEX)->determine_canvas(image_canvas, unused); + + init_data(); + if (invert_) { + /* Scale -> Rotate -> Translate. */ + scale_canvas_ = image_canvas; + ScaleOperation::scale_area(scale_canvas_, scale_, scale_); + const Size2f max_scale_size = { + MAX2(BLI_rcti_size_x(&image_canvas), max_scale_canvas_size_.x), + MAX2(BLI_rcti_size_y(&image_canvas), max_scale_canvas_size_.y)}; + ScaleOperation::clamp_area_size_max(scale_canvas_, max_scale_size); + + RotateOperation::get_rotation_canvas( + scale_canvas_, rotate_sine_, rotate_cosine_, rotate_canvas_); + + translate_canvas_ = rotate_canvas_; + BLI_rcti_translate(&translate_canvas_, translate_x_, translate_y_); + + r_area = translate_canvas_; + } + else { + /* Translate -> Rotate -> Scale. */ + translate_canvas_ = image_canvas; + BLI_rcti_translate(&translate_canvas_, translate_x_, translate_y_); + + RotateOperation::get_rotation_canvas( + translate_canvas_, rotate_sine_, rotate_cosine_, rotate_canvas_); + + scale_canvas_ = rotate_canvas_; + ScaleOperation::scale_area(scale_canvas_, scale_, scale_); + + const Size2f max_scale_size = { + MAX2(BLI_rcti_size_x(&rotate_canvas_), max_scale_canvas_size_.x), + MAX2(BLI_rcti_size_y(&rotate_canvas_), max_scale_canvas_size_.y)}; + ScaleOperation::clamp_area_size_max(scale_canvas_, max_scale_size); + + r_area = scale_canvas_; + } + } +} + +/** Translate -> Rotate -> Scale. */ void TransformOperation::transform(BuffersIterator<float> &it, const MemoryBuffer *input_img) { + float rotate_center_x, rotate_center_y; + RotateOperation::get_rotation_center(translate_canvas_, rotate_center_x, rotate_center_y); + float rotate_offset_x, rotate_offset_y; + RotateOperation::get_rotation_offset( + translate_canvas_, rotate_canvas_, rotate_offset_x, rotate_offset_y); + + const float scale_center_x = BLI_rcti_size_x(&rotate_canvas_) / 2.0f; + const float scale_center_y = BLI_rcti_size_y(&rotate_canvas_) / 2.0f; + float scale_offset_x, scale_offset_y; + ScaleOperation::get_scale_offset(rotate_canvas_, scale_canvas_, scale_offset_x, scale_offset_y); + for (; !it.is_end(); ++it) { - const float scale = *it.in(0); - float x = it.x - translate_x_; - float y = it.y - translate_y_; + float x = ScaleOperation::scale_coord_inverted(it.x + scale_offset_x, scale_center_x, scale_); + float y = ScaleOperation::scale_coord_inverted(it.y + scale_offset_y, scale_center_y, scale_); + + x = rotate_offset_x + x; + y = rotate_offset_y + y; RotateOperation::rotate_coords( - x, y, rotate_center_x_, rotate_center_y_, rotate_sine_, rotate_cosine_); - x = ScaleOperation::scale_coord(x, scale_center_x_, scale); - y = ScaleOperation::scale_coord(y, scale_center_y_, scale); - input_img->read_elem_sampled(x, y, sampler_, it.out); + x, y, rotate_center_x, rotate_center_y, rotate_sine_, rotate_cosine_); + + input_img->read_elem_sampled(x - translate_x_, y - translate_y_, sampler_, it.out); } } +/** Scale -> Rotate -> Translate. */ void TransformOperation::transform_inverted(BuffersIterator<float> &it, const MemoryBuffer *input_img) { + const rcti &image_canvas = get_input_operation(IMAGE_INPUT_INDEX)->get_canvas(); + const float scale_center_x = BLI_rcti_size_x(&image_canvas) / 2.0f - translate_x_; + const float scale_center_y = BLI_rcti_size_y(&image_canvas) / 2.0f - translate_y_; + float scale_offset_x, scale_offset_y; + ScaleOperation::get_scale_offset(image_canvas, scale_canvas_, scale_offset_x, scale_offset_y); + + float rotate_center_x, rotate_center_y; + RotateOperation::get_rotation_center(translate_canvas_, rotate_center_x, rotate_center_y); + rotate_center_x -= translate_x_; + rotate_center_y -= translate_y_; + float rotate_offset_x, rotate_offset_y; + RotateOperation::get_rotation_offset( + scale_canvas_, rotate_canvas_, rotate_offset_x, rotate_offset_y); + for (; !it.is_end(); ++it) { - const float scale = *it.in(0); - float x = ScaleOperation::scale_coord(it.x, scale_center_x_, scale); - float y = ScaleOperation::scale_coord(it.y, scale_center_y_, scale); + float x = rotate_offset_x + (it.x - translate_x_); + float y = rotate_offset_y + (it.y - translate_y_); RotateOperation::rotate_coords( - x, y, rotate_center_x_, rotate_center_y_, rotate_sine_, rotate_cosine_); - x -= translate_x_; - y -= translate_y_; + x, y, rotate_center_x, rotate_center_y, rotate_sine_, rotate_cosine_); + + x = ScaleOperation::scale_coord_inverted(x + scale_offset_x, scale_center_x, scale_); + y = ScaleOperation::scale_coord_inverted(y + scale_offset_y, scale_center_y, scale_); + input_img->read_elem_sampled(x, y, sampler_, it.out); } } diff --git a/source/blender/compositor/operations/COM_TransformOperation.h b/source/blender/compositor/operations/COM_TransformOperation.h index 480998a0207..3c5584a1bea 100644 --- a/source/blender/compositor/operations/COM_TransformOperation.h +++ b/source/blender/compositor/operations/COM_TransformOperation.h @@ -30,15 +30,14 @@ class TransformOperation : public MultiThreadedOperation { constexpr static int DEGREE_INPUT_INDEX = 3; constexpr static int SCALE_INPUT_INDEX = 4; - float scale_center_x_; - float scale_center_y_; - float rotate_center_x_; - float rotate_center_y_; float rotate_cosine_; float rotate_sine_; - float translate_x_; - float translate_y_; - float constant_scale_; + int translate_x_; + int translate_y_; + float scale_; + rcti scale_canvas_; + rcti rotate_canvas_; + rcti translate_canvas_; /* Set variables. */ PixelSampler sampler_; @@ -46,6 +45,7 @@ class TransformOperation : public MultiThreadedOperation { float translate_factor_x_; float translate_factor_y_; bool invert_; + Size2f max_scale_canvas_size_; public: TransformOperation(); @@ -71,16 +71,18 @@ class TransformOperation : public MultiThreadedOperation { invert_ = value; } + void set_scale_canvas_max_size(Size2f size); + void init_data() override; void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> inputs) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; + private: - /** Translate -> Rotate -> Scale. */ void transform(BuffersIterator<float> &it, const MemoryBuffer *input_img); - /** Scale -> Rotate -> Translate. */ void transform_inverted(BuffersIterator<float> &it, const MemoryBuffer *input_img); }; diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cc b/source/blender/compositor/operations/COM_TranslateOperation.cc index a3db086e974..9868f21654e 100644 --- a/source/blender/compositor/operations/COM_TranslateOperation.cc +++ b/source/blender/compositor/operations/COM_TranslateOperation.cc @@ -23,13 +23,13 @@ namespace blender::compositor { TranslateOperation::TranslateOperation() : TranslateOperation(DataType::Color) { } -TranslateOperation::TranslateOperation(DataType data_type) +TranslateOperation::TranslateOperation(DataType data_type, ResizeMode resize_mode) { - this->addInputSocket(data_type); - this->addInputSocket(DataType::Value); - this->addInputSocket(DataType::Value); + this->addInputSocket(data_type, resize_mode); + this->addInputSocket(DataType::Value, ResizeMode::None); + this->addInputSocket(DataType::Value, ResizeMode::None); this->addOutputSocket(data_type); - this->setResolutionInputSocketIndex(0); + this->set_canvas_input_index(0); this->m_inputOperation = nullptr; this->m_inputXOperation = nullptr; this->m_inputYOperation = nullptr; @@ -39,6 +39,7 @@ TranslateOperation::TranslateOperation(DataType data_type) this->x_extend_mode_ = MemoryBufferExtend::Clip; this->y_extend_mode_ = MemoryBufferExtend::Clip; } + void TranslateOperation::initExecution() { this->m_inputOperation = this->getInputSocketReader(0); @@ -122,6 +123,9 @@ void TranslateOperation::get_area_of_interest(const int input_idx, BLI_rcti_translate(&r_input_area, 0, -delta_y); } } + else { + r_input_area = output_area; + } } void TranslateOperation::update_memory_buffer_partial(MemoryBuffer *output, @@ -142,4 +146,27 @@ void TranslateOperation::update_memory_buffer_partial(MemoryBuffer *output, } } +TranslateCanvasOperation::TranslateCanvasOperation() + : TranslateOperation(DataType::Color, ResizeMode::None) +{ +} + +void TranslateCanvasOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) +{ + const bool determined = + getInputSocket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area); + if (determined) { + NodeOperationInput *x_socket = getInputSocket(X_INPUT_INDEX); + NodeOperationInput *y_socket = getInputSocket(Y_INPUT_INDEX); + rcti unused; + x_socket->determine_canvas(r_area, unused); + y_socket->determine_canvas(r_area, unused); + + ensureDelta(); + const float delta_x = x_extend_mode_ == MemoryBufferExtend::Clip ? getDeltaX() : 0.0f; + const float delta_y = y_extend_mode_ == MemoryBufferExtend::Clip ? getDeltaY() : 0.0f; + BLI_rcti_translate(&r_area, delta_x, delta_y); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TranslateOperation.h b/source/blender/compositor/operations/COM_TranslateOperation.h index ce1965cecef..c5a3d1ffd99 100644 --- a/source/blender/compositor/operations/COM_TranslateOperation.h +++ b/source/blender/compositor/operations/COM_TranslateOperation.h @@ -24,6 +24,11 @@ namespace blender::compositor { class TranslateOperation : public MultiThreadedOperation { + protected: + static constexpr int IMAGE_INPUT_INDEX = 0; + static constexpr int X_INPUT_INDEX = 1; + static constexpr int Y_INPUT_INDEX = 2; + private: SocketReader *m_inputOperation; SocketReader *m_inputXOperation; @@ -33,12 +38,14 @@ class TranslateOperation : public MultiThreadedOperation { bool m_isDeltaSet; float m_factorX; float m_factorY; + + protected: MemoryBufferExtend x_extend_mode_; MemoryBufferExtend y_extend_mode_; public: TranslateOperation(); - TranslateOperation(DataType data_type); + TranslateOperation(DataType data_type, ResizeMode mode = ResizeMode::Center); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; @@ -67,16 +74,8 @@ class TranslateOperation : public MultiThreadedOperation { this->m_deltaY = tempDelta[0]; } else { - this->m_deltaX = 0; - NodeOperation *x_op = getInputOperation(1); - if (x_op->get_flags().is_constant_operation) { - this->m_deltaX = ((ConstantOperation *)x_op)->get_constant_elem()[0]; - } - this->m_deltaY = 0; - NodeOperation *y_op = getInputOperation(2); - if (y_op->get_flags().is_constant_operation) { - this->m_deltaY = ((ConstantOperation *)y_op)->get_constant_elem()[0]; - } + m_deltaX = get_input_operation(X_INPUT_INDEX)->get_constant_value_default(0.0f); + m_deltaY = get_input_operation(Y_INPUT_INDEX)->get_constant_value_default(0.0f); } this->m_isDeltaSet = true; @@ -93,4 +92,10 @@ class TranslateOperation : public MultiThreadedOperation { Span<MemoryBuffer *> inputs) override; }; +class TranslateCanvasOperation : public TranslateOperation { + public: + TranslateCanvasOperation(); + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; +}; + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc index b8274576cb5..c524447a4fa 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc @@ -28,8 +28,8 @@ namespace blender::compositor { VariableSizeBokehBlurOperation::VariableSizeBokehBlurOperation() { this->addInputSocket(DataType::Color); - this->addInputSocket(DataType::Color, ResizeMode::None); /* Do not resize the bokeh image. */ - this->addInputSocket(DataType::Value); /* Radius. */ + this->addInputSocket(DataType::Color, ResizeMode::Align); /* Do not resize the bokeh image. */ + this->addInputSocket(DataType::Value); /* Radius. */ #ifdef COM_DEFOCUS_SEARCH /* Inverse search radius optimization structure. */ this->addInputSocket(DataType::Color, ResizeMode::None); @@ -77,7 +77,7 @@ void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect) this->determineDependingAreaOfInterest( rect, (ReadBufferOperation *)this->m_inputSizeProgram, &rect2); - const float max_dim = MAX2(m_width, m_height); + const float max_dim = MAX2(this->getWidth(), this->getHeight()); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; data->maxBlurScalar = (int)(data->size->get_max_value(rect2) * scalar); @@ -105,7 +105,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, float multiplier_accum[4]; float color_accum[4]; - const float max_dim = MAX2(m_width, m_height); + const float max_dim = MAX2(getWidth(), getHeight()); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; int maxBlurScalar = tileData->maxBlurScalar; @@ -125,8 +125,8 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, #else int minx = MAX2(x - maxBlurScalar, 0); int miny = MAX2(y - maxBlurScalar, 0); - int maxx = MIN2(x + maxBlurScalar, (int)m_width); - int maxy = MIN2(y + maxBlurScalar, (int)m_height); + int maxx = MIN2(x + maxBlurScalar, (int)getWidth()); + int maxy = MIN2(y + maxBlurScalar, (int)getHeight()); #endif { inputSizeBuffer->readNoCheck(tempSize, x, y); @@ -200,7 +200,7 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *sizeMemoryBuffer = this->m_inputSizeProgram->getInputMemoryBuffer( inputMemoryBuffers); - const float max_dim = MAX2(m_width, m_height); + const float max_dim = MAX2(getWidth(), getHeight()); cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; maxBlur = (cl_int)min_ff(sizeMemoryBuffer->get_max_value() * scalar, (float)this->m_maxBlur); @@ -238,7 +238,7 @@ bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest( rcti newInput; rcti bokehInput; - const float max_dim = MAX2(m_width, m_height); + const float max_dim = MAX2(getWidth(), getHeight()); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; int maxBlurScalar = this->m_maxBlur * scalar; @@ -294,10 +294,9 @@ void VariableSizeBokehBlurOperation::get_area_of_interest(const int input_idx, break; } case BOKEH_INPUT_INDEX: { - r_input_area.xmax = COM_BLUR_BOKEH_PIXELS; - r_input_area.xmin = 0; - r_input_area.ymax = COM_BLUR_BOKEH_PIXELS; - r_input_area.ymin = 0; + r_input_area = output_area; + r_input_area.xmax = r_input_area.xmin + COM_BLUR_BOKEH_PIXELS; + r_input_area.ymax = r_input_area.ymin + COM_BLUR_BOKEH_PIXELS; break; } #ifdef COM_DEFOCUS_SEARCH @@ -441,7 +440,7 @@ void VariableSizeBokehBlurOperation::update_memory_buffer_partial(MemoryBuffer * /* #InverseSearchRadiusOperation. */ InverseSearchRadiusOperation::InverseSearchRadiusOperation() { - this->addInputSocket(DataType::Value, ResizeMode::None); /* Radius. */ + this->addInputSocket(DataType::Value, ResizeMode::Align); /* Radius. */ this->addOutputSocket(DataType::Color); this->flags.complex = true; this->m_inputRadius = nullptr; diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h index 56b4677087b..3634bc2f1d7 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h @@ -130,8 +130,7 @@ class InverseSearchRadiusOperation : public NodeOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void setMaxBlur(int maxRadius) { diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cc b/source/blender/compositor/operations/COM_VectorBlurOperation.cc index 5405e6d424a..63956410b60 100644 --- a/source/blender/compositor/operations/COM_VectorBlurOperation.cc +++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc @@ -126,10 +126,7 @@ void VectorBlurOperation::get_area_of_interest(const int UNUSED(input_idx), const rcti &UNUSED(output_area), rcti &r_input_area) { - r_input_area.xmin = 0; - r_input_area.xmax = this->getWidth(); - r_input_area.ymin = 0; - r_input_area.ymax = this->getHeight(); + r_input_area = this->get_canvas(); } void VectorBlurOperation::update_memory_buffer(MemoryBuffer *output, diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cc b/source/blender/compositor/operations/COM_ViewerOperation.cc index a038e8994d8..1faff0fd07f 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.cc +++ b/source/blender/compositor/operations/COM_ViewerOperation.cc @@ -23,6 +23,7 @@ #include "BLI_math_color.h" #include "BLI_math_vector.h" #include "BLI_utildefines.h" +#include "COM_ExecutionSystem.h" #include "MEM_guardedalloc.h" #include "PIL_time.h" #include "WM_api.h" @@ -34,6 +35,8 @@ namespace blender::compositor { +static int MAX_VIEWER_TRANSLATION_PADDING = 12000; + ViewerOperation::ViewerOperation() { this->setImage(nullptr); @@ -67,7 +70,7 @@ void ViewerOperation::initExecution() this->m_depthInput = getInputSocketReader(2); this->m_doDepthBuffer = (this->m_depthInput != nullptr); - if (isActiveViewerOutput()) { + if (isActiveViewerOutput() && !exec_system_->is_breaked()) { initImage(); } } @@ -122,15 +125,16 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) updateImage(rect); } -void ViewerOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) +void ViewerOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { const int sceneRenderWidth = this->m_rd->xsch * this->m_rd->size / 100; const int sceneRenderHeight = this->m_rd->ysch * this->m_rd->size / 100; - unsigned int localPrefRes[2] = {static_cast<unsigned int>(sceneRenderWidth), - static_cast<unsigned int>(sceneRenderHeight)}; - NodeOperation::determineResolution(resolution, localPrefRes); + rcti local_preferred = preferred_area; + local_preferred.xmax = local_preferred.xmin + sceneRenderWidth; + local_preferred.ymax = local_preferred.ymin + sceneRenderHeight; + + NodeOperation::determine_canvas(local_preferred, r_area); } void ViewerOperation::initImage() @@ -155,13 +159,24 @@ void ViewerOperation::initImage() BLI_thread_unlock(LOCK_DRAW_IMAGE); return; } - if (ibuf->x != (int)getWidth() || ibuf->y != (int)getHeight()) { + int padding_x = abs(canvas_.xmin) * 2; + int padding_y = abs(canvas_.ymin) * 2; + if (padding_x > MAX_VIEWER_TRANSLATION_PADDING) { + padding_x = MAX_VIEWER_TRANSLATION_PADDING; + } + if (padding_y > MAX_VIEWER_TRANSLATION_PADDING) { + padding_y = MAX_VIEWER_TRANSLATION_PADDING; + } + + display_width_ = getWidth() + padding_x; + display_height_ = getHeight() + padding_y; + if (ibuf->x != display_width_ || ibuf->y != display_height_) { imb_freerectImBuf(ibuf); imb_freerectfloatImBuf(ibuf); IMB_freezbuffloatImBuf(ibuf); - ibuf->x = getWidth(); - ibuf->y = getHeight(); + ibuf->x = display_width_; + ibuf->y = display_height_; /* zero size can happen if no image buffers exist to define a sensible resolution */ if (ibuf->x > 0 && ibuf->y > 0) { imb_addrectfloatImBuf(ibuf); @@ -193,11 +208,15 @@ void ViewerOperation::initImage() void ViewerOperation::updateImage(const rcti *rect) { + if (exec_system_->is_breaked()) { + return; + } + float *buffer = m_outputBuffer; IMB_partial_display_buffer_update(this->m_ibuf, buffer, nullptr, - getWidth(), + display_width_, 0, 0, this->m_viewSettings, @@ -227,29 +246,46 @@ void ViewerOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output), return; } + const int offset_x = area.xmin + (canvas_.xmin > 0 ? canvas_.xmin * 2 : 0); + const int offset_y = area.ymin + (canvas_.ymin > 0 ? canvas_.ymin * 2 : 0); MemoryBuffer output_buffer( - m_outputBuffer, COM_DATA_TYPE_COLOR_CHANNELS, getWidth(), getHeight()); + m_outputBuffer, COM_DATA_TYPE_COLOR_CHANNELS, display_width_, display_height_); const MemoryBuffer *input_image = inputs[0]; - output_buffer.copy_from(input_image, area); + output_buffer.copy_from(input_image, area, offset_x, offset_y); if (this->m_useAlphaInput) { const MemoryBuffer *input_alpha = inputs[1]; - output_buffer.copy_from(input_alpha, area, 0, COM_DATA_TYPE_VALUE_CHANNELS, 3); + output_buffer.copy_from( + input_alpha, area, 0, COM_DATA_TYPE_VALUE_CHANNELS, offset_x, offset_y, 3); } if (m_depthBuffer) { MemoryBuffer depth_buffer( - m_depthBuffer, COM_DATA_TYPE_VALUE_CHANNELS, getWidth(), getHeight()); + m_depthBuffer, COM_DATA_TYPE_VALUE_CHANNELS, display_width_, display_height_); const MemoryBuffer *input_depth = inputs[2]; - depth_buffer.copy_from(input_depth, area); + depth_buffer.copy_from(input_depth, area, offset_x, offset_y); } - updateImage(&area); + rcti display_area; + BLI_rcti_init(&display_area, + offset_x, + offset_x + BLI_rcti_size_x(&area), + offset_y, + offset_y + BLI_rcti_size_y(&area)); + updateImage(&display_area); } void ViewerOperation::clear_display_buffer() { BLI_assert(isActiveViewerOutput()); + if (exec_system_->is_breaked()) { + return; + } + initImage(); + if (m_outputBuffer == nullptr) { + return; + } + size_t buf_bytes = (size_t)m_ibuf->y * m_ibuf->x * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float); if (buf_bytes > 0) { memset(m_outputBuffer, 0, buf_bytes); diff --git a/source/blender/compositor/operations/COM_ViewerOperation.h b/source/blender/compositor/operations/COM_ViewerOperation.h index 06ac501a535..95ee982f692 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.h +++ b/source/blender/compositor/operations/COM_ViewerOperation.h @@ -50,13 +50,15 @@ class ViewerOperation : public MultiThreadedOperation { SocketReader *m_alphaInput; SocketReader *m_depthInput; + int display_width_; + int display_height_; + public: ViewerOperation(); void initExecution() override; void deinitExecution() override; void executeRegion(rcti *rect, unsigned int tileNumber) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; bool isOutputOperation(bool /*rendering*/) const override { if (G.background) { diff --git a/source/blender/compositor/operations/COM_WrapOperation.cc b/source/blender/compositor/operations/COM_WrapOperation.cc index 888602114cc..393128ded41 100644 --- a/source/blender/compositor/operations/COM_WrapOperation.cc +++ b/source/blender/compositor/operations/COM_WrapOperation.cc @@ -33,7 +33,7 @@ inline float WrapOperation::getWrappedOriginalXPos(float x) return 0; } while (x < 0) { - x += this->m_width; + x += this->getWidth(); } return fmodf(x, this->getWidth()); } @@ -44,7 +44,7 @@ inline float WrapOperation::getWrappedOriginalYPos(float y) return 0; } while (y < 0) { - y += this->m_height; + y += this->getHeight(); } return fmodf(y, this->getHeight()); } diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cc b/source/blender/compositor/operations/COM_WriteBufferOperation.cc index 6380f6bf3df..a1c1e514eb7 100644 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.cc +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cc @@ -50,7 +50,7 @@ void WriteBufferOperation::executePixelSampled(float output[4], void WriteBufferOperation::initExecution() { this->m_input = this->getInputOperation(0); - this->m_memoryProxy->allocate(this->m_width, this->m_height); + this->m_memoryProxy->allocate(this->getWidth(), this->getHeight()); } void WriteBufferOperation::deinitExecution() @@ -206,18 +206,17 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, delete clKernelsToCleanUp; } -void WriteBufferOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) +void WriteBufferOperation::determine_canvas(const rcti &preferred_area, rcti &r_area) { - NodeOperation::determineResolution(resolution, preferredResolution); + NodeOperation::determine_canvas(preferred_area, r_area); /* make sure there is at least one pixel stored in case the input is a single value */ m_single_value = false; - if (resolution[0] == 0) { - resolution[0] = 1; + if (BLI_rcti_size_x(&r_area) == 0) { + r_area.xmax += 1; m_single_value = true; } - if (resolution[1] == 0) { - resolution[1] = 1; + if (BLI_rcti_size_y(&r_area) == 0) { + r_area.ymax += 1; m_single_value = true; } } diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.h b/source/blender/compositor/operations/COM_WriteBufferOperation.h index 2817fbe24b9..b7dededc69f 100644 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.h +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.h @@ -56,8 +56,7 @@ class WriteBufferOperation : public NodeOperation { unsigned int chunkNumber, MemoryBuffer **memoryBuffers, MemoryBuffer *outputBuffer) override; - void determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) override; + void determine_canvas(const rcti &preferred_area, rcti &r_area) override; void readResolutionFromInputSocket(); inline NodeOperation *getInput() { |