WIP: Compositor: Add interpolation option to scale node #119902

Draft
Noah Pinales wants to merge 3 commits from Noah-Pinales/blender:com-scale-interp into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
5 changed files with 93 additions and 10 deletions

View File

@ -19,15 +19,31 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const const CompositorContext &context) const
{ {
const bNode *bnode = this->get_bnode(); const bNode *bnode = this->get_bnode();
const NodeScaleData *data = (const NodeScaleData *)bnode->storage;
NodeInput *input_socket = this->get_input_socket(0); NodeInput *input_socket = this->get_input_socket(0);
NodeInput *input_xsocket = this->get_input_socket(1); NodeInput *input_xsocket = this->get_input_socket(1);
NodeInput *input_ysocket = this->get_input_socket(2); NodeInput *input_ysocket = this->get_input_socket(2);
NodeOutput *output_socket = this->get_output_socket(0); NodeOutput *output_socket = this->get_output_socket(0);
PixelSampler sampler = PixelSampler::Nearest;
switch (data->interpolation) {
case 0:
sampler = PixelSampler::Nearest;
break;
case 1:
sampler = PixelSampler::Bilinear;
break;
case 2:
sampler = PixelSampler::Bicubic;
break;
}
switch (bnode->custom1) { switch (bnode->custom1) {
case CMP_NODE_SCALE_RELATIVE: { case CMP_NODE_SCALE_RELATIVE: {
ScaleRelativeOperation *operation = new ScaleRelativeOperation(); ScaleRelativeOperation *operation = new ScaleRelativeOperation();
operation->set_sampler(sampler);
converter.add_operation(operation); converter.add_operation(operation);
converter.map_input_socket(input_socket, operation->get_input_socket(0)); converter.map_input_socket(input_socket, operation->get_input_socket(0));
@ -44,6 +60,8 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
converter.add_operation(scale_factor_operation); converter.add_operation(scale_factor_operation);
ScaleRelativeOperation *operation = new ScaleRelativeOperation(); ScaleRelativeOperation *operation = new ScaleRelativeOperation();
operation->set_sampler(sampler);
converter.add_operation(operation); converter.add_operation(operation);
converter.map_input_socket(input_socket, operation->get_input_socket(0)); converter.map_input_socket(input_socket, operation->get_input_socket(0));
@ -68,6 +86,7 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
operation->set_offset(bnode->custom3, bnode->custom4); operation->set_offset(bnode->custom3, bnode->custom4);
operation->set_new_width(rd->xsch * render_size_factor); operation->set_new_width(rd->xsch * render_size_factor);
operation->set_new_height(rd->ysch * render_size_factor); operation->set_new_height(rd->ysch * render_size_factor);
operation->set_sampler(sampler);
converter.add_operation(operation); converter.add_operation(operation);
converter.map_input_socket(input_socket, operation->get_input_socket(0)); converter.map_input_socket(input_socket, operation->get_input_socket(0));
@ -80,6 +99,8 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
case CMP_NODE_SCALE_ABSOLUTE: { case CMP_NODE_SCALE_ABSOLUTE: {
/* TODO: what is the use of this one.... perhaps some issues when the ui was updated... */ /* TODO: what is the use of this one.... perhaps some issues when the ui was updated... */
ScaleAbsoluteOperation *operation = new ScaleAbsoluteOperation(); ScaleAbsoluteOperation *operation = new ScaleAbsoluteOperation();
operation->set_sampler(sampler);
converter.add_operation(operation); converter.add_operation(operation);
converter.map_input_socket(input_socket, operation->get_input_socket(0)); converter.map_input_socket(input_socket, operation->get_input_socket(0));

View File

@ -23,9 +23,9 @@ class BaseScaleOperation : public MultiThreadedOperation {
protected: protected:
BaseScaleOperation(); BaseScaleOperation();
PixelSampler get_effective_sampler(PixelSampler sampler) PixelSampler get_effective_sampler()
{ {
return (sampler_ == -1) ? sampler : (PixelSampler)sampler_; return (PixelSampler)sampler_;
} }
int sampler_; int sampler_;

View File

@ -1418,6 +1418,13 @@ typedef struct NodeTranslateData {
char relative; char relative;
} NodeTranslateData; } NodeTranslateData;
typedef struct NodeScaleData {
int16_t space, frame_method;
float offset_x, offset_y;
short interpolation;
char _pad[2];
} NodeScaleData;
typedef struct NodePlaneTrackDeformData { typedef struct NodePlaneTrackDeformData {
char tracking_object[64]; char tracking_object[64];
char plane_track_name[64]; char plane_track_name[64];

View File

@ -6612,28 +6612,55 @@ static void def_cmp_scale(StructRNA *srna)
{0, nullptr, 0, nullptr, nullptr}, {0, nullptr, 0, nullptr, nullptr},
}; };
static const EnumPropertyItem interpolation_items[] = {
{CMP_NODE_STABILIZE_INTERPOLATION_NEAREST,
"NEAREST",
0,
"Nearest",
"Use nearest interpolation"},
{CMP_NODE_STABILIZE_INTERPOLATION_BILINEAR,
"BILINEAR",
0,
"Bilinear",
"Use bilinear interpolation"},
{CMP_NODE_STABILIZE_INTERPOLATION_BICUBIC,
"BICUBIC",
0,
"Bicubic",
"Use bicubic interpolation"},
{0, nullptr, 0, nullptr, nullptr},
};
RNA_def_struct_sdna_from(srna, "NodeScaleData", "storage");
prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "custom1"); RNA_def_property_enum_sdna(prop, nullptr, "space");
RNA_def_property_enum_items(prop, space_items); RNA_def_property_enum_items(prop, space_items);
RNA_def_property_ui_text(prop, "Space", "Coordinate space to scale relative to"); RNA_def_property_ui_text(prop, "Space", "Coordinate space to scale relative to");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_CompositorNodeScale_update"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_CompositorNodeScale_update");
/* expose 2 flags as a enum of 3 items */ /* expose 2 flags as a enum of 3 items */
prop = RNA_def_property(srna, "frame_method", PROP_ENUM, PROP_NONE); prop = RNA_def_property(srna, "frame_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, nullptr, "custom2"); RNA_def_property_enum_bitflag_sdna(prop, nullptr, "frame_method");
RNA_def_property_enum_items(prop, space_frame_items); RNA_def_property_enum_items(prop, space_frame_items);
RNA_def_property_ui_text(prop, "Frame Method", "How the image fits in the camera frame"); RNA_def_property_ui_text(prop, "Frame Method", "How the image fits in the camera frame");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_NONE); prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, nullptr, "custom3"); RNA_def_property_float_sdna(prop, nullptr, "offset_x");
RNA_def_property_ui_text(prop, "X Offset", "Offset image horizontally (factor of image size)"); RNA_def_property_ui_text(prop, "X Offset", "Offset image horizontally (factor of image size)");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_NONE); prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, nullptr, "custom4"); RNA_def_property_float_sdna(prop, nullptr, "offset_y");
RNA_def_property_ui_text(prop, "Y Offset", "Offset image vertically (factor of image size)"); RNA_def_property_ui_text(prop, "Y Offset", "Offset image vertically (factor of image size)");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "interpolation");
RNA_def_property_enum_items(prop, interpolation_items);
RNA_def_property_ui_text(prop, "Interpolation", "Which interpolation method to use");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
} }
static void def_cmp_rotate(StructRNA *srna) static void def_cmp_rotate(StructRNA *srna)

