diff options
Diffstat (limited to 'source/blender/compositor/operations')
-rw-r--r-- | source/blender/compositor/operations/COM_ScaleOperation.cc | 188 | ||||
-rw-r--r-- | source/blender/compositor/operations/COM_ScaleOperation.h | 67 |
2 files changed, 196 insertions, 59 deletions
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc index f03b9fcf34d..2cb61ae746b 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cc +++ b/source/blender/compositor/operations/COM_ScaleOperation.cc @@ -17,6 +17,7 @@ */ #include "COM_ScaleOperation.h" +#include "COM_ConstantOperation.h" namespace blender::compositor { @@ -52,13 +53,60 @@ ScaleOperation::ScaleOperation(DataType data_type) : BaseScaleOperation() this->m_inputXOperation = nullptr; this->m_inputYOperation = nullptr; } + +static std::optional<float> get_constant_scale(NodeOperation *op) +{ + if (op->get_flags().is_constant_operation) { + return ((ConstantOperation *)op)->get_constant_elem()[0]; + } + + return std::optional<float>(); +} + +float ScaleOperation::get_constant_scale_x() +{ + std::optional<float> scale_x = get_constant_scale(getInputOperation(1)); + if (scale_x.has_value()) { + return scale_x.value() * get_relative_scale_x_factor(); + } + + return 1.0f; +} + +float ScaleOperation::get_constant_scale_y() +{ + std::optional<float> scale_y = get_constant_scale(getInputOperation(2)); + if (scale_y.has_value()) { + return scale_y.value() * get_relative_scale_y_factor(); + } + + return 1.0f; +} + +BLI_INLINE float scale_coord(const int coord, const float center, const float relative_scale) +{ + return center + (coord - center) / relative_scale; +} + +void ScaleOperation::scale_area(rcti &rect, float scale_x, float scale_y) +{ + rect.xmin = scale_coord(rect.xmin, m_centerX, scale_x); + rect.xmax = scale_coord(rect.xmax, m_centerX, scale_x); + rect.ymin = scale_coord(rect.ymin, m_centerY, scale_y); + rect.ymax = scale_coord(rect.ymax, m_centerY, scale_y); +} + +void ScaleOperation::init_data() +{ + m_centerX = getWidth() / 2.0f; + m_centerY = getHeight() / 2.0f; +} + void ScaleOperation::initExecution() { this->m_inputOperation = this->getInputSocketReader(0); this->m_inputXOperation = this->getInputSocketReader(1); this->m_inputYOperation = this->getInputSocketReader(2); - this->m_centerX = this->getWidth() / 2.0; - this->m_centerY = this->getHeight() / 2.0; } void ScaleOperation::deinitExecution() @@ -68,7 +116,52 @@ void ScaleOperation::deinitExecution() this->m_inputYOperation = nullptr; } -void ScaleOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +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) { + return; + } + + float scale_x = get_constant_scale_x(); + float scale_y = get_constant_scale_y(); + scale_area(r_input_area, scale_x, scale_y); + expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler); +} + +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(); + 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); + } +} + +ScaleRelativeOperation::ScaleRelativeOperation() : ScaleOperation() +{ +} + +ScaleRelativeOperation::ScaleRelativeOperation(DataType data_type) : ScaleOperation(data_type) +{ +} + +void ScaleRelativeOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) { PixelSampler effective_sampler = getEffectiveSampler(sampler); @@ -86,9 +179,9 @@ void ScaleOperation::executePixelSampled(float output[4], float x, float y, Pixe this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); } -bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) +bool ScaleRelativeOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) { rcti newInput; if (!m_variable_size) { @@ -115,34 +208,6 @@ bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } -// SCALE ABSOLUTE -ScaleAbsoluteOperation::ScaleAbsoluteOperation() : BaseScaleOperation() -{ - this->addInputSocket(DataType::Color); - this->addInputSocket(DataType::Value); - this->addInputSocket(DataType::Value); - this->addOutputSocket(DataType::Color); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; - this->m_inputXOperation = nullptr; - this->m_inputYOperation = nullptr; -} -void ScaleAbsoluteOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - this->m_inputXOperation = this->getInputSocketReader(1); - this->m_inputYOperation = this->getInputSocketReader(2); - this->m_centerX = this->getWidth() / 2.0; - this->m_centerY = this->getHeight() / 2.0; -} - -void ScaleAbsoluteOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; - this->m_inputXOperation = nullptr; - this->m_inputYOperation = nullptr; -} - void ScaleAbsoluteOperation::executePixelSampled(float output[4], float x, float y, @@ -202,8 +267,7 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, newInput.ymax = this->getHeight(); newInput.ymin = 0; } - - return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + return ScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } // Absolute fixed size @@ -215,11 +279,12 @@ ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation() this->m_inputOperation = nullptr; this->m_is_offset = false; } -void ScaleFixedSizeOperation::initExecution() + +void ScaleFixedSizeOperation::init_data() { - this->m_inputOperation = this->getInputSocketReader(0); - this->m_relX = this->m_inputOperation->getWidth() / (float)this->m_newWidth; - this->m_relY = this->m_inputOperation->getHeight() / (float)this->m_newHeight; + 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; /* *** all the options below are for a fairly special case - camera framing *** */ if (this->m_offsetX != 0.0f || this->m_offsetY != 0.0f) { @@ -237,8 +302,8 @@ void ScaleFixedSizeOperation::initExecution() if (this->m_is_aspect) { /* apply aspect from clip */ - const float w_src = this->m_inputOperation->getWidth(); - const float h_src = this->m_inputOperation->getHeight(); + const float w_src = input_op->getWidth(); + const float h_src = input_op->getHeight(); /* destination aspect is already applied from the camera frame */ const float w_dst = this->m_newWidth; @@ -267,6 +332,11 @@ void ScaleFixedSizeOperation::initExecution() /* *** end framing options *** */ } +void ScaleFixedSizeOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); +} + void ScaleFixedSizeOperation::deinitExecution() { this->m_inputOperation = nullptr; @@ -315,4 +385,38 @@ void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], resolution[1] = this->m_newHeight; } +void ScaleFixedSizeOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + 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; + expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler); +} + +void ScaleFixedSizeOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_img = inputs[0]; + PixelSampler sampler = (PixelSampler)m_sampler; + 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); + } + } + else { + for (; !it.is_end(); ++it) { + input_img->read_elem_sampled(it.x * this->m_relX, it.y * this->m_relY, sampler, it.out); + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h index 2f9a7be92e6..b2f41a1e98a 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.h +++ b/source/blender/compositor/operations/COM_ScaleOperation.h @@ -18,11 +18,11 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class BaseScaleOperation : public NodeOperation { +class BaseScaleOperation : public MultiThreadedOperation { public: void setSampler(PixelSampler sampler) { @@ -46,7 +46,7 @@ class BaseScaleOperation : public NodeOperation { }; class ScaleOperation : public BaseScaleOperation { - private: + protected: SocketReader *m_inputOperation; SocketReader *m_inputXOperation; SocketReader *m_inputYOperation; @@ -56,31 +56,58 @@ class ScaleOperation : public BaseScaleOperation { public: ScaleOperation(); ScaleOperation(DataType data_type); - bool determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) override; - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + void init_data() override; void initExecution() override; void deinitExecution() override; -}; -class ScaleAbsoluteOperation : public BaseScaleOperation { - SocketReader *m_inputOperation; - SocketReader *m_inputXOperation; - SocketReader *m_inputYOperation; - float m_centerX; - float m_centerY; + 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; + + protected: + virtual float get_relative_scale_x_factor() = 0; + virtual float get_relative_scale_y_factor() = 0; + + private: + float get_constant_scale_x(); + float get_constant_scale_y(); + void scale_area(rcti &rect, float scale_x, float scale_y); +}; +class ScaleRelativeOperation : public ScaleOperation { public: - ScaleAbsoluteOperation(); + ScaleRelativeOperation(); + ScaleRelativeOperation(DataType data_type); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + float get_relative_scale_x_factor() override + { + return 1.0f; + } + float get_relative_scale_y_factor() override + { + return 1.0f; + } +}; - void initExecution() override; - void deinitExecution() override; +class ScaleAbsoluteOperation : public ScaleOperation { + public: + bool determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + float get_relative_scale_x_factor() override + { + return 1.0f / getWidth(); + } + float get_relative_scale_y_factor() override + { + return 1.0f / getHeight(); + } }; class ScaleFixedSizeOperation : public BaseScaleOperation { @@ -108,6 +135,7 @@ class ScaleFixedSizeOperation : public BaseScaleOperation { unsigned int preferredResolution[2]) 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) @@ -131,6 +159,11 @@ class ScaleFixedSizeOperation : public BaseScaleOperation { this->m_offsetX = x; this->m_offsetY = y; } + + 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; }; } // namespace blender::compositor |