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_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)
{

View File

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

View File

@@ -43,6 +43,16 @@ int CompositorContext::getFramenumber() const
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
{
if (U.experimental.use_full_frame_compositor) {

View File

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

View File

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

View File

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

View File

@@ -162,8 +162,10 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system,
len += snprintf(str + len,
maxlen > len ? maxlen - len : 0,
"#%d (%u,%u)",
"#%d (%i,%i) (%u,%u)",
operation->get_id(),
operation->get_canvas().xmin,
operation->get_canvas().ymin,
operation->getWidth(),
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();
Vector<MemoryBuffer *> inputs_buffers(num_inputs);
for (int i = 0; i < num_inputs; i++) {
NodeOperation *input_op = op->get_input_operation(i);
inputs_buffers[i] = active_buffers_.get_rendered_buffer(input_op);
NodeOperation *input = op->get_input_operation(i);
const int offset_x = (input->get_canvas().xmin - op->get_canvas().xmin) + output_x;
const int offset_y = (input->get_canvas().ymin - op->get_canvas().ymin) + output_y;
MemoryBuffer *buf = active_buffers_.get_rendered_buffer(input);
rcti rect = buf->get_rect();
BLI_rcti_translate(&rect, offset_x, offset_y);
inputs_buffers[i] = new MemoryBuffer(
buf->getBuffer(), buf->get_num_channels(), rect, buf->is_a_single_elem());
}
return inputs_buffers;
}
MemoryBuffer *FullFrameExecutionModel::create_operation_buffer(NodeOperation *op)
MemoryBuffer *FullFrameExecutionModel::create_operation_buffer(NodeOperation *op,
const int output_x,
const int output_y)
{
rcti op_rect;
BLI_rcti_init(&op_rect, 0, op->getWidth(), 0, op->getHeight());
rcti rect;
BLI_rcti_init(&rect, output_x, output_x + op->getWidth(), output_y, output_y + op->getHeight());
const DataType data_type = op->getOutputSocket(0)->getDataType();
const bool is_a_single_elem = op->get_flags().is_constant_operation;
return new MemoryBuffer(data_type, op_rect, is_a_single_elem);
return new MemoryBuffer(data_type, rect, is_a_single_elem);
}
void FullFrameExecutionModel::render_operation(NodeOperation *op)
{
Vector<MemoryBuffer *> input_bufs = get_input_buffers(op);
/* Output has no offset for easier image algorithms implementation on operations. */
constexpr int output_x = 0;
constexpr int output_y = 0;
const bool has_outputs = op->getNumberOfOutputSockets() > 0;
MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op) : nullptr;
MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op, output_x, output_y) : nullptr;
if (op->getWidth() > 0 && op->getHeight() > 0) {
Span<rcti> areas = active_buffers_.get_areas_to_render(op);
Vector<MemoryBuffer *> input_bufs = get_input_buffers(op, output_x, output_y);
const int op_offset_x = output_x - op->get_canvas().xmin;
const int op_offset_y = output_y - op->get_canvas().ymin;
Span<rcti> areas = active_buffers_.get_areas_to_render(op, op_offset_x, op_offset_y);
op->render(op_buf, areas, input_bufs);
DebugInfo::operation_rendered(op, op_buf);
for (MemoryBuffer *buf : input_bufs) {
delete buf;
}
}
/* Even if operation has no resolution set the empty buffer. It will be clipped with a
* TranslateOperation from convert resolutions if linked to an operation with resolution. */
@@ -190,7 +214,8 @@ void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op
std::pair<NodeOperation *, rcti> pair = stack.pop_last();
NodeOperation *operation = pair.first;
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;
}
@@ -199,12 +224,11 @@ void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op
const int num_inputs = operation->getNumberOfInputSockets();
for (int i = 0; i < num_inputs; i++) {
NodeOperation *input_op = operation->get_input_operation(i);
rcti input_op_rect, input_area;
BLI_rcti_init(&input_op_rect, 0, input_op->getWidth(), 0, input_op->getHeight());
rcti input_area;
operation->get_area_of_interest(input_op, render_area, input_area);
/* 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});
}
@@ -243,9 +267,8 @@ void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, r
BLI_assert(output_op->isOutputOperation(context_.isRendering()));
/* By default return operation bounds (no border). */
const int op_width = output_op->getWidth();
const int op_height = output_op->getHeight();
BLI_rcti_init(&r_area, 0, op_width, 0, op_height);
rcti canvas = output_op->get_canvas();
r_area = canvas;
const bool has_viewer_border = border_.use_viewer_border &&
(output_op->get_flags().is_viewer_operation ||
@@ -255,12 +278,13 @@ void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, r
/* Get border with normalized coordinates. */
const rctf *norm_border = has_viewer_border ? border_.viewer_border : border_.render_border;
/* Return de-normalized border. */
BLI_rcti_init(&r_area,
norm_border->xmin * op_width,
norm_border->xmax * op_width,
norm_border->ymin * op_height,
norm_border->ymax * op_height);
/* Return de-normalized border within canvas. */
const int w = output_op->getWidth();
const int h = output_op->getHeight();
r_area.xmin = canvas.xmin + norm_border->xmin * w;
r_area.xmax = canvas.xmin + norm_border->xmax * w;
r_area.ymin = canvas.ymin + norm_border->ymin * h;
r_area.ymax = canvas.ymin + norm_border->ymax * h;
}
}

View File

@@ -61,8 +61,10 @@ class FullFrameExecutionModel : public ExecutionModel {
void determine_areas_to_render_and_reads();
void render_operations();
void render_output_dependencies(NodeOperation *output_op);
Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op);
MemoryBuffer *create_operation_buffer(NodeOperation *op);
Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op,
const int output_x,
const int output_y);
MemoryBuffer *create_operation_buffer(NodeOperation *op, const int output_x, const int output_y);
void render_operation(NodeOperation *op);
void operation_finished(NodeOperation *operation);