View File

@ -28,6 +28,8 @@
namespace blender::nodes::node_composite_scale_cc { namespace blender::nodes::node_composite_scale_cc {
NODE_STORAGE_FUNCS(NodeScaleData)
static void cmp_node_scale_declare(NodeDeclarationBuilder &b) static void cmp_node_scale_declare(NodeDeclarationBuilder &b)
{ {
b.add_input<decl::Color>("Image") b.add_input<decl::Color>("Image")
@ -46,6 +48,12 @@ static void cmp_node_scale_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>("Image"); b.add_output<decl::Color>("Image");
} }
static void node_composit_init_scale(bNodeTree * /*ntree*/, bNode *node)
{
NodeScaleData *data = MEM_cnew<NodeScaleData>(__func__);
node->storage = data;
}
static void node_composite_update_scale(bNodeTree *ntree, bNode *node) static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
{ {
bool use_xy_scale = ELEM(node->custom1, CMP_NODE_SCALE_RELATIVE, CMP_NODE_SCALE_ABSOLUTE); bool use_xy_scale = ELEM(node->custom1, CMP_NODE_SCALE_RELATIVE, CMP_NODE_SCALE_ABSOLUTE);
@ -60,6 +68,7 @@ static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
static void node_composit_buts_scale(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) static void node_composit_buts_scale(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{ {
uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
if (RNA_enum_get(ptr, "space") == CMP_NODE_SCALE_RENDER_SIZE) { if (RNA_enum_get(ptr, "space") == CMP_NODE_SCALE_RENDER_SIZE) {
@ -93,7 +102,10 @@ class ScaleOperation : public NodeOperation {
const float3x3 transformation = math::from_loc_rot_scale<float3x3>( const float3x3 transformation = math::from_loc_rot_scale<float3x3>(
translation, rotation, scale); translation, rotation, scale);
transform(context(), input, output, transformation, input.get_realization_options()); RealizationOptions realization_options = input.get_realization_options();
realization_options.interpolation = get_interpolation();
transform(context(), input, output, transformation, realization_options);
} }
float2 get_scale() float2 get_scale()
@ -113,6 +125,21 @@ class ScaleOperation : public NodeOperation {
} }
} }
Interpolation get_interpolation()
{
switch (node_storage(bnode()).interpolation) {
case 0:
return Interpolation::Nearest;
case 1:
return Interpolation::Bilinear;
case 2:
return Interpolation::Bicubic;
}
BLI_assert_unreachable();
return Interpolation::Nearest;
}
/* Scale by the input factors. */ /* Scale by the input factors. */
float2 get_scale_relative() float2 get_scale_relative()
{ {
@ -201,17 +228,17 @@ class ScaleOperation : public NodeOperation {
CMPNodeScaleMethod get_scale_method() CMPNodeScaleMethod get_scale_method()
{ {
return (CMPNodeScaleMethod)bnode().custom1; return (CMPNodeScaleMethod)node_storage(bnode()).space;
} }
CMPNodeScaleRenderSizeMethod get_scale_render_size_method() CMPNodeScaleRenderSizeMethod get_scale_render_size_method()
{ {
return (CMPNodeScaleRenderSizeMethod)bnode().custom2; return (CMPNodeScaleRenderSizeMethod)node_storage(bnode()).frame_method;
} }
float2 get_offset() float2 get_offset()
{ {
return float2(bnode().custom3, bnode().custom4); return float2(node_storage(bnode()).offset_x, node_storage(bnode()).offset_y);
} }
}; };
@ -233,6 +260,7 @@ void register_node_type_cmp_scale()
ntype.draw_buttons = file_ns::node_composit_buts_scale; ntype.draw_buttons = file_ns::node_composit_buts_scale;
ntype.updatefunc = file_ns::node_composite_update_scale; ntype.updatefunc = file_ns::node_composite_update_scale;
ntype.get_compositor_operation = file_ns::get_compositor_operation; ntype.get_compositor_operation = file_ns::get_compositor_operation;
ntype.initfunc = file_ns::node_composit_init_scale;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }