1
1

Compare commits

...

2 Commits

Author SHA1 Message Date
313ea8a28e Compositor: Add support for canvas compositing
This patch adds functionality for operations that require pixels
translation or resizing on "Full Frame" mode, allowing to adjust
their canvas within the output canvas. It fixes current cropping
issues in translate, scale, rotate and transform nodes by adjusting
their canvas to the result, instead of the input canvas.
Only the scale node canvas is limited to the scene output
resolution size for performance reasons as there are many
operations that require their whole input to be rendered.

Operations output buffer is still always on (0,0) position for
easier image algorithm implementation, even when operation
canvas is not.
2021-09-12 20:00:03 +02:00
a0a9499a3a Compositor: Replace resolution concept by canvas
This is a code refactor in preparation of supporting canvas
compositing.

No functional changes, all canvases are at (0, 0) position matching
tiled implementation.
2021-09-12 19:18:08 +02:00
125 changed files with 1185 additions and 811 deletions

View File

@@ -121,7 +121,8 @@ constexpr float COM_PREVIEW_SIZE = 140.f;
constexpr float COM_RULE_OF_THIRDS_DIVIDER = 100.0f; constexpr float COM_RULE_OF_THIRDS_DIVIDER = 100.0f;
constexpr float COM_BLUR_BOKEH_PIXELS = 512; constexpr float COM_BLUR_BOKEH_PIXELS = 512;
constexpr rcti COM_SINGLE_ELEM_AREA = {0, 1, 0, 1}; constexpr rcti COM_AREA_NONE = {0, 0, 0, 0};
constexpr rcti COM_CONSTANT_INPUT_AREA_OF_INTEREST = COM_AREA_NONE;
constexpr IndexRange XRange(const rcti &area) constexpr IndexRange XRange(const rcti &area)
{ {

View File

@@ -24,12 +24,7 @@ BufferOperation::BufferOperation(MemoryBuffer *buffer, DataType data_type)
{ {
buffer_ = buffer; buffer_ = buffer;
inflated_buffer_ = nullptr; inflated_buffer_ = nullptr;
/* TODO: Implement a MemoryBuffer get_size() method returning a Size2d type. Shorten following set_canvas(buffer->get_rect());
* code to: set_resolution(buffer.get_size()) */
unsigned int resolution[2];
resolution[0] = buffer->getWidth();
resolution[1] = buffer->getHeight();
setResolution(resolution);
addOutputSocket(data_type); addOutputSocket(data_type);
flags.is_constant_operation = buffer_->is_a_single_elem(); flags.is_constant_operation = buffer_->is_a_single_elem();
flags.is_fullframe_operation = false; flags.is_fullframe_operation = false;

View File

@@ -43,6 +43,16 @@ int CompositorContext::getFramenumber() const
return m_rd->cfra; return m_rd->cfra;
} }
float CompositorContext::get_render_width() const
{
return getRenderData()->xsch * getRenderPercentageAsFactor();
}
float CompositorContext::get_render_height() const
{
return getRenderData()->ysch * getRenderPercentageAsFactor();
}
eExecutionModel CompositorContext::get_execution_model() const eExecutionModel CompositorContext::get_execution_model() const
{ {
if (U.experimental.use_full_frame_compositor) { if (U.experimental.use_full_frame_compositor) {

View File

@@ -288,6 +288,9 @@ class CompositorContext {
return m_rd->size * 0.01f; return m_rd->size * 0.01f;
} }
float get_render_width() const;
float get_render_height() const;
/** /**
* Get active execution model. * Get active execution model.
*/ */

View File

@@ -460,14 +460,16 @@ NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const Node
return nullptr; return nullptr;
} }
void COM_convert_resolution(NodeOperationBuilder &builder, void COM_convert_canvas(NodeOperationBuilder &builder,
NodeOperationOutput *fromSocket, NodeOperationOutput *fromSocket,
NodeOperationInput *toSocket) NodeOperationInput *toSocket)
{ {
/* Data type conversions are executed before resolutions to ensure convert operations have /* 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. */ * resolution. This method have to ensure same datatypes are linked for new operations. */
BLI_assert(fromSocket->getDataType() == toSocket->getDataType()); BLI_assert(fromSocket->getDataType() == toSocket->getDataType());
ResizeMode mode = toSocket->getResizeMode(); ResizeMode mode = toSocket->getResizeMode();
BLI_assert(mode != ResizeMode::None);
NodeOperation *toOperation = &toSocket->getOperation(); NodeOperation *toOperation = &toSocket->getOperation();
const float toWidth = toOperation->getWidth(); const float toWidth = toOperation->getWidth();
@@ -477,13 +479,12 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
const float fromHeight = fromOperation->getHeight(); const float fromHeight = fromOperation->getHeight();
bool doCenter = false; bool doCenter = false;
bool doScale = false; bool doScale = false;
float addX = (toWidth - fromWidth) / 2.0f;
float addY = (toHeight - fromHeight) / 2.0f;
float scaleX = 0; float scaleX = 0;
float scaleY = 0; float scaleY = 0;
switch (mode) { switch (mode) {
case ResizeMode::None: case ResizeMode::None:
case ResizeMode::Align:
break; break;
case ResizeMode::Center: case ResizeMode::Center:
doCenter = true; doCenter = true;
@@ -518,7 +519,6 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
break; break;
} }
if (doCenter) {
NodeOperation *first = nullptr; NodeOperation *first = nullptr;
ScaleOperation *scaleOperation = nullptr; ScaleOperation *scaleOperation = nullptr;
if (doScale) { if (doScale) {
@@ -535,10 +535,10 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
builder.addOperation(sxop); builder.addOperation(sxop);
builder.addOperation(syop); builder.addOperation(syop);
unsigned int resolution[2] = {fromOperation->getWidth(), fromOperation->getHeight()}; const rcti &scale_canvas = fromOperation->get_canvas();
scaleOperation->setResolution(resolution); scaleOperation->set_canvas(scale_canvas);
sxop->setResolution(resolution); sxop->set_canvas(scale_canvas);
syop->setResolution(resolution); syop->set_canvas(scale_canvas);
builder.addOperation(scaleOperation); builder.addOperation(scaleOperation);
} }
@@ -548,6 +548,8 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
if (!first) { if (!first) {
first = translateOperation; 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(); SetValueOperation *xop = new SetValueOperation();
xop->setValue(addX); xop->setValue(addX);
builder.addLink(xop->getOutputSocket(), translateOperation->getInputSocket(1)); builder.addLink(xop->getOutputSocket(), translateOperation->getInputSocket(1));
@@ -557,10 +559,14 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
builder.addOperation(xop); builder.addOperation(xop);
builder.addOperation(yop); builder.addOperation(yop);
unsigned int resolution[2] = {toOperation->getWidth(), toOperation->getHeight()}; rcti translate_canvas = toOperation->get_canvas();
translateOperation->setResolution(resolution); if (mode == ResizeMode::Align) {
xop->setResolution(resolution); translate_canvas.xmax = translate_canvas.xmin + fromWidth;
yop->setResolution(resolution); 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); builder.addOperation(translateOperation);
if (doScale) { if (doScale) {
@@ -574,7 +580,6 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
toSocket->setResizeMode(ResizeMode::None); toSocket->setResizeMode(ResizeMode::None);
builder.addLink(fromSocket, first->getInputSocket(0)); builder.addLink(fromSocket, first->getInputSocket(0));
builder.addLink(translateOperation->getOutputSocket(), toSocket); builder.addLink(translateOperation->getOutputSocket(), toSocket);
}
} }
} // namespace blender::compositor } // namespace blender::compositor

View File

@@ -65,7 +65,7 @@ NodeOperation *COM_convert_data_type(const NodeOperationOutput &from,
* \note Conversion logic is implemented in this function. * \note Conversion logic is implemented in this function.
* \see InputSocketResizeMode for the possible conversions. * \see InputSocketResizeMode for the possible conversions.
*/ */
void COM_convert_resolution(NodeOperationBuilder &builder, void COM_convert_canvas(NodeOperationBuilder &builder,
NodeOperationOutput *fromSocket, NodeOperationOutput *fromSocket,
NodeOperationInput *toSocket); NodeOperationInput *toSocket);

View File

@@ -162,8 +162,10 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system,
len += snprintf(str + len, len += snprintf(str + len,
maxlen > len ? maxlen - len : 0, maxlen > len ? maxlen - len : 0,
"#%d (%u,%u)", "#%d (%i,%i) (%u,%u)",
operation->get_id(), operation->get_id(),
operation->get_canvas().xmin,
operation->get_canvas().ymin,
operation->getWidth(), operation->getWidth(),
operation->getHeight()); operation->getHeight());

View File

@@ -74,37 +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(); const int num_inputs = op->getNumberOfInputSockets();
Vector<MemoryBuffer *> inputs_buffers(num_inputs); Vector<MemoryBuffer *> inputs_buffers(num_inputs);
for (int i = 0; i < num_inputs; i++) { for (int i = 0; i < num_inputs; i++) {
NodeOperation *input_op = op->get_input_operation(i); NodeOperation *input = op->get_input_operation(i);
inputs_buffers[i] = active_buffers_.get_rendered_buffer(input_op); 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; 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 op_rect; rcti rect;
BLI_rcti_init(&op_rect, 0, op->getWidth(), 0, op->getHeight()); 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 DataType data_type = op->getOutputSocket(0)->getDataType();
const bool is_a_single_elem = op->get_flags().is_constant_operation; const bool is_a_single_elem = op->get_flags().is_constant_operation;
return new MemoryBuffer(data_type, op_rect, is_a_single_elem); return new MemoryBuffer(data_type, rect, is_a_single_elem);
} }
void FullFrameExecutionModel::render_operation(NodeOperation *op) 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; 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) { 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); op->render(op_buf, areas, input_bufs);
DebugInfo::operation_rendered(op, op_buf); 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 /* 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. */ * TranslateOperation from convert resolutions if linked to an operation with resolution. */
@@ -190,7 +214,8 @@ void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op
std::pair<NodeOperation *, rcti> pair = stack.pop_last(); std::pair<NodeOperation *, rcti> pair = stack.pop_last();
NodeOperation *operation = pair.first; NodeOperation *operation = pair.first;
const rcti &render_area = pair.second; const rcti &render_area = pair.second;
if (active_buffers_.is_area_registered(operation, render_area)) { if (BLI_rcti_is_empty(&render_area) ||
active_buffers_.is_area_registered(operation, render_area)) {
continue; continue;
} }
@@ -199,12 +224,11 @@ void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op
const int num_inputs = operation->getNumberOfInputSockets(); const int num_inputs = operation->getNumberOfInputSockets();
for (int i = 0; i < num_inputs; i++) { for (int i = 0; i < num_inputs; i++) {
NodeOperation *input_op = operation->get_input_operation(i); NodeOperation *input_op = operation->get_input_operation(i);
rcti input_op_rect, input_area; rcti input_area;
BLI_rcti_init(&input_op_rect, 0, input_op->getWidth(), 0, input_op->getHeight());
operation->get_area_of_interest(input_op, render_area, input_area); operation->get_area_of_interest(input_op, render_area, input_area);
/* Ensure area of interest is within operation bounds, cropping areas outside. */ /* Ensure area of interest is within operation bounds, cropping areas outside. */
BLI_rcti_isect(&input_area, &input_op_rect, &input_area); BLI_rcti_isect(&input_area, &input_op->get_canvas(), &input_area);
stack.append({input_op, input_area}); stack.append({input_op, input_area});
} }
@@ -243,9 +267,8 @@ void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, r
BLI_assert(output_op->isOutputOperation(context_.isRendering())); BLI_assert(output_op->isOutputOperation(context_.isRendering()));
/* By default return operation bounds (no border). */ /* By default return operation bounds (no border). */
const int op_width = output_op->getWidth(); rcti canvas = output_op->get_canvas();
const int op_height = output_op->getHeight(); r_area = canvas;
BLI_rcti_init(&r_area, 0, op_width, 0, op_height);
const bool has_viewer_border = border_.use_viewer_border && const bool has_viewer_border = border_.use_viewer_border &&
(output_op->get_flags().is_viewer_operation || (output_op->get_flags().is_viewer_operation ||
@@ -255,12 +278,13 @@ void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, r
/* Get border with normalized coordinates. */ /* Get border with normalized coordinates. */
const rctf *norm_border = has_viewer_border ? border_.viewer_border : border_.render_border; const rctf *norm_border = has_viewer_border ? border_.viewer_border : border_.render_border;
/* Return de-normalized border. */ /* Return de-normalized border within canvas. */
BLI_rcti_init(&r_area, const int w = output_op->getWidth();
norm_border->xmin * op_width, const int h = output_op->getHeight();
norm_border->xmax * op_width, r_area.xmin = canvas.xmin + norm_border->xmin * w;
norm_border->ymin * op_height, r_area.xmax = canvas.xmin + norm_border->xmax * w;
norm_border->ymax * op_height); r_area.ymin = canvas.ymin + norm_border->ymin * h;
r_area.ymax = canvas.ymin + norm_border->ymax * h;
} }
} }

View File

@@ -61,8 +61,10 @@ class FullFrameExecutionModel : public ExecutionModel {
void determine_areas_to_render_and_reads(); void determine_areas_to_render_and_reads();
void render_operations(); void render_operations();
void render_output_dependencies(NodeOperation *output_op); void render_output_dependencies(NodeOperation *output_op);
Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op); Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op,
MemoryBuffer *create_operation_buffer(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 render_operation(NodeOperation *op);
void operation_finished(NodeOperation *operation); void operation_finished(NodeOperation *operation);

View File

@@ -122,6 +122,8 @@ void MemoryBuffer::set_strides()
this->elem_stride = m_num_channels; this->elem_stride = m_num_channels;
this->row_stride = getWidth() * 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() void MemoryBuffer::clear()

View File

@@ -114,6 +114,12 @@ class MemoryBuffer {
*/ */
bool owns_data_; 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: public:
/** /**
* \brief construct new temporarily MemoryBuffer for an area * \brief construct new temporarily MemoryBuffer for an area
@@ -176,7 +182,7 @@ class MemoryBuffer {
*/ */
float *get_elem(int x, int y) 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); return m_buffer + get_coords_offset(x, y);
} }
@@ -185,7 +191,7 @@ class MemoryBuffer {
*/ */
const float *get_elem(int x, int y) const 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); 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 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); clear_elem(out);
} }
else { else {
@@ -206,12 +212,7 @@ class MemoryBuffer {
void read_elem_checked(float x, float y, float *out) const 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) { read_elem_checked(floor_x(x), floor_y(y), out);
clear_elem(out);
}
else {
read_elem(x, y, out);
}
} }
void read_elem_bilinear(float x, float y, float *out) const 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) 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 && BLI_assert(has_coords(x, y) && channel >= 0 && channel < m_num_channels);
channel >= 0 && channel < m_num_channels);
return m_buffer[get_coords_offset(x, y) + channel]; 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 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 && BLI_assert(has_coords(x, y) && channel >= 0 && channel < m_num_channels);
channel >= 0 && channel < m_num_channels);
return m_buffer[get_coords_offset(x, y) + channel]; return m_buffer[get_coords_offset(x, y) + channel];
} }
@@ -306,7 +305,7 @@ class MemoryBuffer {
*/ */
const float *get_row_end(int y) const 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)); 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; 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, void copy_single_elem_from(const MemoryBuffer *src,
int channel_offset, int channel_offset,
int elem_size, int elem_size,

View File

@@ -35,12 +35,29 @@ namespace blender::compositor {
NodeOperation::NodeOperation() NodeOperation::NodeOperation()
{ {
this->m_resolutionInputSocketIndex = 0; canvas_input_index_ = 0;
this->m_width = 0; canvas_ = COM_AREA_NONE;
this->m_height = 0;
this->m_btree = nullptr; this->m_btree = nullptr;
} }
/** Get constant value when operation is constant, otherwise return default_value. */
float NodeOperation::get_constant_value_default(float default_value)
{
BLI_assert(m_outputs.size() > 0 && getOutputSocket()->getDataType() == DataType::Value);
return *get_constant_elem_default(&default_value);
}
/** Get constant elem when operation is constant, otherwise return default_elem. */
const float *NodeOperation::get_constant_elem_default(const float *default_elem)
{
BLI_assert(m_outputs.size() > 0);
if (get_flags().is_constant_operation) {
return static_cast<ConstantOperation *>(this)->get_constant_elem();
}
return default_elem;
}
/** /**
* Generate a hash that identifies the operation result in the current execution. * Generate a hash that identifies the operation result in the current execution.
* Requires `hash_output_params` to be implemented, otherwise `std::nullopt` is returned. * Requires `hash_output_params` to be implemented, otherwise `std::nullopt` is returned.
@@ -48,7 +65,7 @@ NodeOperation::NodeOperation()
*/ */
std::optional<NodeOperationHash> NodeOperation::generate_hash() std::optional<NodeOperationHash> NodeOperation::generate_hash()
{ {
params_hash_ = get_default_hash_2(m_width, m_height); params_hash_ = get_default_hash_2(canvas_.xmin, canvas_.xmax);
/* Hash subclasses params. */ /* Hash subclasses params. */
is_hash_output_params_implemented_ = true; is_hash_output_params_implemented_ = true;
@@ -57,7 +74,11 @@ std::optional<NodeOperationHash> NodeOperation::generate_hash()
return std::nullopt; return std::nullopt;
} }
hash_param(getOutputSocket()->getDataType()); hash_params(canvas_.ymin, canvas_.ymax);
if (m_outputs.size() > 0) {
BLI_assert(m_outputs.size() == 1);
hash_param(this->getOutputSocket()->getDataType());
}
NodeOperationHash hash; NodeOperationHash hash;
hash.params_hash_ = params_hash_; hash.params_hash_ = params_hash_;
@@ -108,48 +129,46 @@ void NodeOperation::addOutputSocket(DataType datatype)
m_outputs.append(NodeOperationOutput(this, datatype)); m_outputs.append(NodeOperationOutput(this, datatype));
} }
void NodeOperation::determineResolution(unsigned int resolution[2], void NodeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
unsigned int used_resolution_index = 0; unsigned int used_canvas_index = 0;
if (m_resolutionInputSocketIndex == RESOLUTION_INPUT_ANY) { if (canvas_input_index_ == RESOLUTION_INPUT_ANY) {
for (NodeOperationInput &input : m_inputs) { for (NodeOperationInput &input : m_inputs) {
unsigned int any_resolution[2] = {0, 0}; rcti any_area = COM_AREA_NONE;
input.determineResolution(any_resolution, preferredResolution); const bool determined = input.determine_canvas(preferred_area, any_area);
if (any_resolution[0] * any_resolution[1] > 0) { if (determined) {
resolution[0] = any_resolution[0]; r_area = any_area;
resolution[1] = any_resolution[1];
break; break;
} }
used_resolution_index += 1; used_canvas_index += 1;
} }
} }
else if (m_resolutionInputSocketIndex < m_inputs.size()) { else if (canvas_input_index_ < m_inputs.size()) {
NodeOperationInput &input = m_inputs[m_resolutionInputSocketIndex]; NodeOperationInput &input = m_inputs[canvas_input_index_];
input.determineResolution(resolution, preferredResolution); input.determine_canvas(preferred_area, r_area);
used_resolution_index = m_resolutionInputSocketIndex; used_canvas_index = canvas_input_index_;
} }
if (modify_determined_resolution_fn_) { if (modify_determined_canvas_fn_) {
modify_determined_resolution_fn_(resolution); modify_determined_canvas_fn_(r_area);
} }
unsigned int temp2[2] = {resolution[0], resolution[1]}; rcti unused_area;
unsigned int temp[2]; const rcti &local_preferred_area = r_area;
for (unsigned int index = 0; index < m_inputs.size(); index++) { for (unsigned int index = 0; index < m_inputs.size(); index++) {
if (index == used_resolution_index) { if (index == used_canvas_index) {
continue; continue;
} }
NodeOperationInput &input = m_inputs[index]; NodeOperationInput &input = m_inputs[index];
if (input.isConnected()) { if (input.isConnected()) {
input.determineResolution(temp, temp2); input.determine_canvas(local_preferred_area, unused_area);
} }
} }
} }
void NodeOperation::setResolutionInputSocketIndex(unsigned int index) void NodeOperation::set_canvas_input_index(unsigned int index)
{ {
this->m_resolutionInputSocketIndex = index; this->canvas_input_index_ = index;
} }
void NodeOperation::init_data() void NodeOperation::init_data()
@@ -185,6 +204,28 @@ void NodeOperation::deinitExecution()
{ {
/* pass */ /* 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_;
}
/**
* Mainly used for re-determining canvas of constant operations in cases where preferred canvas
* depends on the constant element.
*/
void NodeOperation::unset_canvas()
{
BLI_assert(m_inputs.size() == 0);
flags.is_canvas_set = false;
}
SocketReader *NodeOperation::getInputSocketReader(unsigned int inputSocketIndex) SocketReader *NodeOperation::getInputSocketReader(unsigned int inputSocketIndex)
{ {
return this->getInputSocket(inputSocketIndex)->getReader(); return this->getInputSocket(inputSocketIndex)->getReader();
@@ -260,7 +301,7 @@ void NodeOperation::get_area_of_interest(const int input_idx,
/* Non full-frame operations never implement this method. To ensure correctness assume /* Non full-frame operations never implement this method. To ensure correctness assume
* whole area is used. */ * whole area is used. */
NodeOperation *input_op = getInputOperation(input_idx); NodeOperation *input_op = getInputOperation(input_idx);
BLI_rcti_init(&r_input_area, 0, input_op->getWidth(), 0, input_op->getHeight()); r_input_area = input_op->get_canvas();
} }
} }
@@ -420,12 +461,16 @@ SocketReader *NodeOperationInput::getReader()
return nullptr; return nullptr;
} }
void NodeOperationInput::determineResolution(unsigned int resolution[2], /**
unsigned int preferredResolution[2]) * \return Whether canvas area could be determined.
*/
bool NodeOperationInput::determine_canvas(const rcti &preferred_area, rcti &r_area)
{ {
if (m_link) { if (m_link) {
m_link->determineResolution(resolution, preferredResolution); m_link->determine_canvas(preferred_area, r_area);
return !BLI_rcti_is_empty(&r_area);
} }
return false;
} }
/****************** /******************
@@ -437,18 +482,16 @@ NodeOperationOutput::NodeOperationOutput(NodeOperation *op, DataType datatype)
{ {
} }
void NodeOperationOutput::determineResolution(unsigned int resolution[2], void NodeOperationOutput::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
NodeOperation &operation = getOperation(); NodeOperation &operation = getOperation();
if (operation.get_flags().is_resolution_set) { if (operation.get_flags().is_canvas_set) {
resolution[0] = operation.getWidth(); r_area = operation.get_canvas();
resolution[1] = operation.getHeight();
} }
else { else {
operation.determineResolution(resolution, preferredResolution); operation.determine_canvas(preferred_area, r_area);
if (resolution[0] > 0 && resolution[1] > 0) { if (!BLI_rcti_is_empty(&r_area)) {
operation.setResolution(resolution); operation.set_canvas(r_area);
} }
} }
} }
@@ -470,8 +513,8 @@ std::ostream &operator<<(std::ostream &os, const NodeOperationFlags &node_operat
if (node_operation_flags.use_viewer_border) { if (node_operation_flags.use_viewer_border) {
os << "view_border,"; os << "view_border,";
} }
if (node_operation_flags.is_resolution_set) { if (node_operation_flags.is_canvas_set) {
os << "resolution_set,"; os << "canvas_set,";
} }
if (node_operation_flags.is_set_operation) { if (node_operation_flags.is_set_operation) {
os << "set_operation,"; os << "set_operation,";

View File

@@ -62,9 +62,13 @@ enum class ResizeMode {
/** \brief Center the input image to the center of the working area of the node, no resizing /** \brief Center the input image to the center of the working area of the node, no resizing
* occurs */ * occurs */
Center = NS_CR_CENTER, 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 or translation. */
* no resizing occurs */
None = NS_CR_NONE, 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 */ /** \brief Fit the width of the input image to the width of the working area of the node */
FitWidth = NS_CR_FIT_WIDTH, FitWidth = NS_CR_FIT_WIDTH,
/** \brief Fit the height of the input image to the height of the working area of the node */ /** \brief Fit the height of the input image to the height of the working area of the node */
@@ -130,7 +134,7 @@ class NodeOperationInput {
SocketReader *getReader(); SocketReader *getReader();
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); bool determine_canvas(const rcti &preferred_area, rcti &r_area);
#ifdef WITH_CXX_GUARDEDALLOC #ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation") MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
@@ -158,12 +162,7 @@ class NodeOperationOutput {
return m_datatype; return m_datatype;
} }
/** void determine_canvas(const rcti &preferred_area, rcti &r_area);
* \brief determine the resolution of this data going through this socket
* \param resolution: the result of this operation
* \param preferredResolution: the preferable resolution as no resolution could be determined
*/
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
#ifdef WITH_CXX_GUARDEDALLOC #ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation") MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
@@ -211,9 +210,9 @@ struct NodeOperationFlags {
bool use_viewer_border : 1; bool use_viewer_border : 1;
/** /**
* Is the resolution of the operation set. * Is the canvas of the operation set.
*/ */
bool is_resolution_set : 1; bool is_canvas_set : 1;
/** /**
* Is this a set operation (value, color, vector). * Is this a set operation (value, color, vector).
@@ -257,7 +256,7 @@ struct NodeOperationFlags {
open_cl = false; open_cl = false;
use_render_border = false; use_render_border = false;
use_viewer_border = false; use_viewer_border = false;
is_resolution_set = false; is_canvas_set = false;
is_set_operation = false; is_set_operation = false;
is_read_buffer_operation = false; is_read_buffer_operation = false;
is_write_buffer_operation = false; is_write_buffer_operation = false;
@@ -324,11 +323,11 @@ class NodeOperation {
bool is_hash_output_params_implemented_; bool is_hash_output_params_implemented_;
/** /**
* \brief the index of the input socket that will be used to determine the resolution * \brief the index of the input socket that will be used to determine the canvas
*/ */
unsigned int m_resolutionInputSocketIndex; unsigned int canvas_input_index_;
std::function<void(unsigned int resolution[2])> modify_determined_resolution_fn_; std::function<void(rcti &canvas)> modify_determined_canvas_fn_;
/** /**
* \brief mutex reference for very special node initializations * \brief mutex reference for very special node initializations
@@ -352,15 +351,7 @@ class NodeOperation {
*/ */
eExecutionModel execution_model_; eExecutionModel execution_model_;
/** rcti canvas_;
* Width of the output of this operation.
*/
unsigned int m_width;
/**
* Height of the output of this operation.
*/
unsigned int m_height;
/** /**
* Flags how to evaluate this operation. * Flags how to evaluate this operation.
@@ -374,11 +365,6 @@ class NodeOperation {
{ {
} }
void set_execution_model(const eExecutionModel model)
{
execution_model_ = model;
}
void set_name(const std::string name) void set_name(const std::string name)
{ {
m_name = name; m_name = name;
@@ -399,6 +385,9 @@ class NodeOperation {
return m_id; return m_id;
} }
float get_constant_value_default(float default_value);
const float *get_constant_elem_default(const float *default_elem);
const NodeOperationFlags get_flags() const const NodeOperationFlags get_flags() const
{ {
return flags; return flags;
@@ -424,14 +413,7 @@ class NodeOperation {
return getInputOperation(index); return getInputOperation(index);
} }
/** virtual void determine_canvas(const rcti &preferred_area, rcti &r_area);
* \brief determine the resolution of this node
* \note this method will not set the resolution, this is the responsibility of the caller
* \param resolution: the result of this operation
* \param preferredResolution: the preferable resolution as no resolution could be determined
*/
virtual void determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2]);
/** /**
* \brief isOutputOperation determines whether this operation is an output of the * \brief isOutputOperation determines whether this operation is an output of the
@@ -453,6 +435,11 @@ class NodeOperation {
return false; return false;
} }
void set_execution_model(const eExecutionModel model)
{
execution_model_ = model;
}
void setbNodeTree(const bNodeTree *tree) void setbNodeTree(const bNodeTree *tree)
{ {
this->m_btree = tree; this->m_btree = tree;
@@ -527,18 +514,9 @@ class NodeOperation {
} }
virtual void deinitExecution(); virtual void deinitExecution();
/** void set_canvas(const rcti &canvas_area);
* \brief set the resolution const rcti &get_canvas() const;
* \param resolution: the resolution to set void unset_canvas();
*/
void setResolution(unsigned int resolution[2])
{
if (!this->flags.is_resolution_set) {
this->m_width = resolution[0];
this->m_height = resolution[1];
this->flags.is_resolution_set = true;
}
}
/** /**
* \brief is this operation the active viewer output * \brief is this operation the active viewer output
@@ -557,18 +535,18 @@ class NodeOperation {
rcti *output); rcti *output);
/** /**
* \brief set the index of the input socket that will determine the resolution of this * \brief set the index of the input socket that will determine the canvas of this
* operation \param index: the index to set * operation \param index: the index to set
*/ */
void setResolutionInputSocketIndex(unsigned int index); void set_canvas_input_index(unsigned int index);
/** /**
* Set a custom function to modify determined resolution from main input just before setting it * Set a custom function to modify determined canvas from main input just before setting it
* as preferred resolution for the other inputs. * as preferred for the other inputs.
*/ */
void set_determined_resolution_modifier(std::function<void(unsigned int resolution[2])> fn) void set_determined_canvas_modifier(std::function<void(rcti &canvas)> fn)
{ {
modify_determined_resolution_fn_ = fn; modify_determined_canvas_fn_ = fn;
} }
/** /**
@@ -595,12 +573,12 @@ class NodeOperation {
unsigned int getWidth() const unsigned int getWidth() const
{ {
return m_width; return BLI_rcti_size_x(&get_canvas());
} }
unsigned int getHeight() const unsigned int getHeight() const
{ {
return m_height; return BLI_rcti_size_y(&get_canvas());
} }
inline void readSampled(float result[4], float x, float y, PixelSampler sampler) inline void readSampled(float result[4], float x, float y, PixelSampler sampler)
@@ -697,16 +675,18 @@ class NodeOperation {
void addInputSocket(DataType datatype, ResizeMode resize_mode = ResizeMode::Center); void addInputSocket(DataType datatype, ResizeMode resize_mode = ResizeMode::Center);
void addOutputSocket(DataType datatype); void addOutputSocket(DataType datatype);
/* TODO(manzanilla): to be removed with tiled implementation. */
void setWidth(unsigned int width) void setWidth(unsigned int width)
{ {
this->m_width = width; canvas_.xmax = canvas_.xmin + width;
this->flags.is_resolution_set = true; this->flags.is_canvas_set = true;
} }
void setHeight(unsigned int height) void setHeight(unsigned int height)
{ {
this->m_height = height; canvas_.ymax = canvas_.ymin + height;
this->flags.is_resolution_set = true; this->flags.is_canvas_set = true;
} }
SocketReader *getInputSocketReader(unsigned int inputSocketindex); SocketReader *getInputSocketReader(unsigned int inputSocketindex);
NodeOperation *getInputOperation(unsigned int inputSocketindex); NodeOperation *getInputOperation(unsigned int inputSocketindex);

