This patch adds support for boolean sockets in the compositor. This involves adding a new Bool ResultType and handling it in relevant code. For shader operations, booleans are passes as floats since GPUMaterial does not yet support boolean types. Pull Request: https://projects.blender.org/blender/blender/pulls/136296
242 lines
7.2 KiB
C++
242 lines
7.2 KiB
C++
/* SPDX-FileCopyrightText: 2007 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup nodes
|
|
*/
|
|
|
|
#include "DNA_node_types.h"
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
|
|
#include "BKE_context.hh"
|
|
#include "BKE_global.hh"
|
|
#include "BKE_image.hh"
|
|
#include "BKE_main.hh"
|
|
#include "BKE_node.hh"
|
|
#include "BKE_node_runtime.hh"
|
|
#include "BKE_node_tree_update.hh"
|
|
#include "BKE_tracking.h"
|
|
|
|
#include "UI_resources.hh"
|
|
|
|
#include "node_common.h"
|
|
|
|
#include "RNA_prototypes.hh"
|
|
|
|
#include "NOD_composite.hh"
|
|
#include "node_composite_util.hh"
|
|
|
|
static void composite_get_from_context(const bContext *C,
|
|
blender::bke::bNodeTreeType * /*treetype*/,
|
|
bNodeTree **r_ntree,
|
|
ID **r_id,
|
|
ID **r_from)
|
|
{
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
*r_from = nullptr;
|
|
*r_id = &scene->id;
|
|
*r_ntree = scene->nodetree;
|
|
}
|
|
|
|
static void foreach_nodeclass(void *calldata, blender::bke::bNodeClassCallback func)
|
|
{
|
|
func(calldata, NODE_CLASS_INPUT, N_("Input"));
|
|
func(calldata, NODE_CLASS_OUTPUT, N_("Output"));
|
|
func(calldata, NODE_CLASS_OP_COLOR, N_("Color"));
|
|
func(calldata, NODE_CLASS_OP_VECTOR, N_("Vector"));
|
|
func(calldata, NODE_CLASS_OP_FILTER, N_("Filter"));
|
|
func(calldata, NODE_CLASS_CONVERTER, N_("Converter"));
|
|
func(calldata, NODE_CLASS_MATTE, N_("Matte"));
|
|
func(calldata, NODE_CLASS_DISTORT, N_("Distort"));
|
|
func(calldata, NODE_CLASS_GROUP, N_("Group"));
|
|
func(calldata, NODE_CLASS_INTERFACE, N_("Interface"));
|
|
func(calldata, NODE_CLASS_LAYOUT, N_("Layout"));
|
|
}
|
|
|
|
/* local tree then owns all compbufs */
|
|
static void localize(bNodeTree *localtree, bNodeTree *ntree)
|
|
{
|
|
|
|
bNode *node = (bNode *)ntree->nodes.first;
|
|
bNode *local_node = (bNode *)localtree->nodes.first;
|
|
while (node != nullptr) {
|
|
|
|
/* Ensure new user input gets handled ok. */
|
|
node->runtime->need_exec = 0;
|
|
local_node->runtime->original = node;
|
|
|
|
/* move over the compbufs */
|
|
/* right after #blender::bke::node_tree_copy_tree() `oldsock` pointers are valid */
|
|
|
|
if (node->type_legacy == CMP_NODE_VIEWER) {
|
|
if (node->id) {
|
|
if (node->flag & NODE_DO_OUTPUT) {
|
|
local_node->id = (ID *)node->id;
|
|
}
|
|
else {
|
|
local_node->id = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
node = node->next;
|
|
local_node = local_node->next;
|
|
}
|
|
}
|
|
|
|
static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
|
|
{
|
|
/* move over the compbufs and previews */
|
|
blender::bke::node_preview_merge_tree(ntree, localtree, true);
|
|
|
|
LISTBASE_FOREACH (bNode *, lnode, &localtree->nodes) {
|
|
if (bNode *orig_node = blender::bke::node_find_node_by_name(*ntree, lnode->name)) {
|
|
if (lnode->type_legacy == CMP_NODE_VIEWER) {
|
|
if (lnode->id && (lnode->flag & NODE_DO_OUTPUT)) {
|
|
/* image_merge does sanity check for pointers */
|
|
BKE_image_merge(bmain, (Image *)orig_node->id, (Image *)lnode->id);
|
|
}
|
|
}
|
|
else if (lnode->type_legacy == CMP_NODE_MOVIEDISTORTION) {
|
|
/* special case for distortion node: distortion context is allocating in exec function
|
|
* and to achieve much better performance on further calls this context should be
|
|
* copied back to original node */
|
|
if (lnode->storage) {
|
|
if (orig_node->storage) {
|
|
BKE_tracking_distortion_free((MovieDistortion *)orig_node->storage);
|
|
}
|
|
|
|
orig_node->storage = BKE_tracking_distortion_copy((MovieDistortion *)lnode->storage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void update(bNodeTree *ntree)
|
|
{
|
|
blender::bke::node_tree_set_output(*ntree);
|
|
|
|
ntree_update_reroute_nodes(ntree);
|
|
}
|
|
|
|
static void composite_node_add_init(bNodeTree * /*bnodetree*/, bNode *bnode)
|
|
{
|
|
/* Composite node will only show previews for input classes
|
|
* by default, other will be hidden
|
|
* but can be made visible with the show_preview option */
|
|
if (bnode->typeinfo->nclass != NODE_CLASS_INPUT) {
|
|
bnode->flag &= ~NODE_PREVIEW;
|
|
}
|
|
}
|
|
|
|
static bool composite_node_tree_socket_type_valid(blender::bke::bNodeTreeType * /*ntreetype*/,
|
|
blender::bke::bNodeSocketType *socket_type)
|
|
{
|
|
return blender::bke::node_is_static_socket_type(*socket_type) &&
|
|
ELEM(socket_type->type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
|
|
}
|
|
|
|
static bool composite_validate_link(eNodeSocketDatatype /*from*/, eNodeSocketDatatype /*to*/)
|
|
{
|
|
/* All supported types can be implicitly converted to other types. */
|
|
return true;
|
|
}
|
|
|
|
blender::bke::bNodeTreeType *ntreeType_Composite;
|
|
|
|
void register_node_tree_type_cmp()
|
|
{
|
|
blender::bke::bNodeTreeType *tt = ntreeType_Composite = MEM_new<blender::bke::bNodeTreeType>(
|
|
__func__);
|
|
|
|
tt->type = NTREE_COMPOSIT;
|
|
tt->idname = "CompositorNodeTree";
|
|
tt->group_idname = "CompositorNodeGroup";
|
|
tt->ui_name = N_("Compositor");
|
|
tt->ui_icon = ICON_NODE_COMPOSITING;
|
|
tt->ui_description = N_("Compositing nodes");
|
|
|
|
tt->foreach_nodeclass = foreach_nodeclass;
|
|
tt->localize = localize;
|
|
tt->local_merge = local_merge;
|
|
tt->update = update;
|
|
tt->get_from_context = composite_get_from_context;
|
|
tt->node_add_init = composite_node_add_init;
|
|
tt->validate_link = composite_validate_link;
|
|
tt->valid_socket_type = composite_node_tree_socket_type_valid;
|
|
|
|
tt->rna_ext.srna = &RNA_CompositorNodeTree;
|
|
|
|
blender::bke::node_tree_type_add(*tt);
|
|
}
|
|
|
|
/* *********************************************** */
|
|
|
|
void ntreeCompositUpdateRLayers(bNodeTree *ntree)
|
|
{
|
|
if (ntree == nullptr) {
|
|
return;
|
|
}
|
|
|
|
for (bNode *node : ntree->all_nodes()) {
|
|
if (node->type_legacy == CMP_NODE_R_LAYERS) {
|
|
node_cmp_rlayers_outputs(ntree, node);
|
|
}
|
|
else if (node->type_legacy == CMP_NODE_CRYPTOMATTE &&
|
|
node->custom1 == CMP_NODE_CRYPTOMATTE_SOURCE_RENDER)
|
|
{
|
|
node->typeinfo->updatefunc(ntree, node);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ntreeCompositTagRender(Scene *scene)
|
|
{
|
|
/* XXX Think using G_MAIN here is valid, since you want to update current file's scene nodes,
|
|
* not the ones in temp main generated for rendering?
|
|
* This is still rather weak though,
|
|
* ideally render struct would store its own main AND original G_MAIN. */
|
|
|
|
for (Scene *sce_iter = (Scene *)G_MAIN->scenes.first; sce_iter;
|
|
sce_iter = (Scene *)sce_iter->id.next)
|
|
{
|
|
if (sce_iter->nodetree) {
|
|
for (bNode *node : sce_iter->nodetree->all_nodes()) {
|
|
if (node->id == (ID *)scene || node->type_legacy == CMP_NODE_COMPOSITE) {
|
|
BKE_ntree_update_tag_node_property(sce_iter->nodetree, node);
|
|
}
|
|
else if (node->type_legacy == CMP_NODE_TEXTURE) /* uses scene size_x/size_y */ {
|
|
BKE_ntree_update_tag_node_property(sce_iter->nodetree, node);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
BKE_ntree_update(*G_MAIN);
|
|
}
|
|
|
|
void ntreeCompositClearTags(bNodeTree *ntree)
|
|
{
|
|
/* XXX: after render animation system gets a refresh, this call allows composite to end clean. */
|
|
|
|
if (ntree == nullptr) {
|
|
return;
|
|
}
|
|
|
|
for (bNode *node : ntree->all_nodes()) {
|
|
node->runtime->need_exec = 0;
|
|
if (node->is_group()) {
|
|
ntreeCompositClearTags((bNodeTree *)node->id);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ntreeCompositTagNeedExec(bNode *node)
|
|
{
|
|
node->runtime->need_exec = true;
|
|
}
|