This patch makes a distinction between passes accessed through nodes like the Render Layers node, and inputs accessed through nodes like the Group Input node. Previously, the Group Input node returned the passes of the active scene and view layer accordingly to the name, while now, it only returns the Image (Combined) pass and the result will be zeros. Pull Request: https://projects.blender.org/blender/blender/pulls/146831
241 lines
6.8 KiB
C++
241 lines
6.8 KiB
C++
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup sequencer
|
|
*/
|
|
|
|
#include "BLI_math_base.h"
|
|
#include "BLI_rect.h"
|
|
|
|
#include "BLT_translation.hh"
|
|
|
|
#include "COM_context.hh"
|
|
#include "COM_domain.hh"
|
|
#include "COM_evaluator.hh"
|
|
|
|
#include "DNA_sequence_types.h"
|
|
|
|
#include "DEG_depsgraph_query.hh"
|
|
|
|
#include "IMB_colormanagement.hh"
|
|
|
|
#include "SEQ_modifier.hh"
|
|
#include "SEQ_modifiertypes.hh"
|
|
#include "SEQ_render.hh"
|
|
|
|
#include "UI_interface.hh"
|
|
#include "UI_interface_layout.hh"
|
|
|
|
#include "RNA_access.hh"
|
|
|
|
#include "modifier.hh"
|
|
#include "render.hh"
|
|
|
|
namespace blender::seq {
|
|
|
|
class CompositorContext : public compositor::Context {
|
|
private:
|
|
const RenderData &render_data_;
|
|
const SequencerCompositorModifierData *modifier_data_;
|
|
|
|
ImBuf *image_buffer_;
|
|
ImBuf *mask_buffer_;
|
|
|
|
public:
|
|
CompositorContext(const RenderData &render_data,
|
|
const SequencerCompositorModifierData *modifier_data,
|
|
ImBuf *image_buffer,
|
|
ImBuf *mask_buffer)
|
|
: compositor::Context(),
|
|
render_data_(render_data),
|
|
modifier_data_(modifier_data),
|
|
image_buffer_(image_buffer),
|
|
mask_buffer_(mask_buffer)
|
|
{
|
|
}
|
|
|
|
const Scene &get_scene() const override
|
|
{
|
|
return *render_data_.scene;
|
|
}
|
|
|
|
const bNodeTree &get_node_tree() const override
|
|
{
|
|
return *DEG_get_evaluated<bNodeTree>(render_data_.depsgraph, modifier_data_->node_group);
|
|
}
|
|
|
|
compositor::OutputTypes needed_outputs() const override
|
|
{
|
|
compositor::OutputTypes needed_outputs = compositor::OutputTypes::Composite;
|
|
if (!render_data_.for_render) {
|
|
needed_outputs |= compositor::OutputTypes::Viewer;
|
|
}
|
|
return needed_outputs;
|
|
}
|
|
|
|
bool treat_viewer_as_compositor_output() const override
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Bounds<int2> get_compositing_region() const override
|
|
{
|
|
return Bounds<int2>(int2(0), int2(image_buffer_->x, image_buffer_->y));
|
|
}
|
|
|
|
compositor::Result get_output() override
|
|
{
|
|
compositor::Result result = this->create_result(compositor::ResultType::Color);
|
|
result.wrap_external(image_buffer_->float_buffer.data,
|
|
int2(image_buffer_->x, image_buffer_->y));
|
|
return result;
|
|
}
|
|
|
|
compositor::Result get_viewer_output(compositor::Domain /*domain*/,
|
|
bool /*is_data*/,
|
|
compositor::ResultPrecision /*precision*/) override
|
|
{
|
|
compositor::Result result = this->create_result(compositor::ResultType::Color);
|
|
result.wrap_external(image_buffer_->float_buffer.data,
|
|
int2(image_buffer_->x, image_buffer_->y));
|
|
return result;
|
|
}
|
|
|
|
compositor::Result get_input(StringRef name) override
|
|
{
|
|
compositor::Result result = this->create_result(compositor::ResultType::Color);
|
|
|
|
if (name == "Image") {
|
|
result.wrap_external(image_buffer_->float_buffer.data,
|
|
int2(image_buffer_->x, image_buffer_->y));
|
|
}
|
|
else if (name == "Mask" && mask_buffer_) {
|
|
result.wrap_external(mask_buffer_->float_buffer.data,
|
|
int2(mask_buffer_->x, mask_buffer_->y));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool use_gpu() const override
|
|
{
|
|
return false;
|
|
}
|
|
};
|
|
|
|
static void compositor_modifier_init_data(StripModifierData *strip_modifier_data)
|
|
{
|
|
SequencerCompositorModifierData *modifier_data =
|
|
reinterpret_cast<SequencerCompositorModifierData *>(strip_modifier_data);
|
|
modifier_data->node_group = nullptr;
|
|
}
|
|
|
|
static bool ensure_linear_float_buffer(ImBuf *ibuf)
|
|
{
|
|
if (!ibuf) {
|
|
return false;
|
|
}
|
|
|
|
/* Already have scene linear float pixels, nothing to do. */
|
|
if (ibuf->float_buffer.data &&
|
|
IMB_colormanagement_space_is_scene_linear(ibuf->float_buffer.colorspace))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (ibuf->float_buffer.data == nullptr) {
|
|
IMB_float_from_byte(ibuf);
|
|
}
|
|
else {
|
|
const char *from_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
|
|
const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(
|
|
COLOR_ROLE_SCENE_LINEAR);
|
|
IMB_colormanagement_transform_float(ibuf->float_buffer.data,
|
|
ibuf->x,
|
|
ibuf->y,
|
|
ibuf->channels,
|
|
from_colorspace,
|
|
to_colorspace,
|
|
true);
|
|
IMB_colormanagement_assign_float_colorspace(ibuf, to_colorspace);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void compositor_modifier_apply(const RenderData *render_data,
|
|
const StripScreenQuad & /*quad*/,
|
|
StripModifierData *strip_modifier_data,
|
|
ImBuf *image_buffer,
|
|
ImBuf *mask)
|
|
{
|
|
const SequencerCompositorModifierData *modifier_data =
|
|
reinterpret_cast<SequencerCompositorModifierData *>(strip_modifier_data);
|
|
if (!modifier_data->node_group) {
|
|
return;
|
|
}
|
|
|
|
ensure_linear_float_buffer(mask);
|
|
const bool was_float_linear = ensure_linear_float_buffer(image_buffer);
|
|
const bool was_byte = image_buffer->float_buffer.data == nullptr;
|
|
|
|
CompositorContext context(*render_data, modifier_data, image_buffer, mask);
|
|
compositor::Evaluator evaluator(context);
|
|
evaluator.evaluate();
|
|
|
|
if (was_float_linear) {
|
|
return;
|
|
}
|
|
|
|
if (was_byte) {
|
|
IMB_byte_from_float(image_buffer);
|
|
IMB_free_float_pixels(image_buffer);
|
|
}
|
|
else {
|
|
seq_imbuf_to_sequencer_space(render_data->scene, image_buffer, true);
|
|
}
|
|
}
|
|
|
|
static void compositor_modifier_panel_draw(const bContext *C, Panel *panel)
|
|
{
|
|
uiLayout *layout = panel->layout;
|
|
PointerRNA *ptr = UI_panel_custom_data_get(panel);
|
|
|
|
layout->use_property_split_set(true);
|
|
|
|
uiTemplateID(layout,
|
|
C,
|
|
ptr,
|
|
"node_group",
|
|
"NODE_OT_new_compositor_sequencer_node_group",
|
|
nullptr,
|
|
nullptr);
|
|
|
|
if (uiLayout *mask_input_layout = layout->panel_prop(
|
|
C, ptr, "open_mask_input_panel", IFACE_("Mask Input")))
|
|
{
|
|
draw_mask_input_type_settings(C, mask_input_layout, ptr);
|
|
}
|
|
}
|
|
|
|
static void compositor_modifier_register(ARegionType *region_type)
|
|
{
|
|
modifier_panel_register(
|
|
region_type, eSeqModifierType_Compositor, compositor_modifier_panel_draw);
|
|
}
|
|
|
|
StripModifierTypeInfo seqModifierType_Compositor = {
|
|
/*idname*/ "Compositor",
|
|
/*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Compositor"),
|
|
/*struct_name*/ "SequencerCompositorModifierData",
|
|
/*struct_size*/ sizeof(SequencerCompositorModifierData),
|
|
/*init_data*/ compositor_modifier_init_data,
|
|
/*free_data*/ nullptr,
|
|
/*copy_data*/ nullptr,
|
|
/*apply*/ compositor_modifier_apply,
|
|
/*panel_register*/ compositor_modifier_register,
|
|
};
|
|
|
|
}; // namespace blender::seq
|