View File

@@ -33,6 +33,7 @@
#include "COM_SetValueOperation.h" #include "COM_SetValueOperation.h"
#include "COM_SetVectorOperation.h" #include "COM_SetVectorOperation.h"
#include "COM_SocketProxyOperation.h" #include "COM_SocketProxyOperation.h"
#include "COM_TranslateOperation.h"
#include "COM_ViewerOperation.h" #include "COM_ViewerOperation.h"
#include "COM_WriteBufferOperation.h" #include "COM_WriteBufferOperation.h"
@@ -106,7 +107,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
folder.fold_operations(); folder.fold_operations();
} }
determineResolutions(); determine_canvases();
save_graphviz("compositor_prior_merging"); save_graphviz("compositor_prior_merging");
merge_equal_operations(); merge_equal_operations();
@@ -423,41 +424,50 @@ void NodeOperationBuilder::resolve_proxies()
} }
} }
void NodeOperationBuilder::determineResolutions() void NodeOperationBuilder::determine_canvases()
{ {
/* determine all resolutions of the operations (Width/Height) */ /* Determine all canvas areas of the operations. */
const rcti &preferred_area = COM_AREA_NONE;
for (NodeOperation *op : m_operations) { for (NodeOperation *op : m_operations) {
if (op->isOutputOperation(m_context->isRendering()) && !op->get_flags().is_preview_operation) { if (op->isOutputOperation(m_context->isRendering()) && !op->get_flags().is_preview_operation) {
unsigned int resolution[2] = {0, 0}; rcti canvas = COM_AREA_NONE;
unsigned int preferredResolution[2] = {0, 0}; op->determine_canvas(preferred_area, canvas);
op->determineResolution(resolution, preferredResolution); op->set_canvas(canvas);
op->setResolution(resolution);
} }
} }
for (NodeOperation *op : m_operations) { for (NodeOperation *op : m_operations) {
if (op->isOutputOperation(m_context->isRendering()) && op->get_flags().is_preview_operation) { if (op->isOutputOperation(m_context->isRendering()) && op->get_flags().is_preview_operation) {
unsigned int resolution[2] = {0, 0}; rcti canvas = COM_AREA_NONE;
unsigned int preferredResolution[2] = {0, 0}; op->determine_canvas(preferred_area, canvas);
op->determineResolution(resolution, preferredResolution); op->set_canvas(canvas);
op->setResolution(resolution);
} }
} }
/* add convert resolution operations when needed */ /* Convert operation canvases when needed. */
{ {
Vector<Link> convert_links; Vector<Link> convert_links;
for (const Link &link : m_links) { for (const Link &link : m_links) {
if (link.to()->getResizeMode() != ResizeMode::None) { if (link.to()->getResizeMode() != ResizeMode::None) {
NodeOperation &from_op = link.from()->getOperation(); const rcti &from_canvas = link.from()->getOperation().get_canvas();
NodeOperation &to_op = link.to()->getOperation(); const rcti &to_canvas = link.to()->getOperation().get_canvas();
if (from_op.getWidth() != to_op.getWidth() || from_op.getHeight() != to_op.getHeight()) {
bool needs_conversion;
if (link.to()->getResizeMode() == ResizeMode::Align) {
needs_conversion = from_canvas.xmin != to_canvas.xmin ||
from_canvas.ymin != to_canvas.ymin;
}
else {
needs_conversion = !BLI_rcti_compare(&from_canvas, &to_canvas);
}
if (needs_conversion) {
convert_links.append(link); convert_links.append(link);
} }
} }
} }
for (const Link &link : convert_links) { for (const Link &link : convert_links) {
COM_convert_resolution(*this, link.from(), link.to()); COM_convert_canvas(*this, link.from(), link.to());
} }
} }
} }

