Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Castilla <manzanillawork@gmail.com>2021-09-28 20:33:06 +0300
committerManuel Castilla <manzanillawork@gmail.com>2021-09-28 23:00:17 +0300
commitf84fb12f5d72433780a96c3cc4381399f153cf1a (patch)
tree62ca25765b3b5ccc2bc8ca35449ddd8f3999071a /source/blender/compositor/operations
parent76377f0176b9561a7fc8f46b4ed704c631ddd90d (diff)
Compositor: Add support for canvas compositing
This commit adds functionality for operations that require pixel translation or resizing on "Full Frame" mode, allowing to adjust their canvas. It fixes most cropping issues in translate, scale, rotate and transform nodes by adjusting their canvas to the result, instead of the input canvas. Operations output buffer is still always on (0,0) position for easier image algorithm implementation, even when the canvas is not. Current limitations (will be addressed on bcon2): - Displayed translation in Viewer node is limited to 6000px. - When scaling up the canvas size is limited to the scene resolution size x 1.5 . From that point it crops. If none of these limitations are hit, the Viewer node displays the full input with any translation. Differential Revision: https://developer.blender.org/D12466
Diffstat (limited to 'source/blender/compositor/operations')
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_CalculateMeanOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc14
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.h9
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc17
-rw-r--r--source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h1
-rw-r--r--source/blender/compositor/operations/COM_RotateOperation.cc133
-rw-r--r--source/blender/compositor/operations/COM_RotateOperation.h25
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.cc263
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.h72
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc17
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h1
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cc32
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_TransformOperation.cc205
-rw-r--r--source/blender/compositor/operations/COM_TransformOperation.h20
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.cc35
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.h27
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc6
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cc58
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.h3
25 files changed, 726 insertions, 228 deletions
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cc b/source/blender/compositor/operations/COM_BokehBlurOperation.cc
index 3f61a300849..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);
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_MovieClipAttributeOperation.cc b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
index 5654ea0425d..aed91d4d46e 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
@@ -31,6 +31,7 @@ MovieClipAttributeOperation::MovieClipAttributeOperation()
this->m_invert = false;
needs_canvas_to_get_constant_ = true;
is_value_calculated_ = false;
+ stabilization_resolution_socket_ = nullptr;
}
void MovieClipAttributeOperation::initExecution()
@@ -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;
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
index e42605e5026..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:
/**
@@ -76,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_PlaneDistortCommonOperation.cc b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
index ab45899b7f5..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;
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cc b/source/blender/compositor/operations/COM_PreviewOperation.cc
index 7b1dd89bd75..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;
@@ -162,7 +162,7 @@ void PreviewOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti
width = width * this->m_divider;
height = height * this->m_divider;
- BLI_rcti_init(&r_area, 0, width, 0, 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_ProjectorLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
index faebaf657cc..2982f59a019 100644
--- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
+++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
@@ -131,6 +131,23 @@ 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)
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_RotateOperation.cc b/source/blender/compositor/operations/COM_RotateOperation.cc
index 8578e5c3269..9e26c93feac 100644
--- a/source/blender/compositor/operations/COM_RotateOperation.cc
+++ b/source/blender/compositor/operations/COM_RotateOperation.cc
@@ -25,8 +25,8 @@ 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->set_canvas_input_index(0);
this->m_imageSocket = nullptr;
@@ -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,6 +216,26 @@ 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)
@@ -169,7 +246,10 @@ 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);
+
+ 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_);
}
@@ -177,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 f5a423ea8e3..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->set_canvas_input_index(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(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(
- rcti &rect, float center_x, float center_y, float scale_x, float scale_y)
+bool ScaleOperation::is_scaling_variable()
{
- 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);
+ 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 scale_x, float scale_y)
+void ScaleOperation::scale_area(rcti &area, float relative_scale_x, float relative_scale_y)
{
- scale_area(rect, m_centerX, m_centerY, scale_x, 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::clamp_area_size_max(rcti &area, Size2f max_size)
+{
+
+ 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();
@@ -272,11 +384,12 @@ ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation()
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;
@@ -371,9 +504,21 @@ void ScaleFixedSizeOperation::determine_canvas(const rcti &preferred_area, rcti
rcti local_preferred = preferred_area;
local_preferred.xmax = local_preferred.xmin + m_newWidth;
local_preferred.ymax = local_preferred.ymin + m_newHeight;
- BaseScaleOperation::determine_canvas(local_preferred, r_area);
- r_area.xmax = r_area.xmin + m_newWidth;
- r_area.ymax = r_area.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,
@@ -382,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);
}
@@ -398,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 04fa4fe62d1..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;
}
};
@@ -144,7 +180,6 @@ class ScaleFixedSizeOperation : public BaseScaleOperation {
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)
@@ -173,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 87949a1b24f..21d9210bdac 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
@@ -382,6 +382,23 @@ 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)
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_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc
index 94977ed5adf..c06e3ac7cb0 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cc
+++ b/source/blender/compositor/operations/COM_TextureOperation.cc
@@ -74,26 +74,18 @@ void TextureBaseOperation::deinitExecution()
void TextureBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- switch (execution_model_) {
- case eExecutionModel::Tiled: {
- 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;
- }
- break;
- }
- case eExecutionModel::FullFrame: {
- /* Determine inputs. */
- rcti temp;
- NodeOperation::determine_canvas(preferred_area, temp);
-
- /* Don't use input areas, they are only used as parameters. */
- r_area = preferred_area;
- 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_TonemapOperation.cc b/source/blender/compositor/operations/COM_TonemapOperation.cc
index 67eb26993d0..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;
diff --git a/source/blender/compositor/operations/COM_TransformOperation.cc b/source/blender/compositor/operations/COM_TransformOperation.cc
index f73c9e9d956..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_CONSTANT_INPUT_AREA_OF_INTEREST;
- 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 266e960037c..9868f21654e 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.cc
+++ b/source/blender/compositor/operations/COM_TranslateOperation.cc
@@ -23,11 +23,11 @@ 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->set_canvas_input_index(0);
this->m_inputOperation = 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 0fe44e3a61f..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);
@@ -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;
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cc b/source/blender/compositor/operations/COM_ViewerOperation.cc
index 1cb98ac8474..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();
}
}
@@ -130,6 +133,7 @@ void ViewerOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
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);
}
@@ -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 e759bcf9898..95ee982f692 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.h
+++ b/source/blender/compositor/operations/COM_ViewerOperation.h
@@ -50,6 +50,9 @@ class ViewerOperation : public MultiThreadedOperation {
SocketReader *m_alphaInput;
SocketReader *m_depthInput;
+ int display_width_;
+ int display_height_;
+
public:
ViewerOperation();
void initExecution() override;