Compositor: Re-write Pixelate node for CPU compositor #117223
@ -16,18 +16,16 @@ PixelateNode::PixelateNode(bNode *editor_node) : Node(editor_node)
|
||||
void PixelateNode::convert_to_operations(NodeConverter &converter,
|
||||
const CompositorContext & /*context*/) const
|
||||
{
|
||||
const bNode *editor_node = this->get_bnode();
|
||||
|
||||
NodeInput *input_socket = this->get_input_socket(0);
|
||||
NodeOutput *output_socket = this->get_output_socket(0);
|
||||
DataType datatype = input_socket->get_data_type();
|
||||
|
||||
if (input_socket->is_linked()) {
|
||||
NodeOutput *link = input_socket->get_link();
|
||||
datatype = link->get_data_type();
|
||||
}
|
||||
|
||||
PixelateOperation *operation = new PixelateOperation(datatype);
|
||||
PixelateOperation *operation = new PixelateOperation();
|
||||
converter.add_operation(operation);
|
||||
|
||||
operation->set_pixel_size(editor_node->custom1);
|
||||
|
||||
converter.map_input_socket(input_socket, operation->get_input_socket(0));
|
||||
converter.map_output_socket(output_socket, operation->get_output_socket(0));
|
||||
}
|
||||
|
@ -4,16 +4,20 @@
|
||||
|
||||
#include "COM_PixelateOperation.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
PixelateOperation::PixelateOperation(DataType data_type)
|
||||
PixelateOperation::PixelateOperation()
|
||||
{
|
||||
this->add_input_socket(data_type);
|
||||
this->add_output_socket(data_type);
|
||||
this->add_input_socket(DataType::Color);
|
||||
this->add_output_socket(DataType::Color);
|
||||
this->set_canvas_input_index(0);
|
||||
input_operation_ = nullptr;
|
||||
|
||||
flags_.can_be_constant = true;
|
||||
|
||||
pixel_size_ = 1;
|
||||
}
|
||||
|
||||
void PixelateOperation::init_execution()
|
||||
@ -26,14 +30,97 @@ void PixelateOperation::deinit_execution()
|
||||
input_operation_ = nullptr;
|
||||
}
|
||||
|
||||
void PixelateOperation::execute_pixel_sampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
PixelSampler sampler)
|
||||
bool PixelateOperation::determine_depending_area_of_interest(rcti *input,
|
||||
ReadBufferOperation *read_operation,
|
||||
rcti *output)
|
||||
{
|
||||
float nx = round(x);
|
||||
float ny = round(y);
|
||||
input_operation_->read_sampled(output, nx, ny, sampler);
|
||||
rcti new_input;
|
||||
|
||||
new_input.xmin = input->xmin;
|
||||
new_input.xmax = input->xmax + pixel_size_ - 1;
|
||||
new_input.ymax = input->ymax;
|
||||
new_input.ymax = input->ymax + pixel_size_ - 1;
|
||||
|
||||
return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
|
||||
}
|
||||
|
||||
void PixelateOperation::execute_pixel_sampled(float output[4],
|
||||
const float x,
|
||||
const float y,
|
||||
const PixelSampler sampler)
|
||||
{
|
||||
const int width = this->get_width();
|
||||
const int height = this->get_height();
|
||||
|
||||
const int x_start = (int(x) / pixel_size_) * pixel_size_;
|
||||
const int y_start = (int(y) / pixel_size_) * pixel_size_;
|
||||
|
||||
const int x_end = std::min(x_start + pixel_size_, width);
|
||||
const int y_end = std::min(y_start + pixel_size_, height);
|
||||
|
||||
float4 color_accum(0, 0, 0, 0);
|
||||
|
||||
for (int iy = y_start; iy < y_end; ++iy) {
|
||||
for (int ix = x_start; ix < x_end; ++ix) {
|
||||
float4 color;
|
||||
input_operation_->read_sampled(color, ix, iy, sampler);
|
||||
|
||||
color_accum += color;
|
||||
}
|
||||
}
|
||||
|
||||
const int scale = (x_end - x_start) * (y_end - y_start);
|
||||
|
||||
copy_v4_v4(output, color_accum / float(scale));
|
||||
}
|
||||
|
||||
void PixelateOperation::get_area_of_interest(const int /*input_idx*/,
|
||||
const rcti &output_area,
|
||||
rcti &r_input_area)
|
||||
{
|
||||
r_input_area.xmin = output_area.xmin;
|
||||
r_input_area.ymin = output_area.ymin;
|
||||
|
||||
r_input_area.xmax = output_area.xmax + pixel_size_ - 1;
|
||||
r_input_area.ymax = output_area.ymax + pixel_size_ - 1;
|
||||
}
|
||||
|
||||
void PixelateOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs)
|
||||
{
|
||||
MemoryBuffer *image = inputs[0];
|
||||
|
||||
if (image->is_a_single_elem()) {
|
||||
copy_v4_v4(output->get_elem(0, 0), image->get_elem(0, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
const int width = image->get_width();
|
||||
const int height = image->get_height();
|
||||
|
||||
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
|
||||
const int x_start = (it.x / pixel_size_) * pixel_size_;
|
||||
const int y_start = (it.y / pixel_size_) * pixel_size_;
|
||||
|
||||
const int x_end = std::min(x_start + pixel_size_, width);
|
||||
const int y_end = std::min(y_start + pixel_size_, height);
|
||||
|
||||
float4 color_accum(0, 0, 0, 0);
|
||||
|
||||
for (int y = y_start; y < y_end; ++y) {
|
||||
for (int x = x_start; x < x_end; ++x) {
|
||||
float4 color;
|
||||
image->read_elem(x, y, color);
|
||||
|
||||
color_accum += color;
|
||||
}
|
||||
}
|
||||
|
||||
const int scale = (x_end - x_start) * (y_end - y_start);
|
||||
|
||||
copy_v4_v4(it.out, color_accum / float(scale));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COM_NodeOperation.h"
|
||||
#include "COM_MultiThreadedOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
@ -15,19 +15,26 @@ namespace blender::compositor {
|
||||
* For some setups you don want this.
|
||||
* This operation will remove the sub-pixel accuracy
|
||||
*/
|
||||
class PixelateOperation : public NodeOperation {
|
||||
class PixelateOperation : public MultiThreadedOperation {
|
||||
private:
|
||||
/**
|
||||
* \brief cached reference to the input operation
|
||||
*/
|
||||
SocketReader *input_operation_;
|
||||
|
||||
int pixel_size_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief PixelateOperation
|
||||
* \param data_type: the datatype to create this operator for (saves datatype conversions)
|
||||
*/
|
||||
PixelateOperation(DataType data_type);
|
||||
PixelateOperation();
|
||||
|
||||
void set_pixel_size(const int pixel_size)
|
||||
{
|
||||
if (pixel_size < 1) {
|
||||
pixel_size_ = 1;
|
||||
return;
|
||||
}
|
||||
pixel_size_ = pixel_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief initialization of the execution
|
||||
@ -39,6 +46,10 @@ class PixelateOperation : public NodeOperation {
|
||||
*/
|
||||
void deinit_execution() override;
|
||||
|
||||
bool determine_depending_area_of_interest(rcti *input,
|
||||
ReadBufferOperation *read_operation,
|
||||
rcti *output) override;
|
||||
|
||||
/**
|
||||
* \brief execute_pixel
|
||||
* \param output: result
|
||||
@ -47,6 +58,11 @@ class PixelateOperation : public NodeOperation {
|
||||
* \param sampler: sampler
|
||||
*/
|
||||
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
|
||||
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
|
||||
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
@ -8305,6 +8305,21 @@ static void def_cmp_trackpos(StructRNA *srna)
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_cmp_pixelate(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* The range of the pixel size is chosen so that it is positive and above zero, and also does not
|
||||
* exceed the underlying int16_t type. The size limit matches the maximum size used by blur
|
||||
|
||||
* nodes. */
|
||||
prop = RNA_def_property(srna, "pixel_size", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "custom1");
|
||||
RNA_def_property_range(prop, 1, 2048);
|
||||
RNA_def_property_int_default(prop, 1);
|
||||
RNA_def_property_ui_text(prop, "Pixel Size", "Pixel size of the output image");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_cmp_translate(StructRNA *srna)
|
||||
{
|
||||
static const EnumPropertyItem translate_items[] = {
|
||||
|
@ -207,7 +207,7 @@ DefNode(CompositorNode, CMP_NODE_MASK, def_cmp_mask, "MASK",
|
||||
DefNode(CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYINGSCREEN", KeyingScreen, "Keying Screen", "" )
|
||||
DefNode(CompositorNode, CMP_NODE_KEYING, def_cmp_keying, "KEYING", Keying, "Keying", "" )
|
||||
DefNode(CompositorNode, CMP_NODE_TRACKPOS, def_cmp_trackpos, "TRACKPOS", TrackPos, "Track Position", "" )
|
||||
DefNode(CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELATE", Pixelate, "Pixelate", "" )
|
||||
DefNode(CompositorNode, CMP_NODE_PIXELATE, def_cmp_pixelate, "PIXELATE", Pixelate, "Pixelate", "" )
|
||||
DefNode(CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" )
|
||||
DefNode(CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" )
|
||||
DefNode(CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" )
|
||||
|
@ -10,6 +10,9 @@
|
||||
|
||||
#include "COM_node_operation.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "node_composite_util.hh"
|
||||
|
||||
/* **************** Pixelate ******************** */
|
||||
@ -22,6 +25,16 @@ static void cmp_node_pixelate_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Color>("Color");
|
||||
}
|
||||
|
||||
static void node_composit_init_pixelate(bNodeTree * /*ntree*/, bNode *node)
|
||||
{
|
||||
node->custom1 = 1;
|
||||
}
|
||||
|
||||
static void node_composit_buts_pixelate(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiItemR(layout, ptr, "pixel_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
using namespace blender::realtime_compositor;
|
||||
|
||||
class PixelateOperation : public NodeOperation {
|
||||
@ -78,6 +91,8 @@ void register_node_type_cmp_pixelate()
|
||||
|
||||
cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER);
|
||||
ntype.declare = file_ns::cmp_node_pixelate_declare;
|
||||
ntype.draw_buttons = file_ns::node_composit_buts_pixelate;
|
||||
ntype.initfunc = file_ns::node_composit_init_pixelate;
|
||||
ntype.get_compositor_operation = file_ns::get_compositor_operation;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
|
Loading…
Reference in New Issue
Block a user
Specify a range to avoid negative input.