View File

@@ -145,8 +145,8 @@ class NodeOperationBuilder {
/** Replace proxy operations with direct links */ /** Replace proxy operations with direct links */
void resolve_proxies(); void resolve_proxies();
/** Calculate resolution for each operation */ /** Calculate canvas area for each operation. */
void determineResolutions(); void determine_canvases();
/** Helper function to store connected inputs for replacement */ /** Helper function to store connected inputs for replacement */
Vector<NodeOperationInput *> cache_output_links(NodeOperationOutput *output) const; Vector<NodeOperationInput *> cache_output_links(NodeOperationOutput *output) const;

View File

@@ -76,9 +76,17 @@ void SharedOperationBuffers::register_read(NodeOperation *read_op)
/** /**
* Get registered areas given operation needs to render. * 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;
} }
/** /**

View File

@@ -53,7 +53,7 @@ class SharedOperationBuffers {
bool has_registered_reads(NodeOperation *op); bool has_registered_reads(NodeOperation *op);
void register_read(NodeOperation *read_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); bool is_operation_rendered(NodeOperation *op);
void set_rendered_buffer(NodeOperation *op, std::unique_ptr<MemoryBuffer> buffer); void set_rendered_buffer(NodeOperation *op, std::unique_ptr<MemoryBuffer> buffer);
MemoryBuffer *get_rendered_buffer(NodeOperation *op); MemoryBuffer *get_rendered_buffer(NodeOperation *op);

View File

@@ -51,13 +51,13 @@ void AlphaOverNode::convertToOperations(NodeConverter &converter,
convertProg->setUseValueAlphaMultiply(false); convertProg->setUseValueAlphaMultiply(false);
if (color1Socket->isLinked()) { if (color1Socket->isLinked()) {
convertProg->setResolutionInputSocketIndex(1); convertProg->set_canvas_input_index(1);
} }
else if (color2Socket->isLinked()) { else if (color2Socket->isLinked()) {
convertProg->setResolutionInputSocketIndex(2); convertProg->set_canvas_input_index(2);
} }
else { else {
convertProg->setResolutionInputSocketIndex(0); convertProg->set_canvas_input_index(0);
} }
converter.addOperation(convertProg); converter.addOperation(convertProg);

View File

@@ -62,7 +62,7 @@ void BoxMaskNode::convertToOperations(NodeConverter &converter,
scaleOperation->setOffset(0.0f, 0.0f); scaleOperation->setOffset(0.0f, 0.0f);
scaleOperation->setNewWidth(rd->xsch * render_size_factor); scaleOperation->setNewWidth(rd->xsch * render_size_factor);
scaleOperation->setNewHeight(rd->ysch * 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.addOperation(scaleOperation);
converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0));

View File

@@ -37,16 +37,16 @@ void CombineColorNode::convertToOperations(NodeConverter &converter,
CombineChannelsOperation *operation = new CombineChannelsOperation(); CombineChannelsOperation *operation = new CombineChannelsOperation();
if (inputRSocket->isLinked()) { if (inputRSocket->isLinked()) {
operation->setResolutionInputSocketIndex(0); operation->set_canvas_input_index(0);
} }
else if (inputGSocket->isLinked()) { else if (inputGSocket->isLinked()) {
operation->setResolutionInputSocketIndex(1); operation->set_canvas_input_index(1);
} }
else if (inputBSocket->isLinked()) { else if (inputBSocket->isLinked()) {
operation->setResolutionInputSocketIndex(2); operation->set_canvas_input_index(2);
} }
else { else {
operation->setResolutionInputSocketIndex(3); operation->set_canvas_input_index(3);
} }
converter.addOperation(operation); converter.addOperation(operation);

View File

@@ -62,7 +62,7 @@ void EllipseMaskNode::convertToOperations(NodeConverter &converter,
scaleOperation->setOffset(0.0f, 0.0f); scaleOperation->setOffset(0.0f, 0.0f);
scaleOperation->setNewWidth(rd->xsch * render_size_factor); scaleOperation->setNewWidth(rd->xsch * render_size_factor);
scaleOperation->setNewHeight(rd->ysch * 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.addOperation(scaleOperation);
converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0));

View File

@@ -66,7 +66,7 @@ void GlareNode::convertToOperations(NodeConverter &converter,
mixvalueoperation->setValue(glare->mix); mixvalueoperation->setValue(glare->mix);
MixGlareOperation *mixoperation = new MixGlareOperation(); MixGlareOperation *mixoperation = new MixGlareOperation();
mixoperation->setResolutionInputSocketIndex(1); mixoperation->set_canvas_input_index(1);
mixoperation->getInputSocket(2)->setResizeMode(ResizeMode::FitAny); mixoperation->getInputSocket(2)->setResizeMode(ResizeMode::FitAny);
converter.addOperation(glareoperation); converter.addOperation(glareoperation);

View File

@@ -53,7 +53,7 @@ void HueSaturationValueCorrectNode::convertToOperations(
converter.addOperation(changeHSV); converter.addOperation(changeHSV);
MixBlendOperation *blend = new MixBlendOperation(); MixBlendOperation *blend = new MixBlendOperation();
blend->setResolutionInputSocketIndex(1); blend->set_canvas_input_index(1);
converter.addOperation(blend); converter.addOperation(blend);
converter.mapInputSocket(colorSocket, rgbToHSV->getInputSocket(0)); converter.mapInputSocket(colorSocket, rgbToHSV->getInputSocket(0));

View File

@@ -56,7 +56,7 @@ void HueSaturationValueNode::convertToOperations(NodeConverter &converter,
converter.addOperation(changeHSV); converter.addOperation(changeHSV);
MixBlendOperation *blend = new MixBlendOperation(); MixBlendOperation *blend = new MixBlendOperation();
blend->setResolutionInputSocketIndex(1); blend->set_canvas_input_index(1);
converter.addOperation(blend); converter.addOperation(blend);
converter.mapInputSocket(colorSocket, rgbToHSV->getInputSocket(0)); converter.mapInputSocket(colorSocket, rgbToHSV->getInputSocket(0));

View File

@@ -34,7 +34,7 @@ void MapUVNode::convertToOperations(NodeConverter &converter,
MapUVOperation *operation = new MapUVOperation(); MapUVOperation *operation = new MapUVOperation();
operation->setAlpha((float)node->custom1); operation->setAlpha((float)node->custom1);
operation->setResolutionInputSocketIndex(1); operation->set_canvas_input_index(1);
converter.addOperation(operation); converter.addOperation(operation);
converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));

View File

@@ -52,6 +52,9 @@ void ScaleNode::convertToOperations(NodeConverter &converter,
converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked());
operation->set_scale_canvas_max_size(context.get_render_width(),
context.get_render_height());
break; break;
} }
case CMP_SCALE_SCENEPERCENT: { case CMP_SCALE_SCENEPERCENT: {
@@ -68,6 +71,8 @@ void ScaleNode::convertToOperations(NodeConverter &converter,
converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked());
operation->set_scale_canvas_max_size(context.get_render_width(),
context.get_render_height());
break; break;
} }
@@ -81,7 +86,7 @@ void ScaleNode::convertToOperations(NodeConverter &converter,
operation->setOffset(bnode->custom3, bnode->custom4); operation->setOffset(bnode->custom3, bnode->custom4);
operation->setNewWidth(rd->xsch * render_size_factor); operation->setNewWidth(rd->xsch * render_size_factor);
operation->setNewHeight(rd->ysch * 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.addOperation(operation);
converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
@@ -102,6 +107,8 @@ void ScaleNode::convertToOperations(NodeConverter &converter,
converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked());
operation->set_scale_canvas_max_size(context.get_render_width(),
context.get_render_height());
break; break;
} }

View File

@@ -39,7 +39,7 @@ void SetAlphaNode::convertToOperations(NodeConverter &converter,
} }
if (!this->getInputSocket(0)->isLinked() && this->getInputSocket(1)->isLinked()) { if (!this->getInputSocket(0)->isLinked() && this->getInputSocket(1)->isLinked()) {
operation->setResolutionInputSocketIndex(1); operation->set_canvas_input_index(1);
} }
converter.addOperation(operation); converter.addOperation(operation);

View File

@@ -127,6 +127,8 @@ void Stabilize2dNode::convertToOperations(NodeConverter &converter,
transform_op->set_sampler(sampler); transform_op->set_sampler(sampler);
transform_op->set_convert_rotate_degree_to_rad(false); transform_op->set_convert_rotate_degree_to_rad(false);
transform_op->set_invert(invert); transform_op->set_invert(invert);
transform_op->set_scale_canvas_max_size(context.get_render_width(),
context.get_render_height());
converter.addOperation(transform_op); converter.addOperation(transform_op);
converter.mapInputSocket(imageInput, transform_op->getInputSocket(0)); converter.mapInputSocket(imageInput, transform_op->getInputSocket(0));
converter.addLink(xAttribute->getOutputSocket(), transform_op->getInputSocket(1)); converter.addLink(xAttribute->getOutputSocket(), transform_op->getInputSocket(1));
@@ -134,6 +136,7 @@ void Stabilize2dNode::convertToOperations(NodeConverter &converter,
converter.addLink(angleAttribute->getOutputSocket(), transform_op->getInputSocket(3)); converter.addLink(angleAttribute->getOutputSocket(), transform_op->getInputSocket(3));
converter.addLink(scaleAttribute->getOutputSocket(), transform_op->getInputSocket(4)); converter.addLink(scaleAttribute->getOutputSocket(), transform_op->getInputSocket(4));
converter.mapOutputSocket(getOutputSocket(), transform_op->getOutputSocket()); converter.mapOutputSocket(getOutputSocket(), transform_op->getOutputSocket());
break;
} }
} }
} }

View File

@@ -75,6 +75,7 @@ void TransformNode::convertToOperations(NodeConverter &converter,
case eExecutionModel::FullFrame: { case eExecutionModel::FullFrame: {
TransformOperation *op = new TransformOperation(); TransformOperation *op = new TransformOperation();
op->set_sampler((PixelSampler)this->getbNode()->custom1); op->set_sampler((PixelSampler)this->getbNode()->custom1);
op->set_scale_canvas_max_size(context.get_render_width(), context.get_render_height());
converter.addOperation(op); converter.addOperation(op);
converter.mapInputSocket(imageInput, op->getInputSocket(0)); converter.mapInputSocket(imageInput, op->getInputSocket(0));

View File

@@ -41,7 +41,9 @@ void TranslateNode::convertToOperations(NodeConverter &converter,
NodeInput *inputYSocket = this->getInputSocket(2); NodeInput *inputYSocket = this->getInputSocket(2);
NodeOutput *outputSocket = this->getOutputSocket(0); 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); operation->set_wrapping(data->wrap_axis);
if (data->relative) { if (data->relative) {
const RenderData *rd = context.getRenderData(); const RenderData *rd = context.getRenderData();

View File

@@ -60,10 +60,10 @@ void ViewerNode::convertToOperations(NodeConverter &converter,
viewerOperation->setViewSettings(context.getViewSettings()); viewerOperation->setViewSettings(context.getViewSettings());
viewerOperation->setDisplaySettings(context.getDisplaySettings()); viewerOperation->setDisplaySettings(context.getDisplaySettings());
viewerOperation->setResolutionInputSocketIndex(0); viewerOperation->set_canvas_input_index(0);
if (!imageSocket->isLinked()) { if (!imageSocket->isLinked()) {
if (alphaSocket->isLinked()) { if (alphaSocket->isLinked()) {
viewerOperation->setResolutionInputSocketIndex(1); viewerOperation->set_canvas_input_index(1);
} }
} }

View File

@@ -212,31 +212,30 @@ void BlurBaseOperation::updateSize()
this->m_sizeavailable = true; this->m_sizeavailable = true;
} }
void BlurBaseOperation::determineResolution(unsigned int resolution[2], void BlurBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
if (!m_extend_bounds) { if (!m_extend_bounds) {
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(preferred_area, r_area);
return; return;
} }
switch (execution_model_) { switch (execution_model_) {
case eExecutionModel::Tiled: { case eExecutionModel::Tiled: {
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(preferred_area, r_area);
resolution[0] += 2 * m_size * m_data.sizex; r_area.xmax += 2 * m_size * m_data.sizex;
resolution[1] += 2 * m_size * m_data.sizey; r_area.ymax += 2 * m_size * m_data.sizey;
break; break;
} }
case eExecutionModel::FullFrame: { case eExecutionModel::FullFrame: {
/* Setting a modifier ensures all non main inputs have extended bounds as preferred /* Setting a modifier ensures all non main inputs have extended bounds as preferred
* resolution, avoiding unnecessary resolution conversions that would hide constant * canvas, avoiding unnecessary canvas convertions that would hide constant
* operations. */ * operations. */
set_determined_resolution_modifier([=](unsigned int res[2]) { set_determined_canvas_modifier([=](rcti &canvas) {
/* Rounding to even prevents jiggling in backdrop while switching size values. */ /* Rounding to even prevents jiggling in backdrop while switching size values. */
res[0] += round_to_even(2 * m_size * m_data.sizex); canvas.xmax += round_to_even(2 * m_size * m_data.sizex);
res[1] += round_to_even(2 * m_size * m_data.sizey); canvas.ymax += round_to_even(2 * m_size * m_data.sizey);
}); });
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(preferred_area, r_area);
break; break;
} }
} }
@@ -251,7 +250,7 @@ void BlurBaseOperation::get_area_of_interest(const int input_idx,
r_input_area = output_area; r_input_area = output_area;
break; break;
case 1: case 1:
r_input_area = use_variable_size_ ? output_area : COM_SINGLE_ELEM_AREA; r_input_area = use_variable_size_ ? output_area : COM_CONSTANT_INPUT_AREA_OF_INTEREST;
break; break;
} }
} }