View File

@@ -122,6 +122,8 @@ void MemoryBuffer::set_strides()
this->elem_stride = m_num_channels;
this->row_stride = getWidth() * m_num_channels;
}
to_positive_x_stride_ = m_rect.xmin < 0 ? -m_rect.xmin + 1 : (m_rect.xmin == 0 ? 1 : 0);
to_positive_y_stride_ = m_rect.ymin < 0 ? -m_rect.ymin + 1 : (m_rect.ymin == 0 ? 1 : 0);
}
void MemoryBuffer::clear()

View File

@@ -114,6 +114,12 @@ class MemoryBuffer {
*/
bool owns_data_;
/** Stride to make any x coordinate within buffer positive (non-zero). */
int to_positive_x_stride_;
/** Stride to make any y coordinate within buffer positive (non-zero). */
int to_positive_y_stride_;
public:
/**
* \brief construct new temporarily MemoryBuffer for an area
@@ -176,7 +182,7 @@ class MemoryBuffer {
*/
float *get_elem(int x, int y)
{
BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax);
BLI_assert(has_coords(x, y));
return m_buffer + get_coords_offset(x, y);
}
@@ -185,7 +191,7 @@ class MemoryBuffer {
*/
const float *get_elem(int x, int y) const
{
BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax);
BLI_assert(has_coords(x, y));
return m_buffer + get_coords_offset(x, y);
}
@@ -196,7 +202,7 @@ class MemoryBuffer {
void read_elem_checked(int x, int y, float *out) const
{
if (x < m_rect.xmin || x >= m_rect.xmax || y < m_rect.ymin || y >= m_rect.ymax) {
if (!has_coords(x, y)) {
clear_elem(out);
}
else {
@@ -206,12 +212,7 @@ class MemoryBuffer {
void read_elem_checked(float x, float y, float *out) const
{
if (x < m_rect.xmin || x >= m_rect.xmax || y < m_rect.ymin || y >= m_rect.ymax) {
clear_elem(out);
}
else {
read_elem(x, y, out);
}
read_elem_checked(floor_x(x), floor_y(y), out);
}
void read_elem_bilinear(float x, float y, float *out) const
@@ -286,8 +287,7 @@ class MemoryBuffer {
*/
float &get_value(int x, int y, int channel)
{
BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax &&
channel >= 0 && channel < m_num_channels);
BLI_assert(has_coords(x, y) && channel >= 0 && channel < m_num_channels);
return m_buffer[get_coords_offset(x, y) + channel];
}
@@ -296,8 +296,7 @@ class MemoryBuffer {
*/
const float &get_value(int x, int y, int channel) const
{
BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax &&
channel >= 0 && channel < m_num_channels);
BLI_assert(has_coords(x, y) && channel >= 0 && channel < m_num_channels);
return m_buffer[get_coords_offset(x, y) + channel];
}
@@ -306,7 +305,7 @@ class MemoryBuffer {
*/
const float *get_row_end(int y) const
{
BLI_assert(y >= 0 && y < getHeight());
BLI_assert(has_y(y));
return m_buffer + (is_a_single_elem() ? m_num_channels : get_coords_offset(getWidth(), y));
}
@@ -681,6 +680,33 @@ class MemoryBuffer {
return y - m_rect.ymin;
}
template<typename T> bool has_coords(T x, T y) const
{
return has_x(x) && has_y(y);
}
template<typename T> bool has_x(T x) const
{
return x >= m_rect.xmin && x < m_rect.xmax;
}
template<typename T> bool has_y(T y) const
{
return y >= m_rect.ymin && y < m_rect.ymax;
}
/* Fast floor functions. The caller should check result is within buffer bounds. It ceils in near
* cases and when given coordinate is negative and less than buffer rect `min - 1`. */
int floor_x(float x) const
{
return (int)(x + to_positive_x_stride_) - to_positive_x_stride_;
}
int floor_y(float y) const
{
return (int)(y + to_positive_y_stride_) - to_positive_y_stride_;
}
void copy_single_elem_from(const MemoryBuffer *src,
int channel_offset,
int elem_size,

View File

@@ -35,12 +35,29 @@ namespace blender::compositor {
NodeOperation::NodeOperation()
{
this->m_resolutionInputSocketIndex = 0;
this->m_width = 0;
this->m_height = 0;
canvas_input_index_ = 0;
canvas_ = COM_AREA_NONE;
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.
* Requires `hash_output_params` to be implemented, otherwise `std::nullopt` is returned.
@@ -48,7 +65,7 @@ NodeOperation::NodeOperation()
*/
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. */
is_hash_output_params_implemented_ = true;
@@ -57,7 +74,11 @@ std::optional<NodeOperationHash> NodeOperation::generate_hash()
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;
hash.params_hash_ = params_hash_;
@@ -108,48 +129,46 @@ void NodeOperation::addOutputSocket(DataType datatype)
m_outputs.append(NodeOperationOutput(this, datatype));
}
void NodeOperation::determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2])
void NodeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
unsigned int used_resolution_index = 0;
if (m_resolutionInputSocketIndex == RESOLUTION_INPUT_ANY) {
unsigned int used_canvas_index = 0;
if (canvas_input_index_ == RESOLUTION_INPUT_ANY) {
for (NodeOperationInput &input : m_inputs) {
unsigned int any_resolution[2] = {0, 0};
input.determineResolution(any_resolution, preferredResolution);
if (any_resolution[0] * any_resolution[1] > 0) {
resolution[0] = any_resolution[0];
resolution[1] = any_resolution[1];
rcti any_area = COM_AREA_NONE;
const bool determined = input.determine_canvas(preferred_area, any_area);
if (determined) {
r_area = any_area;
break;
}
used_resolution_index += 1;
used_canvas_index += 1;
}
}
else if (m_resolutionInputSocketIndex < m_inputs.size()) {
NodeOperationInput &input = m_inputs[m_resolutionInputSocketIndex];
input.determineResolution(resolution, preferredResolution);
used_resolution_index = m_resolutionInputSocketIndex;
else if (canvas_input_index_ < m_inputs.size()) {
NodeOperationInput &input = m_inputs[canvas_input_index_];
input.determine_canvas(preferred_area, r_area);
used_canvas_index = canvas_input_index_;
}
if (modify_determined_resolution_fn_) {
modify_determined_resolution_fn_(resolution);
if (modify_determined_canvas_fn_) {
modify_determined_canvas_fn_(r_area);
}
unsigned int temp2[2] = {resolution[0], resolution[1]};
unsigned int temp[2];
rcti unused_area;
const rcti &local_preferred_area = r_area;
for (unsigned int index = 0; index < m_inputs.size(); index++) {
if (index == used_resolution_index) {
if (index == used_canvas_index) {
continue;
}
NodeOperationInput &input = m_inputs[index];
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()
@@ -185,6 +204,28 @@ void NodeOperation::deinitExecution()
{
/* pass */
}
void NodeOperation::set_canvas(const rcti &canvas_area)
{
canvas_ = canvas_area;
flags.is_canvas_set = true;
}
const rcti &NodeOperation::get_canvas() const
{
return canvas_;
}
/**
* 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)
{
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
* whole area is used. */
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;
}
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) {
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],
unsigned int preferredResolution[2])
void NodeOperationOutput::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperation &operation = getOperation();
if (operation.get_flags().is_resolution_set) {
resolution[0] = operation.getWidth();
resolution[1] = operation.getHeight();
if (operation.get_flags().is_canvas_set) {
r_area = operation.get_canvas();
}
else {
operation.determineResolution(resolution, preferredResolution);
if (resolution[0] > 0 && resolution[1] > 0) {
operation.setResolution(resolution);
operation.determine_canvas(preferred_area, r_area);
if (!BLI_rcti_is_empty(&r_area)) {
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) {
os << "view_border,";
}
if (node_operation_flags.is_resolution_set) {
os << "resolution_set,";
if (node_operation_flags.is_canvas_set) {
os << "canvas_set,";
}
if (node_operation_flags.is_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
* occurs */
Center = NS_CR_CENTER,
/** \brief The bottom left of the input image is the bottom left of the working area of the node,
* no resizing occurs */
/** No resizing or translation. */
None = NS_CR_NONE,
/**
* Input image is translated so that its bottom left matches the bottom left of the working area
* of the node, no resizing occurs.
*/
Align = 100,
/** \brief Fit the width of the input image to the width of the working area of the node */
FitWidth = NS_CR_FIT_WIDTH,
/** \brief Fit the height of the input image to the height of the working area of the node */
@@ -130,7 +134,7 @@ class NodeOperationInput {
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
MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
@@ -158,12 +162,7 @@ class NodeOperationOutput {
return m_datatype;
}
/**
* \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]);
void determine_canvas(const rcti &preferred_area, rcti &r_area);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
@@ -211,9 +210,9 @@ struct NodeOperationFlags {
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).
@@ -257,7 +256,7 @@ struct NodeOperationFlags {
open_cl = false;
use_render_border = false;
use_viewer_border = false;
is_resolution_set = false;
is_canvas_set = false;
is_set_operation = false;
is_read_buffer_operation = false;
is_write_buffer_operation = false;
@@ -324,11 +323,11 @@ class NodeOperation {
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
@@ -352,15 +351,7 @@ class NodeOperation {
*/
eExecutionModel execution_model_;
/**
* Width of the output of this operation.
*/
unsigned int m_width;
/**
* Height of the output of this operation.
*/
unsigned int m_height;
rcti canvas_;
/**
* 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)
{
m_name = name;
@@ -399,6 +385,9 @@ class NodeOperation {
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
{
return flags;
@@ -424,14 +413,7 @@ class NodeOperation {
return getInputOperation(index);
}
/**
* \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]);
virtual void determine_canvas(const rcti &preferred_area, rcti &r_area);
/**
* \brief isOutputOperation determines whether this operation is an output of the
@@ -453,6 +435,11 @@ class NodeOperation {
return false;
}
void set_execution_model(const eExecutionModel model)
{
execution_model_ = model;
}
void setbNodeTree(const bNodeTree *tree)
{
this->m_btree = tree;
@@ -527,18 +514,9 @@ class NodeOperation {
}
virtual void deinitExecution();
/**
* \brief set the resolution
* \param resolution: the resolution to set
*/
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;
}
}
void set_canvas(const rcti &canvas_area);
const rcti &get_canvas() const;
void unset_canvas();
/**
* \brief is this operation the active viewer output
@@ -557,18 +535,18 @@ class NodeOperation {
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
*/
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
* as preferred resolution for the other inputs.
* Set a custom function to modify determined canvas from main input just before setting it
* 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
{
return m_width;
return BLI_rcti_size_x(&get_canvas());
}
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)
@@ -697,16 +675,18 @@ class NodeOperation {
void addInputSocket(DataType datatype, ResizeMode resize_mode = ResizeMode::Center);
void addOutputSocket(DataType datatype);
/* TODO(manzanilla): to be removed with tiled implementation. */
void setWidth(unsigned int width)
{
this->m_width = width;
this->flags.is_resolution_set = true;
canvas_.xmax = canvas_.xmin + width;
this->flags.is_canvas_set = true;
}
void setHeight(unsigned int height)
{
this->m_height = height;
this->flags.is_resolution_set = true;
canvas_.ymax = canvas_.ymin + height;
this->flags.is_canvas_set = true;
}
SocketReader *getInputSocketReader(unsigned int inputSocketindex);
NodeOperation *getInputOperation(unsigned int inputSocketindex);

View File

@@ -33,6 +33,7 @@
#include "COM_SetValueOperation.h"
#include "COM_SetVectorOperation.h"
#include "COM_SocketProxyOperation.h"
#include "COM_TranslateOperation.h"
#include "COM_ViewerOperation.h"
#include "COM_WriteBufferOperation.h"
@@ -106,7 +107,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
folder.fold_operations();
}
determineResolutions();
determine_canvases();
save_graphviz("compositor_prior_merging");
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) {
if (op->isOutputOperation(m_context->isRendering()) && !op->get_flags().is_preview_operation) {
unsigned int resolution[2] = {0, 0};
unsigned int preferredResolution[2] = {0, 0};
op->determineResolution(resolution, preferredResolution);
op->setResolution(resolution);
rcti canvas = COM_AREA_NONE;
op->determine_canvas(preferred_area, canvas);
op->set_canvas(canvas);
}
}
for (NodeOperation *op : m_operations) {
if (op->isOutputOperation(m_context->isRendering()) && op->get_flags().is_preview_operation) {
unsigned int resolution[2] = {0, 0};
unsigned int preferredResolution[2] = {0, 0};
op->determineResolution(resolution, preferredResolution);
op->setResolution(resolution);
rcti canvas = COM_AREA_NONE;
op->determine_canvas(preferred_area, canvas);
op->set_canvas(canvas);
}
}
/* add convert resolution operations when needed */
/* Convert operation canvases when needed. */
{
Vector<Link> convert_links;
for (const Link &link : m_links) {
if (link.to()->getResizeMode() != ResizeMode::None) {
NodeOperation &from_op = link.from()->getOperation();
NodeOperation &to_op = link.to()->getOperation();
if (from_op.getWidth() != to_op.getWidth() || from_op.getHeight() != to_op.getHeight()) {
const rcti &from_canvas = link.from()->getOperation().get_canvas();
const rcti &to_canvas = link.to()->getOperation().get_canvas();
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);
}
}
}
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 */
void resolve_proxies();
/** Calculate resolution for each operation */
void determineResolutions();
/** Calculate canvas area for each operation. */
void determine_canvases();
/** Helper function to store connected inputs for replacement */
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.
*/
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);
void register_read(NodeOperation *read_op);
blender::Span<rcti> get_areas_to_render(NodeOperation *op);
Vector<rcti> get_areas_to_render(NodeOperation *op, int offset_x, int offset_y);
bool is_operation_rendered(NodeOperation *op);
void set_rendered_buffer(NodeOperation *op, std::unique_ptr<MemoryBuffer> buffer);
MemoryBuffer *get_rendered_buffer(NodeOperation *op);

View File

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

View File

@@ -62,7 +62,7 @@ void BoxMaskNode::convertToOperations(NodeConverter &converter,
scaleOperation->setOffset(0.0f, 0.0f);
scaleOperation->setNewWidth(rd->xsch * render_size_factor);
scaleOperation->setNewHeight(rd->ysch * render_size_factor);
scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::None);
scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::Align);
converter.addOperation(scaleOperation);
converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0));

View File

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

View File

@@ -62,7 +62,7 @@ void EllipseMaskNode::convertToOperations(NodeConverter &converter,
scaleOperation->setOffset(0.0f, 0.0f);
scaleOperation->setNewWidth(rd->xsch * render_size_factor);
scaleOperation->setNewHeight(rd->ysch * render_size_factor);
scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::None);
scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::Align);
converter.addOperation(scaleOperation);
converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -127,6 +127,8 @@ void Stabilize2dNode::convertToOperations(NodeConverter &converter,
transform_op->set_sampler(sampler);
transform_op->set_convert_rotate_degree_to_rad(false);
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.mapInputSocket(imageInput, transform_op->getInputSocket(0));
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(scaleAttribute->getOutputSocket(), transform_op->getInputSocket(4));
converter.mapOutputSocket(getOutputSocket(), transform_op->getOutputSocket());
break;
}
}
}

View File

@@ -75,6 +75,7 @@ void TransformNode::convertToOperations(NodeConverter &converter,
case eExecutionModel::FullFrame: {
TransformOperation *op = new TransformOperation();
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.mapInputSocket(imageInput, op->getInputSocket(0));

View File

@@ -41,7 +41,9 @@ void TranslateNode::convertToOperations(NodeConverter &converter,
NodeInput *inputYSocket = this->getInputSocket(2);
NodeOutput *outputSocket = this->getOutputSocket(0);
TranslateOperation *operation = new TranslateOperation();
TranslateOperation *operation = context.get_execution_model() == eExecutionModel::Tiled ?
new TranslateOperation() :
new TranslateCanvasOperation();
operation->set_wrapping(data->wrap_axis);
if (data->relative) {
const RenderData *rd = context.getRenderData();

View File

@@ -60,10 +60,10 @@ void ViewerNode::convertToOperations(NodeConverter &converter,
viewerOperation->setViewSettings(context.getViewSettings());
viewerOperation->setDisplaySettings(context.getDisplaySettings());
viewerOperation->setResolutionInputSocketIndex(0);
viewerOperation->set_canvas_input_index(0);
if (!imageSocket->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;
}
void BlurBaseOperation::determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2])
void BlurBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
if (!m_extend_bounds) {
NodeOperation::determineResolution(resolution, preferredResolution);
NodeOperation::determine_canvas(preferred_area, r_area);
return;
}
switch (execution_model_) {
case eExecutionModel::Tiled: {
NodeOperation::determineResolution(resolution, preferredResolution);
resolution[0] += 2 * m_size * m_data.sizex;
resolution[1] += 2 * m_size * m_data.sizey;
NodeOperation::determine_canvas(preferred_area, r_area);
r_area.xmax += 2 * m_size * m_data.sizex;
r_area.ymax += 2 * m_size * m_data.sizey;
break;
}
case eExecutionModel::FullFrame: {
/* Setting a modifier ensures all non main inputs have extended bounds as preferred
* resolution, avoiding unnecessary resolution conversions that would hide constant
* canvas, avoiding unnecessary canvas convertions that would hide constant
* operations. */
set_determined_resolution_modifier([=](unsigned int res[2]) {
set_determined_canvas_modifier([=](rcti &canvas) {
/* Rounding to even prevents jiggling in backdrop while switching size values. */
res[0] += round_to_even(2 * m_size * m_data.sizex);
res[1] += round_to_even(2 * m_size * m_data.sizey);
canvas.xmax += round_to_even(2 * m_size * m_data.sizex);
canvas.ymax += round_to_even(2 * m_size * m_data.sizey);
});
NodeOperation::determineResolution(resolution, preferredResolution);
NodeOperation::determine_canvas(preferred_area, r_area);
break;
}
}
@@ -251,7 +250,7 @@ void BlurBaseOperation::get_area_of_interest(const int input_idx,
r_input_area = output_area;
break;
case 1:
r_input_area = use_variable_size_ ? output_area : COM_SINGLE_ELEM_AREA;
r_input_area = use_variable_size_ ? output_area : COM_CONSTANT_INPUT_AREA_OF_INTEREST;
break;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -25,10 +25,10 @@ namespace blender::compositor {
RotateOperation::RotateOperation()
{
this->addInputSocket(DataType::Color);
this->addInputSocket(DataType::Value);
this->addInputSocket(DataType::Color, ResizeMode::Align);
this->addInputSocket(DataType::Value, ResizeMode::Align);
this->addOutputSocket(DataType::Color);
this->setResolutionInputSocketIndex(0);
this->set_canvas_input_index(0);
this->m_imageSocket = nullptr;
this->m_degreeSocket = nullptr;
this->m_doDegree2RadConversion = false;
@@ -36,6 +36,30 @@ RotateOperation::RotateOperation()
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,
const float center_x,
const float center_y,
@@ -67,10 +91,44 @@ void RotateOperation::get_area_rotation_bounds(const rcti &area,
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()
{
this->m_centerX = (getWidth() - 1) / 2.0;
this->m_centerY = (getHeight() - 1) / 2.0;
if (execution_model_ == eExecutionModel::Tiled) {
get_rotation_center(get_canvas(), m_centerX, m_centerY);
}
}
void RotateOperation::initExecution()
@@ -94,11 +152,7 @@ inline void RotateOperation::ensureDegree()
this->m_degreeSocket->readSampled(degree, 0, 0, PixelSampler::Nearest);
break;
case eExecutionModel::FullFrame:
NodeOperation *degree_op = getInputOperation(DEGREE_INPUT_INDEX);
const bool is_constant_degree = degree_op->get_flags().is_constant_operation;
degree[0] = is_constant_degree ?
static_cast<ConstantOperation *>(degree_op)->get_constant_elem()[0] :
0.0f;
degree[0] = get_input_operation(DEGREE_INPUT_INDEX)->get_constant_value_default(0.0f);
break;
}
@@ -159,18 +213,39 @@ bool RotateOperation::determineDependingAreaOfInterest(rcti *input,
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
void RotateOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
if (execution_model_ == eExecutionModel::Tiled) {
NodeOperation::determine_canvas(preferred_area, r_area);
return;
}
const bool image_determined =
getInputSocket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (image_determined) {
rcti 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,
const rcti &output_area,
rcti &r_input_area)
{
if (input_idx == DEGREE_INPUT_INDEX) {
/* Degrees input is always used as constant. */
r_input_area = COM_SINGLE_ELEM_AREA;
r_input_area = COM_CONSTANT_INPUT_AREA_OF_INTEREST;
return;
}
ensureDegree();
get_area_rotation_bounds(output_area, m_centerX, m_centerY, m_sine, m_cosine, r_input_area);
const rcti &input_image_canvas = get_input_operation(IMAGE_INPUT_INDEX)->get_canvas();
get_rotation_area_of_interest(
input_image_canvas, this->get_canvas(), m_sine, m_cosine, output_area, r_input_area);
expand_area_for_sampler(r_input_area, sampler_);
}
@@ -178,12 +253,22 @@ void RotateOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
ensureDegree();
const MemoryBuffer *input_img = inputs[IMAGE_INPUT_INDEX];
NodeOperation *image_op = get_input_operation(IMAGE_INPUT_INDEX);
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) {
float x = it.x;
float y = it.y;
rotate_coords(x, y, m_centerX, m_centerY, m_sine, m_cosine);
float x = rotate_offset_x + it.x;
float y = rotate_offset_y + it.y;
rotate_coords(x, y, center_x, center_y, m_sine, m_cosine);
input_img->read_elem_sampled(x, y, sampler_, it.out);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

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