diff options
author | Manuel Castilla <manzanillawork@gmail.com> | 2021-08-26 19:54:51 +0300 |
---|---|---|
committer | Manuel Castilla <manzanillawork@gmail.com> | 2021-08-26 19:54:51 +0300 |
commit | 1662bf8ebf5aacf577e091dbbbb3b6a0fd53ee56 (patch) | |
tree | 93a4d52f0dd3180cd99bb8352d3fb6cd613852a0 | |
parent | e8f41f1b9399471d83f99914c9a2c5074dc0beb3 (diff) |
Compositor: Initial support for canvas compositingcompositor-full-frame
29 files changed, 448 insertions, 194 deletions
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc index 2958e494b55..9a1b894c2c4 100644 --- a/source/blender/compositor/intern/COM_Converter.cc +++ b/source/blender/compositor/intern/COM_Converter.cc @@ -463,7 +463,9 @@ void COM_convert_canvas(NodeOperationBuilder &builder, /* Data type conversions are executed before resolutions to ensure convert operations have * resolution. This method have to ensure same datatypes are linked for new operations. */ BLI_assert(fromSocket->getDataType() == toSocket->getDataType()); + ResizeMode mode = toSocket->getResizeMode(); + BLI_assert(mode != ResizeMode::None); NodeOperation *toOperation = &toSocket->getOperation(); const float toWidth = toOperation->getWidth(); @@ -473,13 +475,12 @@ void COM_convert_canvas(NodeOperationBuilder &builder, const float fromHeight = fromOperation->getHeight(); bool doCenter = false; bool doScale = false; - float addX = (toWidth - fromWidth) / 2.0f; - float addY = (toHeight - fromHeight) / 2.0f; float scaleX = 0; float scaleY = 0; switch (mode) { case ResizeMode::None: + case ResizeMode::Align: break; case ResizeMode::Center: doCenter = true; @@ -514,63 +515,68 @@ void COM_convert_canvas(NodeOperationBuilder &builder, break; } - if (doCenter) { - NodeOperation *first = nullptr; - ScaleOperation *scaleOperation = nullptr; - if (doScale) { - scaleOperation = new ScaleRelativeOperation(fromSocket->getDataType()); - scaleOperation->getInputSocket(1)->setResizeMode(ResizeMode::None); - scaleOperation->getInputSocket(2)->setResizeMode(ResizeMode::None); - first = scaleOperation; - SetValueOperation *sxop = new SetValueOperation(); - sxop->setValue(scaleX); - builder.addLink(sxop->getOutputSocket(), scaleOperation->getInputSocket(1)); - SetValueOperation *syop = new SetValueOperation(); - syop->setValue(scaleY); - builder.addLink(syop->getOutputSocket(), scaleOperation->getInputSocket(2)); - builder.addOperation(sxop); - builder.addOperation(syop); - - const rcti &scale_canvas = fromOperation->get_canvas(); - scaleOperation->set_canvas(scale_canvas); - sxop->set_canvas(scale_canvas); - syop->set_canvas(scale_canvas); - builder.addOperation(scaleOperation); - } + NodeOperation *first = nullptr; + ScaleOperation *scaleOperation = nullptr; + if (doScale) { + scaleOperation = new ScaleRelativeOperation(fromSocket->getDataType()); + scaleOperation->getInputSocket(1)->setResizeMode(ResizeMode::None); + scaleOperation->getInputSocket(2)->setResizeMode(ResizeMode::None); + first = scaleOperation; + SetValueOperation *sxop = new SetValueOperation(); + sxop->setValue(scaleX); + builder.addLink(sxop->getOutputSocket(), scaleOperation->getInputSocket(1)); + SetValueOperation *syop = new SetValueOperation(); + syop->setValue(scaleY); + builder.addLink(syop->getOutputSocket(), scaleOperation->getInputSocket(2)); + builder.addOperation(sxop); + builder.addOperation(syop); - TranslateOperation *translateOperation = new TranslateOperation(toSocket->getDataType()); - translateOperation->getInputSocket(1)->setResizeMode(ResizeMode::None); - translateOperation->getInputSocket(2)->setResizeMode(ResizeMode::None); - if (!first) { - first = translateOperation; - } - SetValueOperation *xop = new SetValueOperation(); - xop->setValue(addX); - builder.addLink(xop->getOutputSocket(), translateOperation->getInputSocket(1)); - SetValueOperation *yop = new SetValueOperation(); - yop->setValue(addY); - builder.addLink(yop->getOutputSocket(), translateOperation->getInputSocket(2)); - builder.addOperation(xop); - builder.addOperation(yop); + unsigned int resolution[2] = {fromOperation->getWidth(), fromOperation->getHeight()}; + const rcti &scale_canvas = fromOperation->get_canvas(); + scaleOperation->set_canvas(scale_canvas); + sxop->set_canvas(scale_canvas); + syop->set_canvas(scale_canvas); + builder.addOperation(scaleOperation); + } - const rcti &translate_canvas = toOperation->get_canvas(); - translateOperation->set_canvas(translate_canvas); - xop->set_canvas(translate_canvas); - yop->set_canvas(translate_canvas); - builder.addOperation(translateOperation); + TranslateOperation *translateOperation = new TranslateOperation(toSocket->getDataType()); + translateOperation->getInputSocket(1)->setResizeMode(ResizeMode::None); + translateOperation->getInputSocket(2)->setResizeMode(ResizeMode::None); + if (!first) { + first = translateOperation; + } + const float addX = doCenter ? (toWidth - fromWidth) / 2.0f : 0.0f; + const float addY = doCenter ? (toHeight - fromHeight) / 2.0f : 0.0f; + SetValueOperation *xop = new SetValueOperation(); + xop->setValue(addX); + builder.addLink(xop->getOutputSocket(), translateOperation->getInputSocket(1)); + SetValueOperation *yop = new SetValueOperation(); + yop->setValue(addY); + builder.addLink(yop->getOutputSocket(), translateOperation->getInputSocket(2)); + builder.addOperation(xop); + builder.addOperation(yop); - if (doScale) { - translateOperation->getInputSocket(0)->setResizeMode(ResizeMode::None); - builder.addLink(scaleOperation->getOutputSocket(), translateOperation->getInputSocket(0)); - } + rcti translate_canvas = toOperation->get_canvas(); + if (mode == ResizeMode::Align) { + translate_canvas.xmax = translate_canvas.xmin + fromWidth; + translate_canvas.ymax = translate_canvas.ymin + fromHeight; + } + translateOperation->set_canvas(translate_canvas); + xop->set_canvas(translate_canvas); + yop->set_canvas(translate_canvas); + builder.addOperation(translateOperation); - /* remove previous link and replace */ - builder.removeInputLink(toSocket); - first->getInputSocket(0)->setResizeMode(ResizeMode::None); - toSocket->setResizeMode(ResizeMode::None); - builder.addLink(fromSocket, first->getInputSocket(0)); - builder.addLink(translateOperation->getOutputSocket(), toSocket); + if (doScale) { + translateOperation->getInputSocket(0)->setResizeMode(ResizeMode::None); + builder.addLink(scaleOperation->getOutputSocket(), translateOperation->getInputSocket(0)); } + + /* remove previous link and replace */ + builder.removeInputLink(toSocket); + first->getInputSocket(0)->setResizeMode(ResizeMode::None); + toSocket->setResizeMode(ResizeMode::None); + builder.addLink(fromSocket, first->getInputSocket(0)); + builder.addLink(translateOperation->getOutputSocket(), toSocket); } } // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc index 66d34e58a3d..1d429a5e229 100644 --- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc +++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc @@ -74,34 +74,61 @@ void FullFrameExecutionModel::determine_areas_to_render_and_reads() } } -Vector<MemoryBuffer *> FullFrameExecutionModel::get_input_buffers(NodeOperation *op) +/** + * Returns input buffers with an offset relative to given output coordinates. Returned memory + * buffers must be deleted. + */ +Vector<MemoryBuffer *> FullFrameExecutionModel::get_input_buffers(NodeOperation *op, + const int output_x, + const int output_y) { const int num_inputs = op->getNumberOfInputSockets(); Vector<MemoryBuffer *> inputs_buffers(num_inputs); for (int i = 0; i < num_inputs; i++) { - NodeOperation *input_op = op->get_input_operation(i); - inputs_buffers[i] = active_buffers_.get_rendered_buffer(input_op); + NodeOperation *input = op->get_input_operation(i); + const int offset_x = (input->get_canvas().xmin - op->get_canvas().xmin) + output_x; + const int offset_y = (input->get_canvas().ymin - op->get_canvas().ymin) + output_y; + MemoryBuffer *buf = active_buffers_.get_rendered_buffer(input); + + rcti rect = buf->get_rect(); + BLI_rcti_translate(&rect, offset_x, offset_y); + inputs_buffers[i] = new MemoryBuffer( + buf->getBuffer(), buf->get_num_channels(), rect, buf->is_a_single_elem()); } return inputs_buffers; } -MemoryBuffer *FullFrameExecutionModel::create_operation_buffer(NodeOperation *op) +MemoryBuffer *FullFrameExecutionModel::create_operation_buffer(NodeOperation *op, + const int output_x, + const int output_y) { + rcti rect; + BLI_rcti_init(&rect, output_x, output_x + op->getWidth(), output_y, output_y + op->getHeight()); + const DataType data_type = op->getOutputSocket(0)->getDataType(); const bool is_a_single_elem = op->get_flags().is_constant_operation; - return new MemoryBuffer(data_type, op->get_canvas(), is_a_single_elem); + return new MemoryBuffer(data_type, rect, is_a_single_elem); } void FullFrameExecutionModel::render_operation(NodeOperation *op) { - Vector<MemoryBuffer *> input_bufs = get_input_buffers(op); + /* Output has no offset for easier image algorithms implementation on operations. */ + constexpr int output_x = 0; + constexpr int output_y = 0; const bool has_outputs = op->getNumberOfOutputSockets() > 0; - MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op) : nullptr; + MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op, output_x, output_y) : nullptr; if (op->getWidth() > 0 && op->getHeight() > 0) { - Span<rcti> areas = active_buffers_.get_areas_to_render(op); + Vector<MemoryBuffer *> input_bufs = get_input_buffers(op, output_x, output_y); + const int op_offset_x = output_x - op->get_canvas().xmin; + const int op_offset_y = output_y - op->get_canvas().ymin; + Span<rcti> areas = active_buffers_.get_areas_to_render(op, op_offset_x, op_offset_y); op->render(op_buf, areas, input_bufs); DebugInfo::operation_rendered(op, op_buf); + + for (MemoryBuffer *buf : input_bufs) { + delete buf; + } } /* Even if operation has no resolution set the empty buffer. It will be clipped with a * TranslateOperation from convert resolutions if linked to an operation with resolution. */ @@ -241,9 +268,8 @@ void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, r BLI_assert(output_op->isOutputOperation(context_.isRendering())); /* By default return operation bounds (no border). */ - const int op_width = output_op->getWidth(); - const int op_height = output_op->getHeight(); - BLI_rcti_init(&r_area, 0, op_width, 0, op_height); + rcti canvas = output_op->get_canvas(); + r_area = canvas; const bool has_viewer_border = border_.use_viewer_border && (output_op->get_flags().is_viewer_operation || @@ -253,12 +279,13 @@ void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, r /* Get border with normalized coordinates. */ const rctf *norm_border = has_viewer_border ? border_.viewer_border : border_.render_border; - /* Return de-normalized border. */ - BLI_rcti_init(&r_area, - norm_border->xmin * op_width, - norm_border->xmax * op_width, - norm_border->ymin * op_height, - norm_border->ymax * op_height); + /* Return de-normalized border within canvas. */ + const int w = output_op->getWidth(); + const int h = output_op->getHeight(); + r_area.xmin = canvas.xmin + norm_border->xmin * w; + r_area.xmax = canvas.xmin + norm_border->xmax * w; + r_area.ymin = canvas.ymin + norm_border->ymin * h; + r_area.ymax = canvas.ymin + norm_border->ymax * h; } } diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h index f75d4f1afdc..66dfb8f052c 100644 --- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h +++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h @@ -61,8 +61,10 @@ class FullFrameExecutionModel : public ExecutionModel { void determine_areas_to_render_and_reads(); void render_operations(); void render_output_dependencies(NodeOperation *output_op); - Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op); - MemoryBuffer *create_operation_buffer(NodeOperation *op); + Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op, + const int output_x, + const int output_y); + MemoryBuffer *create_operation_buffer(NodeOperation *op, const int output_x, const int output_y); void render_operation(NodeOperation *op); void operation_finished(NodeOperation *operation); diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc index 1ae8e20eafb..3a9c184e2b4 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cc +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc @@ -122,6 +122,8 @@ void MemoryBuffer::set_strides() this->elem_stride = m_num_channels; this->row_stride = getWidth() * m_num_channels; } + to_positive_x_stride_ = m_rect.xmin < 0 ? -m_rect.xmin + 1 : (m_rect.xmin == 0 ? 1 : 0); + to_positive_y_stride_ = m_rect.ymin < 0 ? -m_rect.ymin + 1 : (m_rect.ymin == 0 ? 1 : 0); } void MemoryBuffer::clear() diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h index a4f99371a4f..5784ee4cd44 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.h +++ b/source/blender/compositor/intern/COM_MemoryBuffer.h @@ -114,6 +114,12 @@ class MemoryBuffer { */ bool owns_data_; + /** Stride to make any x coordinate within buffer positive (non-zero). */ + int to_positive_x_stride_; + + /** Stride to make any y coordinate within buffer positive (non-zero). */ + int to_positive_y_stride_; + public: /** * \brief construct new temporarily MemoryBuffer for an area @@ -176,7 +182,7 @@ class MemoryBuffer { */ float *get_elem(int x, int y) { - BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax); + BLI_assert(has_coords(x, y)); return m_buffer + get_coords_offset(x, y); } @@ -185,7 +191,7 @@ class MemoryBuffer { */ const float *get_elem(int x, int y) const { - BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax); + BLI_assert(has_coords(x, y)); return m_buffer + get_coords_offset(x, y); } @@ -196,7 +202,7 @@ class MemoryBuffer { void read_elem_checked(int x, int y, float *out) const { - if (x < m_rect.xmin || x >= m_rect.xmax || y < m_rect.ymin || y >= m_rect.ymax) { + if (!has_coords(x, y)) { clear_elem(out); } else { @@ -206,12 +212,7 @@ class MemoryBuffer { void read_elem_checked(float x, float y, float *out) const { - if (x < m_rect.xmin || x >= m_rect.xmax || y < m_rect.ymin || y >= m_rect.ymax) { - clear_elem(out); - } - else { - read_elem(x, y, out); - } + read_elem_checked(floor_x(x), floor_y(y), out); } void read_elem_bilinear(float x, float y, float *out) const @@ -286,8 +287,7 @@ class MemoryBuffer { */ float &get_value(int x, int y, int channel) { - BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax && - channel >= 0 && channel < m_num_channels); + BLI_assert(has_coords(x, y) && channel >= 0 && channel < m_num_channels); return m_buffer[get_coords_offset(x, y) + channel]; } @@ -296,8 +296,7 @@ class MemoryBuffer { */ const float &get_value(int x, int y, int channel) const { - BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax && - channel >= 0 && channel < m_num_channels); + BLI_assert(has_coords(x, y) && channel >= 0 && channel < m_num_channels); return m_buffer[get_coords_offset(x, y) + channel]; } @@ -306,7 +305,7 @@ class MemoryBuffer { */ const float *get_row_end(int y) const { - BLI_assert(y >= 0 && y < getHeight()); + BLI_assert(has_y(y)); return m_buffer + (is_a_single_elem() ? m_num_channels : get_coords_offset(getWidth(), y)); } @@ -681,6 +680,33 @@ class MemoryBuffer { return y - m_rect.ymin; } + template<typename T> bool has_coords(T x, T y) const + { + return has_x(x) && has_y(y); + } + + template<typename T> bool has_x(T x) const + { + return x >= m_rect.xmin && x < m_rect.xmax; + } + + template<typename T> bool has_y(T y) const + { + return y >= m_rect.ymin && y < m_rect.ymax; + } + + /* Fast floor functions. The caller should check result is within buffer bounds. It ceils in near + * cases and when given coordinate is negative and less than buffer rect `min - 1`. */ + int floor_x(float x) const + { + return (int)(x + to_positive_x_stride_) - to_positive_x_stride_; + } + + int floor_y(float y) const + { + return (int)(y + to_positive_y_stride_) - to_positive_y_stride_; + } + void copy_single_elem_from(const MemoryBuffer *src, int channel_offset, int elem_size, diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc index 550801a8cdd..8bb46700f22 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.cc +++ b/source/blender/compositor/intern/COM_NodeOperation.cc @@ -135,6 +135,23 @@ void NodeOperation::deinitExecution() { /* pass */ } + +void NodeOperation::set_canvas(const rcti &canvas_area) +{ + canvas_ = canvas_area; + flags.is_canvas_set = true; +} + +const rcti &NodeOperation::get_canvas() const +{ + return canvas_; +} + +void NodeOperation::unset_canvas() +{ + flags.is_canvas_set = false; +} + SocketReader *NodeOperation::getInputSocketReader(unsigned int inputSocketIndex) { return this->getInputSocket(inputSocketIndex)->getReader(); diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index 368ab6c4602..c49b6eccc59 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -60,9 +60,13 @@ enum class ResizeMode { /** \brief Center the input image to the center of the working area of the node, no resizing * occurs */ Center = NS_CR_CENTER, - /** \brief The bottom left of the input image is the bottom left of the working area of the node, - * no resizing occurs */ + /** No resizing or translation. */ None = NS_CR_NONE, + /** + * Input image is translated so that its bottom left matches the bottom left of the working area + * of the node, no resizing occurs. + */ + Align = 100, /** \brief Fit the width of the input image to the width of the working area of the node */ FitWidth = NS_CR_FIT_WIDTH, /** \brief Fit the height of the input image to the height of the working area of the node */ @@ -467,18 +471,9 @@ class NodeOperation { } virtual void deinitExecution(); - void set_canvas(const rcti &canvas_area) - { - if (!this->flags.is_canvas_set) { - canvas_ = canvas_area; - flags.is_canvas_set = true; - } - } - - const rcti &get_canvas() const - { - return canvas_; - } + void set_canvas(const rcti &canvas_area); + const rcti &get_canvas() const; + void unset_canvas(); /** * \brief is this operation the active viewer output @@ -535,12 +530,12 @@ class NodeOperation { unsigned int getWidth() const { - return BLI_rcti_size_x(&canvas_); + return BLI_rcti_size_x(&get_canvas()); } unsigned int getHeight() const { - return BLI_rcti_size_y(&canvas_); + return BLI_rcti_size_y(&get_canvas()); } inline void readSampled(float result[4], float x, float y, PixelSampler sampler) @@ -610,6 +605,7 @@ class NodeOperation { void addInputSocket(DataType datatype, ResizeMode resize_mode = ResizeMode::Center); void addOutputSocket(DataType datatype); + /* TODO(manzanilla): to be removed with tiled implementation. */ void setWidth(unsigned int width) { canvas_.xmax = canvas_.xmin + width; @@ -620,6 +616,7 @@ class NodeOperation { canvas_.ymax = canvas_.ymin + height; this->flags.is_canvas_set = true; } + SocketReader *getInputSocketReader(unsigned int inputSocketindex); NodeOperation *getInputOperation(unsigned int inputSocketindex); diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc index 895aaa8102b..86e5f175026 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc @@ -33,6 +33,7 @@ #include "COM_SetValueOperation.h" #include "COM_SetVectorOperation.h" #include "COM_SocketProxyOperation.h" +#include "COM_TranslateOperation.h" #include "COM_ViewerOperation.h" #include "COM_WriteBufferOperation.h" @@ -444,7 +445,7 @@ void NodeOperationBuilder::determine_canvases() if (link.to()->getResizeMode() != ResizeMode::None) { NodeOperation &from_op = link.from()->getOperation(); NodeOperation &to_op = link.to()->getOperation(); - if (from_op.getWidth() != to_op.getWidth() || from_op.getHeight() != to_op.getHeight()) { + if (!BLI_rcti_compare(&from_op.get_canvas(), &to_op.get_canvas())) { convert_links.append(link); } } diff --git a/source/blender/compositor/intern/COM_SharedOperationBuffers.cc b/source/blender/compositor/intern/COM_SharedOperationBuffers.cc index 7e0486b0f54..55153bd4f0a 100644 --- a/source/blender/compositor/intern/COM_SharedOperationBuffers.cc +++ b/source/blender/compositor/intern/COM_SharedOperationBuffers.cc @@ -76,9 +76,17 @@ void SharedOperationBuffers::register_read(NodeOperation *read_op) /** * Get registered areas given operation needs to render. */ -blender::Span<rcti> SharedOperationBuffers::get_areas_to_render(NodeOperation *op) +Vector<rcti> SharedOperationBuffers::get_areas_to_render(NodeOperation *op, + const int offset_x, + const int offset_y) { - return get_buffer_data(op).render_areas.as_span(); + Span<rcti> render_areas = get_buffer_data(op).render_areas.as_span(); + Vector<rcti> dst_areas; + for (rcti dst : render_areas) { + BLI_rcti_translate(&dst, offset_x, offset_y); + dst_areas.append(std::move(dst)); + } + return dst_areas; } /** diff --git a/source/blender/compositor/intern/COM_SharedOperationBuffers.h b/source/blender/compositor/intern/COM_SharedOperationBuffers.h index f7763cd8ae4..4461ba75cbe 100644 --- a/source/blender/compositor/intern/COM_SharedOperationBuffers.h +++ b/source/blender/compositor/intern/COM_SharedOperationBuffers.h @@ -53,7 +53,7 @@ class SharedOperationBuffers { bool has_registered_reads(NodeOperation *op); void register_read(NodeOperation *read_op); - blender::Span<rcti> get_areas_to_render(NodeOperation *op); + Vector<rcti> get_areas_to_render(NodeOperation *op, int offset_x, int offset_y); bool is_operation_rendered(NodeOperation *op); void set_rendered_buffer(NodeOperation *op, std::unique_ptr<MemoryBuffer> buffer); MemoryBuffer *get_rendered_buffer(NodeOperation *op); diff --git a/source/blender/compositor/nodes/COM_BoxMaskNode.cc b/source/blender/compositor/nodes/COM_BoxMaskNode.cc index 14f42cc42f7..8017e063a69 100644 --- a/source/blender/compositor/nodes/COM_BoxMaskNode.cc +++ b/source/blender/compositor/nodes/COM_BoxMaskNode.cc @@ -62,7 +62,7 @@ void BoxMaskNode::convertToOperations(NodeConverter &converter, scaleOperation->setOffset(0.0f, 0.0f); scaleOperation->setNewWidth(rd->xsch * render_size_factor); scaleOperation->setNewHeight(rd->ysch * render_size_factor); - scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::None); + scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::Align); converter.addOperation(scaleOperation); converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); diff --git a/source/blender/compositor/nodes/COM_EllipseMaskNode.cc b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc index 3b4f5ca8c94..752597ef937 100644 --- a/source/blender/compositor/nodes/COM_EllipseMaskNode.cc +++ b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc @@ -62,7 +62,7 @@ void EllipseMaskNode::convertToOperations(NodeConverter &converter, scaleOperation->setOffset(0.0f, 0.0f); scaleOperation->setNewWidth(rd->xsch * render_size_factor); scaleOperation->setNewHeight(rd->ysch * render_size_factor); - scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::None); + scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::Align); converter.addOperation(scaleOperation); converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cc b/source/blender/compositor/nodes/COM_ScaleNode.cc index 819d2e72f30..4b2d4382b75 100644 --- a/source/blender/compositor/nodes/COM_ScaleNode.cc +++ b/source/blender/compositor/nodes/COM_ScaleNode.cc @@ -81,7 +81,7 @@ void ScaleNode::convertToOperations(NodeConverter &converter, operation->setOffset(bnode->custom3, bnode->custom4); operation->setNewWidth(rd->xsch * render_size_factor); operation->setNewHeight(rd->ysch * render_size_factor); - operation->getInputSocket(0)->setResizeMode(ResizeMode::None); + operation->getInputSocket(0)->setResizeMode(ResizeMode::Align); converter.addOperation(operation); converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cc b/source/blender/compositor/nodes/COM_TranslateNode.cc index 3a3e98c3472..165a03baf41 100644 --- a/source/blender/compositor/nodes/COM_TranslateNode.cc +++ b/source/blender/compositor/nodes/COM_TranslateNode.cc @@ -41,7 +41,9 @@ void TranslateNode::convertToOperations(NodeConverter &converter, NodeInput *inputYSocket = this->getInputSocket(2); NodeOutput *outputSocket = this->getOutputSocket(0); - TranslateOperation *operation = new TranslateOperation(); + TranslateOperation *operation = context.get_execution_model() == eExecutionModel::Tiled ? + new TranslateOperation() : + new TranslateCanvasOperation(); operation->set_wrapping(data->wrap_axis); if (data->relative) { const RenderData *rd = context.getRenderData(); diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cc b/source/blender/compositor/operations/COM_BokehBlurOperation.cc index 1453571c3f3..fdc21e4a091 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); diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cc b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc index 5fff4da62ae..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; diff --git a/source/blender/compositor/operations/COM_CropOperation.cc b/source/blender/compositor/operations/COM_CropOperation.cc index 73805b76864..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; diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cc b/source/blender/compositor/operations/COM_MapUVOperation.cc index 5062b0c42cb..ba38e583b30 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.cc +++ b/source/blender/compositor/operations/COM_MapUVOperation.cc @@ -23,7 +23,7 @@ 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; diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc index 936d06d3842..ffb8616656a 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; diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cc b/source/blender/compositor/operations/COM_PreviewOperation.cc index e718eee2585..dcf376d2530 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; diff --git a/source/blender/compositor/operations/COM_RotateOperation.cc b/source/blender/compositor/operations/COM_RotateOperation.cc index 35276551ee7..ccf70c931d4 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.cc +++ b/source/blender/compositor/operations/COM_RotateOperation.cc @@ -25,7 +25,7 @@ namespace blender::compositor { RotateOperation::RotateOperation() { - this->addInputSocket(DataType::Color); + this->addInputSocket(DataType::Color, ResizeMode::Align); this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Color); this->set_canvas_input_index(0); @@ -69,8 +69,13 @@ void RotateOperation::get_area_rotation_bounds(const rcti &area, 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); + } + + NodeOperation *input = get_input_operation(0); + rotate_offset_x_ = ((int)input->getWidth() - (int)getWidth()) / 2.0f; + rotate_offset_y_ = ((int)input->getHeight() - (int)getHeight()) / 2.0f; } void RotateOperation::initExecution() @@ -159,6 +164,36 @@ 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 determined = getInputSocket(0)->determine_canvas(preferred_area, r_area); + if (determined) { + /* Degree input canvas need to be determined before getting its constant. */ + rcti unused; + if (get_input_operation(1)->get_flags().is_constant_operation) { + getInputSocket(1)->determine_canvas(r_area, unused); + } + + ensureDegree(); + + get_rotation_center(r_area, m_centerX, m_centerY); + + rcti rot_bounds; + get_area_rotation_bounds(r_area, m_centerX, m_centerY, m_sine, m_cosine, rot_bounds); + r_area.xmax = r_area.xmin + BLI_rcti_size_x(&rot_bounds); + r_area.ymax = r_area.ymin + BLI_rcti_size_y(&rot_bounds); + + /* Determine degree input canvas with scaled canvas as preferred. */ + get_input_operation(1)->unset_canvas(); + getInputSocket(1)->determine_canvas(r_area, unused); + } +} + void RotateOperation::get_area_of_interest(const int input_idx, const rcti &output_area, rcti &r_input_area) @@ -170,7 +205,14 @@ void RotateOperation::get_area_of_interest(const int input_idx, } ensureDegree(); - get_area_rotation_bounds(output_area, m_centerX, m_centerY, m_sine, m_cosine, r_input_area); + + float center_x; + float center_y; + get_rotation_center(get_input_operation(0)->get_canvas(), center_x, center_y); + + r_input_area = output_area; + BLI_rcti_translate(&r_input_area, rotate_offset_x_, rotate_offset_y_); + get_area_rotation_bounds(r_input_area, center_x, center_y, m_sine, m_cosine, r_input_area); expand_area_for_sampler(r_input_area, sampler_); } @@ -178,12 +220,14 @@ void RotateOperation::update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> inputs) { - ensureDegree(); const MemoryBuffer *input_img = inputs[0]; + float center_x; + float center_y; + get_rotation_center(input_img->get_rect(), center_x, center_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); + float x = rotate_offset_x_ + it.x; + float y = rotate_offset_y_ + it.y; + rotate_coords(x, y, center_x, center_y, m_sine, m_cosine); input_img->read_elem_sampled(x, y, sampler_, it.out); } } diff --git a/source/blender/compositor/operations/COM_RotateOperation.h b/source/blender/compositor/operations/COM_RotateOperation.h index 56224811238..e3aabc835a0 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.h +++ b/source/blender/compositor/operations/COM_RotateOperation.h @@ -26,13 +26,17 @@ class RotateOperation : public MultiThreadedOperation { private: 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; bool m_isDegreeSet; PixelSampler sampler_; + float rotate_offset_x_; + float rotate_offset_y_; public: RotateOperation(); @@ -45,6 +49,15 @@ class RotateOperation : public MultiThreadedOperation { x = center_x + (cosine * dx + sine * dy); y = center_y + (-sine * dx + cosine * dy); } + + static void get_rotation_center(const rcti &area, float &r_x, float &r_y) + { + r_x = area.xmin + (BLI_rcti_size_x(&area) - 1) / 2.0; + r_y = area.ymin + (BLI_rcti_size_y(&area) - 1) / 2.0; + } + + // static void rotate_area( + // rcti& area, float center_x, float center_y, float sine, float cosine); static void get_area_rotation_bounds(const rcti &area, const float center_x, const float center_y, @@ -74,6 +87,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 5e46bf05f04..4408d4c7095 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cc +++ b/source/blender/compositor/operations/COM_ScaleOperation.cc @@ -44,11 +44,11 @@ ScaleOperation::ScaleOperation() : ScaleOperation(DataType::Color) ScaleOperation::ScaleOperation(DataType data_type) : BaseScaleOperation() { - this->addInputSocket(data_type); + this->addInputSocket(data_type, ResizeMode::Align); this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); this->addOutputSocket(data_type); - this->set_canvas_input_index(0); + this->set_canvas_input_index(IMAGE_INPUT_INDEX); this->m_inputOperation = nullptr; this->m_inputXOperation = nullptr; this->m_inputYOperation = nullptr; @@ -64,34 +64,43 @@ 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(1, get_relative_scale_x_factor()); + return get_constant_scale(X_INPUT_INDEX, get_relative_scale_x_factor(width)); } -float ScaleOperation::get_constant_scale_y() +float ScaleOperation::get_constant_scale_y(const float height) { - return get_constant_scale(2, get_relative_scale_y_factor()); + return get_constant_scale(Y_INPUT_INDEX, get_relative_scale_y_factor(height)); } -void ScaleOperation::scale_area( +void ScaleOperation::scale_area_inverted( rcti &rect, float center_x, float center_y, float scale_x, float 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); + rect.xmin = scale_coord_inverted(rect.xmin, center_x, scale_x); + rect.xmax = scale_coord_inverted(rect.xmax, center_x, scale_x); + rect.ymin = scale_coord_inverted(rect.ymin, center_y, scale_y); + rect.ymax = scale_coord_inverted(rect.ymax, center_y, scale_y); } -void ScaleOperation::scale_area(rcti &rect, float scale_x, float scale_y) +void ScaleOperation::scale_area(rcti &rect, + float scale_offset_x, + float scale_offset_y, + float relative_scale_x, + float relative_scale_y) { - scale_area(rect, m_centerX, m_centerY, scale_x, scale_y); + rect.xmin = scale_coord(rect.xmin, scale_offset_x, relative_scale_x); + rect.xmax = scale_coord(rect.xmax, scale_offset_x, relative_scale_x); + rect.ymin = scale_coord(rect.ymin, scale_offset_y, relative_scale_y); + rect.ymax = scale_coord(rect.ymax, scale_offset_y, relative_scale_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; + scale_offset_x_ = (input_width_scaled_ - getWidth()) / 2.0f; + scale_offset_y_ = (input_height_scaled_ - getHeight()) / 2.0f; } void ScaleOperation::initExecution() @@ -117,31 +126,71 @@ void ScaleOperation::get_area_of_interest(const int input_idx, 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); + NodeOperation *input_img = get_input_operation(IMAGE_INPUT_INDEX); + const float scale_x = get_constant_scale_x(input_img->getWidth()); + const float scale_y = get_constant_scale_y(input_img->getHeight()); + scale_area(r_input_area, scale_offset_x_, scale_offset_y_, scale_x, scale_y); } 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(); + const MemoryBuffer *input_img = inputs[IMAGE_INPUT_INDEX]; + MemoryBuffer *input_x = inputs[X_INPUT_INDEX]; + MemoryBuffer *input_y = inputs[Y_INPUT_INDEX]; + const float scale_x_factor = get_relative_scale_x_factor(input_img->getWidth()); + const float scale_y_factor = get_relative_scale_y_factor(input_img->getHeight()); 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); + const float scaled_x = scale_coord(it.x, scale_offset_x_, rel_scale_x); + const float scaled_y = scale_coord(it.y, scale_offset_y_, rel_scale_y); input_img->read_elem_sampled(scaled_x, scaled_y, (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 determined = getInputSocket(0)->determine_canvas(preferred_area, r_area); + if (determined) { + /* Constant input canvases need to be determined before getting constants. */ + rcti unused; + if (get_input_operation(X_INPUT_INDEX)->get_flags().is_constant_operation) { + getInputSocket(X_INPUT_INDEX)->determine_canvas(r_area, unused); + } + if (get_input_operation(Y_INPUT_INDEX)->get_flags().is_constant_operation) { + getInputSocket(Y_INPUT_INDEX)->determine_canvas(r_area, unused); + } + + const float width = BLI_rcti_size_x(&r_area); + const float height = BLI_rcti_size_y(&r_area); + const float scale_x = get_constant_scale_x(width); + const float scale_y = get_constant_scale_y(height); + + input_width_scaled_ = width * scale_x; + input_height_scaled_ = height * scale_y; + const float max_scale_width = width * MAX_CANVAS_SCALE_FACTOR; + const float max_scale_height = height * MAX_CANVAS_SCALE_FACTOR; + r_area.xmax = r_area.xmin + + (input_width_scaled_ < max_scale_width ? input_width_scaled_ : max_scale_width); + r_area.ymax = r_area.ymin + (input_height_scaled_ < max_scale_height ? input_height_scaled_ : + max_scale_height); + + /* Determine x/y inputs canvases with scaled canvas as preferred. */ + get_input_operation(X_INPUT_INDEX)->unset_canvas(); + get_input_operation(Y_INPUT_INDEX)->unset_canvas(); + getInputSocket(X_INPUT_INDEX)->determine_canvas(r_area, unused); + getInputSocket(Y_INPUT_INDEX)->determine_canvas(r_area, unused); + } +} + ScaleRelativeOperation::ScaleRelativeOperation() : ScaleOperation() { } @@ -166,8 +215,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 +235,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 +271,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 +297,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(); @@ -265,7 +318,7 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, // Absolute fixed size ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation() { - this->addInputSocket(DataType::Color, ResizeMode::None); + this->addInputSocket(DataType::Color, ResizeMode::Align); this->addOutputSocket(DataType::Color); this->set_canvas_input_index(0); this->m_inputOperation = nullptr; diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h index 04fa4fe62d1..2f33bbb5032 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.h +++ b/source/blender/compositor/operations/COM_ScaleOperation.h @@ -47,24 +47,49 @@ class BaseScaleOperation : public MultiThreadedOperation { class ScaleOperation : public BaseScaleOperation { public: - static constexpr float MIN_SCALE = 0.0001f; + static constexpr float MIN_SCALE_FACTOR = 0.0001f; + static constexpr float MAX_CANVAS_SCALE_FACTOR = 2.0f; 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_; + float input_width_scaled_; + float input_height_scaled_; + float scale_offset_x_; + float scale_offset_y_; public: ScaleOperation(); ScaleOperation(DataType data_type); - static float scale_coord(const float coord, const float center, const float relative_scale) + /** Scale a coordinate from a center inverting given relative scale . */ + static float scale_coord_inverted(const float coord, + const float center, + const float relative_scale) + { + return center + (coord - center) / MAX2(relative_scale, MIN_SCALE_FACTOR); + } + + static float scale_coord(float coord, float scale_offset, float relative_scale) { - return center + (coord - center) / MAX2(relative_scale, MIN_SCALE); + return (scale_offset + coord) / + (relative_scale < MIN_SCALE_FACTOR ? MIN_SCALE_FACTOR : relative_scale); } - static void scale_area(rcti &rect, float center_x, float center_y, float scale_x, float scale_y); + + static void scale_area(rcti &rect, + float scale_offset_x, + float scale_offset_y, + float relative_scale_x, + float relative_scale_y); + static void scale_area_inverted( + rcti &rect, float center_x, float center_y, float scale_x, float scale_y); void init_data() override; void initExecution() override; @@ -75,15 +100,16 @@ 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: 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 +120,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 width) override { return 1.0f; } - float get_relative_scale_y_factor() override + + float get_relative_scale_y_factor(float height) override { return 1.0f; } @@ -110,13 +138,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; } }; diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cc b/source/blender/compositor/operations/COM_TonemapOperation.cc index 1c65ad6ed32..b1abe91eff8 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; diff --git a/source/blender/compositor/operations/COM_TransformOperation.cc b/source/blender/compositor/operations/COM_TransformOperation.cc index 0feca07ac82..1cbdf690b08 100644 --- a/source/blender/compositor/operations/COM_TransformOperation.cc +++ b/source/blender/compositor/operations/COM_TransformOperation.cc @@ -86,7 +86,7 @@ void TransformOperation::get_area_of_interest(const int input_idx, case 0: { r_input_area = output_area; BLI_rcti_translate(&r_input_area, translate_x_, translate_y_); - ScaleOperation::scale_area( + ScaleOperation::scale_area_inverted( r_input_area, scale_center_x_, scale_center_y_, constant_scale_, constant_scale_); RotateOperation::get_area_rotation_bounds(r_input_area, rotate_center_x_, @@ -135,8 +135,8 @@ void TransformOperation::transform(BuffersIterator<float> &it, const MemoryBuffe float y = it.y - translate_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); + x = ScaleOperation::scale_coord_inverted(x, scale_center_x_, scale); + y = ScaleOperation::scale_coord_inverted(y, scale_center_y_, scale); input_img->read_elem_sampled(x, y, sampler_, it.out); } } @@ -146,8 +146,8 @@ void TransformOperation::transform_inverted(BuffersIterator<float> &it, { 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 = ScaleOperation::scale_coord_inverted(it.x, scale_center_x_, scale); + float y = ScaleOperation::scale_coord_inverted(it.y, scale_center_y_, scale); RotateOperation::rotate_coords( x, y, rotate_center_x_, rotate_center_y_, rotate_sine_, rotate_cosine_); x -= translate_x_; diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cc b/source/blender/compositor/operations/COM_TranslateOperation.cc index 266e960037c..96a7c00ee69 100644 --- a/source/blender/compositor/operations/COM_TranslateOperation.cc +++ b/source/blender/compositor/operations/COM_TranslateOperation.cc @@ -23,9 +23,9 @@ 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(data_type, resize_mode); this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); this->addOutputSocket(data_type); @@ -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); @@ -142,4 +143,21 @@ 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) +{ + getInputSocket(0)->determine_canvas(preferred_area, r_area); + + ensureDelta(); + BLI_rcti_translate(&r_area, getDeltaX(), getDeltaY()); + const rcti &preferred = r_area; + rcti unused; + getInputSocket(1)->determine_canvas(preferred, unused); + getInputSocket(2)->determine_canvas(preferred, unused); +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TranslateOperation.h b/source/blender/compositor/operations/COM_TranslateOperation.h index ce1965cecef..070b143fd9d 100644 --- a/source/blender/compositor/operations/COM_TranslateOperation.h +++ b/source/blender/compositor/operations/COM_TranslateOperation.h @@ -38,7 +38,7 @@ class TranslateOperation : public MultiThreadedOperation { public: TranslateOperation(); - TranslateOperation(DataType data_type); + TranslateOperation(DataType data_type, ResizeMode mode = ResizeMode::Center); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; @@ -93,4 +93,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 ccb62123774..320c8381d0a 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc @@ -28,11 +28,11 @@ 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 this->addInputSocket(DataType::Color, - ResizeMode::None); // inverse search radius optimization structure. + ResizeMode::Align); // inverse search radius optimization structure. #endif this->addOutputSocket(DataType::Color); flags.complex = true; @@ -440,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; |