View File

@@ -85,8 +85,7 @@ class BlurBaseOperation : public MultiThreadedOperation, public QualityStepHelpe
int get_blur_size(eDimension dim) const; int get_blur_size(eDimension dim) const;
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
virtual void get_area_of_interest(int input_idx, virtual void get_area_of_interest(int input_idx,
const rcti &output_area, const rcti &output_area,

View File

@@ -34,7 +34,7 @@ constexpr int SIZE_INPUT_INDEX = 3;
BokehBlurOperation::BokehBlurOperation() BokehBlurOperation::BokehBlurOperation()
{ {
this->addInputSocket(DataType::Color); 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->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
@@ -266,31 +266,30 @@ void BokehBlurOperation::updateSize()
this->m_sizeavailable = true; this->m_sizeavailable = true;
} }
void BokehBlurOperation::determineResolution(unsigned int resolution[2], void BokehBlurOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
if (!m_extend_bounds) { if (!m_extend_bounds) {
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(preferred_area, r_area);
return; return;
} }
switch (execution_model_) { switch (execution_model_) {
case eExecutionModel::Tiled: { case eExecutionModel::Tiled: {
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(preferred_area, r_area);
const float max_dim = MAX2(resolution[0], resolution[1]); const float max_dim = MAX2(BLI_rcti_size_x(&r_area), BLI_rcti_size_y(&r_area));
resolution[0] += 2 * this->m_size * max_dim / 100.0f; r_area.xmax += 2 * this->m_size * max_dim / 100.0f;
resolution[1] += 2 * this->m_size * max_dim / 100.0f; r_area.ymax += 2 * this->m_size * max_dim / 100.0f;
break; break;
} }
case eExecutionModel::FullFrame: { case eExecutionModel::FullFrame: {
set_determined_resolution_modifier([=](unsigned int res[2]) { set_determined_canvas_modifier([=](rcti &canvas) {
const float max_dim = MAX2(res[0], res[1]); const float max_dim = MAX2(BLI_rcti_size_x(&canvas), BLI_rcti_size_y(&canvas));
/* Rounding to even prevents image jiggling in backdrop while switching size values. */ /* Rounding to even prevents image jiggling in backdrop while switching size values. */
float add_size = round_to_even(2 * this->m_size * max_dim / 100.0f); float add_size = round_to_even(2 * this->m_size * max_dim / 100.0f);
res[0] += add_size; canvas.xmax += add_size;
res[1] += add_size; canvas.ymax += add_size;
}); });
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(preferred_area, r_area);
break; break;
} }
} }
@@ -312,17 +311,14 @@ void BokehBlurOperation::get_area_of_interest(const int input_idx,
} }
case BOKEH_INPUT_INDEX: { case BOKEH_INPUT_INDEX: {
NodeOperation *bokeh_input = getInputOperation(BOKEH_INPUT_INDEX); NodeOperation *bokeh_input = getInputOperation(BOKEH_INPUT_INDEX);
r_input_area.xmin = 0; r_input_area = bokeh_input->get_canvas();
r_input_area.xmax = bokeh_input->getWidth();
r_input_area.ymin = 0;
r_input_area.ymax = bokeh_input->getHeight();
break; break;
} }
case BOUNDING_BOX_INPUT_INDEX: case BOUNDING_BOX_INPUT_INDEX:
r_input_area = output_area; r_input_area = output_area;
break; break;
case SIZE_INPUT_INDEX: { case SIZE_INPUT_INDEX: {
r_input_area = COM_SINGLE_ELEM_AREA; r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST;
break; break;
} }
} }

View File

@@ -80,8 +80,7 @@ class BokehBlurOperation : public MultiThreadedOperation, public QualityStepHelp
this->m_extend_bounds = extend_bounds; this->m_extend_bounds = extend_bounds;
} }
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_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, void update_memory_buffer_partial(MemoryBuffer *output,

View File

@@ -145,11 +145,13 @@ void BokehImageOperation::deinitExecution()
} }
} }
void BokehImageOperation::determineResolution(unsigned int resolution[2], void BokehImageOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int /*preferredResolution*/[2])
{ {
resolution[0] = COM_BLUR_BOKEH_PIXELS; BLI_rcti_init(&r_area,
resolution[1] = COM_BLUR_BOKEH_PIXELS; preferred_area.xmin,
preferred_area.xmin + COM_BLUR_BOKEH_PIXELS,
preferred_area.ymin,
preferred_area.ymin + COM_BLUR_BOKEH_PIXELS);
} }
} // namespace blender::compositor } // namespace blender::compositor

View File

@@ -128,8 +128,7 @@ class BokehImageOperation : public MultiThreadedOperation {
* \brief determine the resolution of this operation. currently fixed at [COM_BLUR_BOKEH_PIXELS, * \brief determine the resolution of this operation. currently fixed at [COM_BLUR_BOKEH_PIXELS,
* COM_BLUR_BOKEH_PIXELS] \param resolution: \param preferredResolution: * COM_BLUR_BOKEH_PIXELS] \param resolution: \param preferredResolution:
*/ */
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
/** /**
* \brief set the node data * \brief set the node data

View File

@@ -27,7 +27,7 @@ namespace blender::compositor {
CalculateMeanOperation::CalculateMeanOperation() CalculateMeanOperation::CalculateMeanOperation()
{ {
this->addInputSocket(DataType::Color, ResizeMode::None); this->addInputSocket(DataType::Color, ResizeMode::Align);
this->addOutputSocket(DataType::Value); this->addOutputSocket(DataType::Value);
this->m_imageReader = nullptr; this->m_imageReader = nullptr;
this->m_iscalculated = false; this->m_iscalculated = false;
@@ -165,11 +165,7 @@ void CalculateMeanOperation::get_area_of_interest(int input_idx,
rcti &r_input_area) rcti &r_input_area)
{ {
BLI_assert(input_idx == 0); BLI_assert(input_idx == 0);
NodeOperation *operation = getInputOperation(input_idx); r_input_area = get_input_operation(input_idx)->get_canvas();
r_input_area.xmin = 0;
r_input_area.ymin = 0;
r_input_area.xmax = operation->getWidth();
r_input_area.ymax = operation->getHeight();
} }
void CalculateMeanOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output), void CalculateMeanOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output),

View File

@@ -40,7 +40,7 @@ ColorBalanceASCCDLOperation::ColorBalanceASCCDLOperation()
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->m_inputValueOperation = nullptr; this->m_inputValueOperation = nullptr;
this->m_inputColorOperation = nullptr; this->m_inputColorOperation = nullptr;
this->setResolutionInputSocketIndex(1); this->set_canvas_input_index(1);
flags.can_be_constant = true; flags.can_be_constant = true;
} }

View File

@@ -45,7 +45,7 @@ ColorBalanceLGGOperation::ColorBalanceLGGOperation()
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->m_inputValueOperation = nullptr; this->m_inputValueOperation = nullptr;
this->m_inputColorOperation = nullptr; this->m_inputColorOperation = nullptr;
this->setResolutionInputSocketIndex(1); this->set_canvas_input_index(1);
flags.can_be_constant = true; flags.can_be_constant = true;
} }

View File

@@ -37,7 +37,7 @@ ColorCurveOperation::ColorCurveOperation()
this->m_inputBlackProgram = nullptr; this->m_inputBlackProgram = nullptr;
this->m_inputWhiteProgram = nullptr; this->m_inputWhiteProgram = nullptr;
this->setResolutionInputSocketIndex(1); this->set_canvas_input_index(1);
} }
void ColorCurveOperation::initExecution() void ColorCurveOperation::initExecution()
{ {
@@ -139,7 +139,7 @@ ConstantLevelColorCurveOperation::ConstantLevelColorCurveOperation()
this->m_inputFacProgram = nullptr; this->m_inputFacProgram = nullptr;
this->m_inputImageProgram = nullptr; this->m_inputImageProgram = nullptr;
this->setResolutionInputSocketIndex(1); this->set_canvas_input_index(1);
} }
void ConstantLevelColorCurveOperation::initExecution() void ConstantLevelColorCurveOperation::initExecution()
{ {

View File

@@ -236,8 +236,7 @@ void CompositorOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(outp
depth_buf.copy_from(inputs[2], area); depth_buf.copy_from(inputs[2], area);
} }
void CompositorOperation::determineResolution(unsigned int resolution[2], void CompositorOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
unsigned int preferredResolution[2])
{ {
int width = this->m_rd->xsch * this->m_rd->size / 100; int width = this->m_rd->xsch * this->m_rd->size / 100;
int height = this->m_rd->ysch * this->m_rd->size / 100; int height = this->m_rd->ysch * this->m_rd->size / 100;
@@ -254,13 +253,11 @@ void CompositorOperation::determineResolution(unsigned int resolution[2],
RE_ReleaseResult(re); RE_ReleaseResult(re);
} }
preferredResolution[0] = width; rcti local_preferred;
preferredResolution[1] = height; BLI_rcti_init(&local_preferred, 0, width, 0, height);
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(local_preferred, r_area);
r_area = local_preferred;
resolution[0] = width;
resolution[1] = height;
} }
} // namespace blender::compositor } // namespace blender::compositor

View File

@@ -115,8 +115,7 @@ class CompositorOperation : public MultiThreadedOperation {
{ {
return eCompositorPriority::Medium; return eCompositorPriority::Medium;
} }
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
void setUseAlphaInput(bool value) void setUseAlphaInput(bool value)
{ {
this->m_useAlphaInput = value; this->m_useAlphaInput = value;

View File

@@ -22,14 +22,14 @@ namespace blender::compositor {
ConstantOperation::ConstantOperation() ConstantOperation::ConstantOperation()
{ {
needs_resolution_to_get_constant_ = false; needs_canvas_to_get_constant_ = false;
flags.is_constant_operation = true; flags.is_constant_operation = true;
flags.is_fullframe_operation = true; flags.is_fullframe_operation = true;
} }
bool ConstantOperation::can_get_constant_elem() const bool ConstantOperation::can_get_constant_elem() const
{ {
return !needs_resolution_to_get_constant_ || this->flags.is_resolution_set; return !needs_canvas_to_get_constant_ || this->flags.is_canvas_set;
} }
void ConstantOperation::update_memory_buffer(MemoryBuffer *output, void ConstantOperation::update_memory_buffer(MemoryBuffer *output,

View File

@@ -31,7 +31,7 @@ namespace blender::compositor {
*/ */
class ConstantOperation : public NodeOperation { class ConstantOperation : public NodeOperation {
protected: protected:
bool needs_resolution_to_get_constant_; bool needs_canvas_to_get_constant_;
public: public:
ConstantOperation(); ConstantOperation();

View File

@@ -587,7 +587,7 @@ CombineChannelsOperation::CombineChannelsOperation()
this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value);
this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
this->m_inputChannel1Operation = nullptr; this->m_inputChannel1Operation = nullptr;
this->m_inputChannel2Operation = nullptr; this->m_inputChannel2Operation = nullptr;
this->m_inputChannel3Operation = nullptr; this->m_inputChannel3Operation = nullptr;

View File

@@ -29,7 +29,7 @@ ConvolutionFilterOperation::ConvolutionFilterOperation()
this->addInputSocket(DataType::Color); this->addInputSocket(DataType::Color);
this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
this->m_inputOperation = nullptr; this->m_inputOperation = nullptr;
this->flags.complex = true; this->flags.complex = true;
} }

View File

@@ -23,7 +23,7 @@ namespace blender::compositor {
CropBaseOperation::CropBaseOperation() CropBaseOperation::CropBaseOperation()
{ {
this->addInputSocket(DataType::Color, ResizeMode::None); this->addInputSocket(DataType::Color, ResizeMode::Align);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->m_inputOperation = nullptr; this->m_inputOperation = nullptr;
this->m_settings = nullptr; this->m_settings = nullptr;
@@ -142,13 +142,12 @@ void CropImageOperation::get_area_of_interest(const int input_idx,
r_input_area.ymin = output_area.ymin + this->m_ymin; r_input_area.ymin = output_area.ymin + this->m_ymin;
} }
void CropImageOperation::determineResolution(unsigned int resolution[2], void CropImageOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(preferred_area, r_area);
updateArea(); updateArea();
resolution[0] = this->m_xmax - this->m_xmin; r_area.xmax = r_area.xmin + (m_xmax - m_xmin);
resolution[1] = this->m_ymax - this->m_ymin; r_area.ymax = r_area.ymin + (m_ymax - m_ymin);
} }
void CropImageOperation::executePixelSampled(float output[4], void CropImageOperation::executePixelSampled(float output[4],

View File

@@ -66,8 +66,7 @@ class CropImageOperation : public CropBaseOperation {
bool determineDependingAreaOfInterest(rcti *input, bool determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation, ReadBufferOperation *readOperation,
rcti *output) override; rcti *output) override;
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;

View File

@@ -190,10 +190,7 @@ void DenoiseOperation::get_area_of_interest(const int UNUSED(input_idx),
const rcti &UNUSED(output_area), const rcti &UNUSED(output_area),
rcti &r_input_area) rcti &r_input_area)
{ {
r_input_area.xmin = 0; r_input_area = this->get_canvas();
r_input_area.xmax = this->getWidth();
r_input_area.ymin = 0;
r_input_area.ymax = this->getHeight();
} }
void DenoiseOperation::update_memory_buffer(MemoryBuffer *output, void DenoiseOperation::update_memory_buffer(MemoryBuffer *output,

View File

@@ -29,7 +29,7 @@ DespeckleOperation::DespeckleOperation()
this->addInputSocket(DataType::Color); this->addInputSocket(DataType::Color);
this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
this->m_inputOperation = nullptr; this->m_inputOperation = nullptr;
this->flags.complex = true; this->flags.complex = true;
} }

View File

@@ -152,10 +152,7 @@ void DirectionalBlurOperation::get_area_of_interest(const int input_idx,
{ {
BLI_assert(input_idx == 0); BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx); UNUSED_VARS_NDEBUG(input_idx);
r_input_area.xmin = 0; r_input_area = this->get_canvas();
r_input_area.xmax = this->getWidth();
r_input_area.ymin = 0;
r_input_area.ymax = this->getHeight();
} }
void DirectionalBlurOperation::update_memory_buffer_partial(MemoryBuffer *output, void DirectionalBlurOperation::update_memory_buffer_partial(MemoryBuffer *output,

View File

@@ -211,10 +211,7 @@ void DisplaceOperation::get_area_of_interest(const int input_idx,
{ {
switch (input_idx) { switch (input_idx) {
case 0: { case 0: {
r_input_area.xmin = 0; r_input_area = getInputOperation(input_idx)->get_canvas();
r_input_area.ymin = 0;
r_input_area.xmax = getInputOperation(input_idx)->getWidth();
r_input_area.ymax = getInputOperation(input_idx)->getHeight();
break; break;
} }
case 1: { case 1: {

View File

@@ -138,10 +138,7 @@ void DisplaceSimpleOperation::get_area_of_interest(const int input_idx,
{ {
switch (input_idx) { switch (input_idx) {
case 0: { case 0: {
r_input_area.xmin = 0; r_input_area = get_input_operation(input_idx)->get_canvas();
r_input_area.ymin = 0;
r_input_area.xmax = getInputOperation(input_idx)->getWidth();
r_input_area.ymax = getInputOperation(input_idx)->getHeight();
break; break;
} }
default: { default: {

View File

@@ -25,7 +25,7 @@ DotproductOperation::DotproductOperation()
this->addInputSocket(DataType::Vector); this->addInputSocket(DataType::Vector);
this->addInputSocket(DataType::Vector); this->addInputSocket(DataType::Vector);
this->addOutputSocket(DataType::Value); this->addOutputSocket(DataType::Value);
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
this->m_input1Operation = nullptr; this->m_input1Operation = nullptr;
this->m_input2Operation = nullptr; this->m_input2Operation = nullptr;
flags.can_be_constant = true; flags.can_be_constant = true;

View File

@@ -1399,10 +1399,7 @@ void DoubleEdgeMaskOperation::get_area_of_interest(int UNUSED(input_idx),
const rcti &UNUSED(output_area), const rcti &UNUSED(output_area),
rcti &r_input_area) rcti &r_input_area)
{ {
r_input_area.xmax = this->getWidth(); r_input_area = this->get_canvas();
r_input_area.xmin = 0;
r_input_area.ymax = this->getHeight();
r_input_area.ymin = 0;
} }
void DoubleEdgeMaskOperation::update_memory_buffer(MemoryBuffer *output, void DoubleEdgeMaskOperation::update_memory_buffer(MemoryBuffer *output,

View File

@@ -271,10 +271,7 @@ void FastGaussianBlurOperation::get_area_of_interest(const int input_idx,
{ {
switch (input_idx) { switch (input_idx) {
case IMAGE_INPUT_INDEX: case IMAGE_INPUT_INDEX:
r_input_area.xmin = 0; r_input_area = this->get_canvas();
r_input_area.xmax = getWidth();
r_input_area.ymin = 0;
r_input_area.ymax = getHeight();
break; break;
default: default:
BlurBaseOperation::get_area_of_interest(input_idx, output_area, r_input_area); BlurBaseOperation::get_area_of_interest(input_idx, output_area, r_input_area);
@@ -411,10 +408,7 @@ void FastGaussianBlurValueOperation::get_area_of_interest(const int UNUSED(input
const rcti &UNUSED(output_area), const rcti &UNUSED(output_area),
rcti &r_input_area) rcti &r_input_area)
{ {
r_input_area.xmin = 0; r_input_area = this->get_canvas();
r_input_area.xmax = getWidth();
r_input_area.ymin = 0;
r_input_area.ymax = getHeight();
} }
void FastGaussianBlurValueOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output), void FastGaussianBlurValueOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output),

View File

@@ -24,7 +24,7 @@ FlipOperation::FlipOperation()
{ {
this->addInputSocket(DataType::Color); this->addInputSocket(DataType::Color);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
this->m_inputOperation = nullptr; this->m_inputOperation = nullptr;
this->m_flipX = true; this->m_flipX = true;
this->m_flipY = false; this->m_flipY = false;

View File

@@ -30,12 +30,13 @@ GlareThresholdOperation::GlareThresholdOperation()
this->m_inputProgram = nullptr; this->m_inputProgram = nullptr;
} }
void GlareThresholdOperation::determineResolution(unsigned int resolution[2], void GlareThresholdOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(preferred_area, r_area);
resolution[0] = resolution[0] / (1 << this->m_settings->quality); const int width = BLI_rcti_size_x(&r_area) / (1 << this->m_settings->quality);
resolution[1] = resolution[1] / (1 << this->m_settings->quality); const int height = BLI_rcti_size_y(&r_area) / (1 << this->m_settings->quality);
r_area.xmax = r_area.xmin + width;
r_area.ymax = r_area.ymin + height;
} }
void GlareThresholdOperation::initExecution() void GlareThresholdOperation::initExecution()

View File

@@ -58,8 +58,7 @@ class GlareThresholdOperation : public NodeOperation {
this->m_settings = settings; this->m_settings = settings;
} }
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
}; };
} // namespace blender::compositor } // namespace blender::compositor

View File

@@ -112,17 +112,14 @@ void BaseImageOperation::deinitExecution()
} }
} }
void BaseImageOperation::determineResolution(unsigned int resolution[2], void BaseImageOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
unsigned int /*preferredResolution*/[2])
{ {
ImBuf *stackbuf = getImBuf(); ImBuf *stackbuf = getImBuf();
resolution[0] = 0; r_area = COM_AREA_NONE;
resolution[1] = 0;
if (stackbuf) { if (stackbuf) {
resolution[0] = stackbuf->x; BLI_rcti_init(&r_area, 0, stackbuf->x, 0, stackbuf->y);
resolution[1] = stackbuf->y;
} }
BKE_image_release_ibuf(this->m_image, stackbuf, nullptr); BKE_image_release_ibuf(this->m_image, stackbuf, nullptr);
@@ -222,7 +219,7 @@ void ImageDepthOperation::executePixelSampled(float output[4],
output[0] = 0.0f; output[0] = 0.0f;
} }
else { else {
int offset = y * this->m_width + x; int offset = y * getWidth() + x;
output[0] = this->m_depthBuffer[offset]; output[0] = this->m_depthBuffer[offset];
} }
} }

View File

@@ -54,8 +54,7 @@ class BaseImageOperation : public MultiThreadedOperation {
/** /**
* Determine the output resolution. The resolution is retrieved from the Renderer * Determine the output resolution. The resolution is retrieved from the Renderer
*/ */
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
virtual ImBuf *getImBuf(); virtual ImBuf *getImBuf();

View File

@@ -293,10 +293,7 @@ void InpaintSimpleOperation::get_area_of_interest(const int input_idx,
{ {
BLI_assert(input_idx == 0); BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx); UNUSED_VARS_NDEBUG(input_idx);
r_input_area.xmin = 0; r_input_area = this->get_canvas();
r_input_area.xmax = this->getWidth();
r_input_area.ymin = 0;
r_input_area.ymax = this->getHeight();
} }
void InpaintSimpleOperation::update_memory_buffer(MemoryBuffer *output, void InpaintSimpleOperation::update_memory_buffer(MemoryBuffer *output,

View File

@@ -29,7 +29,7 @@ InvertOperation::InvertOperation()
this->m_inputColorProgram = nullptr; this->m_inputColorProgram = nullptr;
this->m_color = true; this->m_color = true;
this->m_alpha = false; this->m_alpha = false;
setResolutionInputSocketIndex(1); set_canvas_input_index(1);
this->flags.can_be_constant = true; this->flags.can_be_constant = true;
} }
void InvertOperation::initExecution() void InvertOperation::initExecution()

View File

@@ -303,11 +303,9 @@ void KeyingScreenOperation::deinitializeTileData(rcti * /*rect*/, void *data)
MEM_freeN(tile_data); MEM_freeN(tile_data);
} }
void KeyingScreenOperation::determineResolution(unsigned int resolution[2], void KeyingScreenOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int /*preferredResolution*/[2])
{ {
resolution[0] = 0; r_area = COM_AREA_NONE;
resolution[1] = 0;
if (this->m_movieClip) { if (this->m_movieClip) {
MovieClipUser user = {0}; MovieClipUser user = {0};
@@ -317,9 +315,9 @@ void KeyingScreenOperation::determineResolution(unsigned int resolution[2],
BKE_movieclip_user_set_frame(&user, clip_frame); BKE_movieclip_user_set_frame(&user, clip_frame);
BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height); BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height);
r_area = preferred_area;
resolution[0] = width; r_area.xmax = r_area.xmin + width;
resolution[1] = height; r_area.ymax = r_area.ymin + height;
} }
} }

View File

@@ -57,8 +57,7 @@ class KeyingScreenOperation : public MultiThreadedOperation {
/** /**
* Determine the output resolution. The resolution is retrieved from the Renderer * Determine the output resolution. The resolution is retrieved from the Renderer
*/ */
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
TriangulationData *buildVoronoiTriangulation(); TriangulationData *buildVoronoiTriangulation();

View File

@@ -23,12 +23,12 @@ namespace blender::compositor {
MapUVOperation::MapUVOperation() MapUVOperation::MapUVOperation()
{ {
this->addInputSocket(DataType::Color, ResizeMode::None); this->addInputSocket(DataType::Color, ResizeMode::Align);
this->addInputSocket(DataType::Vector); this->addInputSocket(DataType::Vector);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->m_alpha = 0.0f; this->m_alpha = 0.0f;
this->flags.complex = true; this->flags.complex = true;
setResolutionInputSocketIndex(1); set_canvas_input_index(UV_INPUT_INDEX);
this->m_inputUVProgram = nullptr; this->m_inputUVProgram = nullptr;
this->m_inputColorProgram = nullptr; this->m_inputColorProgram = nullptr;
@@ -36,11 +36,11 @@ MapUVOperation::MapUVOperation()
void MapUVOperation::init_data() void MapUVOperation::init_data()
{ {
NodeOperation *image_input = get_input_operation(0); NodeOperation *image_input = get_input_operation(IMAGE_INPUT_INDEX);
image_width_ = image_input->getWidth(); image_width_ = image_input->getWidth();
image_height_ = image_input->getHeight(); image_height_ = image_input->getHeight();
NodeOperation *uv_input = get_input_operation(1); NodeOperation *uv_input = get_input_operation(UV_INPUT_INDEX);
uv_width_ = uv_input->getWidth(); uv_width_ = uv_input->getWidth();
uv_height_ = uv_input->getHeight(); uv_height_ = uv_input->getHeight();
} }
@@ -205,14 +205,11 @@ void MapUVOperation::get_area_of_interest(const int input_idx,
rcti &r_input_area) rcti &r_input_area)
{ {
switch (input_idx) { switch (input_idx) {
case 0: { case IMAGE_INPUT_INDEX: {
r_input_area.xmin = 0; r_input_area = get_input_operation(IMAGE_INPUT_INDEX)->get_canvas();
r_input_area.xmax = image_width_;
r_input_area.ymin = 0;
r_input_area.ymax = image_height_;
break; break;
} }
case 1: { case UV_INPUT_INDEX: {
r_input_area = output_area; r_input_area = output_area;
expand_area_for_sampler(r_input_area, PixelSampler::Bilinear); expand_area_for_sampler(r_input_area, PixelSampler::Bilinear);
break; break;
@@ -224,7 +221,7 @@ void MapUVOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output),
const rcti &UNUSED(area), const rcti &UNUSED(area),
Span<MemoryBuffer *> inputs) Span<MemoryBuffer *> inputs)
{ {
const MemoryBuffer *uv_input = inputs[1]; const MemoryBuffer *uv_input = inputs[UV_INPUT_INDEX];
uv_input_read_fn_ = [=](float x, float y, float *out) { uv_input_read_fn_ = [=](float x, float y, float *out) {
uv_input->read_elem_bilinear(x, y, out); uv_input->read_elem_bilinear(x, y, out);
}; };
@@ -234,7 +231,7 @@ void MapUVOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area, const rcti &area,
Span<MemoryBuffer *> inputs) Span<MemoryBuffer *> inputs)
{ {
const MemoryBuffer *input_image = inputs[0]; const MemoryBuffer *input_image = inputs[IMAGE_INPUT_INDEX];
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
float xy[2] = {(float)it.x, (float)it.y}; float xy[2] = {(float)it.x, (float)it.y};
float uv[2]; float uv[2];

View File

@@ -24,6 +24,8 @@ namespace blender::compositor {
class MapUVOperation : public MultiThreadedOperation { class MapUVOperation : public MultiThreadedOperation {
private: private:
static constexpr int IMAGE_INPUT_INDEX = 0;
static constexpr int UV_INPUT_INDEX = 1;
/** /**
* Cached reference to the inputProgram * Cached reference to the inputProgram
*/ */

View File

@@ -109,22 +109,15 @@ void MaskOperation::deinitExecution()
} }
} }
void MaskOperation::determineResolution(unsigned int resolution[2], void MaskOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
if (this->m_maskWidth == 0 || this->m_maskHeight == 0) { if (this->m_maskWidth == 0 || this->m_maskHeight == 0) {
NodeOperation::determineResolution(resolution, preferredResolution); r_area = COM_AREA_NONE;
} }
else { else {
unsigned int nr[2]; r_area = preferred_area;
r_area.xmax = r_area.xmin + m_maskWidth;
nr[0] = this->m_maskWidth; r_area.ymax = r_area.ymin + m_maskHeight;
nr[1] = this->m_maskHeight;
NodeOperation::determineResolution(resolution, nr);
resolution[0] = this->m_maskWidth;
resolution[1] = this->m_maskHeight;
} }
} }

View File

@@ -54,8 +54,7 @@ class MaskOperation : public MultiThreadedOperation {
/** /**
* Determine the output resolution. The resolution is retrieved from the Renderer * Determine the output resolution. The resolution is retrieved from the Renderer
*/ */
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
public: public:
MaskOperation(); MaskOperation();

View File

@@ -51,22 +51,19 @@ void MathBaseOperation::deinitExecution()
this->m_inputValue3Operation = nullptr; this->m_inputValue3Operation = nullptr;
} }
void MathBaseOperation::determineResolution(unsigned int resolution[2], void MathBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
NodeOperationInput *socket; NodeOperationInput *socket;
unsigned int tempPreferredResolution[2] = {0, 0}; rcti temp_area;
unsigned int tempResolution[2];
socket = this->getInputSocket(0); socket = this->getInputSocket(0);
socket->determineResolution(tempResolution, tempPreferredResolution); const bool determined = socket->determine_canvas(COM_AREA_NONE, temp_area);
if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { if (determined) {
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
} }
else { else {
this->setResolutionInputSocketIndex(1); this->set_canvas_input_index(1);
} }
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(preferred_area, r_area);
} }
void MathBaseOperation::clampIfNeeded(float *color) void MathBaseOperation::clampIfNeeded(float *color)

View File

@@ -75,8 +75,7 @@ class MathBaseOperation : public MultiThreadedOperation {
/** /**
* Determine resolution * Determine resolution
*/ */
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
void setUseClamp(bool value) void setUseClamp(bool value)
{ {

View File

@@ -66,29 +66,27 @@ void MixBaseOperation::executePixelSampled(float output[4], float x, float y, Pi
output[3] = inputColor1[3]; output[3] = inputColor1[3];
} }
void MixBaseOperation::determineResolution(unsigned int resolution[2], void MixBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
NodeOperationInput *socket; NodeOperationInput *socket;
unsigned int tempPreferredResolution[2] = {0, 0}; rcti temp_area;
unsigned int tempResolution[2];
socket = this->getInputSocket(1); socket = this->getInputSocket(1);
socket->determineResolution(tempResolution, tempPreferredResolution); bool determined = socket->determine_canvas(COM_AREA_NONE, temp_area);
if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { if (determined) {
this->setResolutionInputSocketIndex(1); this->set_canvas_input_index(1);
} }
else { else {
socket = this->getInputSocket(2); socket = this->getInputSocket(2);
socket->determineResolution(tempResolution, tempPreferredResolution); determined = socket->determine_canvas(COM_AREA_NONE, temp_area);
if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { if (determined) {
this->setResolutionInputSocketIndex(2); this->set_canvas_input_index(2);
} }
else { else {
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
} }
} }
NodeOperation::determineResolution(resolution, preferredResolution); NodeOperation::determine_canvas(preferred_area, r_area);
} }
void MixBaseOperation::deinitExecution() void MixBaseOperation::deinitExecution()

View File

@@ -87,8 +87,7 @@ class MixBaseOperation : public MultiThreadedOperation {
*/ */
void deinitExecution() override; void deinitExecution() override;
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
void setUseValueAlphaMultiply(const bool value) void setUseValueAlphaMultiply(const bool value)
{ {

View File

@@ -29,7 +29,7 @@ MovieClipAttributeOperation::MovieClipAttributeOperation()
this->m_framenumber = 0; this->m_framenumber = 0;
this->m_attribute = MCA_X; this->m_attribute = MCA_X;
this->m_invert = false; this->m_invert = false;
needs_resolution_to_get_constant_ = true; needs_canvas_to_get_constant_ = true;
is_value_calculated_ = false; is_value_calculated_ = false;
} }
@@ -42,7 +42,7 @@ void MovieClipAttributeOperation::initExecution()
void MovieClipAttributeOperation::calc_value() void MovieClipAttributeOperation::calc_value()
{ {
BLI_assert(this->get_flags().is_resolution_set); BLI_assert(this->get_flags().is_canvas_set);
is_value_calculated_ = true; is_value_calculated_ = true;
if (this->m_clip == nullptr) { if (this->m_clip == nullptr) {
return; return;
@@ -87,11 +87,9 @@ void MovieClipAttributeOperation::executePixelSampled(float output[4],
output[0] = this->m_value; output[0] = this->m_value;
} }
void MovieClipAttributeOperation::determineResolution(unsigned int resolution[2], void MovieClipAttributeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
resolution[0] = preferredResolution[0]; r_area = preferred_area;
resolution[1] = preferredResolution[1];
} }
const float *MovieClipAttributeOperation::get_constant_elem() const float *MovieClipAttributeOperation::get_constant_elem()

View File

@@ -55,8 +55,7 @@ class MovieClipAttributeOperation : public ConstantOperation {
* The inner loop of this operation. * The inner loop of this operation.
*/ */
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
const float *get_constant_elem() override; const float *get_constant_elem() override;

View File

@@ -71,19 +71,13 @@ void MovieClipBaseOperation::deinitExecution()
} }
} }
void MovieClipBaseOperation::determineResolution(unsigned int resolution[2], void MovieClipBaseOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
unsigned int /*preferredResolution*/[2])
{ {
resolution[0] = 0; r_area = COM_AREA_NONE;
resolution[1] = 0;
if (this->m_movieClip) { if (this->m_movieClip) {
int width, height; int width, height;
BKE_movieclip_get_size(this->m_movieClip, this->m_movieClipUser, &width, &height); BKE_movieclip_get_size(this->m_movieClip, this->m_movieClipUser, &width, &height);
BLI_rcti_init(&r_area, 0, width, 0, height);
resolution[0] = width;
resolution[1] = height;
} }
} }

View File

@@ -41,8 +41,7 @@ class MovieClipBaseOperation : public MultiThreadedOperation {
/** /**
* Determine the output resolution. The resolution is retrieved from the Renderer * Determine the output resolution. The resolution is retrieved from the Renderer
*/ */
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
public: public:
MovieClipBaseOperation(); MovieClipBaseOperation();

View File

@@ -29,7 +29,7 @@ MovieDistortionOperation::MovieDistortionOperation(bool distortion)
{ {
this->addInputSocket(DataType::Color); this->addInputSocket(DataType::Color);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
this->m_inputOperation = nullptr; this->m_inputOperation = nullptr;
this->m_movieClip = nullptr; this->m_movieClip = nullptr;
this->m_apply = distortion; this->m_apply = distortion;
@@ -49,10 +49,10 @@ void MovieDistortionOperation::initExecution()
float delta[2]; float delta[2];
rcti full_frame; rcti full_frame;
full_frame.xmin = full_frame.ymin = 0; full_frame.xmin = full_frame.ymin = 0;
full_frame.xmax = this->m_width; full_frame.xmax = this->getWidth();
full_frame.ymax = this->m_height; full_frame.ymax = this->getHeight();
BKE_tracking_max_distortion_delta_across_bound( BKE_tracking_max_distortion_delta_across_bound(
tracking, this->m_width, this->m_height, &full_frame, !this->m_apply, delta); tracking, this->getWidth(), this->getHeight(), &full_frame, !this->m_apply, delta);
/* 5 is just in case we didn't hit real max of distortion in /* 5 is just in case we didn't hit real max of distortion in
* BKE_tracking_max_undistortion_delta_across_bound * BKE_tracking_max_undistortion_delta_across_bound
@@ -89,8 +89,8 @@ void MovieDistortionOperation::executePixelSampled(float output[4],
if (this->m_distortion != nullptr) { if (this->m_distortion != nullptr) {
/* float overscan = 0.0f; */ /* float overscan = 0.0f; */
const float pixel_aspect = this->m_pixel_aspect; const float pixel_aspect = this->m_pixel_aspect;
const float w = (float)this->m_width /* / (1 + overscan) */; const float w = (float)this->getWidth() /* / (1 + overscan) */;
const float h = (float)this->m_height /* / (1 + overscan) */; const float h = (float)this->getHeight() /* / (1 + overscan) */;
const float aspx = w / (float)this->m_calibration_width; const float aspx = w / (float)this->m_calibration_width;
const float aspy = h / (float)this->m_calibration_height; const float aspy = h / (float)this->m_calibration_height;
float in[2]; float in[2];
@@ -152,8 +152,8 @@ void MovieDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output
/* `float overscan = 0.0f;` */ /* `float overscan = 0.0f;` */
const float pixel_aspect = this->m_pixel_aspect; const float pixel_aspect = this->m_pixel_aspect;
const float w = (float)this->m_width /* `/ (1 + overscan)` */; const float w = (float)this->getWidth() /* `/ (1 + overscan)` */;
const float h = (float)this->m_height /* `/ (1 + overscan)` */; const float h = (float)this->getHeight() /* `/ (1 + overscan)` */;
const float aspx = w / (float)this->m_calibration_width; const float aspx = w / (float)this->m_calibration_width;
const float aspy = h / (float)this->m_calibration_height; const float aspy = h / (float)this->m_calibration_height;
float xy[2]; float xy[2];

View File

@@ -133,11 +133,7 @@ void NormalizeOperation::get_area_of_interest(const int UNUSED(input_idx),
const rcti &UNUSED(output_area), const rcti &UNUSED(output_area),
rcti &r_input_area) rcti &r_input_area)
{ {
NodeOperation *input = get_input_operation(0); r_input_area = get_input_operation(0)->get_canvas();
r_input_area.xmin = 0;
r_input_area.xmax = input->getWidth();
r_input_area.ymin = 0;
r_input_area.ymax = input->getHeight();
} }
void NormalizeOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output), void NormalizeOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output),

View File

@@ -339,7 +339,7 @@ OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(const Scene *
this->m_exr_codec = exr_codec; this->m_exr_codec = exr_codec;
this->m_exr_half_float = exr_half_float; this->m_exr_half_float = exr_half_float;
this->m_viewName = viewName; this->m_viewName = viewName;
this->setResolutionInputSocketIndex(RESOLUTION_INPUT_ANY); this->set_canvas_input_index(RESOLUTION_INPUT_ANY);
} }
void OutputOpenExrMultiLayerOperation::add_layer(const char *name, void OutputOpenExrMultiLayerOperation::add_layer(const char *name,

View File

@@ -24,7 +24,7 @@ PixelateOperation::PixelateOperation(DataType datatype)
{ {
this->addInputSocket(datatype); this->addInputSocket(datatype);
this->addOutputSocket(datatype); this->addOutputSocket(datatype);
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
this->m_inputOperation = nullptr; this->m_inputOperation = nullptr;
} }

View File

@@ -209,15 +209,13 @@ void *PlaneCornerPinMaskOperation::initializeTileData(rcti *rect)
return data; return data;
} }
void PlaneCornerPinMaskOperation::determineResolution(unsigned int resolution[2], void PlaneCornerPinMaskOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
if (execution_model_ == eExecutionModel::FullFrame) { if (execution_model_ == eExecutionModel::FullFrame) {
/* Determine inputs resolution. */ /* Determine input canvases. */
PlaneDistortMaskOperation::determineResolution(resolution, preferredResolution); PlaneDistortMaskOperation::determine_canvas(preferred_area, r_area);
} }
resolution[0] = preferredResolution[0]; r_area = preferred_area;
resolution[1] = preferredResolution[1];
} }
void PlaneCornerPinMaskOperation::get_area_of_interest(const int UNUSED(input_idx), void PlaneCornerPinMaskOperation::get_area_of_interest(const int UNUSED(input_idx),
@@ -225,7 +223,7 @@ void PlaneCornerPinMaskOperation::get_area_of_interest(const int UNUSED(input_id
rcti &r_input_area) rcti &r_input_area)
{ {
/* All corner inputs are used as constants. */ /* All corner inputs are used as constants. */
r_input_area = COM_SINGLE_ELEM_AREA; r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST;
} }
/* ******** PlaneCornerPinWarpImageOperation ******** */ /* ******** PlaneCornerPinWarpImageOperation ******** */
@@ -322,7 +320,7 @@ void PlaneCornerPinWarpImageOperation::get_area_of_interest(const int input_idx,
} }
else { else {
/* Corner inputs are used as constants. */ /* Corner inputs are used as constants. */
r_input_area = COM_SINGLE_ELEM_AREA; r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST;
} }
} }

View File

@@ -43,8 +43,7 @@ class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation {
void *initializeTileData(rcti *rect) override; void *initializeTileData(rcti *rect) override;
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
}; };

View File

@@ -73,7 +73,7 @@ BLI_INLINE void warpCoord(float x, float y, float matrix[3][3], float uv[2], flo
PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation() : PlaneDistortBaseOperation() PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation() : PlaneDistortBaseOperation()
{ {
this->addInputSocket(DataType::Color, ResizeMode::None); this->addInputSocket(DataType::Color, ResizeMode::Align);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->m_pixelReader = nullptr; this->m_pixelReader = nullptr;
this->flags.complex = true; this->flags.complex = true;
@@ -196,10 +196,7 @@ void PlaneDistortWarpImageOperation::get_area_of_interest(const int input_idx,
} }
/* TODO: figure out the area needed for warping and EWA filtering. */ /* TODO: figure out the area needed for warping and EWA filtering. */
r_input_area.xmin = 0; r_input_area = get_input_operation(0)->get_canvas();
r_input_area.ymin = 0;
r_input_area.xmax = get_input_operation(0)->getWidth();
r_input_area.ymax = get_input_operation(0)->getHeight();
/* Old implementation but resulting coordinates are way out of input operation bounds and in some /* Old implementation but resulting coordinates are way out of input operation bounds and in some
* cases the area result may incorrectly cause cropping. */ * cases the area result may incorrectly cause cropping. */

View File

@@ -83,19 +83,17 @@ void PlaneTrackCommon::readCornersFromTrack(float corners[4][2], float frame)
} }
} }
void PlaneTrackCommon::determineResolution(unsigned int resolution[2], void PlaneTrackCommon::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int /*preferredResolution*/[2])
{ {
resolution[0] = 0; r_area = COM_AREA_NONE;
resolution[1] = 0;
if (this->m_movieClip) { if (this->m_movieClip) {
int width, height; int width, height;
MovieClipUser user = {0}; MovieClipUser user = {0};
BKE_movieclip_user_set_frame(&user, this->m_framenumber); BKE_movieclip_user_set_frame(&user, this->m_framenumber);
BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height); BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height);
resolution[0] = width; r_area = preferred_area;
resolution[1] = height; r_area.xmax = r_area.xmin + width;
r_area.ymax = r_area.ymin + height;
} }
} }

View File

@@ -41,7 +41,7 @@ class PlaneTrackCommon {
* implementation classes must make wrappers to use these methods, see below. * implementation classes must make wrappers to use these methods, see below.
*/ */
void read_and_calculate_corners(PlaneDistortBaseOperation *distort_op); void read_and_calculate_corners(PlaneDistortBaseOperation *distort_op);
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); void determine_canvas(const rcti &preferred_area, rcti &r_area);
public: public:
PlaneTrackCommon(); PlaneTrackCommon();
@@ -77,13 +77,13 @@ class PlaneTrackMaskOperation : public PlaneDistortMaskOperation, public PlaneTr
void initExecution() override; void initExecution() override;
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override
unsigned int preferredResolution[2]) override
{ {
PlaneTrackCommon::determineResolution(resolution, preferredResolution); PlaneTrackCommon::determine_canvas(preferred_area, r_area);
unsigned int temp[2]; rcti unused;
NodeOperation::determineResolution(temp, resolution); rcti &preferred = r_area;
NodeOperation::determine_canvas(preferred, unused);
} }
}; };
@@ -98,12 +98,13 @@ class PlaneTrackWarpImageOperation : public PlaneDistortWarpImageOperation,
void initExecution() override; void initExecution() override;
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override
unsigned int preferredResolution[2]) override
{ {
PlaneTrackCommon::determineResolution(resolution, preferredResolution); PlaneTrackCommon::determine_canvas(preferred_area, r_area);
unsigned int temp[2];
NodeOperation::determineResolution(temp, resolution); rcti unused;
rcti &preferred = r_area;
NodeOperation::determine_canvas(preferred, unused);
} }
}; };

View File

@@ -41,7 +41,7 @@ PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings,
const unsigned int defaultHeight) const unsigned int defaultHeight)
{ {
this->addInputSocket(DataType::Color, ResizeMode::None); this->addInputSocket(DataType::Color, ResizeMode::Align);
this->m_preview = nullptr; this->m_preview = nullptr;
this->m_outputBuffer = nullptr; this->m_outputBuffer = nullptr;
this->m_input = nullptr; this->m_input = nullptr;
@@ -130,14 +130,14 @@ bool PreviewOperation::determineDependingAreaOfInterest(rcti *input,
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
} }
void PreviewOperation::determineResolution(unsigned int resolution[2], void PreviewOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
unsigned int /*preferredResolution*/[2])
{ {
/* Use default preview resolution as preferred ensuring it has size so that /* Use default preview resolution as preferred ensuring it has size so that
* generated inputs (which don't have resolution on their own) are displayed */ * generated inputs (which don't have resolution on their own) are displayed */
BLI_assert(this->m_defaultWidth > 0 && this->m_defaultHeight > 0); BLI_assert(this->m_defaultWidth > 0 && this->m_defaultHeight > 0);
unsigned int previewPreferredRes[2] = {this->m_defaultWidth, this->m_defaultHeight}; rcti local_preferred;
NodeOperation::determineResolution(resolution, previewPreferredRes); BLI_rcti_init(&local_preferred, 0, m_defaultWidth, 0, m_defaultHeight);
NodeOperation::determine_canvas(local_preferred, r_area);
/* If resolution is 0 there are two possible scenarios: /* If resolution is 0 there are two possible scenarios:
* - Either node is not connected at all * - Either node is not connected at all
@@ -148,8 +148,8 @@ void PreviewOperation::determineResolution(unsigned int resolution[2],
* The latter case would only happen if an input doesn't set any resolution ignoring output * The latter case would only happen if an input doesn't set any resolution ignoring output
* preferred resolution. In such case preview size will be 0 too. * preferred resolution. In such case preview size will be 0 too.
*/ */
int width = resolution[0]; int width = BLI_rcti_size_x(&r_area);
int height = resolution[1]; int height = BLI_rcti_size_y(&r_area);
this->m_divider = 0.0f; this->m_divider = 0.0f;
if (width > 0 && height > 0) { if (width > 0 && height > 0) {
if (width > height) { if (width > height) {
@@ -162,8 +162,7 @@ void PreviewOperation::determineResolution(unsigned int resolution[2],
width = width * this->m_divider; width = width * this->m_divider;
height = height * this->m_divider; height = height * this->m_divider;
resolution[0] = width; BLI_rcti_init(&r_area, 0, width, 0, height);
resolution[1] = height;
} }
eCompositorPriority PreviewOperation::getRenderPriority() const eCompositorPriority PreviewOperation::getRenderPriority() const

View File

@@ -58,8 +58,7 @@ class PreviewOperation : public MultiThreadedOperation {
eCompositorPriority getRenderPriority() const override; eCompositorPriority getRenderPriority() const override;
void executeRegion(rcti *rect, unsigned int tileNumber) override; void executeRegion(rcti *rect, unsigned int tileNumber) override;
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
bool determineDependingAreaOfInterest(rcti *input, bool determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation, ReadBufferOperation *readOperation,
rcti *output) override; rcti *output) override;

View File

@@ -137,7 +137,7 @@ void ProjectorLensDistortionOperation::get_area_of_interest(const int input_idx,
{ {
if (input_idx == 1) { if (input_idx == 1) {
/* Dispersion input is used as constant only. */ /* Dispersion input is used as constant only. */
r_input_area = COM_SINGLE_ELEM_AREA; r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST;
return; return;
} }

View File

@@ -36,16 +36,17 @@ void *ReadBufferOperation::initializeTileData(rcti * /*rect*/)
return m_buffer; return m_buffer;
} }
void ReadBufferOperation::determineResolution(unsigned int resolution[2], void ReadBufferOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
if (this->m_memoryProxy != nullptr) { if (this->m_memoryProxy != nullptr) {
WriteBufferOperation *operation = this->m_memoryProxy->getWriteBufferOperation(); WriteBufferOperation *operation = this->m_memoryProxy->getWriteBufferOperation();
operation->determineResolution(resolution, preferredResolution); operation->determine_canvas(preferred_area, r_area);
operation->setResolution(resolution); operation->set_canvas(r_area);
/** \todo may not occur! But does with blur node. */ /** \todo may not occur! But does with blur node. */
if (this->m_memoryProxy->getExecutor()) { if (this->m_memoryProxy->getExecutor()) {
uint resolution[2] = {static_cast<uint>(BLI_rcti_size_x(&r_area)),
static_cast<uint>(BLI_rcti_size_y(&r_area))};
this->m_memoryProxy->getExecutor()->setResolution(resolution); this->m_memoryProxy->getExecutor()->setResolution(resolution);
} }

View File

@@ -43,8 +43,7 @@ class ReadBufferOperation : public NodeOperation {
return this->m_memoryProxy; return this->m_memoryProxy;
} }
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
void *initializeTileData(rcti *rect) override; void *initializeTileData(rcti *rect) override;
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;

View File

@@ -196,15 +196,13 @@ void RenderLayersProg::deinitExecution()
} }
} }
void RenderLayersProg::determineResolution(unsigned int resolution[2], void RenderLayersProg::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
unsigned int /*preferredResolution*/[2])
{ {
Scene *sce = this->getScene(); Scene *sce = this->getScene();
Render *re = (sce) ? RE_GetSceneRender(sce) : nullptr; Render *re = (sce) ? RE_GetSceneRender(sce) : nullptr;
RenderResult *rr = nullptr; RenderResult *rr = nullptr;
resolution[0] = 0; r_area = COM_AREA_NONE;
resolution[1] = 0;
if (re) { if (re) {
rr = RE_AcquireResultRead(re); rr = RE_AcquireResultRead(re);
@@ -215,8 +213,7 @@ void RenderLayersProg::determineResolution(unsigned int resolution[2],
if (view_layer) { if (view_layer) {
RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name); RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name);
if (rl) { if (rl) {
resolution[0] = rl->rectx; BLI_rcti_init(&r_area, 0, rl->rectx, 0, rl->recty);
resolution[1] = rl->recty;
} }
} }
} }

View File

@@ -73,8 +73,7 @@ class RenderLayersProg : public MultiThreadedOperation {
/** /**
* Determine the output resolution. The resolution is retrieved from the Renderer * Determine the output resolution. The resolution is retrieved from the Renderer
*/ */
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
/** /**
* retrieve the reference to the float buffer of the renderer. * retrieve the reference to the float buffer of the renderer.

View File

@@ -25,10 +25,10 @@ namespace blender::compositor {
RotateOperation::RotateOperation() RotateOperation::RotateOperation()
{ {
this->addInputSocket(DataType::Color); this->addInputSocket(DataType::Color, ResizeMode::Align);
this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value, ResizeMode::Align);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
this->m_imageSocket = nullptr; this->m_imageSocket = nullptr;
this->m_degreeSocket = nullptr; this->m_degreeSocket = nullptr;
this->m_doDegree2RadConversion = false; this->m_doDegree2RadConversion = false;
@@ -36,6 +36,30 @@ RotateOperation::RotateOperation()
sampler_ = PixelSampler::Bilinear; sampler_ = PixelSampler::Bilinear;
} }
void RotateOperation::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;
}
void RotateOperation::get_rotation_center(const float width,
const float height,
float &r_x,
float &r_y)
{
r_x = (width - 1) / 2.0;
r_y = (height - 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, void RotateOperation::get_area_rotation_bounds(const rcti &area,
const float center_x, const float center_x,
const float center_y, const float center_y,
@@ -67,10 +91,44 @@ void RotateOperation::get_area_rotation_bounds(const rcti &area,
r_bounds.ymax = ceil(maxy); r_bounds.ymax = ceil(maxy);
} }
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(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);
r_canvas = input_canvas;
r_canvas.xmax = input_canvas.xmin + BLI_rcti_size_x(&rot_bounds);
r_canvas.ymax = input_canvas.ymin + BLI_rcti_size_y(&rot_bounds);
}
void RotateOperation::init_data() void RotateOperation::init_data()
{ {
this->m_centerX = (getWidth() - 1) / 2.0; if (execution_model_ == eExecutionModel::Tiled) {
this->m_centerY = (getHeight() - 1) / 2.0; get_rotation_center(get_canvas(), m_centerX, m_centerY);
}
} }
void RotateOperation::initExecution() void RotateOperation::initExecution()
@@ -94,11 +152,7 @@ inline void RotateOperation::ensureDegree()
this->m_degreeSocket->readSampled(degree, 0, 0, PixelSampler::Nearest); this->m_degreeSocket->readSampled(degree, 0, 0, PixelSampler::Nearest);
break; break;
case eExecutionModel::FullFrame: case eExecutionModel::FullFrame:
NodeOperation *degree_op = getInputOperation(DEGREE_INPUT_INDEX); degree[0] = get_input_operation(DEGREE_INPUT_INDEX)->get_constant_value_default(0.0f);
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;
break; break;
} }
@@ -159,18 +213,39 @@ bool RotateOperation::determineDependingAreaOfInterest(rcti *input,
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); 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 unused;
getInputSocket(DEGREE_INPUT_INDEX)->determine_canvas(r_area, unused);
ensureDegree();
get_rotation_canvas(r_area, m_sine, m_cosine, r_area);
}
}
void RotateOperation::get_area_of_interest(const int input_idx, void RotateOperation::get_area_of_interest(const int input_idx,
const rcti &output_area, const rcti &output_area,
rcti &r_input_area) rcti &r_input_area)
{ {
if (input_idx == DEGREE_INPUT_INDEX) { if (input_idx == DEGREE_INPUT_INDEX) {
/* Degrees input is always used as constant. */ r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST;
r_input_area = COM_SINGLE_ELEM_AREA;
return; return;
} }
ensureDegree(); 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_); expand_area_for_sampler(r_input_area, sampler_);
} }
@@ -178,12 +253,22 @@ void RotateOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area, const rcti &area,
Span<MemoryBuffer *> inputs) Span<MemoryBuffer *> inputs)
{ {
ensureDegree();
const MemoryBuffer *input_img = inputs[IMAGE_INPUT_INDEX]; const MemoryBuffer *input_img = inputs[IMAGE_INPUT_INDEX];
NodeOperation *image_op = get_input_operation(IMAGE_INPUT_INDEX);
const float image_width = image_op->getWidth();
const float image_height = image_op->getHeight();
float center_x, center_y;
get_rotation_center(image_width, image_height, 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) { for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
float x = it.x; float x = rotate_offset_x + it.x;
float y = it.y; float y = rotate_offset_y + it.y;
rotate_coords(x, y, m_centerX, m_centerY, m_sine, m_cosine); rotate_coords(x, y, center_x, center_y, m_sine, m_cosine);
input_img->read_elem_sampled(x, y, sampler_, it.out); input_img->read_elem_sampled(x, y, sampler_, it.out);
} }
} }

View File

@@ -29,8 +29,10 @@ class RotateOperation : public MultiThreadedOperation {
SocketReader *m_imageSocket; SocketReader *m_imageSocket;
SocketReader *m_degreeSocket; SocketReader *m_degreeSocket;
/* TODO(manzanilla): to be removed with tiled implementation. */
float m_centerX; float m_centerX;
float m_centerY; float m_centerY;
float m_cosine; float m_cosine;
float m_sine; float m_sine;
bool m_doDegree2RadConversion; bool m_doDegree2RadConversion;
@@ -49,12 +51,28 @@ class RotateOperation : public MultiThreadedOperation {
y = center_y + (-sine * dx + cosine * dy); 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_center(const float width, const float height, 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, static void get_area_rotation_bounds(const rcti &area,
const float center_x, const float center_x,
const float center_y, const float center_y,
const float sine, const float sine,
const float cosine, const float cosine,
rcti &r_bounds); 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, bool determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation, ReadBufferOperation *readOperation,
@@ -80,6 +98,8 @@ class RotateOperation : public MultiThreadedOperation {
void update_memory_buffer_partial(MemoryBuffer *output, void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area, const rcti &area,
Span<MemoryBuffer *> inputs) override; Span<MemoryBuffer *> inputs) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
}; };
} // namespace blender::compositor } // namespace blender::compositor

View File

@@ -44,11 +44,10 @@ ScaleOperation::ScaleOperation() : ScaleOperation(DataType::Color)
ScaleOperation::ScaleOperation(DataType data_type) : BaseScaleOperation() 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->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value);
this->addOutputSocket(data_type); this->addOutputSocket(data_type);
this->setResolutionInputSocketIndex(0);
this->m_inputOperation = nullptr; this->m_inputOperation = nullptr;
this->m_inputXOperation = nullptr; this->m_inputXOperation = nullptr;
this->m_inputYOperation = nullptr; this->m_inputYOperation = nullptr;
@@ -64,34 +63,60 @@ float ScaleOperation::get_constant_scale(const int input_op_idx, const float fac
return 1.0f; 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( bool ScaleOperation::is_scaling_variable()
rcti &rect, float center_x, float center_y, float scale_x, float scale_y)
{ {
rect.xmin = scale_coord(rect.xmin, center_x, scale_x); return !get_input_operation(X_INPUT_INDEX)->get_flags().is_constant_operation ||
rect.xmax = scale_coord(rect.xmax, center_x, scale_x); !get_input_operation(Y_INPUT_INDEX)->get_flags().is_constant_operation;
rect.ymin = scale_coord(rect.ymin, center_y, scale_y);
rect.ymax = scale_coord(rect.ymax, center_y, scale_y);
} }
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 int src_xmin = area.xmin;
const int src_ymin = area.ymin;
/* Scale. */
const float center_x = BLI_rcti_cent_x_fl(&area);
const float center_y = BLI_rcti_cent_y_fl(&area);
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));
/* Move area to original position. */
BLI_rcti_translate(&area, src_xmin - area.xmin, src_ymin - area.ymin);
}
void ScaleOperation::clamp_area_size_max(rcti &area, int width, int height)
{
if (BLI_rcti_size_x(&area) > width) {
area.xmax = area.xmin + width;
}
if (BLI_rcti_size_y(&area) > height) {
area.ymax = area.ymin + height;
}
}
void ScaleOperation::set_scale_canvas_max_size(int width, int height)
{
max_scale_canvas_width_ = width;
max_scale_canvas_height_ = height;
} }
void ScaleOperation::init_data() void ScaleOperation::init_data()
{ {
m_centerX = getWidth() / 2.0f; canvas_center_x_ = canvas_.xmin + getWidth() / 2.0f;
m_centerY = getHeight() / 2.0f; canvas_center_y_ = canvas_.ymin + getHeight() / 2.0f;
} }
void ScaleOperation::initExecution() void ScaleOperation::initExecution()
@@ -108,18 +133,52 @@ void ScaleOperation::deinitExecution()
this->m_inputYOperation = nullptr; 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_cent_x(&input_canvas);
const float scale_center_y = BLI_rcti_cent_y(&input_canvas);
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, void ScaleOperation::get_area_of_interest(const int input_idx,
const rcti &output_area, const rcti &output_area,
rcti &r_input_area) rcti &r_input_area)
{ {
r_input_area = output_area; r_input_area = output_area;
if (input_idx != 0 || m_variable_size) { if (input_idx != 0 || is_scaling_variable()) {
return; return;
} }
float scale_x = get_constant_scale_x(); NodeOperation *image_op = get_input_operation(IMAGE_INPUT_INDEX);
float scale_y = get_constant_scale_y(); const float scale_x = get_constant_scale_x(image_op->getWidth());
scale_area(r_input_area, scale_x, scale_y); 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); expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler);
} }
@@ -127,18 +186,68 @@ void ScaleOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area, const rcti &area,
Span<MemoryBuffer *> inputs) Span<MemoryBuffer *> inputs)
{ {
const MemoryBuffer *input_img = inputs[0]; NodeOperation *input_image_op = get_input_operation(IMAGE_INPUT_INDEX);
MemoryBuffer *input_x = inputs[1]; const int input_image_width = input_image_op->getWidth();
MemoryBuffer *input_y = inputs[2]; const int input_image_height = input_image_op->getHeight();
const float scale_x_factor = get_relative_scale_x_factor(); const float scale_x_factor = get_relative_scale_x_factor(input_image_width);
const float scale_y_factor = get_relative_scale_y_factor(); 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 scale_offset_x, scale_offset_y;
ScaleOperation::get_scale_offset(
input_image_op->get_canvas(), this->get_canvas(), scale_offset_x, 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); BuffersIterator<float> it = output->iterate_with({input_x, input_y}, area);
for (; !it.is_end(); ++it) { for (; !it.is_end(); ++it) {
const float rel_scale_x = *it.in(0) * scale_x_factor; const float rel_scale_x = *it.in(0) * scale_x_factor;
const float rel_scale_y = *it.in(1) * scale_y_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_x = scale_coord_inverted(
const float scaled_y = scale_coord(it.y, m_centerY, rel_scale_y); it.x + scale_offset_x, scale_center_x, rel_scale_x);
input_img->read_elem_sampled(scaled_x, scaled_y, (PixelSampler)m_sampler, it.out); const float scaled_y = scale_coord_inverted(
it.y + scale_offset_y, scale_center_y, rel_scale_y);
input_image->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 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);
clamp_area_size_max(r_area,
MAX2(input_width, max_scale_canvas_width_),
MAX2(input_height, max_scale_canvas_height_));
/* 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 +275,8 @@ void ScaleRelativeOperation::executePixelSampled(float output[4],
const float scx = scaleX[0]; const float scx = scaleX[0];
const float scy = scaleY[0]; const float scy = scaleY[0];
float nx = this->m_centerX + (x - this->m_centerX) / scx; float nx = this->canvas_center_x_ + (x - this->canvas_center_x_) / scx;
float ny = this->m_centerY + (y - this->m_centerY) / scy; float ny = this->canvas_center_y_ + (y - this->canvas_center_y_) / scy;
this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); this->m_inputOperation->readSampled(output, nx, ny, effective_sampler);
} }
@@ -186,10 +295,10 @@ bool ScaleRelativeOperation::determineDependingAreaOfInterest(rcti *input,
const float scx = scaleX[0]; const float scx = scaleX[0];
const float scy = scaleY[0]; const float scy = scaleY[0];
newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / scx + 1; newInput.xmax = this->canvas_center_x_ + (input->xmax - this->canvas_center_x_) / scx + 1;
newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / scx - 1; newInput.xmin = this->canvas_center_x_ + (input->xmin - this->canvas_center_x_) / scx - 1;
newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / scy + 1; newInput.ymax = this->canvas_center_y_ + (input->ymax - this->canvas_center_y_) / scy + 1;
newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / scy - 1; newInput.ymin = this->canvas_center_y_ + (input->ymin - this->canvas_center_y_) / scy - 1;
} }
else { else {
newInput.xmax = this->getWidth(); newInput.xmax = this->getWidth();
@@ -222,8 +331,8 @@ void ScaleAbsoluteOperation::executePixelSampled(float output[4],
float relativeXScale = scx / width; float relativeXScale = scx / width;
float relativeYScale = scy / height; float relativeYScale = scy / height;
float nx = this->m_centerX + (x - this->m_centerX) / relativeXScale; float nx = this->canvas_center_x_ + (x - this->canvas_center_x_) / relativeXScale;
float ny = this->m_centerY + (y - this->m_centerY) / relativeYScale; float ny = this->canvas_center_y_ + (y - this->canvas_center_y_) / relativeYScale;
this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); this->m_inputOperation->readSampled(output, nx, ny, effective_sampler);
} }
@@ -248,10 +357,14 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input,
float relateveXScale = scx / width; float relateveXScale = scx / width;
float relateveYScale = scy / height; float relateveYScale = scy / height;
newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / relateveXScale; newInput.xmax = this->canvas_center_x_ +
newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / relateveXScale; (input->xmax - this->canvas_center_x_) / relateveXScale;
newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / relateveYScale; newInput.xmin = this->canvas_center_x_ +
newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / relateveYScale; (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 { else {
newInput.xmax = this->getWidth(); newInput.xmax = this->getWidth();
@@ -265,9 +378,9 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input,
/* Absolute fixed size. */ /* Absolute fixed size. */
ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation() ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation()
{ {
this->addInputSocket(DataType::Color, ResizeMode::None); this->addInputSocket(DataType::Color, ResizeMode::Align);
this->addOutputSocket(DataType::Color); this->addOutputSocket(DataType::Color);
this->setResolutionInputSocketIndex(0); this->set_canvas_input_index(0);
this->m_inputOperation = nullptr; this->m_inputOperation = nullptr;
this->m_is_offset = false; this->m_is_offset = false;
} }
@@ -366,15 +479,14 @@ bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input,
return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
} }
void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], void ScaleFixedSizeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int /*preferredResolution*/[2])
{ {
unsigned int nr[2]; rcti local_preferred = preferred_area;
nr[0] = this->m_newWidth; local_preferred.xmax = local_preferred.xmin + m_newWidth;
nr[1] = this->m_newHeight; local_preferred.ymax = local_preferred.ymin + m_newHeight;
BaseScaleOperation::determineResolution(resolution, nr); BaseScaleOperation::determine_canvas(local_preferred, r_area);
resolution[0] = this->m_newWidth; r_area.xmax = r_area.xmin + m_newWidth;
resolution[1] = this->m_newHeight; r_area.ymax = r_area.ymin + m_newHeight;
} }
void ScaleFixedSizeOperation::get_area_of_interest(const int input_idx, void ScaleFixedSizeOperation::get_area_of_interest(const int input_idx,
@@ -383,10 +495,14 @@ void ScaleFixedSizeOperation::get_area_of_interest(const int input_idx,
{ {
BLI_assert(input_idx == 0); BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx); 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 = output_area;
r_input_area.ymax = (output_area.ymax - m_offsetY) * this->m_relY; BLI_rcti_translate(&r_input_area, -canvas_.xmin, -canvas_.ymin);
r_input_area.ymin = (output_area.ymin - m_offsetY) * this->m_relY; r_input_area.xmax = (r_input_area.xmax - m_offsetX) * this->m_relX;
r_input_area.xmin = (r_input_area.xmin - m_offsetX) * this->m_relX;
r_input_area.ymax = (r_input_area.ymax - m_offsetY) * this->m_relY;
r_input_area.ymin = (r_input_area.ymin - m_offsetY) * this->m_relY;
BLI_rcti_translate(&r_input_area, canvas_.xmin, canvas_.ymin);
expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler); expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler);
} }

View File

@@ -42,19 +42,27 @@ class BaseScaleOperation : public MultiThreadedOperation {
} }
int m_sampler; int m_sampler;
/* TODO(manzanilla): to be removed with tiled implementation. */
bool m_variable_size; bool m_variable_size;
}; };
class ScaleOperation : public BaseScaleOperation { class ScaleOperation : public BaseScaleOperation {
public: public:
static constexpr float MIN_SCALE = 0.0001f; static constexpr float MIN_RELATIVE_SCALE = 0.0001f;
static constexpr float DEFAULT_MAX_SCALE_CANVAS_SIZE = 12000;
protected: 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_inputOperation;
SocketReader *m_inputXOperation; SocketReader *m_inputXOperation;
SocketReader *m_inputYOperation; SocketReader *m_inputYOperation;
float m_centerX; float canvas_center_x_;
float m_centerY; float canvas_center_y_;
int max_scale_canvas_width_ = DEFAULT_MAX_SCALE_CANVAS_SIZE;
int max_scale_canvas_height_ = DEFAULT_MAX_SCALE_CANVAS_SIZE;
public: public:
ScaleOperation(); ScaleOperation();
@@ -62,9 +70,30 @@ class ScaleOperation : public BaseScaleOperation {
static float scale_coord(const float coord, const float center, const float relative_scale) 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, int max_width, int max_height);
void set_scale_canvas_max_size(int width, int height);
void init_data() override; void init_data() override;
void initExecution() override; void initExecution() override;
@@ -75,15 +104,17 @@ class ScaleOperation : public BaseScaleOperation {
const rcti &area, const rcti &area,
Span<MemoryBuffer *> inputs) override; Span<MemoryBuffer *> inputs) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
protected: protected:
virtual float get_relative_scale_x_factor() = 0; virtual float get_relative_scale_x_factor(float width) = 0;
virtual float get_relative_scale_y_factor() = 0; virtual float get_relative_scale_y_factor(float height) = 0;
private: private:
bool is_scaling_variable();
float get_constant_scale(int input_op_idx, float factor); float get_constant_scale(int input_op_idx, float factor);
float get_constant_scale_x(); float get_constant_scale_x(float width);
float get_constant_scale_y(); float get_constant_scale_y(float height);
void scale_area(rcti &rect, float scale_x, float scale_y);
}; };
class ScaleRelativeOperation : public ScaleOperation { class ScaleRelativeOperation : public ScaleOperation {
@@ -94,11 +125,13 @@ class ScaleRelativeOperation : public ScaleOperation {
ReadBufferOperation *readOperation, ReadBufferOperation *readOperation,
rcti *output) override; rcti *output) override;
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) 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; return 1.0f;
} }
float get_relative_scale_y_factor() override
float get_relative_scale_y_factor(float UNUSED(height)) override
{ {
return 1.0f; return 1.0f;
} }
@@ -110,13 +143,15 @@ class ScaleAbsoluteOperation : public ScaleOperation {
ReadBufferOperation *readOperation, ReadBufferOperation *readOperation,
rcti *output) override; rcti *output) override;
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
float get_relative_scale_x_factor() override
float get_relative_scale_x_factor(float width) override
{ {
return 1.0f / getWidth(); return 1.0f / width;
} }
float get_relative_scale_y_factor() override
float get_relative_scale_y_factor(float height) override
{ {
return 1.0f / getHeight(); return 1.0f / height;
} }
}; };
@@ -141,8 +176,7 @@ class ScaleFixedSizeOperation : public BaseScaleOperation {
bool determineDependingAreaOfInterest(rcti *input, bool determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation, ReadBufferOperation *readOperation,
rcti *output) override; rcti *output) override;
void determineResolution(unsigned int resolution[2], void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
unsigned int preferredResolution[2]) override;
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
void init_data() override; void init_data() override;

View File

@@ -388,7 +388,7 @@ void ScreenLensDistortionOperation::get_area_of_interest(const int input_idx,
{ {
if (input_idx != 0) { if (input_idx != 0) {
/* Dispersion and distortion inputs are used as constants only. */ /* Dispersion and distortion inputs are used as constants only. */
r_input_area = COM_SINGLE_ELEM_AREA; r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST;
} }
/* XXX the original method of estimating the area-of-interest does not work /* XXX the original method of estimating the area-of-interest does not work
@@ -398,10 +398,7 @@ void ScreenLensDistortionOperation::get_area_of_interest(const int input_idx,
*/ */
#if 1 #if 1
NodeOperation *image = getInputOperation(0); NodeOperation *image = getInputOperation(0);
r_input_area.xmax = image->getWidth(); r_input_area = image->get_canvas();
r_input_area.xmin = 0;
r_input_area.ymax = image->getHeight();
r_input_area.ymin = 0;
#else /* Original method in tiled implementation. */ #else /* Original method in tiled implementation. */
rcti newInput; rcti newInput;

View File

@@ -34,11 +34,9 @@ void SetColorOperation::executePixelSampled(float output[4],
copy_v4_v4(output, this->m_color); copy_v4_v4(output, this->m_color);
} }
void SetColorOperation::determineResolution(unsigned int resolution[2], void SetColorOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
unsigned int preferredResolution[2])
{ {
resolution[0] = preferredResolution[0]; r_area = preferred_area;
resolution[1] = preferredResolution[1];
} }
} // namespace blender::compositor } // namespace blender::compositor

Some files were not shown because too many files have changed in this diff Show More